1 /* 2 * ComplexVector_IntBuffer.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 33 package org.armedbear.lisp; 34 35 import static org.armedbear.lisp.Lisp.*; 36 37 import java.nio.ByteBuffer; 38 import java.nio.IntBuffer; 39 40 // A specialized vector of element type (UNSIGNED-BYTE 32) that is displaced to 41 // another array, has a fill pointer, and/or is expressly adjustable. 42 public final class ComplexVector_IntBuffer 43 extends AbstractVector 44 { 45 private int capacity; 46 private int fillPointer = -1; // -1 indicates no fill pointer. 47 private boolean isDisplaced; 48 49 // For non-displaced arrays. 50 private IntBuffer elements; 51 private boolean directAllocation; 52 53 // For displaced arrays. 54 private AbstractArray array; 55 private int displacement; 56 ComplexVector_IntBuffer(int capacity)57 public ComplexVector_IntBuffer(int capacity) { 58 this(capacity, false); 59 } 60 ComplexVector_IntBuffer(int capacity, boolean directAllocation)61 public ComplexVector_IntBuffer(int capacity, boolean directAllocation) { 62 this.capacity = capacity; 63 this.directAllocation = directAllocation; 64 if (directAllocation) { 65 ByteBuffer b = ByteBuffer.allocateDirect(capacity * 4); 66 elements = b.asIntBuffer(); 67 } else { 68 elements = IntBuffer.allocate(capacity); 69 } 70 } 71 ComplexVector_IntBuffer(int capacity, AbstractArray array, int displacement)72 public ComplexVector_IntBuffer(int capacity, AbstractArray array, 73 int displacement) { 74 this(capacity, array, displacement, false); 75 } 76 ComplexVector_IntBuffer(int capacity, AbstractArray array, int displacement, boolean directAllocation)77 public ComplexVector_IntBuffer(int capacity, AbstractArray array, 78 int displacement, boolean directAllocation) { 79 this.capacity = capacity; 80 this.array = array; 81 this.displacement = displacement; 82 this.directAllocation = directAllocation; 83 isDisplaced = true; 84 } 85 86 @Override typeOf()87 public LispObject typeOf() { 88 return list(Symbol.VECTOR, UNSIGNED_BYTE_32, Fixnum.getInstance(capacity)); 89 } 90 91 @Override classOf()92 public LispObject classOf() { 93 return BuiltInClass.VECTOR; 94 } 95 96 @Override hasFillPointer()97 public boolean hasFillPointer() { 98 return fillPointer >= 0; 99 } 100 101 @Override getFillPointer()102 public int getFillPointer() { 103 return fillPointer; 104 } 105 106 @Override setFillPointer(int n)107 public void setFillPointer(int n) { 108 fillPointer = n; 109 } 110 111 @Override setFillPointer(LispObject obj)112 public void setFillPointer(LispObject obj) { 113 if (obj == T) { 114 fillPointer = capacity(); 115 } else { 116 int n = Fixnum.getValue(obj); 117 if (n > capacity()) { 118 StringBuffer sb = new StringBuffer("The new fill pointer ("); 119 sb.append(n); 120 sb.append(") exceeds the capacity of the vector ("); 121 sb.append(capacity()); 122 sb.append(")."); 123 error(new LispError(sb.toString())); 124 } else if (n < 0) { 125 StringBuffer sb = new StringBuffer("The new fill pointer ("); 126 sb.append(n); 127 sb.append(") is negative."); 128 error(new LispError(sb.toString())); 129 } else { 130 fillPointer = n; 131 } 132 } 133 } 134 135 @Override isDisplaced()136 public boolean isDisplaced() { 137 return isDisplaced; 138 } 139 140 @Override arrayDisplacement()141 public LispObject arrayDisplacement() { 142 LispObject value1, value2; 143 if (array != null) { 144 value1 = array; 145 value2 = Fixnum.getInstance(displacement); 146 } else { 147 value1 = NIL; 148 value2 = Fixnum.ZERO; 149 } 150 return LispThread.currentThread().setValues(value1, value2); 151 } 152 153 @Override getElementType()154 public LispObject getElementType() { 155 return UNSIGNED_BYTE_32; 156 } 157 isSimpleVector()158 @Override public boolean isSimpleVector() { 159 return false; 160 } 161 162 @Override capacity()163 public int capacity() { 164 return capacity; 165 } 166 167 @Override length()168 public int length() { 169 return fillPointer >= 0 ? fillPointer : capacity; 170 } 171 172 @Override elt(int index)173 public LispObject elt(int index) { 174 final int limit = length(); 175 if (index < 0 || index >= limit) 176 badIndex(index, limit); 177 return AREF(index); 178 } 179 180 // Ignores fill pointer. 181 @Override AREF(int index)182 public LispObject AREF(int index) { 183 if (elements != null) { 184 try { 185 return number(((long)elements.get(index)) & 0xffffffffL); 186 } catch (IndexOutOfBoundsException e) { 187 badIndex(index, ((java.nio.Buffer)elements).limit()); 188 return NIL; // Not reached. 189 } 190 } else { 191 // Displaced array. 192 if (index < 0 || index >= capacity) { 193 badIndex(index, capacity); 194 } 195 return array.AREF(index + displacement); 196 } 197 } 198 199 @Override aset(int index, LispObject newValue)200 public void aset(int index, LispObject newValue) { 201 if (newValue.isLessThan(Fixnum.ZERO) 202 || newValue.isGreaterThan(UNSIGNED_BYTE_32_MAX_VALUE)) { 203 type_error(newValue, UNSIGNED_BYTE_32); 204 } 205 if (elements != null) { 206 try { 207 elements.put(index, (int)(newValue.longValue() & 0xffffffffL)); 208 } catch (IndexOutOfBoundsException e) { 209 badIndex(index, ((java.nio.Buffer)elements).limit()); 210 } 211 } else { 212 // Displaced array. 213 if (index < 0 || index >= capacity) { 214 badIndex(index, capacity); 215 } else { 216 array.aset(index + displacement, newValue); 217 } 218 } 219 } 220 221 @Override subseq(int start, int end)222 public LispObject subseq(int start, int end) { 223 SimpleVector v = new SimpleVector(end - start); 224 int i = start, j = 0; 225 try { 226 while (i < end) { 227 v.aset(j++, AREF(i++)); 228 } 229 return v; 230 } catch (IndexOutOfBoundsException e) { 231 return error(new TypeError("Array index out of bounds: " + i + ".")); 232 } 233 } 234 235 @Override fill(LispObject obj)236 public void fill(LispObject obj) { 237 if (!(obj instanceof LispInteger)) { 238 type_error(obj, Symbol.INTEGER); 239 // Not reached. 240 return; 241 } 242 if (obj.isLessThan(Fixnum.ZERO) || obj.isGreaterThan(UNSIGNED_BYTE_32_MAX_VALUE)) { 243 type_error(obj, UNSIGNED_BYTE_32); 244 } 245 for (int i = capacity; i-- > 0;) { 246 elements.put(i, coerceToJavaUnsignedInt(obj)); 247 } 248 } 249 250 @Override shrink(int n)251 public void shrink(int n) { 252 // One cannot shrink the underlying ByteBuffer physically, so 253 // use the limit marker to denote the length 254 if (n < length()) { 255 ((java.nio.Buffer)elements).limit(n); 256 this.capacity = n; 257 return; 258 } 259 if (n == ((java.nio.Buffer)elements).limit()) { 260 return; 261 } 262 error(new LispError()); 263 } 264 265 @Override reverse()266 public LispObject reverse() { 267 int length = length(); 268 SimpleVector result = new SimpleVector(length); 269 int i, j; 270 for (i = 0, j = length - 1; i < length; i++, j--) { 271 result.aset(i, AREF(j)); 272 } 273 return result; 274 } 275 276 @Override nreverse()277 public LispObject nreverse() { 278 if (elements != null) { 279 int i = 0; 280 int j = length() - 1; 281 while (i < j) { 282 int temp = elements.get(i); 283 elements.put(i, elements.get(j)); 284 elements.put(j, temp); 285 ++i; 286 --j; 287 } 288 } else { 289 // Displaced array. 290 int length = length(); 291 IntBuffer data = null; 292 if (directAllocation) { 293 ByteBuffer b = ByteBuffer.allocateDirect(length * 4); 294 data = b.asIntBuffer(); 295 } else { 296 data = IntBuffer.allocate(length); 297 } 298 int i, j; 299 for (i = 0, j = length - 1; i < length; i++, j--) { 300 data.put(i, coerceToJavaUnsignedInt(AREF(j))); 301 } 302 elements = data; 303 capacity = length; 304 array = null; 305 displacement = 0; 306 isDisplaced = false; 307 fillPointer = -1; 308 } 309 return this; 310 } 311 312 @Override vectorPushExtend(LispObject element)313 public void vectorPushExtend(LispObject element) { 314 if (fillPointer < 0) { 315 noFillPointer(); 316 } 317 if (fillPointer >= capacity) { 318 // Need to extend vector. 319 ensureCapacity(capacity * 2 + 1); 320 } 321 aset(fillPointer, element); 322 ++fillPointer; 323 } 324 325 @Override VECTOR_PUSH_EXTEND(LispObject element)326 public LispObject VECTOR_PUSH_EXTEND(LispObject element) { 327 vectorPushExtend(element); 328 return Fixnum.getInstance(fillPointer - 1); 329 } 330 331 @Override VECTOR_PUSH_EXTEND(LispObject element, LispObject extension)332 public LispObject VECTOR_PUSH_EXTEND(LispObject element, 333 LispObject extension) { 334 int ext = Fixnum.getValue(extension); 335 if (fillPointer < 0) { 336 noFillPointer(); 337 } 338 if (fillPointer >= capacity) { 339 // Need to extend vector. 340 ext = Math.max(ext, capacity + 1); 341 ensureCapacity(capacity + ext); 342 } 343 aset(fillPointer, element); 344 return Fixnum.getInstance(fillPointer++); 345 } 346 ensureCapacity(int minCapacity)347 private final void ensureCapacity(int minCapacity) { 348 if (elements != null) { 349 if (capacity < minCapacity) { 350 IntBuffer newBuffer = null; 351 if (directAllocation) { 352 ByteBuffer b = ByteBuffer.allocateDirect(minCapacity * 4); 353 newBuffer = b.asIntBuffer(); 354 } else { 355 newBuffer = IntBuffer.allocate(minCapacity); 356 } 357 newBuffer.put(elements); 358 elements = newBuffer; 359 capacity = minCapacity; 360 } 361 } else { 362 // Displaced array. 363 Debug.assertTrue(array != null); 364 if (capacity < minCapacity 365 || array.getTotalSize() - displacement < minCapacity) { 366 // Copy array. 367 if (directAllocation) { 368 ByteBuffer b = ByteBuffer.allocateDirect(minCapacity * 4); 369 elements = b.asIntBuffer(); 370 } else { 371 elements = IntBuffer.allocate(minCapacity); 372 } 373 final int limit 374 = Math.min(capacity, array.getTotalSize() - displacement); 375 for (int i = 0; i < limit; i++) { 376 elements.put(i, coerceToJavaUnsignedInt(AREF(displacement + i))); 377 } 378 capacity = minCapacity; 379 array = null; 380 displacement = 0; 381 isDisplaced = false; 382 } 383 } 384 } 385 386 @Override adjustArray(int newCapacity, LispObject initialElement, LispObject initialContents)387 public AbstractVector adjustArray(int newCapacity, 388 LispObject initialElement, 389 LispObject initialContents) { 390 if (initialContents != null) { 391 // "If INITIAL-CONTENTS is supplied, it is treated as for MAKE- 392 // ARRAY. In this case none of the original contents of array 393 // appears in the resulting array." 394 IntBuffer newElements = null; 395 if (directAllocation) { 396 ByteBuffer b = ByteBuffer.allocateDirect(newCapacity * 4); 397 newElements = b.asIntBuffer(); 398 } else { 399 newElements = IntBuffer.allocate(newCapacity); 400 } 401 if (initialContents.listp()) { 402 LispObject list = initialContents; 403 for (int i = 0; i < newCapacity; i++) { 404 newElements.put(i, coerceToJavaUnsignedInt(list.car())); 405 list = list.cdr(); 406 } 407 } else if (initialContents.vectorp()) { 408 for (int i = 0; i < newCapacity; i++) { 409 newElements.put(i, coerceToJavaUnsignedInt(initialContents.elt(i))); 410 411 } 412 } else { 413 type_error(initialContents, Symbol.SEQUENCE); 414 } 415 elements = newElements; 416 } else { 417 if (elements == null) { 418 // Displaced array. Copy existing elements. 419 if (directAllocation) { 420 ByteBuffer b = ByteBuffer.allocateDirect(newCapacity * 4); 421 elements = b.asIntBuffer(); 422 } else { 423 elements = IntBuffer.allocate(newCapacity); 424 } 425 final int limit = Math.min(capacity, newCapacity); 426 for (int i = 0; i < limit; i++) { 427 elements.put(i,(int)(array.AREF(displacement + i).longValue() & 0xffffffffL)); 428 } 429 } else if (capacity != newCapacity) { 430 IntBuffer newElements = null; 431 if (directAllocation) { 432 ByteBuffer b = ByteBuffer.allocateDirect(newCapacity * 4); 433 newElements = b.asIntBuffer(); 434 } else { 435 newElements = IntBuffer.allocate(newCapacity); 436 } 437 newElements.put(elements.array(), 438 0, Math.min(capacity, newCapacity)); 439 elements = newElements; 440 } 441 // Initialize new elements (if aapplicable). 442 if (initialElement != null) { 443 for (int i = capacity; i < newCapacity; i++) { 444 elements.put(i, coerceToJavaUnsignedInt(initialElement)); 445 } 446 } 447 } 448 capacity = newCapacity; 449 array = null; 450 displacement = 0; 451 isDisplaced = false; 452 return this; 453 } 454 455 @Override adjustArray(int newCapacity, AbstractArray displacedTo, int displacement)456 public AbstractVector adjustArray(int newCapacity, 457 AbstractArray displacedTo, 458 int displacement) { 459 capacity = newCapacity; 460 array = displacedTo; 461 this.displacement = displacement; 462 elements = null; 463 isDisplaced = true; 464 return this; 465 } 466 } 467