1 19 20 package org.netbeans.lib.editor.util; 21 22 import java.util.AbstractList ; 23 import java.util.Collection ; 24 import java.util.List ; 25 import java.util.RandomAccess ; 26 27 34 35 public class GapList<E> extends AbstractList <E> 36 implements List <E>, RandomAccess , Cloneable , java.io.Serializable { 37 38 45 private transient E[] elementData; 47 50 private int gapStart; 52 55 private int gapLength; 57 64 public GapList(int initialCapacity) { 65 if (initialCapacity < 0) { 66 throw new IllegalArgumentException ("Illegal Capacity: " + initialCapacity); 68 } 69 this.elementData = allocateElementsArray(initialCapacity); 70 this.gapLength = initialCapacity; 71 } 72 73 76 public GapList() { 77 this(10); 78 } 79 80 89 public GapList(Collection <? extends E> c) { 90 int size = c.size(); 91 int capacity = (int)Math.min((size*110L)/100,Integer.MAX_VALUE); 93 @SuppressWarnings ("unchecked") 94 E[] data = (E[])c.toArray(new Object [capacity]); 95 elementData = data; 96 this.gapStart = size; 97 this.gapLength = elementData.length - size; 98 } 99 100 105 public void trimToSize() { 106 modCount++; 107 if (gapLength > 0) { 108 int newLength = elementData.length - gapLength; 109 E[] newElementData = allocateElementsArray(newLength); 110 copyAllData(newElementData); 111 elementData = newElementData; 112 gapLength = 0; 114 } 115 } 116 117 124 public void ensureCapacity(int minCapacity) { 125 modCount++; int oldCapacity = elementData.length; 127 if (minCapacity > oldCapacity) { 128 int newCapacity = (oldCapacity * 3)/2 + 1; 129 if (newCapacity < minCapacity) { 130 newCapacity = minCapacity; 131 } 132 int gapEnd = gapStart + gapLength; 133 int afterGapLength = (oldCapacity - gapEnd); 134 int newGapEnd = newCapacity - afterGapLength; 135 E[] newElementData = allocateElementsArray(newCapacity); 136 System.arraycopy(elementData, 0, newElementData, 0, gapStart); 137 System.arraycopy(elementData, gapEnd, newElementData, newGapEnd, afterGapLength); 138 elementData = newElementData; 139 gapLength = newGapEnd - gapStart; 140 } 141 } 142 143 148 public int size() { 149 return elementData.length - gapLength; 150 } 151 152 158 public boolean isEmpty() { 159 return (elementData.length == gapLength); 160 } 161 162 169 public boolean contains(Object elem) { 170 return indexOf(elem) >= 0; 171 } 172 173 182 public int indexOf(Object elem) { 183 if (elem == null) { 184 int i = 0; 185 while (i < gapStart) { 186 if (elementData[i] == null) { 187 return i; 188 } 189 i++; 190 } 191 i += gapLength; 192 int elementDataLength = elementData.length; 193 while (i < elementDataLength) { 194 if (elementData[i] == null) { 195 return i; 196 } 197 i++; 198 } 199 200 } else { int i = 0; 202 while (i < gapStart) { 203 if (elem.equals(elementData[i])) { 204 return i; 205 } 206 i++; 207 } 208 i += gapLength; 209 int elementDataLength = elementData.length; 210 while (i < elementDataLength) { 211 if (elem.equals(elementData[i])) { 212 return i; 213 } 214 i++; 215 } 216 } 217 218 return -1; 219 } 220 221 229 public int lastIndexOf(Object elem) { 230 if (elem == null) { 231 int i = elementData.length - 1; 232 int gapEnd = gapStart + gapLength; 233 while (i >= gapEnd) { 234 if (elementData[i] == null) { 235 return i; 236 } 237 i--; 238 } 239 i -= gapLength; 240 while (i >= 0) { 241 if (elementData[i] == null) { 242 return i; 243 } 244 i--; 245 } 246 247 } else { int i = elementData.length - 1; 249 int gapEnd = gapStart + gapLength; 250 while (i >= gapEnd) { 251 if (elem.equals(elementData[i])) { 252 return i; 253 } 254 i--; 255 } 256 i -= gapLength; 257 while (i >= 0) { 258 if (elem.equals(elementData[i])) { 259 return i; 260 } 261 i--; 262 } 263 } 264 265 return -1; 266 } 267 268 274 public Object clone() { 275 try { 276 @SuppressWarnings ("unchecked") 277 GapList<E> clonedList = (GapList<E>)super.clone(); 278 int size = size(); 279 E[] clonedElementData = allocateElementsArray(size); 280 copyAllData(clonedElementData); 281 clonedList.elementData = clonedElementData; 282 clonedList.gapStart = size; 284 clonedList.resetModCount(); 285 return clonedList; 286 287 } catch (CloneNotSupportedException e) { 288 throw new InternalError (); 290 } 291 } 292 293 296 public void copyItems(int startIndex, int endIndex, 297 Object [] dest, int destIndex) { 298 copyElements(startIndex, endIndex, dest, destIndex); 299 } 300 301 308 public void copyElements(int startIndex, int endIndex, 309 Object [] dest, int destIndex) { 310 311 if (startIndex < 0 || endIndex < startIndex || endIndex > size()) { 312 throw new IndexOutOfBoundsException ("startIndex=" + startIndex + ", endIndex=" + endIndex + ", size()=" + size()); } 315 316 if (endIndex < gapStart) { System.arraycopy(elementData, startIndex, 318 dest, destIndex, endIndex - startIndex); 319 320 } else { if (startIndex >= gapStart) { System.arraycopy(elementData, startIndex + gapLength, dest, destIndex, 323 endIndex - startIndex); 324 325 } else { int beforeGap = gapStart - startIndex; 327 System.arraycopy(elementData, startIndex, dest, destIndex, beforeGap); 328 System.arraycopy(elementData, gapStart + gapLength, dest, destIndex + beforeGap, 329 endIndex - startIndex - beforeGap); 330 } 331 } 332 } 333 334 342 public void copyElements(int startIndex, int endIndex, Collection <E> dest) { 343 344 if (startIndex < 0 || endIndex < startIndex || endIndex > size()) { 345 throw new IndexOutOfBoundsException ("startIndex=" + startIndex + ", endIndex=" + endIndex + ", size()=" + size()); } 348 349 if (endIndex < gapStart) { while (startIndex < endIndex) { 351 dest.add(elementData[startIndex++]); 352 } 353 354 } else { if (startIndex >= gapStart) { startIndex += gapLength; 357 endIndex += gapLength; 358 while (startIndex < endIndex) { 359 dest.add(elementData[startIndex++]); 360 } 361 362 } else { while (startIndex < gapStart) { 364 dest.add(elementData[startIndex++]); 365 } 366 startIndex += gapLength; 367 endIndex += gapLength; 368 while (startIndex < endIndex) { 369 dest.add(elementData[startIndex++]); 370 } 371 } 372 } 373 } 374 375 382 public Object [] toArray() { 383 int size = size(); 384 Object [] result = new Object [size]; 385 copyAllData(result); 386 return result; 387 } 388 389 410 public <T> T[] toArray(T[] a) { 411 int size = size(); 412 if (a.length < size) { 413 @SuppressWarnings ("unchecked") 414 T[] tmp = (T[])java.lang.reflect.Array.newInstance( 415 a.getClass().getComponentType(), size); 416 a = tmp; 417 } 418 copyAllData(a); 419 if (a.length > size) 420 a[size] = null; 421 422 return a; 423 } 424 425 427 435 public E get(int index) { 436 return elementData[(index < gapStart) ? index : (index + gapLength)]; 438 } 439 440 450 public E set(int index, E element) { 451 if (index >= gapStart) { 453 index += gapLength; 454 } 455 E oldValue = elementData[index]; 456 elementData[index] = element; 457 return oldValue; 458 } 459 460 463 public void swap(int index1, int index2) { 464 if (index1 >= gapStart) { 467 index1 += gapLength; 468 } 469 if (index2 >= gapStart) { 470 index2 += gapLength; 471 } 472 E tmpValue = elementData[index1]; 473 elementData[index1] = elementData[index2]; 474 elementData[index2] = tmpValue; 475 } 476 477 483 public boolean add(E element) { 484 int size = size(); 485 ensureCapacity(size + 1); addImpl(size, element); 487 return true; 488 } 489 490 500 public void add(int index, E element) { 501 int size = size(); 502 if (index > size || index < 0) { 503 throw new IndexOutOfBoundsException ( 504 "Index: " + index + ", Size: " + size); } 506 ensureCapacity(size + 1); addImpl(index, element); 508 } 509 510 private void addImpl(int index, E element) { 511 moveGap(index); 512 elementData[gapStart++] = element; 513 gapLength--; 514 } 515 516 529 public boolean addAll(Collection <? extends E> c) { 530 return addAll(size(), c); 531 } 532 533 549 public boolean addAll(int index, Collection <? extends E> c) { 550 return addArray(index, c.toArray()); 551 } 552 553 560 public boolean addArray(int index, Object [] elements) { 561 return addArray(index, elements, 0, elements.length); 562 } 563 564 573 public boolean addArray(int index, Object [] elements, int off, int len) { 574 int size = size(); 575 if (index > size || index < 0) { 576 throw new IndexOutOfBoundsException ( 577 "Index: " + index + ", Size: " + size); } 579 580 ensureCapacity(size + len); 582 moveGap(index); System.arraycopy(elements, off, elementData, index, len); 584 gapStart += len; 585 gapLength -= len; 586 587 return (len != 0); 588 } 589 590 594 public void clear() { 595 removeRange(0, size()); 596 } 597 598 608 public E remove(int index) { 609 int size = size(); 610 if (index >= size || index < 0) { 611 throw new IndexOutOfBoundsException ( 612 "remove(): Index: " + index + ", Size: " + size); } 614 615 modCount++; 616 moveGap(index + 1); E oldValue = elementData[index]; 618 elementData[index] = null; 619 gapStart--; 620 gapLength++; 621 622 return oldValue; 623 } 624 625 631 public void remove(int index, int count) { 632 int toIndex = index + count; 633 if (index < 0 || toIndex < index || toIndex > size()) { 634 throw new IndexOutOfBoundsException ("index=" + index + ", count=" + count + ", size()=" + size()); } 637 removeRange(index, toIndex); 638 } 639 640 650 protected void removeRange(int fromIndex, int toIndex) { 651 modCount++; 652 if (fromIndex == toIndex) { 653 return; 654 } 655 656 int removeCount = toIndex - fromIndex; 657 if (fromIndex >= gapStart) { moveGap(fromIndex); 661 662 fromIndex += gapLength; toIndex += gapLength; 665 while (fromIndex < toIndex) { 666 elementData[fromIndex] = null; 667 fromIndex++; 668 } 669 670 } else { if (toIndex <= gapStart) { 672 moveGap(toIndex); 675 gapStart = fromIndex; 676 677 } else { for (int clearIndex = fromIndex; clearIndex < gapStart; clearIndex++) { 680 elementData[clearIndex] = null; 681 } 682 683 fromIndex = gapStart + gapLength; gapStart = toIndex - removeCount; toIndex += gapLength; 686 } 687 688 while (fromIndex < toIndex) { 690 elementData[fromIndex++] = null; 691 } 692 693 } 694 695 gapLength += removeCount; 696 } 697 698 private void moveGap(int index) { 699 if (index == gapStart) { 700 return; } 702 703 if (gapLength > 0) { 704 if (index < gapStart) { int moveSize = gapStart - index; 706 System.arraycopy(elementData, index, elementData, 707 gapStart + gapLength - moveSize, moveSize); 708 clearEmpty(index, Math.min(moveSize, gapLength)); 709 710 } else { int gapEnd = gapStart + gapLength; 712 int moveSize = index - gapStart; 713 System.arraycopy(elementData, gapEnd, elementData, gapStart, moveSize); 714 if (index < gapEnd) { 715 clearEmpty(gapEnd, moveSize); 716 } else { 717 clearEmpty(index, gapLength); 718 } 719 } 720 } 721 gapStart = index; 722 } 723 724 private void copyAllData(Object [] toArray) { 725 if (gapLength != 0) { 726 int gapEnd = gapStart + gapLength; 727 System.arraycopy(elementData, 0, toArray, 0, gapStart); 728 System.arraycopy(elementData, gapEnd, toArray, gapStart, 729 elementData.length - gapEnd); 730 } else { System.arraycopy(elementData, 0, toArray, 0, elementData.length); 732 } 733 } 734 735 private void clearEmpty(int index, int length) { 736 while (--length >= 0) { 737 elementData[index++] = null; } 739 } 740 741 private void resetModCount() { 742 modCount = 0; 743 } 744 745 753 private void writeObject(java.io.ObjectOutputStream s) 754 throws java.io.IOException { 755 s.defaultWriteObject(); 757 758 s.writeInt(elementData.length); 760 761 int i = 0; 763 while (i < gapStart) { 764 s.writeObject(elementData[i]); 765 i++; 766 } 767 i += gapLength; 768 int elementDataLength = elementData.length; 769 while (i < elementDataLength) { 770 s.writeObject(elementData[i]); 771 i++; 772 } 773 } 774 775 779 private void readObject(java.io.ObjectInputStream s) 780 throws java.io.IOException , ClassNotFoundException { 781 s.defaultReadObject(); 783 784 int arrayLength = s.readInt(); 786 elementData = allocateElementsArray(arrayLength); 787 788 int i = 0; 790 while (i < gapStart) { 791 @SuppressWarnings ("unchecked") 792 E e = (E)s.readObject(); 793 elementData[i] = e; 794 i++; 795 } 796 i += gapLength; 797 int elementDataLength = elementData.length; 798 while (i < elementDataLength) { 799 @SuppressWarnings ("unchecked") 800 E e = (E)s.readObject(); 801 elementData[i] = e; 802 i++; 803 } 804 } 805 806 809 protected void consistencyCheck() { 810 if (gapStart < 0 || gapLength < 0 811 || gapStart + gapLength > elementData.length 812 ) { 813 consistencyError("Inconsistent gap"); } 815 816 for (int i = gapStart + gapLength - 1; i >= gapStart; i--) { 818 if (elementData[i] != null) { 819 consistencyError("Non-null value at raw-index i"); } 821 } 822 } 823 824 protected final void consistencyError(String s) { 825 throw new IllegalStateException (s + ": " + dumpDetails()); } 827 828 protected String dumpDetails() { 829 return dumpInternals() + "; DATA:\n" + toString(); } 831 832 protected String dumpInternals() { 833 return "elems: " + size() + '(' + elementData.length + "), gap(s=" + gapStart + ", l=" + gapLength + ')'; } 836 837 @SuppressWarnings ("unchecked") 838 private E[] allocateElementsArray(int capacity) { 839 return (E[])new Object [capacity]; 840 } 841 842 public String toString() { 843 return dumpElements(this); 844 } 845 846 public static String dumpElements(java.util.List l) { 847 StringBuffer sb = new StringBuffer (); 848 int size = l.size(); 849 int sizeDigitCount = indexDigitCount(size); 850 for (int i = 0; i < size; i++) { 851 sb.append('['); 852 int extraSpacesCount = sizeDigitCount - indexDigitCount(i); 853 while (extraSpacesCount > 0) { 854 sb.append(' '); 855 } 856 sb.append(i); 857 sb.append("]: "); sb.append(l.get(i)); 859 sb.append("\n"); } 861 return sb.toString(); 862 } 863 864 private static int indexDigitCount(int i) { 865 int digitCount = 1; 866 while (i >= 10) { 867 i /= 10; 868 digitCount++; 869 } 870 return digitCount; 871 } 872 873 } 874 | Popular Tags |