1 package prefuse.util.collections; 2 17 18 import java.util.AbstractList ; 19 import java.util.Collection ; 20 import java.util.ConcurrentModificationException ; 21 import java.util.Iterator ; 22 import java.util.List ; 23 import java.util.ListIterator ; 24 import java.util.NoSuchElementException ; 25 import java.util.RandomAccess ; 26 27 28 57 public class CopyOnWriteArrayList 58 implements List , RandomAccess , Cloneable , java.io.Serializable { 59 private static final long serialVersionUID = 8673264195747942595L; 60 61 62 private volatile transient Object [] array; 63 64 71 public Object [] getArray() { return array; } 72 73 void setArray(Object [] a) { array = a; } 74 75 78 public CopyOnWriteArrayList() { 79 setArray(new Object [0]); 80 } 81 82 90 public CopyOnWriteArrayList(Collection c) { 91 Object [] elements = new Object [c.size()]; 92 int size = 0; 93 for (Iterator itr = c.iterator(); itr.hasNext(); ) { 94 Object e = itr.next(); 95 elements[size++] = e; 96 } 97 setArray(elements); 98 } 99 100 107 public CopyOnWriteArrayList(Object [] toCopyIn) { 108 copyIn(toCopyIn, 0, toCopyIn.length); 109 } 110 111 123 private void copyIn(Object [] toCopyIn, int first, int n) { 124 int limit = first + n; 125 if (limit > toCopyIn.length) 126 throw new IndexOutOfBoundsException (); 127 Object [] newElements = copyOfRange(toCopyIn, first, limit, 128 Object [].class); 129 synchronized (this) { setArray(newElements); } 130 } 131 132 137 public int size() { 138 return getArray().length; 139 } 140 141 146 public boolean isEmpty() { 147 return size() == 0; 148 } 149 150 153 private static boolean eq(Object o1, Object o2) { 154 return (o1 == null ? o2 == null : o1.equals(o2)); 155 } 156 157 166 private static int indexOf(Object o, Object [] elements, 167 int index, int fence) { 168 if (o == null) { 169 for (int i = index; i < fence; i++) 170 if (elements[i] == null) 171 return i; 172 } else { 173 for (int i = index; i < fence; i++) 174 if (o.equals(elements[i])) 175 return i; 176 } 177 return -1; 178 } 179 180 187 private static int lastIndexOf(Object o, Object [] elements, int index) { 188 if (o == null) { 189 for (int i = index; i >= 0; i--) 190 if (elements[i] == null) 191 return i; 192 } else { 193 for (int i = index; i >= 0; i--) 194 if (o.equals(elements[i])) 195 return i; 196 } 197 return -1; 198 } 199 200 209 public boolean contains(Object o) { 210 Object [] elements = getArray(); 211 return indexOf(o, elements, 0, elements.length) >= 0; 212 } 213 214 217 public int indexOf(Object o) { 218 Object [] elements = getArray(); 219 return indexOf(o, elements, 0, elements.length); 220 } 221 222 223 238 public int indexOf(Object e, int index) { 239 Object [] elements = getArray(); 240 return indexOf(e, elements, index, elements.length); 241 } 242 243 246 public int lastIndexOf(Object o) { 247 Object [] elements = getArray(); 248 return lastIndexOf(o, elements, elements.length - 1); 249 } 250 251 267 public int lastIndexOf(Object e, int index) { 268 Object [] elements = getArray(); 269 return lastIndexOf(e, elements, index); 270 } 271 272 278 public Object clone() { 279 try { 280 return super.clone(); 281 } catch (CloneNotSupportedException e) { 282 throw new InternalError (); 284 } 285 } 286 287 300 public Object [] toArray() { 301 Object [] elements = getArray(); 302 return copyOf(elements, elements.length); 303 } 304 305 344 public Object [] toArray(Object a[]) { 345 Object [] elements = getArray(); 346 int len = elements.length; 347 if (a.length < len) 348 return copyOf(elements, len, a.getClass()); 349 else { 350 System.arraycopy(elements, 0, a, 0, len); 351 if (a.length > len) 352 a[len] = null; 353 return a; 354 } 355 } 356 357 359 364 public Object get(int index) { 365 return (getArray()[index]); 366 } 367 368 374 public synchronized Object set(int index, Object element) { 375 Object [] elements = getArray(); 376 int len = elements.length; 377 Object oldValue = elements[index]; 378 379 if (oldValue != element) { 380 Object [] newElements = copyOf(elements, len); 381 newElements[index] = element; 382 setArray(newElements); 383 } 384 return oldValue; 385 } 386 387 393 public boolean add(Object e) { 394 synchronized (this) { 395 Object [] elements = getArray(); 396 int len = elements.length; 397 Object [] newElements = copyOf(elements, len + 1); 398 newElements[len] = e; 399 setArray(newElements); 400 } 401 return true; 402 } 403 404 411 public synchronized void add(int index, Object element) { 412 Object [] elements = getArray(); 413 int len = elements.length; 414 if (index > len || index < 0) 415 throw new IndexOutOfBoundsException ("Index: " + index+ 416 ", Size: " + len); 417 Object [] newElements; 418 int numMoved = len - index; 419 if (numMoved == 0) 420 newElements = copyOf(elements, len + 1); 421 else { 422 newElements = new Object [len + 1]; 423 System.arraycopy(elements, 0, newElements, 0, index); 424 System.arraycopy(elements, index, newElements, index + 1, 425 numMoved); 426 } 427 newElements[index] = element; 428 setArray(newElements); 429 } 430 431 438 public synchronized Object remove(int index) { 439 Object [] elements = getArray(); 440 int len = elements.length; 441 Object oldValue = elements[index]; 442 int numMoved = len - index - 1; 443 if (numMoved == 0) 444 setArray(copyOf(elements, len - 1)); 445 else { 446 Object [] newElements = new Object [len - 1]; 447 System.arraycopy(elements, 0, newElements, 0, index); 448 System.arraycopy(elements, index + 1, newElements, index, 449 numMoved); 450 setArray(newElements); 451 } 452 return oldValue; 453 } 454 455 468 public synchronized boolean remove(Object o) { 469 Object [] elements = getArray(); 470 int len = elements.length; 471 if (len != 0) { 472 int newlen = len - 1; 475 Object [] newElements = new Object [newlen]; 476 477 for (int i = 0; i < newlen; ++i) { 478 if (eq(o, elements[i])) { 479 for (int k = i + 1; k < len; ++k) 481 newElements[k-1] = elements[k]; 482 setArray(newElements); 483 return true; 484 } else 485 newElements[i] = elements[i]; 486 } 487 488 if (eq(o, elements[newlen])) { 490 setArray(newElements); 491 return true; 492 } 493 } 494 return false; 495 } 496 497 510 private synchronized void removeRange(int fromIndex, int toIndex) { 511 Object [] elements = getArray(); 512 int len = elements.length; 513 514 if (fromIndex < 0 || fromIndex >= len || 515 toIndex > len || toIndex < fromIndex) 516 throw new IndexOutOfBoundsException (); 517 int newlen = len - (toIndex - fromIndex); 518 int numMoved = len - toIndex; 519 if (numMoved == 0) 520 setArray(copyOf(elements, newlen)); 521 else { 522 Object [] newElements = new Object [newlen]; 523 System.arraycopy(elements, 0, newElements, 0, fromIndex); 524 System.arraycopy(elements, toIndex, newElements, 525 fromIndex, numMoved); 526 setArray(newElements); 527 } 528 } 529 530 536 public synchronized boolean addIfAbsent(Object e) { 537 Object [] elements = getArray(); 540 int len = elements.length; 541 Object [] newElements = new Object [len + 1]; 542 for (int i = 0; i < len; ++i) { 543 if (eq(e, elements[i])) 544 return false; else 546 newElements[i] = elements[i]; 547 } 548 newElements[len] = e; 549 setArray(newElements); 550 return true; 551 } 552 553 563 public boolean containsAll(Collection c) { 564 Object [] elements = getArray(); 565 int len = elements.length; 566 for (Iterator itr = c.iterator(); itr.hasNext(); ) { 567 Object e = itr.next(); 568 if (indexOf(e, elements, 0, len) < 0) 569 return false; 570 } 571 return true; 572 } 573 574 588 public synchronized boolean removeAll(Collection c) { 589 Object [] elements = getArray(); 590 int len = elements.length; 591 if (len != 0) { 592 int newlen = 0; 594 Object [] temp = new Object [len]; 595 for (int i = 0; i < len; ++i) { 596 Object element = elements[i]; 597 if (!c.contains(element)) 598 temp[newlen++] = element; 599 } 600 if (newlen != len) { 601 setArray(copyOfRange(temp, 0, newlen, Object [].class)); 602 return true; 603 } 604 } 605 return false; 606 } 607 608 622 public synchronized boolean retainAll(Collection c) { 623 Object [] elements = getArray(); 624 int len = elements.length; 625 if (len != 0) { 626 int newlen = 0; 628 Object [] temp = new Object [len]; 629 for (int i = 0; i < len; ++i) { 630 Object element = elements[i]; 631 if (c.contains(element)) 632 temp[newlen++] = element; 633 } 634 if (newlen != len) { 635 setArray(copyOfRange(temp, 0, newlen, Object [].class)); 636 return true; 637 } 638 } 639 return false; 640 } 641 642 653 public int addAllAbsent(Collection c) { 654 int numNew = c.size(); 655 if (numNew == 0) 656 return 0; 657 synchronized (this) { 658 Object [] elements = getArray(); 659 int len = elements.length; 660 661 Object [] temp = new Object [numNew]; 662 int added = 0; 663 for (Iterator itr = c.iterator(); itr.hasNext(); ) { 664 Object e = itr.next(); 665 if (indexOf(e, elements, 0, len) < 0 && 666 indexOf(e, temp, 0, added) < 0) 667 temp[added++] = e; 668 } 669 if (added != 0) { 670 Object [] newElements = new Object [len + added]; 671 System.arraycopy(elements, 0, newElements, 0, len); 672 System.arraycopy(temp, 0, newElements, len, added); 673 setArray(newElements); 674 } 675 return added; 676 } 677 } 678 679 683 public synchronized void clear() { 684 setArray(new Object [0]); 685 } 686 687 697 public boolean addAll(Collection c) { 698 int numNew = c.size(); 699 if (numNew == 0) 700 return false; 701 synchronized (this) { 702 Object [] elements = getArray(); 703 int len = elements.length; 704 Object [] newElements = new Object [len + numNew]; 705 System.arraycopy(elements, 0, newElements, 0, len); 706 for (Iterator itr = c.iterator(); itr.hasNext(); ) { 707 Object e = itr.next(); 708 newElements[len++] = e; 709 } 710 setArray(newElements); 711 return true; 712 } 713 } 714 715 731 public boolean addAll(int index, Collection c) { 732 int numNew = c.size(); 733 synchronized (this) { 734 Object [] elements = getArray(); 735 int len = elements.length; 736 if (index > len || index < 0) 737 throw new IndexOutOfBoundsException ("Index: " + index + 738 ", Size: "+ len); 739 if (numNew == 0) 740 return false; 741 int numMoved = len - index; 742 Object [] newElements; 743 if (numMoved == 0) 744 newElements = copyOf(elements, len + numNew); 745 else { 746 newElements = new Object [len + numNew]; 747 System.arraycopy(elements, 0, newElements, 0, index); 748 System.arraycopy(elements, index, 749 newElements, index + numNew, 750 numMoved); 751 } 752 for (Iterator itr = c.iterator(); itr.hasNext(); ) { 753 Object e = itr.next(); 754 newElements[index++] = e; 755 } 756 setArray(newElements); 757 return true; 758 } 759 } 760 761 769 private void writeObject(java.io.ObjectOutputStream s) 770 throws java.io.IOException { 771 772 s.defaultWriteObject(); 774 775 Object [] elements = getArray(); 776 int len = elements.length; 777 s.writeInt(len); 779 780 for (int i = 0; i < len; i++) 782 s.writeObject(elements[i]); 783 } 784 785 789 private void readObject(java.io.ObjectInputStream s) 790 throws java.io.IOException , ClassNotFoundException { 791 792 s.defaultReadObject(); 794 795 int len = s.readInt(); 797 Object [] elements = new Object [len]; 798 799 for (int i = 0; i < len; i++) 801 elements[i] = s.readObject(); 802 setArray(elements); 803 804 } 805 806 810 public String toString() { 811 Object [] elements = getArray(); 812 int maxIndex = elements.length - 1; 813 StringBuffer buf = new StringBuffer (); 814 buf.append("["); 815 for (int i = 0; i <= maxIndex; i++) { 816 buf.append(String.valueOf(elements[i])); 817 if (i < maxIndex) 818 buf.append(", "); 819 } 820 buf.append("]"); 821 return buf.toString(); 822 } 823 824 837 public boolean equals(Object o) { 838 if (o == this) 839 return true; 840 if (!(o instanceof List )) 841 return false; 842 843 List l2 = (List )(o); 844 if (size() != l2.size()) 845 return false; 846 847 ListIterator e1 = listIterator(); 848 ListIterator e2 = l2.listIterator(); 849 while (e1.hasNext()) { 850 if (!eq(e1.next(), e2.next())) 851 return false; 852 } 853 return true; 854 } 855 856 863 public int hashCode() { 864 int hashCode = 1; 865 Object [] elements = getArray(); 866 int len = elements.length; 867 for (int i = 0; i < len; ++i) { 868 Object obj = elements[i]; 869 hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode()); 870 } 871 return hashCode; 872 } 873 874 884 public Iterator iterator() { 885 return new COWIterator(getArray(), 0); 886 } 887 888 896 public ListIterator listIterator() { 897 return new COWIterator(getArray(), 0); 898 } 899 900 909 public ListIterator listIterator(final int index) { 910 Object [] elements = getArray(); 911 int len = elements.length; 912 if (index < 0 || index > len) 913 throw new IndexOutOfBoundsException ("Index: " + index); 914 915 return new COWIterator(getArray(), index); 916 } 917 918 private static class COWIterator implements ListIterator { 919 920 private final Object [] snapshot; 921 922 private int cursor; 923 924 private COWIterator(Object [] elements, int initialCursor) { 925 cursor = initialCursor; 926 snapshot = elements; 927 } 928 929 public boolean hasNext() { 930 return cursor < snapshot.length; 931 } 932 933 public boolean hasPrevious() { 934 return cursor > 0; 935 } 936 937 public Object next() { 938 try { 939 return (snapshot[cursor++]); 940 } catch (IndexOutOfBoundsException ex) { 941 throw new NoSuchElementException (); 942 } 943 } 944 945 public Object previous() { 946 try { 947 return (snapshot[--cursor]); 948 } catch (IndexOutOfBoundsException e) { 949 throw new NoSuchElementException (); 950 } 951 } 952 953 public int nextIndex() { 954 return cursor; 955 } 956 957 public int previousIndex() { 958 return cursor - 1; 959 } 960 961 966 public void remove() { 967 throw new UnsupportedOperationException (); 968 } 969 970 975 public void set(Object e) { 976 throw new UnsupportedOperationException (); 977 } 978 979 984 public void add(Object e) { 985 throw new UnsupportedOperationException (); 986 } 987 } 988 989 1009 public synchronized List subList(int fromIndex, int toIndex) { 1010 Object [] elements = getArray(); 1011 int len = elements.length; 1012 if (fromIndex < 0 || toIndex > len || fromIndex > toIndex) 1013 throw new IndexOutOfBoundsException (); 1014 return new COWSubList(this, fromIndex, toIndex); 1015 } 1016 1017 1018 1033 private static class COWSubList extends AbstractList { 1034 private final CopyOnWriteArrayList l; 1035 private final int offset; 1036 private int size; 1037 private Object [] expectedArray; 1038 1039 private COWSubList(CopyOnWriteArrayList list, 1041 int fromIndex, int toIndex) { 1042 l = list; 1043 expectedArray = l.getArray(); 1044 offset = fromIndex; 1045 size = toIndex - fromIndex; 1046 } 1047 1048 private void checkForComodification() { 1050 if (l.getArray() != expectedArray) 1051 throw new ConcurrentModificationException (); 1052 } 1053 1054 private void rangeCheck(int index) { 1056 if (index < 0 || index >= size) 1057 throw new IndexOutOfBoundsException ("Index: " + index + 1058 ",Size: " + size); 1059 } 1060 1061 public Object set(int index, Object element) { 1062 synchronized (l) { 1063 rangeCheck(index); 1064 checkForComodification(); 1065 Object x = l.set(index + offset, element); 1066 expectedArray = l.getArray(); 1067 return x; 1068 } 1069 } 1070 1071 public Object get(int index) { 1072 synchronized (l) { 1073 rangeCheck(index); 1074 checkForComodification(); 1075 return l.get(index + offset); 1076 } 1077 } 1078 1079 public int size() { 1080 synchronized (l) { 1081 checkForComodification(); 1082 return size; 1083 } 1084 } 1085 1086 public void add(int index, Object element) { 1087 synchronized (l) { 1088 checkForComodification(); 1089 if (index<0 || index>size) 1090 throw new IndexOutOfBoundsException (); 1091 l.add(index + offset, element); 1092 expectedArray = l.getArray(); 1093 size++; 1094 } 1095 } 1096 1097 public void clear() { 1098 synchronized (l) { 1099 checkForComodification(); 1100 l.removeRange(offset, offset+size); 1101 expectedArray = l.getArray(); 1102 size = 0; 1103 } 1104 } 1105 1106 public Object remove(int index) { 1107 synchronized (l) { 1108 rangeCheck(index); 1109 checkForComodification(); 1110 Object result = l.remove(index + offset); 1111 expectedArray = l.getArray(); 1112 size--; 1113 return result; 1114 } 1115 } 1116 1117 public Iterator iterator() { 1118 synchronized (l) { 1119 checkForComodification(); 1120 return new COWSubListIterator(l, 0, offset, size); 1121 } 1122 } 1123 1124 public ListIterator listIterator(final int index) { 1125 synchronized (l) { 1126 checkForComodification(); 1127 if (index<0 || index>size) 1128 throw new IndexOutOfBoundsException ("Index: "+index+ 1129 ", Size: "+size); 1130 return new COWSubListIterator(l, index, offset, size); 1131 } 1132 } 1133 1134 public List subList(int fromIndex, int toIndex) { 1135 synchronized (l) { 1136 checkForComodification(); 1137 if (fromIndex<0 || toIndex>size) 1138 throw new IndexOutOfBoundsException (); 1139 return new COWSubList(l, fromIndex + offset, 1140 toIndex + offset); 1141 } 1142 } 1143 1144 } 1145 1146 1147 private static class COWSubListIterator implements ListIterator { 1148 private final ListIterator i; 1149 private final int offset; 1150 private final int size; 1151 private COWSubListIterator(List l, int index, int offset, 1152 int size) { 1153 this.offset = offset; 1154 this.size = size; 1155 i = l.listIterator(index + offset); 1156 } 1157 1158 public boolean hasNext() { 1159 return nextIndex() < size; 1160 } 1161 1162 public Object next() { 1163 if (hasNext()) 1164 return i.next(); 1165 else 1166 throw new NoSuchElementException (); 1167 } 1168 1169 public boolean hasPrevious() { 1170 return previousIndex() >= 0; 1171 } 1172 1173 public Object previous() { 1174 if (hasPrevious()) 1175 return i.previous(); 1176 else 1177 throw new NoSuchElementException (); 1178 } 1179 1180 public int nextIndex() { 1181 return i.nextIndex() - offset; 1182 } 1183 1184 public int previousIndex() { 1185 return i.previousIndex() - offset; 1186 } 1187 1188 public void remove() { 1189 throw new UnsupportedOperationException (); 1190 } 1191 1192 public void set(Object e) { 1193 throw new UnsupportedOperationException (); 1194 } 1195 1196 public void add(Object e) { 1197 throw new UnsupportedOperationException (); 1198 } 1199 } 1200 1201 1215 1217 private static Object [] copyOfRange(Object [] original, int from, int to, 1218 Class newType) { 1219 int newLength = to - from; 1220 if (newLength < 0) 1221 throw new IllegalArgumentException (from + " > " + to); 1222 Object [] copy = (Object []) java.lang.reflect.Array.newInstance 1223 (newType.getComponentType(), newLength); 1224 System.arraycopy(original, from, copy, 0, 1225 Math.min(original.length - from, newLength)); 1226 return copy; 1227 } 1228 1229 private static Object [] copyOf(Object [] original, int newLength, 1230 Class newType) { 1231 Object [] copy = (Object []) java.lang.reflect.Array.newInstance 1232 (newType.getComponentType(), newLength); 1233 System.arraycopy(original, 0, copy, 0, 1234 Math.min(original.length, newLength)); 1235 return copy; 1236 } 1237 1238 private static Object [] copyOf(Object [] original, int newLength) { 1239 return copyOf(original, newLength, original.getClass()); 1240 } 1241} 1242 | Popular Tags |