001/* 002 * Copyright (C) 2002-2015 Sebastiano Vigna 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package squidpony.squidmath; 017 018import squidpony.annotation.GwtIncompatible; 019 020import java.util.*; 021 022/** 023 * A generic unordered hash set with with a fast implementation, based on {@link OrderedSet} in this library, which is 024 * based on the fastutil library's ObjectLinkedOpenHashSet class; the ordering and indexed access have been removed to 025 * potentially reduce the time cost of insertion and removal at the expense of increasing time cost for access by index. 026 * This does support optional hash strategies for array (and other) keys, which fastutil's collections can do in a 027 * different way, and has better support than {@link HashSet} for construction with an array of items or construction 028 * with a Collection of items (this also helps {@link #addAll(Object[])}). 029 * <p> 030 * Instances of this class use a hash table to represent a set. The table is 031 * filled up to a specified <em>load factor</em>, and then doubled in size to 032 * accommodate new entries. If the table is emptied below <em>one fourth</em> of 033 * the load factor, it is halved in size. However, halving is not performed when 034 * deleting entries from an iterator, as it would interfere with the iteration 035 * process. 036 * </p> 037 * <p> 038 * Note that {@link #clear()} does not modify the hash table size. Rather, a 039 * family of {@linkplain #trim() trimming methods} lets you control the size of 040 * the table; this is particularly useful if you reuse instances of this class. 041 * </p> 042 * <p> 043 * This class implements the interface of a Set, not a SortedSet. 044 * <p> 045 * <p> 046 * You can pass an {@link CrossHash.IHasher} instance such as {@link CrossHash#generalHasher} as an extra parameter to 047 * most of this class' constructors, which allows the OrderedSet to use arrays (usually primitive arrays) as items. If 048 * you expect only one type of array, you can use an instance like {@link CrossHash#intHasher} to hash int arrays, or 049 * the aforementioned generalHasher to hash most kinds of arrays (it can't handle most multi-dimensional arrays well). 050 * If you aren't using array items, you don't need to give an IHasher to the constructor and can ignore this feature. 051 * </p> 052 * <br> 053 * Thank you, Sebastiano Vigna, for making FastUtil available to the public with such high quality. 054 * <br> 055 * See https://github.com/vigna/fastutil for the original library. 056 * 057 * @author Sebastiano Vigna (responsible for all the hard parts) 058 * @author Tommy Ettinger (mostly responsible for squashing several layers of parent classes into one monster class) 059 */ 060public class UnorderedSet<K> implements Set<K>, java.io.Serializable, Cloneable { 061 private static final long serialVersionUID = 0L; 062 /** 063 * The array of keys. 064 */ 065 protected K[] key; 066 /* 067 The array of values. 068 */ 069 //protected V[] value; 070 /** 071 * The mask for wrapping a position counter. 072 */ 073 protected int mask; 074 /** 075 * Whether this set contains the key zero. 076 */ 077 protected boolean containsNull; 078 /** 079 * The current table size. 080 */ 081 protected int n; 082 /** 083 * Threshold after which we rehash. It must be the table size times {@link #f}. 084 */ 085 protected int maxFill; 086 /** 087 * Number of entries in the set (including the key zero, if present). 088 */ 089 protected int size; 090 /** 091 * The acceptable load factor. 092 */ 093 public final float f; 094 095 /** 096 * The initial default size of a hash table. 097 */ 098 public static final int DEFAULT_INITIAL_SIZE = 16; 099 /** 100 * The default load factor of a hash table. 101 */ 102 public static final float DEFAULT_LOAD_FACTOR = .25f; // .1875f; // .75f; 103 /** 104 * The load factor for a (usually small) table that is meant to be particularly fast. 105 */ 106 public static final float FAST_LOAD_FACTOR = .5f; 107 /** 108 * The load factor for a (usually very small) table that is meant to be extremely fast. 109 */ 110 public static final float VERY_FAST_LOAD_FACTOR = .25f; 111 112 protected final CrossHash.IHasher hasher; 113 114 /** 115 * Creates a new hash map. 116 * <p> 117 * <p>The actual table size will be the least power of two greater than <code>expected</code>/<code>f</code>. 118 * 119 * @param expected the expected number of elements in the hash set. 120 * @param f the load factor. 121 */ 122 123 @SuppressWarnings("unchecked") 124 public UnorderedSet(final int expected, final float f) { 125 if (f <= 0 || f > 1) 126 throw new IllegalArgumentException("Load factor must be greater than 0 and smaller than or equal to 1"); 127 if (expected < 0) throw new IllegalArgumentException("The expected number of elements must be nonnegative"); 128 this.f = f; 129 n = arraySize(expected, f); 130 mask = n - 1; 131 maxFill = maxFill(n, f); 132 key = (K[]) new Object[n + 1]; 133 hasher = CrossHash.mildHasher; 134 } 135 136 /** 137 * Creates a new hash set with {@link #DEFAULT_LOAD_FACTOR} as load 138 * factor. 139 * 140 * @param expected the expected number of elements in the hash set. 141 */ 142 public UnorderedSet(final int expected) { 143 this(expected, DEFAULT_LOAD_FACTOR); 144 } 145 146 /** 147 * Creates a new hash set with initial expected 148 * {@link #DEFAULT_INITIAL_SIZE} elements and 149 * {@link #DEFAULT_LOAD_FACTOR} as load factor. 150 */ 151 public UnorderedSet() { 152 this(DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR); 153 } 154 155 /** 156 * Creates a new hash set copying a given collection. 157 * 158 * @param c a {@link Collection} to be copied into the new hash set. 159 * @param f the load factor. 160 */ 161 public UnorderedSet(final Collection<? extends K> c, 162 final float f) { 163 this(c.size(), f, (c instanceof UnorderedSet) ? ((UnorderedSet) c).hasher : CrossHash.mildHasher); 164 addAll(c); 165 } 166 167 /** 168 * Creates a new hash set with {@link #DEFAULT_LOAD_FACTOR} as load 169 * factor copying a given collection. 170 * 171 * @param c a {@link Collection} to be copied into the new hash set. 172 */ 173 public UnorderedSet(final Collection<? extends K> c) { 174 this(c, (c instanceof UnorderedSet) ? ((UnorderedSet) c).f : DEFAULT_LOAD_FACTOR, (c instanceof UnorderedSet) ? ((UnorderedSet) c).hasher : CrossHash.mildHasher); 175 } 176 177 /** 178 * Creates a new hash set using elements provided by a type-specific 179 * iterator. 180 * 181 * @param i a type-specific iterator whose elements will fill the set. 182 * @param f the load factor. 183 */ 184 public UnorderedSet(final Iterator<? extends K> i, final float f) { 185 this(DEFAULT_INITIAL_SIZE, f); 186 while (i.hasNext()) 187 add(i.next()); 188 } 189 190 /** 191 * Creates a new hash set with {@link #DEFAULT_LOAD_FACTOR} as load 192 * factor using elements provided by a type-specific iterator. 193 * 194 * @param i a type-specific iterator whose elements will fill the set. 195 */ 196 public UnorderedSet(final Iterator<? extends K> i) { 197 this(i, DEFAULT_LOAD_FACTOR); 198 } 199 200 /** 201 * Creates a new hash set and fills it with the elements of a given array. 202 * 203 * @param a an array whose elements will be used to fill the set. 204 * @param offset the first element to use. 205 * @param length the number of elements to use. 206 * @param f the load factor. 207 */ 208 public UnorderedSet(final K[] a, final int offset, 209 final int length, final float f) { 210 this(Math.max(length, 0), f); 211 if (a == null) throw new NullPointerException("Array passed to OrderedSet constructor cannot be null"); 212 if (offset < 0) throw new ArrayIndexOutOfBoundsException("Offset (" + offset + ") is negative"); 213 if (length < 0) throw new IllegalArgumentException("Length (" + length + ") is negative"); 214 if (offset + length > a.length) { 215 throw new ArrayIndexOutOfBoundsException( 216 "Last index (" + (offset + length) + ") is greater than array length (" + a.length + ")"); 217 } 218 for (int i = 0; i < length; i++) 219 add(a[offset + i]); 220 } 221 222 /** 223 * Creates a new hash set with {@link #DEFAULT_LOAD_FACTOR} as load 224 * factor and fills it with the elements of a given array. 225 * 226 * @param a an array whose elements will be used to fill the set. 227 * @param offset the first element to use. 228 * @param length the number of elements to use. 229 */ 230 public UnorderedSet(final K[] a, final int offset, 231 final int length) { 232 this(a, offset, length, DEFAULT_LOAD_FACTOR); 233 } 234 235 /** 236 * Creates a new hash set copying the elements of an array. 237 * 238 * @param a an array to be copied into the new hash set. 239 * @param f the load factor. 240 */ 241 public UnorderedSet(final K[] a, final float f) { 242 this(a, 0, a.length, f); 243 } 244 245 /** 246 * Creates a new hash set with {@link #DEFAULT_LOAD_FACTOR} as load 247 * factor copying the elements of an array. 248 * 249 * @param a an array to be copied into the new hash set. 250 */ 251 public UnorderedSet(final K[] a) { 252 this(a, DEFAULT_LOAD_FACTOR); 253 } 254 255 /** 256 * Creates a new hash map. 257 * <p> 258 * <p>The actual table size will be the least power of two greater than <code>expected</code>/<code>f</code>. 259 * 260 * @param expected the expected number of elements in the hash set. 261 * @param f the load factor. 262 * @param hasher used to hash items; typically only needed when K is an array, where CrossHash has implementations 263 */ 264 @SuppressWarnings("unchecked") 265 public UnorderedSet(final int expected, final float f, CrossHash.IHasher hasher) { 266 if (f <= 0 || f > 1) 267 throw new IllegalArgumentException("Load factor must be greater than 0 and smaller than or equal to 1"); 268 if (expected < 0) throw new IllegalArgumentException("The expected number of elements must be nonnegative"); 269 this.f = f; 270 n = arraySize(expected, f); 271 mask = n - 1; 272 maxFill = maxFill(n, f); 273 key = (K[]) new Object[n + 1]; 274 this.hasher = hasher == null ? CrossHash.mildHasher : hasher; 275 } 276 277 /** 278 * Creates a new hash set with {@link #DEFAULT_LOAD_FACTOR} as load 279 * factor. 280 * 281 * @param hasher used to hash items; typically only needed when K is an array, where CrossHash has implementations 282 */ 283 public UnorderedSet(CrossHash.IHasher hasher) { 284 this(DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR, hasher); 285 } 286 287 /** 288 * Creates a new hash set with {@link #DEFAULT_LOAD_FACTOR} as load 289 * factor. 290 * 291 * @param hasher used to hash items; typically only needed when K is an array, where CrossHash has implementations 292 */ 293 public UnorderedSet(final int expected, CrossHash.IHasher hasher) { 294 this(expected, DEFAULT_LOAD_FACTOR, hasher); 295 } 296 297 /** 298 * Creates a new hash set copying a given collection. 299 * 300 * @param c a {@link Collection} to be copied into the new hash set. 301 * @param f the load factor. 302 * @param hasher used to hash items; typically only needed when K is an array, where CrossHash has implementations 303 */ 304 public UnorderedSet(final Collection<? extends K> c, 305 final float f, CrossHash.IHasher hasher) { 306 this(c.size(), f, hasher); 307 addAll(c); 308 } 309 310 /** 311 * Creates a new hash set with {@link #DEFAULT_LOAD_FACTOR} as load 312 * factor copying a given collection. 313 * 314 * @param c a {@link Collection} to be copied into the new hash set. 315 * @param hasher used to hash items; typically only needed when K is an array, where CrossHash has implementations 316 */ 317 public UnorderedSet(final Collection<? extends K> c, CrossHash.IHasher hasher) { 318 this(c, DEFAULT_LOAD_FACTOR, hasher); 319 } 320 321 /** 322 * Creates a new hash set and fills it with the elements of a given array. 323 * 324 * @param a an array whose elements will be used to fill the set. 325 * @param offset the first element to use. 326 * @param length the number of elements to use. 327 * @param f the load factor. 328 */ 329 public UnorderedSet(final K[] a, final int offset, 330 final int length, final float f, CrossHash.IHasher hasher) { 331 this(Math.max(length, 0), f, hasher); 332 if (a == null) throw new NullPointerException("Array passed to OrderedSet constructor cannot be null"); 333 if (offset < 0) throw new ArrayIndexOutOfBoundsException("Offset (" + offset + ") is negative"); 334 if (length < 0) throw new IllegalArgumentException("Length (" + length + ") is negative"); 335 if (offset + length > a.length) { 336 throw new ArrayIndexOutOfBoundsException( 337 "Last index (" + (offset + length) + ") is greater than array length (" + a.length + ")"); 338 } 339 for (int i = 0; i < length; i++) 340 add(a[offset + i]); 341 } 342 343 /** 344 * Creates a new hash set with {@link #DEFAULT_LOAD_FACTOR} as load 345 * factor and fills it with the elements of a given array. 346 * 347 * @param a an array whose elements will be used to fill the set. 348 * @param offset the first element to use. 349 * @param length the number of elements to use. 350 */ 351 public UnorderedSet(final K[] a, final int offset, 352 final int length, CrossHash.IHasher hasher) { 353 this(a, offset, length, DEFAULT_LOAD_FACTOR, hasher); 354 } 355 356 /** 357 * Creates a new hash set copying the elements of an array. 358 * 359 * @param a an array to be copied into the new hash set. 360 * @param f the load factor. 361 */ 362 public UnorderedSet(final K[] a, final float f, CrossHash.IHasher hasher) { 363 this(a, 0, a.length, f, hasher); 364 } 365 366 /** 367 * Creates a new hash set with {@link #DEFAULT_LOAD_FACTOR} as load 368 * factor copying the elements of an array. 369 * 370 * @param a an array to be copied into the new hash set. 371 */ 372 public UnorderedSet(final K[] a, CrossHash.IHasher hasher) { 373 this(a, DEFAULT_LOAD_FACTOR, hasher); 374 } 375 376 private int realSize() { 377 return containsNull ? size - 1 : size; 378 } 379 380 private void ensureCapacity(final int capacity) { 381 final int needed = arraySize(capacity, f); 382 if (needed > n) 383 rehash(needed); 384 } 385 386 private void tryCapacity(final long capacity) { 387 final int needed = (int) Math.min( 388 1 << 30, 389 Math.max(2, HashCommon.nextPowerOfTwo((long) Math.ceil(capacity 390 / f)))); 391 if (needed > n) 392 rehash(needed); 393 } 394 395 public boolean addAll(Collection<? extends K> c) { 396 int n = c.size(); 397 // The resulting collection will be at least c.size() big 398 if (f <= .5) 399 ensureCapacity(n); // The resulting collection will be sized 400 // for c.size() elements 401 else 402 tryCapacity(size + n); // The resulting collection will be 403 // tentatively sized for size() + c.size() elements 404 boolean retVal = false; 405 final Iterator<? extends K> i = c.iterator(); 406 while (n-- != 0) 407 if (add(i.next())) 408 retVal = true; 409 return retVal; 410 } 411 412 public boolean addAll(K[] a) { 413 if(a == null) 414 return false; 415 int n = a.length; 416 // The resulting collection will be at least a.length big 417 if (f <= .5) 418 ensureCapacity(n); // The resulting collection will be sized 419 // for a.length elements 420 else 421 tryCapacity(size + n); // The resulting collection will be 422 // tentatively sized for size() + a.length elements 423 boolean retVal = false; 424 for (int i = 0; i < n; i++) { 425 if(add(a[i])) 426 retVal = true; 427 } 428 return retVal; 429 } 430 431 432 public boolean add(final K k) { 433 int pos; 434 if (k == null) { 435 if (containsNull) 436 return false; 437 containsNull = true; 438 } else { 439 K curr; 440 final K[] key = this.key; 441 // The starting point. 442 if (!((curr = key[pos = (hasher.hash(k)) & mask]) == null)) { 443 if (hasher.areEqual(curr, k)) 444 return false; 445 while (!((curr = key[pos = pos + 1 & mask]) == null)) 446 if (hasher.areEqual(curr, k)) 447 return false; 448 } 449 key[pos] = k; 450 } 451 if (size++ >= maxFill) 452 rehash(arraySize(size + 1, f)); 453 return true; 454 } 455 456 /** 457 * Add a random element if not present, get the existing value if already 458 * present. 459 * <p> 460 * This is equivalent to (but faster than) doing a: 461 * <p> 462 * <pre> 463 * K exist = set.get(k); 464 * if (exist == null) { 465 * set.add(k); 466 * exist = k; 467 * } 468 * </pre> 469 */ 470 public K addOrGet(final K k) { 471 int pos; 472 if (k == null) { 473 if (containsNull) 474 return key[n]; 475 containsNull = true; 476 } else { 477 K curr; 478 final K[] key = this.key; 479 // The starting point. 480 if (!((curr = key[pos = (hasher.hash(k)) & mask]) == null)) { 481 if (hasher.areEqual(curr, k)) 482 return curr; 483 while (!((curr = key[pos = pos + 1 & mask]) == null)) 484 if (hasher.areEqual(curr, k)) 485 return curr; 486 } 487 key[pos] = k; 488 } 489 if (size++ >= maxFill) 490 rehash(arraySize(size + 1, f)); 491 return k; 492 } 493 494 /** 495 * Shifts left entries with the specified hash code, starting at the 496 * specified position, and empties the resulting free entry. 497 * 498 * @param pos a starting position. 499 */ 500 protected final void shiftKeys(int pos) { 501 // Shift entries with the same hash. 502 int last, slot; 503 K curr; 504 final K[] key = this.key; 505 for (; ; ) { 506 pos = (last = pos) + 1 & mask; 507 for (; ; ) { 508 if ((curr = key[pos]) == null) { 509 key[last] = null; 510 return; 511 } 512 slot = (hasher.hash(curr)) 513 & mask; 514 if (last <= pos ? last >= slot || slot > pos : last >= slot 515 && slot > pos) 516 break; 517 pos = pos + 1 & mask; 518 } 519 key[last] = curr; 520 } 521 } 522 523 private boolean removeEntry(final int pos) { 524 size--; 525 shiftKeys(pos); 526 if (size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE) 527 rehash(n / 2); 528 return true; 529 } 530 531 private boolean removeNullEntry() { 532 containsNull = false; 533 key[n] = null; 534 size--; 535 if (size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE) 536 rehash(n / 2); 537 return true; 538 } 539 540 @Override 541 public boolean remove(final Object k) { 542 if (k == null) 543 return containsNull && removeNullEntry(); 544 K curr; 545 final K[] key = this.key; 546 int pos; 547 // The starting point. 548 if ((curr = key[pos = (hasher.hash(k)) & mask]) == null) 549 return false; 550 if (hasher.areEqual(k, curr)) 551 return removeEntry(pos); 552 while (true) { 553 if ((curr = key[pos = pos + 1 & mask]) == null) 554 return false; 555 if (hasher.areEqual(k, curr)) 556 return removeEntry(pos); 557 } 558 } 559 560 /** 561 * Returns the element of this set that is equal to the given key, or 562 * <code>null</code>. 563 * 564 * @return the element of this set that is equal to the given key, or 565 * <code>null</code>. 566 */ 567 public K get(final Object k) { 568 if (k == null) 569 return key[n]; // This is correct independently of the value of 570 // containsNull and of the map being custom 571 K curr; 572 final K[] key = this.key; 573 int pos; 574 // The starting point. 575 if ((curr = key[pos = (hasher.hash(k)) & mask]) == null) 576 return null; 577 if (hasher.areEqual(k, curr)) 578 return curr; 579 // There's always an unused entry. 580 while (true) { 581 if ((curr = key[pos = pos + 1 & mask]) == null) 582 return null; 583 if (hasher.areEqual(k, curr)) 584 return curr; 585 } 586 } 587 588 public boolean contains(final Object k) { 589 if (k == null) 590 return containsNull; 591 K curr; 592 final K[] key = this.key; 593 int pos; 594 // The starting point. 595 if ((curr = key[pos = (hasher.hash(k)) & mask]) == null) 596 return false; 597 if (hasher.areEqual(k, curr)) 598 return true; 599 // There's always an unused entry. 600 while (true) { 601 if ((curr = key[pos = pos + 1 & mask]) == null) 602 return false; 603 if (hasher.areEqual(k, curr)) 604 return true; 605 } 606 } 607 608 protected int positionOf(final Object k) { 609 if (k == null) 610 { 611 if(containsNull) 612 return n; 613 else 614 return -1; 615 } 616 K curr; 617 final K[] key = this.key; 618 int pos; 619 // The starting point. 620 if ((curr = key[pos = (hasher.hash(k)) & mask]) == null) 621 return -1; 622 if (hasher.areEqual(k, curr)) 623 return pos; 624 // There's always an unused entry. 625 while (true) { 626 if ((curr = key[pos = pos + 1 & mask]) == null) 627 return -1; 628 if (hasher.areEqual(k, curr)) 629 return pos; 630 } 631 } 632 633 /* 634 * Removes all elements from this set. 635 * 636 * <P>To increase object reuse, this method does not change the table size. 637 * If you want to reduce the table size, you must use {@link #trim()}. 638 */ 639 public void clear() { 640 if (size == 0) 641 return; 642 size = 0; 643 containsNull = false; 644 Arrays.fill(key, null); 645 } 646 647 public int size() { 648 return size; 649 } 650 651 /** 652 * Checks whether this collection contains all elements from the given 653 * collection. 654 * 655 * @param c a collection. 656 * @return <code>true</code> if this collection contains all elements of the 657 * argument. 658 */ 659 public boolean containsAll(Collection<?> c) { 660 int n = c.size(); 661 final Iterator<?> i = c.iterator(); 662 while (n-- != 0) 663 if (!contains(i.next())) 664 return false; 665 return true; 666 } 667 668 /** 669 * Retains in this collection only elements from the given collection. 670 * 671 * @param c a collection. 672 * @return <code>true</code> if this collection changed as a result of the 673 * call. 674 */ 675 public boolean retainAll(Collection<?> c) { 676 boolean retVal = false; 677 int n = size; 678 final Iterator<?> i = iterator(); 679 while (n-- != 0) { 680 if (!c.contains(i.next())) { 681 i.remove(); 682 retVal = true; 683 } 684 } 685 return retVal; 686 } 687 688 /** 689 * Remove from this collection all elements in the given collection. If the 690 * collection is an instance of this class, it uses faster iterators. 691 * 692 * @param c a collection. 693 * @return <code>true</code> if this collection changed as a result of the 694 * call. 695 */ 696 public boolean removeAll(Collection<?> c) { 697 boolean retVal = false; 698 int n = c.size(); 699 final Iterator<?> i = c.iterator(); 700 while (n-- != 0) 701 if (remove(i.next())) 702 retVal = true; 703 return retVal; 704 } 705 706 public boolean isEmpty() { 707 return size == 0; 708 } 709 710 711 /* 712 * A list iterator over a set. 713 * <p> 714 * <p> 715 * This class provides a list iterator over a hash set. The 716 * constructor takes constant time. 717 */ 718 private class SetIterator implements Iterator <K> { 719 /** The index of the last entry returned, if positive or zero; initially, {@link #n}. If negative, the last 720 element returned was that of index {@code - pos - 1} from the {@link #wrapped} list. */ 721 int pos = n; 722 /** The index of the last entry that has been returned (more precisely, the value of {@link #pos} if {@link #pos} is positive, 723 or {@link Integer#MIN_VALUE} if {@link #pos} is negative). It is -1 if either 724 we did not return an entry yet, or the last returned entry has been removed. */ 725 int last = -1; 726 /** A downward counter measuring how many entries must still be returned. */ 727 int c = size; 728 /** A boolean telling us whether we should return the null key. */ 729 boolean mustReturnNull = UnorderedSet.this.containsNull; 730 /** A lazily allocated list containing elements that have wrapped around the table because of removals. */ 731 ArrayList <K> wrapped; 732 public boolean hasNext() { 733 return c != 0; 734 } 735 public K next() { 736 if ( ! hasNext() ) throw new NoSuchElementException(); 737 c--; 738 if ( mustReturnNull ) { 739 mustReturnNull = false; 740 last = n; 741 return key[ n ]; 742 } 743 final K[] key = UnorderedSet.this.key; 744 for(;;) { 745 if ( --pos < 0 ) { 746 // We are just enumerating elements from the wrapped list. 747 last = Integer.MIN_VALUE; 748 return wrapped.get( - pos - 1 ); 749 } 750 if ( ! ( (key[ pos ]) == null ) ) return key[ last = pos ]; 751 } 752 } 753 /** Shifts left entries with the specified hash code, starting at the specified position, 754 * and empties the resulting free entry. 755 * 756 * @param pos a starting position. 757 */ 758 private void shiftKeys(int pos ) { 759 // Shift entries with the same hash. 760 int last, slot; 761 K current; 762 final K[] key = UnorderedSet.this.key; 763 for(;;) { 764 pos = ( ( last = pos ) + 1 ) & mask; 765 for(;;) { 766 if ( ( (current = key[ pos ]) == null ) ) { 767 key[ last ] = (null); 768 return; 769 } 770 slot = ( (hasher.hash(current)) ) & mask; 771 if ( last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos ) break; 772 pos = ( pos + 1 ) & mask; 773 } 774 if ( pos < last ) { // Wrapped entry. 775 if ( wrapped == null ) wrapped = new ArrayList<K>( 2 ); 776 wrapped.add( key[ pos ] ); 777 } 778 key[ last ] = current; 779 } 780 } 781 public void remove() { 782 if ( last == -1 ) throw new IllegalStateException(); 783 if ( last == n ) { 784 UnorderedSet.this.containsNull = false; 785 UnorderedSet.this.key[ n ] = (null); 786 } 787 else if ( pos >= 0 ) shiftKeys( last ); 788 else { 789 // We're removing wrapped entries. 790 UnorderedSet.this.remove( wrapped.set( - pos - 1, null ) ); 791 last = -1; // Note that we must not decrement size 792 return; 793 } 794 size--; 795 last = -1; // You can no longer remove this entry. 796 } 797 /** This method just iterates the type-specific version of {@link #next()} for at most 798 * <code>n</code> times, stopping if {@link #hasNext()} becomes false.*/ 799 public int skip( final int n ) { 800 int i = n; 801 while( i-- != 0 && hasNext() ) next(); 802 return n - i - 1; 803 } 804 } 805 806 public Iterator<K> iterator() { 807 return new SetIterator(); 808 } 809 810 /** 811 * Rehashes the map, making the table as small as possible. 812 * <p> 813 * <P>This method rehashes the table to the smallest size satisfying the load factor. It can be used when the set will not be changed anymore, so to optimize access speed and size. 814 * <p> 815 * <P>If the table size is already the minimum possible, this method does nothing. 816 * 817 * @return true if there was enough memory to trim the map. 818 * @see #trim(int) 819 */ 820 public boolean trim() { 821 final int l = arraySize(size, f); 822 if (l >= n || size > maxFill(l, f)) return true; 823 try { 824 rehash(l); 825 } catch (Exception cantDoIt) { 826 return false; 827 } 828 return true; 829 } 830 831 /** 832 * Rehashes this map if the table is too large. 833 * <p> 834 * <P>Let <var>N</var> be the smallest table size that can hold <code>max(n,{@link #size()})</code> entries, still satisfying the load factor. If the current table size is smaller than or equal to 835 * <var>N</var>, this method does nothing. Otherwise, it rehashes this map in a table of size <var>N</var>. 836 * <p> 837 * <P>This method is useful when reusing maps. {@linkplain #clear() Clearing a map} leaves the table size untouched. If you are reusing a map many times, you can call this method with a typical 838 * size to avoid keeping around a very large table just because of a few large transient maps. 839 * 840 * @param n the threshold for the trimming. 841 * @return true if there was enough memory to trim the map. 842 * @see #trim() 843 */ 844 public boolean trim(final int n) { 845 final int l = HashCommon.nextPowerOfTwo((int) Math.ceil(n / f)); 846 if (l >= n || size > maxFill(l, f)) return true; 847 try { 848 rehash(l); 849 } catch (Exception cantDoIt) { 850 return false; 851 } 852 return true; 853 } 854 855 /** 856 * Given a hash position, this finds the next position that contains an item, or -1 if none remain. 857 * To scan from the start, give this -1 for position. 858 * @param position a hash-based masked position in the K array 859 * @return the next position after the given one 860 */ 861 private int scanNext(int position) 862 { 863 int h = position; 864 while (++h < n) 865 { 866 if(key[h] != null) 867 { 868 return h; 869 } 870 } 871 if(containsNull) 872 return n; 873 return -1; 874 } 875 876 /** 877 * Rehashes the map. 878 * <p> 879 * <p> 880 * This method implements the basic rehashing strategy, and may be overriden 881 * by subclasses implementing different rehashing strategies (e.g., 882 * disk-based rehashing). However, you should not override this method 883 * unless you understand the internal workings of this class. 884 * 885 * @param newN the new size 886 */ 887 @SuppressWarnings("unchecked") 888 protected void rehash(final int newN) { 889 final K[] key = this.key; 890 final int mask = newN - 1; 891 final K[] newKey = (K[]) new Object[newN + 1]; 892 K k; 893 int i = -1, pos, sz = size; 894 for (int q = 0; q < sz; q++) { 895 i = scanNext(i); 896 if ((k = key[i]) == null) 897 pos = newN; 898 else { 899 pos = (hasher.hash(k)) & mask; 900 while (!(newKey[pos] == null)) 901 pos = pos + 1 & mask; 902 } 903 newKey[pos] = k; 904 } 905 n = newN; 906 this.mask = mask; 907 maxFill = maxFill(n, f); 908 this.key = newKey; 909 } 910 911 /** 912 * Returns a deep copy of this map. 913 * <p> 914 * <p> 915 * This method performs a deep copy of this hash map; the data stored in the 916 * map, however, is not cloned. Note that this makes a difference only for 917 * object keys. 918 * 919 * @return a deep copy of this map. 920 */ 921 @SuppressWarnings("unchecked") 922 @GwtIncompatible 923 public Object clone() { 924 UnorderedSet<K> c; 925 try { 926 c = new UnorderedSet<>(hasher); 927 c.key = (K[]) new Object[n + 1]; 928 System.arraycopy(key, 0, c.key, 0, n + 1); 929 return c; 930 } catch (Exception cantHappen) { 931 throw new UnsupportedOperationException(cantHappen + (cantHappen.getMessage() != null ? 932 "; " + cantHappen.getMessage() : "")); 933 } 934 } 935 936 /** 937 * Returns a hash code for this set. 938 * <p> 939 * This method overrides the generic method provided by the superclass. 940 * Since <code>equals()</code> is not overriden, it is important that the 941 * value returned by this method is the same value as the one returned by 942 * the overriden method. 943 * 944 * @return a hash code for this set. 945 */ 946 public int hashCode() { 947 int h = 0; 948 for (int j = realSize(), i = 0; j-- != 0; ) { 949 while (key[i] == null) 950 i++; 951 if (this != key[i]) 952 h += hasher.hash(key[i]); 953 i++; 954 } 955 // Zero / null have hash zero. 956 return h; 957 } 958 959 public long hash64() 960 { 961 return 31L * size + CrossHash.hash64(key); 962 } 963 964 /** 965 * Returns the maximum number of entries that can be filled before rehashing. 966 * 967 * @param n the size of the backing array. 968 * @param f the load factor. 969 * @return the maximum number of entries before rehashing. 970 */ 971 public static int maxFill(final int n, final float f) { 972 /* We must guarantee that there is always at least 973 * one free entry (even with pathological load factors). */ 974 return Math.min((int) Math.ceil(n * f), n - 1); 975 } 976 977 /** 978 * Returns the maximum number of entries that can be filled before rehashing. 979 * 980 * @param n the size of the backing array. 981 * @param f the load factor. 982 * @return the maximum number of entries before rehashing. 983 */ 984 public static long maxFill(final long n, final float f) { 985 /* We must guarantee that there is always at least 986 * one free entry (even with pathological load factors). */ 987 return Math.min((long) Math.ceil(n * f), n - 1); 988 } 989 990 /** 991 * Returns the least power of two smaller than or equal to 2<sup>30</sup> and larger than or equal to <code>Math.ceil( expected / f )</code>. 992 * 993 * @param expected the expected number of elements in a hash table. 994 * @param f the load factor. 995 * @return the minimum possible size for a backing array. 996 * @throws IllegalArgumentException if the necessary size is larger than 2<sup>30</sup>. 997 */ 998 public static int arraySize(final int expected, final float f) { 999 final long s = Math.max(2, HashCommon.nextPowerOfTwo((long) Math.ceil(expected / f))); 1000 if (s > 1 << 30) 1001 throw new IllegalArgumentException("Too large (" + expected + " expected elements with load factor " + f + ")"); 1002 return (int) s; 1003 } 1004 1005 @Override 1006 public Object[] toArray() { 1007 final Object[] a = new Object[size]; 1008 objectUnwrap(iterator(), a); 1009 return a; 1010 } 1011 1012 @Override 1013 public <T> T[] toArray(T[] a) { 1014 final int size = this.size; 1015 objectUnwrap(iterator(), a); 1016 if (size < a.length) 1017 a[size] = null; 1018 return a; 1019 } 1020 1021 1022 /** 1023 * Unwraps an iterator into an array starting at a given offset for a given number of elements. 1024 * <p> 1025 * <P>This method iterates over the given type-specific iterator and stores the elements returned, up to a maximum of <code>length</code>, in the given array starting at <code>offset</code>. The 1026 * number of actually unwrapped elements is returned (it may be less than <code>max</code> if the iterator emits less than <code>max</code> elements). 1027 * 1028 * @param i a type-specific iterator. 1029 * @param array an array to contain the output of the iterator. 1030 * @param offset the first element of the array to be returned. 1031 * @param max the maximum number of elements to unwrap. 1032 * @return the number of elements unwrapped. 1033 */ 1034 private static <K> int objectUnwrap(final Iterator<? extends K> i, final K[] array, int offset, final int max) { 1035 if (max < 0) throw new IllegalArgumentException("The maximum number of elements (" + max + ") is negative"); 1036 if (offset < 0 || offset + max > array.length) throw new IllegalArgumentException(); 1037 int j = max; 1038 while (j-- != 0 && i.hasNext()) 1039 array[offset++] = i.next(); 1040 return max - j - 1; 1041 } 1042 1043 /** 1044 * Unwraps an iterator into an array. 1045 * <p> 1046 * <P>This method iterates over the given type-specific iterator and stores the elements returned in the given array. The iteration will stop when the iterator has no more elements or when the end 1047 * of the array has been reached. 1048 * 1049 * @param i a type-specific iterator. 1050 * @param array an array to contain the output of the iterator. 1051 * @return the number of elements unwrapped. 1052 */ 1053 private static <K> int objectUnwrap(final Iterator<? extends K> i, final K[] array) { 1054 return objectUnwrap(i, array, 0, array.length); 1055 } 1056 1057 @Override 1058 public String toString() { 1059 final StringBuilder s = new StringBuilder(); 1060 int i = scanNext(-1); 1061 boolean first = true; 1062 s.append("OrderedSet{"); 1063 while (i != -1) { 1064 if (first) first = false; 1065 else s.append(", "); 1066 s.append(key[i]); 1067 i = scanNext(i); 1068 } 1069 s.append("}"); 1070 return s.toString(); 1071 } 1072 1073 @Override 1074 public boolean equals(final Object o) { 1075 if (o == this) 1076 return true; 1077 if (!(o instanceof Set)) 1078 return false; 1079 Set<?> s = (Set<?>) o; 1080 if (s.size() != size) 1081 return false; 1082 return containsAll(s); 1083 } 1084 1085 @GwtIncompatible 1086 private void writeObject(java.io.ObjectOutputStream s) 1087 throws java.io.IOException { 1088 final Iterator<K> i = iterator(); 1089 s.defaultWriteObject(); 1090 for (int j = size; j-- != 0; ) 1091 s.writeObject(i.next()); 1092 } 1093 1094 @GwtIncompatible 1095 @SuppressWarnings("unchecked") 1096 private void readObject(java.io.ObjectInputStream s) 1097 throws java.io.IOException, ClassNotFoundException { 1098 s.defaultReadObject(); 1099 n = arraySize(size, f); 1100 maxFill = maxFill(n, f); 1101 mask = n - 1; 1102 final K[] key = this.key = (K[]) new Object[n + 1]; 1103 K k; 1104 for (int i = size, pos; i-- != 0; ) { 1105 k = (K) s.readObject(); 1106 if (k == null) { 1107 pos = n; 1108 containsNull = true; 1109 } else { 1110 if (!(key[pos = (hasher.hash(k)) & mask] == null)) 1111 while (!(key[pos = pos + 1 & mask] == null)) ; 1112 } 1113 key[pos] = k; 1114 } 1115 } 1116}