1 /* 2 * ComplexVector.java 3 * 4 * Copyright (C) 2002-2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 // A vector that is displaced to another array, has a fill pointer, and/or is 39 // expressly adjustable. It can hold elements of any type. 40 public final class ComplexVector 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 ComplexVector(int capacity)53 public ComplexVector(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 ComplexVector(int capacity, AbstractArray array, int displacement)61 public ComplexVector(int capacity, AbstractArray array, int displacement) 62 { 63 this.capacity = capacity; 64 this.array = array; 65 this.displacement = displacement; 66 isDisplaced = true; 67 } 68 69 @Override typeOf()70 public LispObject typeOf() 71 { 72 return list(Symbol.VECTOR, T, Fixnum.getInstance(capacity)); 73 } 74 75 @Override classOf()76 public LispObject classOf() 77 { 78 return BuiltInClass.VECTOR; 79 } 80 81 @Override hasFillPointer()82 public boolean hasFillPointer() 83 { 84 return fillPointer >= 0; 85 } 86 87 @Override getFillPointer()88 public int getFillPointer() 89 { 90 return fillPointer; 91 } 92 93 @Override setFillPointer(int n)94 public void setFillPointer(int n) 95 { 96 fillPointer = n; 97 } 98 99 @Override setFillPointer(LispObject obj)100 public void setFillPointer(LispObject obj) 101 { 102 if (obj == T) 103 fillPointer = capacity(); 104 else { 105 int n = Fixnum.getValue(obj); 106 if (n > capacity()) { 107 StringBuffer sb = new StringBuffer("The new fill pointer ("); 108 sb.append(n); 109 sb.append(") exceeds the capacity of the vector ("); 110 sb.append(capacity()); 111 sb.append(")."); 112 error(new LispError(sb.toString())); 113 } else if (n < 0) { 114 StringBuffer sb = new StringBuffer("The new fill pointer ("); 115 sb.append(n); 116 sb.append(") is negative."); 117 error(new LispError(sb.toString())); 118 } else 119 fillPointer = n; 120 } 121 } 122 123 @Override isDisplaced()124 public boolean isDisplaced() 125 { 126 return isDisplaced; 127 } 128 129 @Override arrayDisplacement()130 public LispObject arrayDisplacement() 131 { 132 LispObject value1, value2; 133 if (array != null) { 134 value1 = array; 135 value2 = Fixnum.getInstance(displacement); 136 } else { 137 value1 = NIL; 138 value2 = Fixnum.ZERO; 139 } 140 return LispThread.currentThread().setValues(value1, value2); 141 } 142 143 @Override getElementType()144 public LispObject getElementType() 145 { 146 return T; 147 } 148 149 @Override isSimpleVector()150 public boolean isSimpleVector() 151 { 152 return false; 153 } 154 155 @Override capacity()156 public int capacity() 157 { 158 return capacity; 159 } 160 161 @Override length()162 public int length() 163 { 164 return fillPointer >= 0 ? fillPointer : capacity; 165 } 166 167 @Override elt(int index)168 public LispObject elt(int index) 169 { 170 final int limit = length(); 171 if (index < 0 || index >= limit) 172 badIndex(index, limit); 173 return AREF(index); 174 } 175 176 // Ignores fill pointer. 177 @Override AREF(int index)178 public LispObject AREF(int index) 179 { 180 if (elements != null) { 181 try { 182 return elements[index]; 183 } 184 catch (ArrayIndexOutOfBoundsException e) { 185 badIndex(index, elements.length); 186 return NIL; // Not reached. 187 } 188 } else { 189 // Displaced array. 190 if (index < 0 || index >= capacity) 191 badIndex(index, capacity); 192 return array.AREF(index + displacement); 193 } 194 } 195 196 @Override aset(int index, LispObject newValue)197 public void aset(int index, LispObject newValue) 198 { 199 if (elements != null) { 200 try { 201 elements[index] = newValue; 202 } 203 catch (ArrayIndexOutOfBoundsException e) { 204 badIndex(index, elements.length); 205 } 206 } else { 207 // Displaced array. 208 if (index < 0 || index >= capacity) 209 badIndex(index, capacity); 210 else 211 array.aset(index + displacement, newValue); 212 } 213 } 214 215 @Override subseq(int start, int end)216 public LispObject subseq(int start, int end) 217 { 218 SimpleVector v = new SimpleVector(end - start); 219 int i = start, j = 0; 220 try { 221 while (i < end) 222 v.aset(j++, AREF(i++)); 223 return v; 224 } 225 catch (ArrayIndexOutOfBoundsException e) { 226 return error(new TypeError("Array index out of bounds: " + i + ".")); 227 } 228 } 229 230 @Override fill(LispObject obj)231 public void fill(LispObject obj) 232 { 233 for (int i = capacity; i-- > 0;) 234 elements[i] = obj; 235 } 236 237 @Override shrink(int n)238 public void shrink(int n) 239 { 240 if (elements != null) { 241 if (n < elements.length) { 242 LispObject[] newArray = new LispObject[n]; 243 System.arraycopy(elements, 0, newArray, 0, n); 244 elements = newArray; 245 capacity = n; 246 return; 247 } 248 if (n == elements.length) 249 return; 250 } 251 error(new LispError()); 252 } 253 254 @Override reverse()255 public LispObject reverse() 256 { 257 int length = length(); 258 SimpleVector result = new SimpleVector(length); 259 int i, j; 260 for (i = 0, j = length - 1; i < length; i++, j--) 261 result.aset(i, AREF(j)); 262 return result; 263 } 264 265 @Override nreverse()266 public LispObject nreverse() 267 { 268 if (elements != null) { 269 int i = 0; 270 int j = length() - 1; 271 while (i < j) { 272 LispObject temp = elements[i]; 273 elements[i] = elements[j]; 274 elements[j] = temp; 275 ++i; 276 --j; 277 } 278 } else { 279 // Displaced array. 280 int length = length(); 281 LispObject[] data = new LispObject[length]; 282 int i, j; 283 for (i = 0, j = length - 1; i < length; i++, j--) 284 data[i] = AREF(j); 285 elements = data; 286 capacity = length; 287 array = null; 288 displacement = 0; 289 isDisplaced = false; 290 fillPointer = -1; 291 } 292 return this; 293 } 294 295 @Override vectorPushExtend(LispObject element)296 public void vectorPushExtend(LispObject element) 297 298 { 299 if (fillPointer < 0) 300 noFillPointer(); 301 if (fillPointer >= capacity) { 302 // Need to extend vector. 303 ensureCapacity(capacity * 2 + 1); 304 } 305 aset(fillPointer++, element); 306 } 307 308 @Override VECTOR_PUSH_EXTEND(LispObject element)309 public LispObject VECTOR_PUSH_EXTEND(LispObject element) 310 311 { 312 vectorPushExtend(element); 313 return Fixnum.getInstance(fillPointer - 1); 314 } 315 316 @Override VECTOR_PUSH_EXTEND(LispObject element, LispObject extension)317 public LispObject VECTOR_PUSH_EXTEND(LispObject element, LispObject extension) 318 319 { 320 int ext = Fixnum.getValue(extension); 321 if (fillPointer < 0) 322 noFillPointer(); 323 if (fillPointer >= capacity) { 324 // Need to extend vector. 325 ext = Math.max(ext, capacity + 1); 326 ensureCapacity(capacity + ext); 327 } 328 aset(fillPointer, element); 329 return Fixnum.getInstance(fillPointer++); 330 } 331 ensureCapacity(int minCapacity)332 private final void ensureCapacity(int minCapacity) 333 { 334 if (elements != null) { 335 if (capacity < minCapacity) { 336 LispObject[] newArray = new LispObject[minCapacity]; 337 System.arraycopy(elements, 0, newArray, 0, capacity); 338 elements = newArray; 339 capacity = minCapacity; 340 } 341 } else { 342 // Displaced array. 343 Debug.assertTrue(array != null); 344 if (capacity < minCapacity || 345 array.getTotalSize() - displacement < minCapacity) 346 { 347 // Copy array. 348 elements = new LispObject[minCapacity]; 349 final int limit = 350 Math.min(capacity, array.getTotalSize() - displacement); 351 for (int i = 0; i < limit; i++) 352 elements[i] = array.AREF(displacement + i); 353 capacity = minCapacity; 354 array = null; 355 displacement = 0; 356 isDisplaced = false; 357 } 358 } 359 } 360 361 @Override adjustArray(int newCapacity, LispObject initialElement, LispObject initialContents)362 public AbstractVector adjustArray(int newCapacity, 363 LispObject initialElement, 364 LispObject initialContents) 365 366 { 367 if (initialContents != null) { 368 // "If INITIAL-CONTENTS is supplied, it is treated as for MAKE- 369 // ARRAY. In this case none of the original contents of array 370 // appears in the resulting array." 371 LispObject[] newElements = new LispObject[newCapacity]; 372 if (initialContents.listp()) { 373 LispObject list = initialContents; 374 for (int i = 0; i < newCapacity; i++) { 375 newElements[i] = list.car(); 376 list = list.cdr(); 377 } 378 } else if (initialContents.vectorp()) { 379 for (int i = 0; i < newCapacity; i++) 380 newElements[i] = initialContents.elt(i); 381 } else 382 type_error(initialContents, Symbol.SEQUENCE); 383 elements = newElements; 384 } else { 385 if (elements == null) { 386 // Displaced array. Copy existing elements. 387 elements = new LispObject[newCapacity]; 388 final int limit = Math.min(capacity, newCapacity); 389 for (int i = 0; i < limit; i++) 390 elements[i] = array.AREF(displacement + i); 391 } else if (capacity != newCapacity) { 392 LispObject[] newElements = new LispObject[newCapacity]; 393 System.arraycopy(elements, 0, newElements, 0, 394 Math.min(capacity, newCapacity)); 395 elements = newElements; 396 } 397 // Initialize new elements (if any). 398 if (initialElement != null) 399 for (int i = capacity; i < newCapacity; i++) 400 elements[i] = initialElement; 401 } 402 capacity = newCapacity; 403 array = null; 404 displacement = 0; 405 isDisplaced = false; 406 return this; 407 } 408 409 @Override adjustArray(int newCapacity, AbstractArray displacedTo, int displacement)410 public AbstractVector adjustArray(int newCapacity, 411 AbstractArray displacedTo, 412 int displacement) 413 414 { 415 capacity = newCapacity; 416 array = displacedTo; 417 this.displacement = displacement; 418 elements = null; 419 isDisplaced = true; 420 return this; 421 } 422 } 423