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

Last change on this file was 15734, checked in by Mark Evenson, 8 months ago

Implement vector-to-vector REPLACE as a primitive

File size: 10.0 KB
Line 
1/*
2 * BasicVector_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;
38import java.nio.BufferOverflowException;
39
40
41// A basic vector is a specialized vector that is not displaced to another
42// array, has no fill pointer, and is not expressly adjustable.
43public final class BasicVector_ByteBuffer
44  extends AbstractVector
45{
46  private int capacity;
47  private ByteBuffer elements;
48  private boolean directAllocation;
49
50  public BasicVector_ByteBuffer(int capacity) {
51    this(capacity, false);
52  }
53 
54  public BasicVector_ByteBuffer(int capacity, boolean directAllocation) {
55    this.directAllocation = directAllocation;
56    if (directAllocation) {
57      elements = ByteBuffer.allocateDirect(capacity);
58    } else {
59      elements = ByteBuffer.allocate(capacity);
60    }
61    this.capacity = capacity;
62  }
63
64  public BasicVector_ByteBuffer(byte[] array, boolean directAllocation) {
65    capacity = array.length;
66    this.directAllocation = directAllocation; 
67    elements = ByteBuffer.wrap(array);
68    // ??? Note somehow that we were constructed from a wrapped primitive array
69  }
70 
71  public BasicVector_ByteBuffer(LispObject[] array, boolean directAllocation) {
72    // FIXME: for now we assume that we're being handled an array of
73    // primitive bytes
74    this.directAllocation = directAllocation;
75    capacity = array.length;
76    if (directAllocation) {
77      elements = ByteBuffer.allocateDirect(array.length);
78    } else {
79      elements = ByteBuffer.allocate(array.length);
80    }
81    for (int i = array.length; i-- > 0;) {
82      // Faster please!
83      elements.put(i, (byte)coerceToJavaByte(array[i]));
84    }
85  }
86
87  public BasicVector_ByteBuffer(ByteBuffer buffer, boolean directAllocation) {
88    elements = buffer;
89    this.directAllocation = directAllocation;
90    capacity = ((java.nio.Buffer)buffer).limit(); 
91  }
92
93  @Override
94  public LispObject typeOf() {
95    return list(Symbol.SIMPLE_ARRAY, UNSIGNED_BYTE_8,
96                new Cons(Fixnum.getInstance(capacity)));
97  }
98
99  @Override
100  public LispObject classOf() {
101    return BuiltInClass.VECTOR;
102  }
103
104  @Override
105  public LispObject typep(LispObject type) {
106    if (type == Symbol.SIMPLE_ARRAY)
107      return T;
108    if (type == BuiltInClass.SIMPLE_ARRAY)
109      return T;
110    return super.typep(type);
111  }
112
113  @Override
114  public LispObject getElementType() {
115    return UNSIGNED_BYTE_8;
116  }
117
118  @Override
119  public boolean isSimpleVector() {
120    return false;
121  }
122
123  @Override
124  public boolean hasFillPointer() {
125    return false;
126  }
127
128  @Override
129  public boolean isAdjustable() {
130    return false;
131  }
132
133  @Override
134  public int capacity() {
135    return capacity;
136  }
137
138  @Override
139  public int length() {
140    return capacity;
141  }
142
143  @Override
144  public LispObject elt(int index) {
145    try {
146      return coerceFromJavaByte(elements.get(index));
147    } catch (IndexOutOfBoundsException e) {
148      badIndex(index, capacity);
149      return NIL; // Not reached.
150    }
151  }
152
153  @Override
154  public int aref(int index) {
155    try {
156      return (((int)elements.get(index) & 0xff)); // XXX Hmmm
157    } catch (IndexOutOfBoundsException e) {
158      badIndex(index, ((java.nio.Buffer)elements).limit()); 
159      // Not reached.
160      return 0;
161    }
162  }
163
164  @Override
165  public LispObject AREF(int index) {
166    try {
167      return coerceFromJavaByte(elements.get(index));
168    } catch (IndexOutOfBoundsException e) {
169      badIndex(index, ((java.nio.Buffer)elements).limit()); 
170      return NIL; // Not reached.
171    }
172  }
173
174  @Override
175  public void aset(int index, int n) {
176    try {
177      elements.put(index, (byte) n);
178    } catch (IndexOutOfBoundsException e) {
179      badIndex(index, capacity);
180    }
181  }
182
183  @Override
184  public void aset(int index, LispObject value) {
185    try {
186        elements.put(index, coerceToJavaByte(value));
187    } catch (IndexOutOfBoundsException e) {
188      badIndex(index, capacity);
189    }
190  }
191
192  @Override
193  public LispObject subseq(int start, int end) {
194    // ??? Do we need to check that start, end are valid?
195    BasicVector_ByteBuffer v = new BasicVector_ByteBuffer(end - start, directAllocation);
196    ByteBuffer view = elements.asReadOnlyBuffer();
197    ((java.nio.Buffer)view).position(start);
198    ((java.nio.Buffer)view).limit(end);
199    try {
200      v.elements.put(view);
201      v.elements.position(0);
202      return v;
203    } catch (BufferOverflowException e) {
204      return error(new TypeError("Could not form a subseq from " + start + " to " + end));
205    }
206  }
207
208  @Override
209  public void fill(LispObject obj) {
210    if (!(obj instanceof Fixnum)) {
211      type_error(obj, Symbol.FIXNUM);
212      // Not reached.
213      return;
214    }
215    int n = ((Fixnum) obj).value;
216    if (n < 0 || n > 255) {
217      type_error(obj, UNSIGNED_BYTE_8);
218      // Not reached.
219      return;
220    }
221
222    for (int i = length(); i-- > 0;) {
223      elements.put(i, (byte) n);
224    }
225  }
226
227  @Override
228  public void shrink(int n) {
229    // One cannot shrink a ByteBuffer physically, and the elements
230    // field may refer to malloc()d memory that we shouldn't touch, so
231    // use the java.nio.Buffer limit pointer.  Not totally sure that
232    // this strategy will work out

233    if (n < length()) {
234        ((java.nio.Buffer)elements).limit(n);
235        capacity = n;
236        return;
237    }
238    if (n == length()) {
239      return;
240    }
241    error(new LispError("Attempted to shrink an array to a size greater than its capacity"));
242  }
243
244  @Override
245  public LispObject reverse() {
246    BasicVector_ByteBuffer result = new BasicVector_ByteBuffer(length(), directAllocation);
247    int i, j;
248    for (i = 0, j = length() - 1; i < length(); i++, j--) {
249      result.elements.put(i, elements.get(j));
250    }
251    return result;
252  }
253
254  @Override
255  public LispObject nreverse() {
256    int i = 0;
257    int j = capacity() - 1;
258    while (i < j) {
259      byte temp = elements.get(i);
260      elements.put(i, elements.get(j));
261      elements.put(j, temp);
262      ++i;
263      --j;
264    }
265    return this;
266  }
267
268  @Override
269  public AbstractVector adjustArray(int newCapacity,
270                                    LispObject initialElement,
271                                    LispObject initialContents) {
272    if (initialContents != null) {
273      ByteBuffer newElements;
274      if (directAllocation) {
275        newElements = ByteBuffer.allocateDirect(newCapacity);
276      } else {
277        newElements = ByteBuffer.allocate(newCapacity);
278      }
279
280      if (initialContents.listp()) {
281        LispObject list = initialContents;
282        for (int i = 0; i < newCapacity; i++) {
283          newElements.put(i, coerceToJavaByte(list.car()));
284          list = list.cdr();
285        }
286      } else if (initialContents.vectorp()) {
287        for (int i = 0; i < newCapacity; i++)
288          newElements.put(i, coerceToJavaByte(initialContents.elt(i)));
289      } else
290        type_error(initialContents, Symbol.SEQUENCE);
291      return new BasicVector_ByteBuffer(newElements, directAllocation);
292    }
293    if (length() != newCapacity) {
294      ByteBuffer newElements;
295      if (directAllocation) {
296        newElements = ByteBuffer.allocateDirect(newCapacity);
297      } else {
298        newElements = ByteBuffer.allocate(newCapacity);
299      }
300
301      if (elements.hasArray()) {
302        newElements.put(elements.array(), 0, Math.min(length(), newCapacity));
303      } else {
304        // FIXME: a more efficient version when we don't have a backing array
305        int limit = Math.min(length(), newCapacity);
306        for (int i = 0; i < limit; i++) {
307          newElements.put(i, elements.get(i));
308        }
309      }
310       
311      if (initialElement != null) {
312        byte initValue = (byte)(initialElement.intValue() & 0xFF);
313        for (int i = length(); i < newCapacity; i++)
314          newElements.put(i, initValue);
315      }
316      return new BasicVector_ByteBuffer(newElements, directAllocation);
317    }
318    // No change.
319    return this;
320  }
321
322  @Override
323  public AbstractVector adjustArray(int newCapacity,
324                                    AbstractArray displacedTo,
325                                    int displacement) {
326    return new ComplexVector(newCapacity, displacedTo, displacement);
327  }
328
329  @Override
330  public AbstractVector replace(AbstractVector source,
331                                int targetStart, int targetEnd,
332                                int sourceStart, int sourceEnd)
333  {
334    if (source instanceof BasicVector_ByteBuffer) {
335      ByteBuffer view = ((BasicVector_ByteBuffer)source).elements.asReadOnlyBuffer();
336      view.position(sourceStart);
337      view.limit(sourceEnd);
338      elements.position(targetStart);
339      elements.put(view);
340      elements.position(0);
341      return this;
342    } else {
343      return super.replace(source, targetStart, targetEnd, sourceStart, sourceEnd);
344    }
345  }
346}
Note: See TracBrowser for help on using the repository browser.