1 /*
2  * ComplexBitVector.java
3  *
4  * Copyright (C) 2003-2005 Peter Graves
5  * $Id$
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 
34 package org.armedbear.lisp;
35 
36 import static org.armedbear.lisp.Lisp.*;
37 
38 public final class ComplexBitVector extends AbstractBitVector
39 {
40     private int fillPointer = -1; // -1 indicates no fill pointer.
41     private boolean isDisplaced;
42 
43     // For displaced bit vectors.
44     private AbstractArray array;
45     private int displacement;
46 
ComplexBitVector(int capacity)47     public ComplexBitVector(int capacity)
48     {
49         this.capacity = capacity;
50         int size = capacity >>> 6;
51         if ((capacity & LONG_MASK) != 0)
52             ++size;
53         bits = new long[size];
54     }
55 
ComplexBitVector(int capacity, AbstractArray array, int displacement)56     public ComplexBitVector(int capacity, AbstractArray array, int displacement)
57     {
58         this.capacity = capacity;
59         this.array = array;
60         this.displacement = displacement;
61         isDisplaced = true;
62     }
63 
64     @Override
typeOf()65     public LispObject typeOf()
66     {
67         return list(Symbol.BIT_VECTOR, Fixnum.getInstance(capacity));
68     }
69 
70     @Override
hasFillPointer()71     public boolean hasFillPointer()
72     {
73         return fillPointer >= 0;
74     }
75 
76     @Override
getFillPointer()77     public int getFillPointer()
78     {
79         return fillPointer;
80     }
81 
82     @Override
setFillPointer(int n)83     public void setFillPointer(int n)
84     {
85         fillPointer = n;
86     }
87 
88     @Override
setFillPointer(LispObject obj)89     public void setFillPointer(LispObject obj)
90     {
91         if (obj == T)
92             fillPointer = capacity();
93         else {
94             int n = Fixnum.getValue(obj);
95             if (n > capacity()) {
96                 StringBuffer sb = new StringBuffer("The new fill pointer (");
97                 sb.append(n);
98                 sb.append(") exceeds the capacity of the vector (");
99                 sb.append(capacity());
100                 sb.append(").");
101                 error(new LispError(sb.toString()));
102             } else if (n < 0) {
103                 StringBuffer sb = new StringBuffer("The new fill pointer (");
104                 sb.append(n);
105                 sb.append(") is negative.");
106                 error(new LispError(sb.toString()));
107             } else
108                 fillPointer = n;
109         }
110     }
111 
112     @Override
arrayDisplacement()113     public LispObject arrayDisplacement()
114     {
115         LispObject value1, value2;
116         if (array != null) {
117             value1 = array;
118             value2 = Fixnum.getInstance(displacement);
119         } else {
120             value1 = NIL;
121             value2 = Fixnum.ZERO;
122         }
123         return LispThread.currentThread().setValues(value1, value2);
124     }
125 
126     @Override
length()127     public int length()
128     {
129         return fillPointer >= 0 ? fillPointer : capacity;
130     }
131 
132     @Override
elt(int index)133     public LispObject elt(int index)
134     {
135         if (index >= length())
136             badIndex(index, length());
137         return AREF(index);
138     }
139 
140     @Override
AREF(int index)141     public LispObject AREF(int index)
142     {
143         if (index < 0 || index >= capacity)
144             badIndex(index, capacity);
145         if (bits != null) {
146             int offset = index >> 6;
147             return (bits[offset] & (1L << index)) != 0 ? Fixnum.ONE : Fixnum.ZERO;
148         } else {
149             // Displaced bit vector.
150             return array.AREF(index + displacement);
151         }
152     }
153 
154     @Override
getBit(int index)155     protected int getBit(int index)
156     {
157         if (bits != null) {
158             int offset = index >> 6;
159             return (bits[offset] & (1L << index)) != 0 ? 1 : 0;
160         } else
161             return Fixnum.getValue(array.AREF(index + displacement));
162     }
163 
164     @Override
aset(int index, LispObject newValue)165     public void aset(int index, LispObject newValue)
166     {
167         if (index < 0 || index >= capacity)
168             badIndex(index, capacity);
169         if (newValue instanceof Fixnum) {
170             switch (((Fixnum)newValue).value) {
171                 case 0:
172                     if (bits != null) {
173                         final int offset = index >> 6;
174                         bits[offset] &= ~(1L << index);
175                     } else
176                         clearBit(index);
177                     return;
178                 case 1:
179                     if (bits != null) {
180                         final int offset = index >> 6;
181                         bits[offset] |= 1L << index;
182                     } else
183                         setBit(index);
184                     return;
185             }
186         }
187             // Fall through...
188         type_error(newValue, Symbol.BIT);
189     }
190 
191     @Override
setBit(int index)192     protected void setBit(int index)
193     {
194         if (bits != null) {
195             int offset = index >> 6;
196             bits[offset] |= 1L << index;
197         } else
198             array.aset(index + displacement, Fixnum.ONE);
199     }
200 
201     @Override
clearBit(int index)202     protected void clearBit(int index)
203     {
204         if (bits != null) {
205             int offset = index >> 6;
206             bits[offset] &= ~(1L << index);
207         } else
208             array.aset(index + displacement, Fixnum.ZERO);
209     }
210 
211     @Override
shrink(int n)212     public void shrink(int n)
213     {
214         if (bits != null) {
215             if (n < capacity) {
216                 int size = n >>> 6;
217                 if ((n & LONG_MASK) != 0)
218                     ++size;
219                 if (size < bits.length) {
220                     long[] newbits = new long[size];
221                     System.arraycopy(bits, 0, newbits, 0, size);
222                     bits = newbits;
223                 }
224                 capacity = n;
225                 return;
226             }
227             if (n == capacity)
228                 return;
229         }
230         error(new LispError());
231     }
232 
233     @Override
isSimpleVector()234     public boolean isSimpleVector()
235     {
236         return false;
237     }
238 
239     // FIXME
240     @Override
vectorPushExtend(LispObject element)241     public void vectorPushExtend(LispObject element)
242     {
243         final int fp = getFillPointer();
244         if (fp < 0)
245             noFillPointer();
246         if (fp >= capacity()) {
247             // Need to extend vector.
248             ensureCapacity(capacity() * 2 + 1);
249         }
250         aset(fp, element);
251         setFillPointer(fp + 1);
252     }
253 
254     // FIXME
255     @Override
VECTOR_PUSH_EXTEND(LispObject element)256     public LispObject VECTOR_PUSH_EXTEND(LispObject element)
257 
258     {
259         vectorPushExtend(element);
260         return Fixnum.getInstance(getFillPointer() - 1);
261     }
262 
263     // FIXME
264     @Override
VECTOR_PUSH_EXTEND(LispObject element, LispObject extension)265     public LispObject VECTOR_PUSH_EXTEND(LispObject element, LispObject extension)
266 
267     {
268         int ext = Fixnum.getValue(extension);
269         final int fp = getFillPointer();
270         if (fp < 0)
271             noFillPointer();
272         if (fp >= capacity()) {
273             // Need to extend vector.
274             ext = Math.max(ext, capacity() + 1);
275             ensureCapacity(capacity() + ext);
276         }
277         aset(fp, element);
278         setFillPointer(fp + 1);
279         return Fixnum.getInstance(fp);
280     }
281 
ensureCapacity(int minCapacity)282     private final void ensureCapacity(int minCapacity)
283     {
284         if (bits != null) {
285             if (capacity < minCapacity) {
286                 int size = minCapacity >>> 6;
287                 if ((minCapacity & LONG_MASK) != 0)
288                     ++size;
289                 long[] newBits = new long[size];
290                 System.arraycopy(bits, 0, newBits, 0, bits.length);
291                 bits = newBits;
292                 capacity = minCapacity;
293             }
294         } else {
295             Debug.assertTrue(array != null);
296             if (capacity < minCapacity ||
297                 array.getTotalSize() - displacement < minCapacity)
298             {
299                 // Copy array.
300                 int size = minCapacity >>> 6;
301                 if ((minCapacity & LONG_MASK) != 0)
302                     ++size;
303                 bits = new long[size];
304                 final int limit =
305                     Math.min(capacity, array.getTotalSize() - displacement);
306                 for (int i = 0; i < limit; i++) {
307                     int n = Fixnum.getValue(array.AREF(displacement + i));
308                     if (n == 1)
309                         setBit(i);
310                     else
311                         clearBit(i);
312                 }
313                 capacity = minCapacity;
314                 array = null;
315                 displacement = 0;
316                 isDisplaced = false;
317             }
318         }
319     }
320 
321     @Override
adjustArray(int newCapacity, LispObject initialElement, LispObject initialContents)322     public AbstractVector adjustArray(int newCapacity,
323                                        LispObject initialElement,
324                                        LispObject initialContents)
325 
326     {
327         if (bits == null) {
328             // Copy array.
329             int size = capacity >>> 6;
330             if ((capacity & LONG_MASK) != 0)
331                 ++size;
332             bits = new long[size];
333             for (int i = 0; i < capacity; i++) {
334                 int n = Fixnum.getValue(array.AREF(displacement + i));
335                 if (n == 1)
336                     setBit(i);
337                 else
338                     clearBit(i);
339             }
340             array = null;
341             displacement = 0;
342             isDisplaced = false;
343         }
344         if (capacity != newCapacity) {
345             int size = newCapacity >>> 6;
346             if ((newCapacity & LONG_MASK) != 0)
347                 ++size;
348             if (initialContents != null) {
349                 bits = new long[size];
350                 capacity = newCapacity;
351                 if (initialContents.listp()) {
352                     LispObject list = initialContents;
353                     for (int i = 0; i < newCapacity; i++) {
354                         aset(i, list.car());
355                         list = list.cdr();
356                     }
357                 } else if (initialContents.vectorp()) {
358                     for (int i = 0; i < newCapacity; i++)
359                         aset(i, initialContents.elt(i));
360                 } else
361                     type_error(initialContents, Symbol.SEQUENCE);
362             } else {
363                 long[] newBits = new long[size];
364                 System.arraycopy(bits, 0, newBits, 0,
365                                  Math.min(bits.length, newBits.length));
366                 bits = newBits;
367                 if (newCapacity > capacity && initialElement != null) {
368                     int n = Fixnum.getValue(initialElement);
369                     if (n == 1)
370                         for (int i = capacity; i < newCapacity; i++)
371                             setBit(i);
372                     else
373                         for (int i = capacity; i < newCapacity; i++)
374                             clearBit(i);
375                 }
376             }
377             capacity = newCapacity;
378         }
379         return this;
380     }
381 
382     @Override
adjustArray(int size, AbstractArray displacedTo, int displacement)383     public AbstractVector adjustArray(int size, AbstractArray displacedTo,
384                                        int displacement)
385 
386     {
387         capacity = size;
388         array = displacedTo;
389         this.displacement = displacement;
390         bits = null;
391         isDisplaced = true;
392         return this;
393     }
394 }
395