source: trunk/abcl/src/org/armedbear/lisp/ComplexArray_ByteBuffer.java

Last change on this file was 15481, checked in by Mark Evenson, 3 years ago

arrays: fix fail to reset position after relative access

The position of all buffers should always be zero. TODO how to
unintrusively make this assertion?

We fix new types specializing (or (unsigned-byte 8) (unsigned-byte
32)) in BasicVector_ByteBuffer, ComplexArray_ByteBuffer,
ComplexVector_ByteBuffer, and ComplexVector_IntBuffer for relative
accesses which always advance the position of the
underlying java.nio.Buffer subclass.

Fixes <https://github.com/armedbear/abcl/issues/345>.

File size: 9.4 KB
Line 
1/*
2 * ComplexArray_ByteBuffer.java
3 *
4 * Copyright (C) 2020 easye
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 *
20 * As a special exception, the copyright holders of this library give you
21 * permission to link this library with independent modules to produce an
22 * executable, regardless of the license terms of these independent
23 * modules, and to copy and distribute the resulting executable under
24 * terms of your choice, provided that you also meet, for each linked
25 * independent module, the terms and conditions of the license of that
26 * module.  An independent module is a module which is not derived from
27 * or based on this library.  If you modify this library, you may extend
28 * this exception to your version of the library, but you are not
29 * obligated to do so.  If you do not wish to do so, delete this
30 * exception statement from your version.
31 */
32
33package org.armedbear.lisp;
34
35import static org.armedbear.lisp.Lisp.*;
36
37import java.nio.ByteBuffer;
38
39public final class ComplexArray_ByteBuffer
40  extends AbstractArray
41{
42  private final int[] dimv;
43  private int totalSize;
44 
45  // For non-displaced arrays.
46  private ByteBuffer data;
47  private boolean directAllocation;
48
49  // For displaced arrays.
50  private AbstractArray array;
51  private int displacement;
52
53  public ComplexArray_ByteBuffer(int[] dimv) {
54    this(dimv, false);
55  }
56
57  public ComplexArray_ByteBuffer(int[] dimv, boolean directAllocation) {
58    this.dimv = dimv;
59    this.directAllocation = directAllocation;
60    totalSize = computeTotalSize(dimv);
61    if (directAllocation) {
62      data = ByteBuffer.allocateDirect(totalSize);
63    } else {
64      data = ByteBuffer.allocate(totalSize);
65    }
66  }
67
68  public ComplexArray_ByteBuffer(int[] dimv, LispObject initialContents) {
69    this(dimv, initialContents, false);
70  }
71
72  public ComplexArray_ByteBuffer(int[] dimv, LispObject initialContents, boolean directAllocation) {
73    this.dimv = dimv;
74    final int rank = dimv.length;
75    LispObject rest = initialContents;
76    this.directAllocation = directAllocation;
77    for (int i = 0; i < rank; i++) {
78      dimv[i] = rest.length();
79      rest = rest.elt(0);
80    }
81    totalSize = computeTotalSize(dimv);
82    if (directAllocation) {
83      data = ByteBuffer.allocateDirect(totalSize);
84    } else {
85      data = ByteBuffer.allocate(totalSize);
86    }
87    setInitialContents(0, dimv, initialContents, 0);
88  }
89
90  public ComplexArray_ByteBuffer(int[] dimv, AbstractArray array, int displacement) {
91    this(dimv, array, displacement, false);
92  }
93 
94  public ComplexArray_ByteBuffer(int[] dimv, AbstractArray array, int displacement, boolean directAllocation) {
95    this.dimv = dimv;
96    this.array = array;
97    this.displacement = displacement;
98    this.directAllocation = directAllocation;
99    totalSize = computeTotalSize(dimv);
100  }
101
102  private int setInitialContents(int axis, int[] dims, LispObject contents,
103                                 int index)
104
105  {
106    if (dims.length == 0) {
107      try {
108        data.put(index, coerceToJavaByte(contents));
109      }
110      catch (IndexOutOfBoundsException e) {
111        error(new LispError("Bad initial contents for array."));
112        return -1;
113      }
114      ++index;
115    } else {
116      int dim = dims[0];
117      if (dim != contents.length()) {
118        error(new LispError("Bad initial contents for array."));
119        return -1;
120      }
121      int[] newDims = new int[dims.length-1];
122      for (int i = 1; i < dims.length; i++)
123        newDims[i-1] = dims[i];
124      if (contents.listp()) {
125        for (int i = contents.length();i-- > 0;) {
126          LispObject content = contents.car();
127          index =
128            setInitialContents(axis + 1, newDims, content, index);
129          contents = contents.cdr();
130        }
131      } else {
132        AbstractVector v = checkVector(contents);
133        final int length = v.length();
134        for (int i = 0; i < length; i++) {
135          LispObject content = v.AREF(i);
136          index =
137            setInitialContents(axis + 1, newDims, content, index);
138        }
139      }
140    }
141    return index;
142  }
143
144  @Override
145  public LispObject typeOf()
146  {
147    return list(Symbol.ARRAY, UNSIGNED_BYTE_8, getDimensions());
148  }
149
150  @Override
151  public LispObject classOf()
152  {
153    return BuiltInClass.ARRAY;
154  }
155
156  @Override
157  public int getRank()
158  {
159    return dimv.length;
160  }
161
162  @Override
163  public LispObject getDimensions()
164  {
165    LispObject result = NIL;
166    for (int i = dimv.length; i-- > 0;)
167      result = new Cons(Fixnum.getInstance(dimv[i]), result);
168    return result;
169  }
170
171  @Override
172  public int getDimension(int n)
173  {
174    try {
175      return dimv[n];
176    }
177    catch (ArrayIndexOutOfBoundsException e) {
178      error(new TypeError("Bad array dimension " + n + "."));
179      return -1;
180    }
181  }
182
183  @Override
184  public LispObject getElementType()
185  {
186    return UNSIGNED_BYTE_8;
187  }
188
189  @Override
190  public int getTotalSize()
191  {
192    return totalSize;
193  }
194
195  @Override
196  public LispObject arrayDisplacement()
197  {
198    LispObject value1, value2;
199    if (array != null) {
200      value1 = array;
201      value2 = Fixnum.getInstance(displacement);
202    } else {
203      value1 = NIL;
204      value2 = Fixnum.ZERO;
205    }
206    return LispThread.currentThread().setValues(value1, value2);
207  }
208
209  @Override
210  public LispObject AREF(int index)
211  {
212    if (data != null) {
213      try {
214        return coerceFromJavaByte(data.get(index));
215      }
216      catch (IndexOutOfBoundsException e) {
217        return error(new TypeError("Bad row major index " + index + "."));
218      }
219    } else
220      return array.AREF(index + displacement);
221  }
222
223  @Override
224  public void aset(int index, LispObject newValue)
225  {
226    if (data != null) {
227      try {
228        data.put(index, coerceToJavaByte(newValue));
229      }
230      catch (IndexOutOfBoundsException e) {
231        error(new TypeError("Bad row major index " + index + "."));
232      }
233    } else
234      array.aset(index + displacement, newValue);
235  }
236
237  @Override
238  public void fill(LispObject obj)
239  {
240    if (!(obj instanceof Fixnum)) {
241      type_error(obj, Symbol.FIXNUM);
242      // Not reached.
243      return;
244    }
245    int n = ((Fixnum) obj).value;
246    if (n < 0 || n > 255) {
247      type_error(obj, UNSIGNED_BYTE_8);
248      // Not reached.
249      return;
250    }
251    if (data != null) {
252      for (int i = ((java.nio.Buffer)data).limit(); i-- > 0;)
253        data.put(i, (byte) n); // FIXME Faster!!
254    } else {
255      for (int i = totalSize; i-- > 0;)
256        aset(i, obj);
257    }
258  }
259
260  @Override
261  public String printObject()
262  {
263    if (Symbol.PRINT_READABLY.symbolValue() != NIL) {
264      error(new PrintNotReadable(list(Keyword.OBJECT, this)));
265      // Not reached.
266      return null;
267    }
268    return printObject(dimv);
269  }
270
271  int arrayTotalSize(int[] dims) {
272    int result = 0;
273    for (int dim : dims) {
274      result += dim;
275    }
276    return result;
277  }
278
279  // FIXME move me to someplace more general
280  public static void fill(ByteBuffer buffer, byte value) {
281    for (int i = 0; i < ((java.nio.Buffer)buffer).limit(); i++) {
282      buffer.put(i, value);
283    }
284  }
285
286  @Override
287  public AbstractArray adjustArray(int[] dims,
288                                   LispObject initialElement,
289                                   LispObject initialContents)
290  {
291    if (isAdjustable()) {
292      if (initialContents != null)
293        setInitialContents(0, dims, initialContents, 0);
294      else {
295        //### FIXME Take the easy way out: we don't want to reorganize
296        // all of the array code yet
297        //        SimpleArray_ByteBuffer newBuffer = new SimpleArray_ByteBuffer(dims);
298        ByteBuffer newBuffer;
299        if (directAllocation) {
300          newBuffer = ByteBuffer.allocateDirect(computeTotalSize(dims));
301        } else {
302          newBuffer = ByteBuffer.allocate(computeTotalSize(dims));
303        }
304        if (initialElement != null) {
305          fill(newBuffer, coerceToJavaByte(initialElement));           
306        }
307        this.data = newBuffer;
308
309        for (int i = 0; i < dims.length; i++)
310          dimv[i] = dims[i];
311      }
312      return this;
313    } else {
314      if (initialContents != null)
315        return new ComplexArray_ByteBuffer(dims, initialContents);
316      else {
317        ComplexArray_ByteBuffer newArray = new ComplexArray_ByteBuffer(dims);
318        if (initialElement != null)
319          newArray.fill(initialElement);
320        return newArray;
321      }
322    }
323  }
324
325  @Override
326  public AbstractArray adjustArray(int[] dims,
327                                   AbstractArray displacedTo,
328                                   int displacement)
329  {
330    if (isAdjustable()) {
331      for (int i = 0; i < dims.length; i++)
332        dimv[i] = dims[i];
333
334      this.data = null;
335      this.array = displacedTo;
336      this.displacement = displacement;
337      this.totalSize = computeTotalSize(dims);
338
339      return this;
340    } else {
341      ComplexArray_ByteBuffer a = new ComplexArray_ByteBuffer(dims, displacedTo, displacement);
342
343      return a;
344    }
345  }
346}
Note: See TracBrowser for help on using the repository browser.