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

Last change on this file was 15143, checked in by Mark Evenson, 4 years ago

Check for element type before filling vectors
(Olof-Joachim Frahm)

Addresses <https://github.com/armedbear/abcl/pull/104>.
Via <https://github.com/armedbear/abcl/pull/104/commits/762cb878a7273fbf82b4415456d88af378934063>.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 12.7 KB
Line 
1/*
2 * ComplexVector_UnsignedByte32.java
3 *
4 * Copyright (C) 2002-2005 Peter Graves
5 * $Id: ComplexVector_UnsignedByte32.java 15143 2019-11-01 21:23:12Z mevenson $
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 *
21 * As a special exception, the copyright holders of this library give you
22 * permission to link this library with independent modules to produce an
23 * executable, regardless of the license terms of these independent
24 * modules, and to copy and distribute the resulting executable under
25 * terms of your choice, provided that you also meet, for each linked
26 * independent module, the terms and conditions of the license of that
27 * module.  An independent module is a module which is not derived from
28 * or based on this library.  If you modify this library, you may extend
29 * this exception to your version of the library, but you are not
30 * obligated to do so.  If you do not wish to do so, delete this
31 * exception statement from your version.
32 */
33
34package org.armedbear.lisp;
35
36import static org.armedbear.lisp.Lisp.*;
37
38// A specialized vector of element type (UNSIGNED-BYTE 32) that is displaced to
39// another array, has a fill pointer, and/or is expressly adjustable.
40public final class ComplexVector_UnsignedByte32 extends AbstractVector
41{
42    private int capacity;
43    private int fillPointer = -1; // -1 indicates no fill pointer.
44    private boolean isDisplaced;
45
46    // For non-displaced arrays.
47    private LispObject[] elements;
48
49    // For displaced arrays.
50    private AbstractArray array;
51    private int displacement;
52
53    public ComplexVector_UnsignedByte32(int capacity)
54    {
55        elements = new LispObject[capacity];
56        for (int i = capacity; i-- > 0;)
57            elements[i] = Fixnum.ZERO;
58        this.capacity = capacity;
59    }
60
61    public ComplexVector_UnsignedByte32(int capacity, AbstractArray array,
62                                        int displacement)
63    {
64        this.capacity = capacity;
65        this.array = array;
66        this.displacement = displacement;
67        isDisplaced = true;
68    }
69
70    @Override
71    public LispObject typeOf()
72    {
73        return list(Symbol.VECTOR, UNSIGNED_BYTE_32, Fixnum.getInstance(capacity));
74    }
75
76    @Override
77    public LispObject classOf()
78    {
79        return BuiltInClass.VECTOR;
80    }
81
82    @Override
83    public boolean hasFillPointer()
84    {
85        return fillPointer >= 0;
86    }
87
88    @Override
89    public int getFillPointer()
90    {
91        return fillPointer;
92    }
93
94    @Override
95    public void setFillPointer(int n)
96    {
97        fillPointer = n;
98    }
99
100    @Override
101    public void setFillPointer(LispObject obj)
102    {
103        if (obj == T)
104            fillPointer = capacity();
105        else {
106            int n = Fixnum.getValue(obj);
107            if (n > capacity()) {
108                StringBuffer sb = new StringBuffer("The new fill pointer (");
109                sb.append(n);
110                sb.append(") exceeds the capacity of the vector (");
111                sb.append(capacity());
112                sb.append(").");
113                error(new LispError(sb.toString()));
114            } else if (n < 0) {
115                StringBuffer sb = new StringBuffer("The new fill pointer (");
116                sb.append(n);
117                sb.append(") is negative.");
118                error(new LispError(sb.toString()));
119            } else
120                fillPointer = n;
121        }
122    }
123
124    @Override
125    public boolean isDisplaced()
126    {
127        return isDisplaced;
128    }
129
130    @Override
131    public LispObject arrayDisplacement()
132    {
133        LispObject value1, value2;
134        if (array != null) {
135            value1 = array;
136            value2 = Fixnum.getInstance(displacement);
137        } else {
138            value1 = NIL;
139            value2 = Fixnum.ZERO;
140        }
141        return LispThread.currentThread().setValues(value1, value2);
142    }
143
144    @Override
145    public LispObject getElementType()
146    {
147        return UNSIGNED_BYTE_32;
148    }
149
150    @Override
151    public boolean isSimpleVector()
152    {
153        return false;
154    }
155
156    @Override
157    public int capacity()
158    {
159        return capacity;
160    }
161
162    @Override
163    public int length()
164    {
165        return fillPointer >= 0 ? fillPointer : capacity;
166    }
167
168    @Override
169    public LispObject elt(int index)
170    {
171        final int limit = length();
172        if (index < 0 || index >= limit)
173            badIndex(index, limit);
174        return AREF(index);
175    }
176
177    // Ignores fill pointer.
178    @Override
179    public LispObject AREF(int index)
180    {
181        if (elements != null) {
182            try {
183                return elements[index];
184            }
185            catch (ArrayIndexOutOfBoundsException e) {
186                badIndex(index, elements.length);
187                return NIL; // Not reached.
188            }
189        } else {
190            // Displaced array.
191            if (index < 0 || index >= capacity)
192                badIndex(index, capacity);
193            return array.AREF(index + displacement);
194        }
195    }
196
197    @Override
198    public void aset(int index, LispObject newValue)
199    {
200        if (elements != null) {
201            try {
202                elements[index] = newValue;
203            }
204            catch (ArrayIndexOutOfBoundsException e) {
205                badIndex(index, elements.length);
206            }
207        } else {
208            // Displaced array.
209            if (index < 0 || index >= capacity)
210                badIndex(index, capacity);
211            else
212                array.aset(index + displacement, newValue);
213        }
214    }
215
216    @Override
217    public LispObject subseq(int start, int end)
218    {
219        SimpleVector v = new SimpleVector(end - start);
220        int i = start, j = 0;
221        try {
222            while (i < end)
223                v.aset(j++, AREF(i++));
224            return v;
225        }
226        catch (ArrayIndexOutOfBoundsException e) {
227            return error(new TypeError("Array index out of bounds: " + i + "."));
228        }
229    }
230
231    @Override
232    public void fill(LispObject obj)
233    {
234        if (!(obj instanceof LispInteger)) {
235            type_error(obj, Symbol.INTEGER);
236            // Not reached.
237            return;
238        }
239        if (obj.isLessThan(Fixnum.ZERO) || obj.isGreaterThan(UNSIGNED_BYTE_32_MAX_VALUE)) {
240            type_error(obj, UNSIGNED_BYTE_32);
241        }
242        for (int i = capacity; i-- > 0;)
243            elements[i] = obj;
244    }
245
246    @Override
247    public void shrink(int n)
248    {
249        if (elements != null) {
250            if (n < elements.length) {
251                LispObject[] newArray = new LispObject[n];
252                System.arraycopy(elements, 0, newArray, 0, n);
253                elements = newArray;
254                capacity = n;
255                return;
256            }
257            if (n == elements.length)
258                return;
259        }
260        error(new LispError());
261    }
262
263    @Override
264    public LispObject reverse()
265    {
266        int length = length();
267        SimpleVector result = new SimpleVector(length);
268        int i, j;
269        for (i = 0, j = length - 1; i < length; i++, j--)
270            result.aset(i, AREF(j));
271        return result;
272    }
273
274    @Override
275    public LispObject nreverse()
276    {
277        if (elements != null) {
278            int i = 0;
279            int j = length() - 1;
280            while (i < j) {
281                LispObject temp = elements[i];
282                elements[i] = elements[j];
283                elements[j] = temp;
284                ++i;
285                --j;
286            }
287        } else {
288            // Displaced array.
289            int length = length();
290            LispObject[] data = new LispObject[length];
291            int i, j;
292            for (i = 0, j = length - 1; i < length; i++, j--)
293                data[i] = AREF(j);
294            elements = data;
295            capacity = length;
296            array = null;
297            displacement = 0;
298            isDisplaced = false;
299            fillPointer = -1;
300        }
301        return this;
302    }
303
304    @Override
305    public void vectorPushExtend(LispObject element)
306
307    {
308        if (fillPointer < 0)
309            noFillPointer();
310        if (fillPointer >= capacity) {
311            // Need to extend vector.
312            ensureCapacity(capacity * 2 + 1);
313        }
314        aset(fillPointer, element);
315        ++fillPointer;
316    }
317
318    @Override
319    public LispObject VECTOR_PUSH_EXTEND(LispObject element)
320
321    {
322        vectorPushExtend(element);
323        return Fixnum.getInstance(fillPointer - 1);
324    }
325
326    @Override
327    public LispObject VECTOR_PUSH_EXTEND(LispObject element, LispObject extension)
328
329    {
330        int ext = Fixnum.getValue(extension);
331        if (fillPointer < 0)
332            noFillPointer();
333        if (fillPointer >= capacity) {
334            // Need to extend vector.
335            ext = Math.max(ext, capacity + 1);
336            ensureCapacity(capacity + ext);
337        }
338        aset(fillPointer, element);
339        return Fixnum.getInstance(fillPointer++);
340    }
341
342    private final void ensureCapacity(int minCapacity)
343    {
344        if (elements != null) {
345            if (capacity < minCapacity) {
346                LispObject[] newArray = new LispObject[minCapacity];
347                System.arraycopy(elements, 0, newArray, 0, capacity);
348                elements = newArray;
349                capacity = minCapacity;
350            }
351        } else {
352            // Displaced array.
353            Debug.assertTrue(array != null);
354            if (capacity < minCapacity ||
355                array.getTotalSize() - displacement < minCapacity)
356            {
357                // Copy array.
358                elements = new LispObject[minCapacity];
359                final int limit =
360                    Math.min(capacity, array.getTotalSize() - displacement);
361                for (int i = 0; i < limit; i++)
362                    elements[i] = array.AREF(displacement + i);
363                capacity = minCapacity;
364                array = null;
365                displacement = 0;
366                isDisplaced = false;
367            }
368        }
369    }
370
371    @Override
372    public AbstractVector adjustArray(int newCapacity,
373                                       LispObject initialElement,
374                                       LispObject initialContents)
375
376    {
377        if (initialContents != null) {
378            // "If INITIAL-CONTENTS is supplied, it is treated as for MAKE-
379            // ARRAY. In this case none of the original contents of array
380            // appears in the resulting array."
381            LispObject[] newElements = new LispObject[newCapacity];
382            if (initialContents.listp()) {
383                LispObject list = initialContents;
384                for (int i = 0; i < newCapacity; i++) {
385                    newElements[i] = list.car();
386                    list = list.cdr();
387                }
388            } else if (initialContents.vectorp()) {
389                for (int i = 0; i < newCapacity; i++)
390                    newElements[i] = initialContents.elt(i);
391            } else
392                type_error(initialContents, Symbol.SEQUENCE);
393            elements = newElements;
394        } else {
395            if (elements == null) {
396                // Displaced array. Copy existing elements.
397                elements = new LispObject[newCapacity];
398                final int limit = Math.min(capacity, newCapacity);
399                for (int i = 0; i < limit; i++)
400                    elements[i] = array.AREF(displacement + i);
401            } else if (capacity != newCapacity) {
402                LispObject[] newElements = new LispObject[newCapacity];
403                System.arraycopy(elements, 0, newElements, 0,
404                                 Math.min(capacity, newCapacity));
405                elements = newElements;
406            }
407            // Initialize new elements (if aapplicable).
408            if (initialElement != null) {
409                for (int i = capacity; i < newCapacity; i++)
410                    elements[i] = initialElement;
411            }
412        }
413        capacity = newCapacity;
414        array = null;
415        displacement = 0;
416        isDisplaced = false;
417        return this;
418    }
419
420    @Override
421    public AbstractVector adjustArray(int newCapacity,
422                                       AbstractArray displacedTo,
423                                       int displacement)
424
425    {
426        capacity = newCapacity;
427        array = displacedTo;
428        this.displacement = displacement;
429        elements = null;
430        isDisplaced = true;
431        return this;
432    }
433}
Note: See TracBrowser for help on using the repository browser.