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.ArrayTools; 019import squidpony.annotation.GwtIncompatible; 020 021import java.io.Serializable; 022import java.util.*; 023 024/** 025 * A bi-directional mapping of objects to positions in an ordering (which this generates), and vice versa. 026 * Useful for various indirection techniques where you want to be able to retrieve a value in several ways, such as with 027 * multiple Arrangements all sharing the same ordering but with different types for keys. 028 * <br> 029 * Originally, this started as a generic linked hash map with with a fast implementation, originally from fastutil as 030 * Object2IntLinkedOpenHashMap but modified to support indexed access. The code is extremely close to {@link OrderedMap}, 031 * and like OrderedMap you can look up keys by index, but this is specialized to int values which it can automatically assign. 032 * <br> 033 * <p>Instances of this class use a hash table to represent a map. The table is filled up to a specified <em>load factor</em>, and then doubled in size to accommodate new entries. If the table is 034 * emptied below <em>one fourth</em> of the load factor, it is halved in size. However, halving is not performed when deleting entries from an iterator, as it would interfere with the iteration 035 * process. 036 * </p> 037 * <p>Note that {@link #clear()} does not modify the hash table size. Rather, a family of {@linkplain #trim() trimming methods} lets you control the size of the table; this is particularly useful if 038 * you reuse instances of this class. 039 * </p> 040 * <p>Iterators generated by this map will enumerate pairs in the same order in which they have been added to the map (addition of pairs whose key is already present in the set does not change the 041 * iteration order). Note that this order has nothing in common with the natural order of the keys. The order is kept by means of a int-specialized list, {@link IntVLA}, and is modifiable with this 042 * class' {@link #reorder(int...)} and {@link #shuffle(IRNG)} methods, among other tools. 043 * </p> 044 * <p>This class implements the interface of a sorted map, so to allow easy access of the iteration order: for instance, you can get the first key in iteration order with {@code firstKey()} without 045 * having to create an iterator; however, this class partially violates the {@link SortedMap} contract because all submap methods throw an exception and {@link #comparator()} returns always 046 * <code>null</code>. 047 * </p> 048 * <p> 049 * Additional methods, such as <code>getAndMoveToFirst()</code>, make it easy to use instances of this class as a cache (e.g., with LRU policy). 050 * </p> 051 * <br> 052 * Thank you, Sebastiano Vigna, for making FastUtil available to the public with such high quality. 053 * <br> 054 * See https://github.com/vigna/fastutil for the original library. 055 * 056 * @author Sebastiano Vigna (responsible for all the hard parts) 057 * @author Tommy Ettinger (mostly responsible for squashing several layers of parent classes into one monster class) 058 */ 059public class Arrangement<K> implements SortedMap<K, Integer>, Iterable<K>, Serializable, Cloneable { 060 private static final long serialVersionUID = 0L; 061 /** 062 * The array of keys. 063 */ 064 protected K[] key; 065 /** 066 * The array of values. 067 */ 068 protected int[] value; 069 /** 070 * The mask for wrapping a position counter. 071 */ 072 protected int mask; 073 /** 074 * Whether this set contains the key zero. 075 */ 076 protected boolean containsNullKey; 077 078 /** 079 * The ordering of entries, with the nth entry in order being the index into {@link #key} and {@link #value} to find 080 * that entry's key and value. The ints in order are always less than or equal to n, and greater than or equal to 0. 081 */ 082 protected IntVLA order; 083 /** 084 * The current table size. 085 */ 086 protected int n; 087 /** 088 * Threshold after which we rehash. It must be the table size times {@link #f}. 089 */ 090 protected int maxFill; 091 /** 092 * Number of entries in the set (including the key zero, if present). 093 */ 094 protected int size; 095 /** 096 * The acceptable load factor. 097 */ 098 public final float f; 099 /** 100 * Cached set of entries. 101 */ 102 protected volatile MapEntrySet entries; 103 /** 104 * Cached set of keys. 105 */ 106 protected volatile KeySet keys; 107 /** 108 * Cached collection of values. 109 */ 110 protected volatile Collection<Integer> values; 111 /** 112 * Default return value. 113 */ 114 protected final int defRetValue = -1; 115 116 /** 117 * The initial default size of a hash table. 118 */ 119 public static final int DEFAULT_INITIAL_SIZE = 16; 120 /** 121 * The default load factor of a hash table. 122 */ 123 public static final float DEFAULT_LOAD_FACTOR = .25f; // .375f // .1875f; // .75f; 124 /** 125 * The load factor for a (usually small) table that is meant to be particularly fast. 126 */ 127 public static final float FAST_LOAD_FACTOR = .5f; 128 /** 129 * The load factor for a (usually very small) table that is meant to be extremely fast. 130 */ 131 public static final float VERY_FAST_LOAD_FACTOR = .25f; 132 133 protected final CrossHash.IHasher hasher; 134 135 /** 136 * Creates a new Arrangement. 137 * <p> 138 * <p>The actual table size will be the least power of two greater than <code>expected</code>/<code>f</code>. 139 * 140 * @param expected the expected number of elements in the hash set. 141 * @param f the load factor. 142 */ 143 144 @SuppressWarnings("unchecked") 145 public Arrangement(final int expected, final float f) { 146 if (f <= 0 || f > 1) 147 throw new IllegalArgumentException("Load factor must be greater than 0 and smaller than or equal to 1"); 148 if (expected < 0) throw new IllegalArgumentException("The expected number of elements must be nonnegative"); 149 this.f = f; 150 n = arraySize(expected, f); 151 mask = n - 1; 152 maxFill = maxFill(n, f); 153 key = (K[]) new Object[n + 1]; 154 value = new int[n + 1]; 155 //link = new long[n + 1]; 156 order = new IntVLA(expected); 157 hasher = CrossHash.mildHasher; 158 } 159 160 /** 161 * Creates a new Arrangement with 0.5f as load factor. 162 * 163 * @param expected the expected number of elements in the Arrangement. 164 */ 165 public Arrangement(final int expected) { 166 this(expected, DEFAULT_LOAD_FACTOR); 167 } 168 169 /** 170 * Creates a new Arrangement with initial expected 16 entries and 0.5f as load factor. 171 */ 172 public Arrangement() { 173 this(DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR); 174 } 175 176 /** 177 * Creates a new Arrangement copying a given one. 178 * 179 * @param m a {@link Map} to be copied into the new Arrangement. 180 * @param f the load factor. 181 */ 182 public Arrangement(final Map<? extends K, ? extends Integer> m, final float f) { 183 this(m.size(), f, (m instanceof Arrangement) ? ((Arrangement) m).hasher : CrossHash.mildHasher); 184 putAll(m); 185 } 186 187 /** 188 * Creates a new Arrangement with 0.5f as load factor copying a given one. 189 * 190 * @param m a {@link Map} to be copied into the new Arrangement. 191 */ 192 public Arrangement(final Map<? extends K, ? extends Integer> m) { 193 this(m, (m instanceof Arrangement) ? ((Arrangement) m).f : DEFAULT_LOAD_FACTOR, (m instanceof Arrangement) ? ((Arrangement) m).hasher : CrossHash.mildHasher); 194 } 195 196 public Arrangement(final Arrangement<? extends K> a) { 197 this(a.size(), a.f, a.hasher); 198 ensureCapacity(a.size()); // The resulting map will be sized for 199 System.arraycopy(a.key, 0, key, 0, a.key.length); 200 System.arraycopy(a.value, 0, value, 0, a.value.length); 201 order.addAll(a.order); 202 containsNullKey = a.containsNullKey; 203 } 204 205 /** 206 * Creates a new Arrangement using the elements of an array. 207 * 208 * @param keyArray the array of keys of the new Arrangement. 209 * @param f the load factor. 210 * @throws IllegalArgumentException if <code>k</code> and <code>v</code> have different lengths. 211 */ 212 public Arrangement(final K[] keyArray, final float f) { 213 this(keyArray.length, f); 214 for (int i = 0; i < keyArray.length; i++) 215 put(keyArray[i], i); 216 } 217 218 /** 219 * Creates a new Arrangement using the elements of an array. 220 * 221 * @param keyColl the collection of keys of the new Arrangement. 222 * @throws IllegalArgumentException if <code>k</code> and <code>v</code> have different lengths. 223 */ 224 public Arrangement(final Collection<K> keyColl) { 225 this(keyColl, DEFAULT_LOAD_FACTOR); 226 } 227 /** 228 * Creates a new Arrangement using the given collection of keys. 229 * 230 * @param keyColl the collection of keys of the new Arrangement. 231 * @param f the load factor. 232 * @throws IllegalArgumentException if <code>k</code> and <code>v</code> have different lengths. 233 */ 234 public Arrangement(final Collection<K> keyColl, final float f) { 235 this(keyColl.size(), f); 236 Iterator<K> ki = keyColl.iterator(); 237 int idx = 0; 238 while (ki.hasNext()) 239 { 240 put(ki.next(), idx++); 241 } 242 } 243 244 /** 245 * Creates a new Arrangement with 0.5f as load factor using the elements of an array. 246 * 247 * @param keyArray the array of keys of the new Arrangement. 248 * @throws IllegalArgumentException if <code>k</code> and <code>v</code> have different lengths. 249 */ 250 public Arrangement(final K[] keyArray) { 251 this(keyArray, DEFAULT_LOAD_FACTOR); 252 } 253 254 /** 255 * Creates a new Arrangement. 256 * <p> 257 * <p>The actual table size will be the least power of two greater than <code>expected</code>/<code>f</code>. 258 * 259 * @param expected the expected number of elements in the hash set. 260 * @param f the load factor. 261 * @param hasher used to hash items; typically only needed when K is an array, where CrossHash has implementations 262 */ 263 @SuppressWarnings("unchecked") 264 public Arrangement(final int expected, final float f, CrossHash.IHasher hasher) { 265 if (f <= 0 || f > 1) 266 throw new IllegalArgumentException("Load factor must be greater than 0 and smaller than or equal to 1"); 267 if (expected < 0) throw new IllegalArgumentException("The expected number of elements must be nonnegative"); 268 this.f = f; 269 n = arraySize(expected, f); 270 mask = n - 1; 271 maxFill = maxFill(n, f); 272 key = (K[]) new Object[n + 1]; 273 value = new int[n + 1]; 274 //link = new long[n + 1]; 275 order = new IntVLA(expected); 276 this.hasher = (hasher == null) ? CrossHash.mildHasher : hasher; 277 } 278 /** 279 * Creates a new Arrangement with 0.5f as load factor. 280 * 281 * @param expected the expected number of elements in the Arrangement. 282 * @param hasher used to hash items; typically only needed when K is an array, where CrossHash has implementations 283 */ 284 public Arrangement(final int expected, CrossHash.IHasher hasher) { 285 this(expected, DEFAULT_LOAD_FACTOR, hasher); 286 } 287 288 /** 289 * Creates a new Arrangement with initial expected 16 entries and 0.5f as load factor. 290 */ 291 public Arrangement(CrossHash.IHasher hasher) { 292 this(DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR, hasher); 293 } 294 295 /** 296 * Creates a new Arrangement copying a given one. 297 * 298 * @param m a {@link Map} to be copied into the new Arrangement. 299 * @param f the load factor. 300 * @param hasher used to hash items; typically only needed when K is an array, where CrossHash has implementations 301 */ 302 public Arrangement(final Map<? extends K, ? extends Integer> m, final float f, CrossHash.IHasher hasher) { 303 this(m.size(), f, hasher); 304 putAll(m); 305 } 306 307 /** 308 * Creates a new Arrangement with 0.5f as load factor copying a given one. 309 * @param m a {@link Map} to be copied into the new Arrangement. 310 * @param hasher used to hash items; typically only needed when K is an array, where CrossHash has implementations 311 */ 312 public Arrangement(final Map<? extends K, ? extends Integer> m, CrossHash.IHasher hasher) { 313 this(m, DEFAULT_LOAD_FACTOR, hasher); 314 } 315 316 /** 317 * Creates a new Arrangement using the elements of two parallel arrays. 318 * 319 * @param keyArray the array of keys of the new Arrangement. 320 * @param f the load factor. 321 * @param hasher used to hash items; typically only needed when K is an array, where CrossHash has implementations 322 * @throws IllegalArgumentException if <code>k</code> and <code>v</code> have different lengths. 323 */ 324 public Arrangement(final K[] keyArray, final float f, CrossHash.IHasher hasher) { 325 this(keyArray.length, f, hasher); 326 327 for (int i = 0; i < keyArray.length; i++) 328 put(keyArray[i], i); 329 } 330 /** 331 * Creates a new Arrangement with 0.5f as load factor using the elements of two parallel arrays. 332 * 333 * @param keyArray the array of keys of the new Arrangement. 334 * @param hasher used to hash items; typically only needed when K is an array, where CrossHash has implementations 335 * @throws IllegalArgumentException if <code>k</code> and <code>v</code> have different lengths. 336 */ 337 public Arrangement(final K[] keyArray, CrossHash.IHasher hasher) { 338 this(keyArray, DEFAULT_LOAD_FACTOR, hasher); 339 } 340 341 private int realSize() { 342 return containsNullKey ? size - 1 : size; 343 } 344 private void ensureCapacity(final int capacity) { 345 final int needed = arraySize(capacity, f); 346 if (needed > n) 347 rehash(needed); 348 } 349 private void tryCapacity(final long capacity) { 350 final int needed = (int) Math.min( 351 1 << 30, 352 Math.max(2, HashCommon.nextPowerOfTwo((long) Math.ceil(capacity 353 / f)))); 354 if (needed > n) 355 rehash(needed); 356 } 357 private int removeEntry(final int pos) { 358 size--; 359 fixOrder(pos); 360 shiftKeys(pos); 361 final int oldValue = value[pos]; 362 fixValues(oldValue); 363 if (size < (maxFill >>> 2) && n > DEFAULT_INITIAL_SIZE) 364 rehash(n / 2); 365 return oldValue; 366 } 367 private int removeNullEntry() { 368 containsNullKey = false; 369 key[n] = null; 370 final int oldValue = value[n]; 371 size--; 372 fixOrder(n); 373 fixValues(oldValue); 374 if (size < (maxFill >>> 2) && n > DEFAULT_INITIAL_SIZE) 375 rehash(n / 2); 376 return oldValue; 377 } 378 379 @Override 380 public void putAll(Map<? extends K, ? extends Integer> m) { 381 if (f <= .5) 382 ensureCapacity(m.size()); // The resulting map will be sized for 383 // m.size() elements 384 else 385 tryCapacity(size() + m.size()); // The resulting map will be 386 int n = m.size(); 387 final Iterator<? extends K> i = m 388 .keySet().iterator(); 389 while (n-- != 0) { 390 add(i.next()); 391 } 392 } 393 394 public void putAll(K[] keyArray) { 395 int n = keyArray.length; 396 if (f <= .5) 397 ensureCapacity(n); // The resulting map will be sized for 398 // m.size() elements 399 else 400 tryCapacity(size() + n); // The resulting map will be 401 // tentatively sized for size() + keyArray.length elements 402 for (int i = 0; i < n; i++) { 403 add(keyArray[i]); 404 } 405 } 406 407 public void putAll(Collection<? extends K> keyColl) { 408 if (f <= .5) 409 ensureCapacity(keyColl.size()); // The resulting map will be sized for 410 // keyColl.size() elements 411 else 412 tryCapacity(size() + keyColl.size()); // The resulting map will be 413 // tentatively sized for size() + keyColl.size() elements 414 Iterator<? extends K> it = keyColl.iterator(); 415 while (it.hasNext()) 416 add(it.next()); 417 } 418 419 private int insert(final K k) { 420 int pos; 421 if (k == null) { 422 if (containsNullKey) 423 return n; 424 containsNullKey = true; 425 pos = n; 426 } else { 427 K curr; 428 final K[] key = this.key; 429 // The starting point. 430 if ((curr = key[pos = (hasher.hash(k)) & mask]) != null) { 431 if (hasher.areEqual(curr, k)) { 432 return pos; 433 } 434 while ((curr = key[pos = (pos + 1) & mask]) != null) 435 if (hasher.areEqual(curr, k)) { 436 return pos; 437 } 438 } 439 } 440 key[pos] = k; 441 order.add(pos); 442 value[pos] = size; 443 if (size++ >= maxFill) 444 rehash(arraySize(size + 1, f)); 445 return -1; 446 } 447 private int insertAt(final K k, final int at) { 448 int pos; 449 if (k == null) { 450 if (containsNullKey) 451 return n; 452 containsNullKey = true; 453 pos = n; 454 } else { 455 K curr; 456 final K[] key = this.key; 457 // The starting point. 458 if ((curr = key[pos = (hasher.hash(k)) & mask]) != null) { 459 if (hasher.areEqual(curr, k)) { 460 order.removeIndex(value[pos]); 461 order.insert(at, pos); 462 return pos; 463 } 464 while ((curr = key[pos = (pos + 1) & mask]) != null) 465 if (hasher.areEqual(curr, k)) { 466 order.removeIndex(value[pos]); 467 order.insert(at, pos); 468 return pos; 469 } 470 } 471 } 472 key[pos] = k; 473 order.insert(at, pos); 474 value[pos] = at; 475 if (size++ >= maxFill) 476 rehash(arraySize(size + 1, f)); 477 return pos; 478 } 479 480 /** 481 * Puts the key k into this Arrangement with a value equal to the current number of keys; v is disregarded. 482 * @param k any K type, including null 483 * @param v any Integer, doesn't matter what it is and will be disregarded. Only here for compatibility 484 * @return the Integer that was previously associated with k, or -1 if there was none 485 */ 486 @Deprecated 487 public Integer put(final K k, final Integer v) { 488 final int pos = insert(k); 489 if (pos < 0) 490 return defRetValue; 491 final Integer oldValue = value[pos]; 492 value[pos] = size-1; 493 return oldValue; 494 } 495 496 public int put(final K k, final int v) { 497 final int pos = insert(k); 498 if (pos < 0) 499 return defRetValue; 500 final int oldValue = value[pos]; 501 value[pos] = size-1; 502 return oldValue; 503 } 504 505 public int add(final K k) { 506 final int pos = insert(k); 507 if (pos < 0) 508 return defRetValue; 509 final int oldValue = value[pos]; 510 value[pos] = size - 1; 511 return oldValue; 512 } 513 514 515 public int addIfAbsent(final K k) 516 { 517 int kPos; 518 if((kPos = getInt(k)) < 0) 519 return add(k); 520 return kPos; 521 } 522 523 /** 524 * If the given key {@code k} is present, this returns its index without modifying the Arrangement; otherwise, it 525 * adds k to the end of the collection and returns the index for it there. 526 * @param k a key to get the index of, adding it if not present 527 * @return the index of {@code k} in this Arrangement 528 */ 529 public int addOrIndex(final K k) 530 { 531 int kPos; 532 if((kPos = getInt(k)) < 0) 533 { 534 insert(k); 535 return size - 1; 536 } 537 return kPos; 538 } 539 540 protected void fixValues(int start) 541 { 542 for (int i = start; i < size; i++) { 543 value[order.items[i]] = i; 544 } 545 } 546 547 /** 548 * Shifts left entries with the specified hash code, starting at the 549 * specified position, and empties the resulting free entry. 550 * 551 * @param pos 552 * a starting position. 553 */ 554 protected final void shiftKeys(int pos) { 555 // Shift entries with the same hash. 556 int last, slot; 557 K curr; 558 final K[] key = this.key; 559 for (;;) { 560 pos = ((last = pos) + 1) & mask; 561 for (;;) { 562 if ((curr = key[pos]) == null) { 563 key[last] = null; 564 return; 565 } 566 slot = (hasher.hash(curr)) 567 & mask; 568 if (last <= pos ? last >= slot || slot > pos : last >= slot 569 && slot > pos) 570 break; 571 pos = (pos + 1) & mask; 572 } 573 key[last] = curr; 574 fixOrder(pos, last); 575 } 576 } 577 578 /** 579 * Shifts left entries with the specified hash code, starting at the 580 * specified position, and empties the resulting free entry. 581 * 582 * @param pos 583 * a starting position. 584 */ 585 protected final void shiftKeysValues(int pos) { 586 // Shift entries with the same hash. 587 int last, slot; 588 K curr; 589 int v; 590 final K[] key = this.key; 591 final int[] val = this.value; 592 for (;;) { 593 pos = ((last = pos) + 1) & mask; 594 for (;;) { 595 if ((curr = key[pos]) == null) { 596 key[last] = null; 597 val[last] = -1; 598 return; 599 } 600 v = val[pos]; 601 slot = (hasher.hash(curr)) 602 & mask; 603 if (last <= pos ? last >= slot || slot > pos : last >= slot 604 && slot > pos) 605 break; 606 pos = (pos + 1) & mask; 607 } 608 key[last] = curr; 609 val[last] = v; 610 fixOrder(pos, last); 611 } 612 } 613 protected Integer rem(final Object k) { 614 if (k == null) { 615 if (containsNullKey) 616 return removeNullEntry(); 617 return null; 618 } 619 K curr; 620 final K[] key = this.key; 621 int pos; 622 // The starting point. 623 if ((curr = key[pos = (hasher.hash(k)) & mask]) == null) 624 return null; 625 if (hasher.areEqual(k, curr)) 626 return removeEntry(pos); 627 while (true) { 628 if ((curr = key[pos = (pos + 1) & mask]) == null) 629 return null; 630 if (hasher.areEqual(k, curr)) 631 return removeEntry(pos); 632 } 633 } 634 public Integer remove(Object o) 635 { 636 return rem(o); 637 } 638 public int removeInt(final Object k) { 639 if (k == null) { 640 if (containsNullKey) 641 return removeNullEntry(); 642 return defRetValue; 643 } 644 K curr; 645 final K[] key = this.key; 646 int pos; 647 // The starting point. 648 if ((curr = key[pos = (hasher.hash(k)) & mask]) == null) 649 return defRetValue; 650 if (hasher.areEqual(k, curr)) 651 return removeEntry(pos); 652 while (true) { 653 if ((curr = key[pos = (pos + 1) & mask]) == null) 654 return defRetValue; 655 if (hasher.areEqual(k, curr)) 656 return removeEntry(pos); 657 } 658 } 659 private int setValue(final int pos, final int v) { 660 final int oldValue = value[pos]; 661 value[pos] = v; 662 return oldValue; 663 } 664 /** 665 * Removes the mapping associated with the first key in iteration order. 666 * 667 * @return the value previously associated with the first key in iteration 668 * order. 669 * @throws NoSuchElementException 670 * is this map is empty. 671 */ 672 public K removeFirst() { 673 if (size == 0) 674 throw new NoSuchElementException(); 675 final int pos = order.removeIndex(0); 676 K fst = key[pos]; 677 size--; 678 final int v = value[pos]; 679 if (pos == n) { 680 containsNullKey = false; 681 key[n] = null; 682 } else 683 shiftKeys(pos); 684 fixValues(v); 685 if (size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE) 686 rehash(n / 2); 687 return fst; 688 } 689 /** 690 * Removes the mapping associated with the last key in iteration order. 691 * 692 * @return the value previously associated with the last key in iteration 693 * order. 694 * @throws NoSuchElementException 695 * is this map is empty. 696 */ 697 public K removeLast() { 698 if (size == 0) 699 throw new NoSuchElementException(); 700 final int pos = order.pop(); 701 K lst = key[pos]; 702 size--; 703 if (pos == n) { 704 containsNullKey = false; 705 key[n] = null; 706 } else 707 shiftKeys(pos); 708 //fixValues(v); // one case where we don't need to do this; the last item is just given -1 709 value[pos] = -1; 710 if (size < maxFill >> 2 && n > DEFAULT_INITIAL_SIZE) 711 rehash(n >> 1); 712 return lst; 713 } 714 private void moveIndexToFirst(final int i) { 715 if(size <= 1 || order.items[0] == i) 716 return; 717 order.moveToFirst(i); 718 fixValues(0); 719 } 720 private void moveIndexToLast(final int i) { 721 if(size <= 1 || order.items[order.size-1] == i) 722 return; 723 order.moveToLast(i); 724 fixValues(i); 725 } 726 /** 727 * Returns the value to which the given key is mapped; if the key is 728 * present, it is moved to the first position of the iteration order. 729 * 730 * @param k 731 * the key. 732 * @return the corresponding value, or -1 if no value was present for the given key. 733 */ 734 public int getAndMoveToFirst(final K k) { 735 if (k == null) { 736 if (containsNullKey) { 737 moveIndexToFirst(n); 738 return value[n]; 739 } 740 return defRetValue; 741 } 742 K curr; 743 final K[] key = this.key; 744 int pos; 745 // The starting point. 746 if ((curr = key[pos = (hasher.hash(k)) & mask]) == null) 747 return defRetValue; 748 if (hasher.areEqual(k, curr)) { 749 moveIndexToFirst(pos); 750 return value[pos]; 751 } 752 // There's always an unused entry. 753 while (true) { 754 if ((curr = key[pos = (pos + 1) & mask]) == null) 755 return defRetValue; 756 if (hasher.areEqual(k, curr)) { 757 moveIndexToFirst(pos); 758 return value[pos]; 759 } 760 } 761 } 762 /** 763 * Returns the value to which the given key is mapped; if the key is 764 * present, it is moved to the last position of the iteration order. 765 * 766 * @param k 767 * the key. 768 * @return the corresponding value, or -1 if no value was present for the given key. 769 */ 770 public int getAndMoveToLast(final K k) { 771 if (k == null) { 772 if (containsNullKey) { 773 moveIndexToLast(n); 774 return value[n]; 775 } 776 return defRetValue; 777 } 778 K curr; 779 final K[] key = this.key; 780 int pos; 781 // The starting point. 782 if ((curr = key[pos = (hasher.hash(k)) & mask]) == null) 783 return defRetValue; 784 if (hasher.areEqual(k, curr)) { 785 moveIndexToLast(pos); 786 return value[pos]; 787 } 788 // There's always an unused entry. 789 while (true) { 790 if ((curr = key[pos = (pos + 1) & mask]) == null) 791 return defRetValue; 792 if (hasher.areEqual(k, curr)) { 793 moveIndexToLast(pos); 794 return value[pos]; 795 } 796 } 797 } 798 /** 799 * Adds a pair to the map; if the key is already present, it is moved to the 800 * first position of the iteration order. 801 * 802 * @param k 803 * the key. 804 * @param v 805 * the value. 806 * @return the old value, or -1 if no value was present for the given key. 807 */ 808 public int putAndMoveToFirst(final K k, final int v) { 809 int pos; 810 if (k == null) { 811 if (containsNullKey) { 812 moveIndexToFirst(n); 813 return setValue(n, 0); 814 } 815 containsNullKey = true; 816 pos = n; 817 } else { 818 K curr; 819 final K[] key = this.key; 820 // The starting point. 821 if (!((curr = key[pos = (hasher.hash(k)) & mask]) == null)) { 822 if (hasher.areEqual(curr, k)) { 823 moveIndexToFirst(pos); 824 return setValue(pos, 0); 825 } 826 while (!((curr = key[pos = (pos + 1) & mask]) == null)) 827 if (hasher.areEqual(curr, k)) { 828 moveIndexToFirst(pos); 829 return setValue(pos, 0); 830 } 831 } 832 } 833 key[pos] = k; 834 order.insert(0, pos); 835 fixValues(0); 836 if (size++ >= maxFill) 837 rehash(arraySize(size, f)); 838 return defRetValue; 839 } 840 /** 841 * Adds a pair to the map; if the key is already present, it is moved to the 842 * last position of the iteration order. 843 * 844 * @param k 845 * the key. 846 * @param v 847 * the value. 848 * @return the old value, or -1 if no value was present for the given key. 849 */ 850 public int putAndMoveToLast(final K k, final int v) { 851 int pos; 852 if (k == null) { 853 if (containsNullKey) { 854 moveIndexToLast(n); 855 return setValue(n, size - 1); 856 } 857 containsNullKey = true; 858 pos = n; 859 } else { 860 K curr; 861 final K[] key = this.key; 862 // The starting point. 863 if (!((curr = key[pos = (hasher.hash(k)) & mask]) == null)) { 864 if (hasher.areEqual(curr, k)) { 865 moveIndexToLast(pos); 866 return setValue(pos, size - 1); 867 } 868 while (!((curr = key[pos = (pos + 1) & mask]) == null)) 869 if (hasher.areEqual(curr, k)) { 870 moveIndexToLast(pos); 871 return setValue(pos, size - 1); 872 } 873 } 874 } 875 key[pos] = k; 876 value[pos] = size; 877 order.add(pos); 878 if (size++ >= maxFill) 879 rehash(arraySize(size, f)); 880 return defRetValue; 881 } 882 public Integer get(final Object k) { 883 if (k == null) 884 return containsNullKey ? value[n] : defRetValue; 885 K curr; 886 final K[] key = this.key; 887 int pos; 888 // The starting point. 889 if ((curr = key[pos = (hasher.hash(k)) & mask]) == null) 890 return defRetValue; 891 if (hasher.areEqual(k, curr)) 892 return value[pos]; 893 // There's always an unused entry. 894 while (true) { 895 if ((curr = key[pos = (pos + 1) & mask]) == null) 896 return defRetValue; 897 if (hasher.areEqual(k, curr)) 898 return value[pos]; 899 } 900 } 901 public int getInt(final Object k) { 902 if (k == null) 903 return containsNullKey ? value[n] : defRetValue; 904 K curr; 905 final K[] key = this.key; 906 int pos; 907 // The starting point. 908 if ((curr = key[pos = (hasher.hash(k)) & mask]) == null) 909 return defRetValue; 910 if (hasher.areEqual(k, curr)) 911 return value[pos]; 912 // There's always an unused entry. 913 while (true) { 914 if ((curr = key[pos = (pos + 1) & mask]) == null) 915 return defRetValue; 916 if (hasher.areEqual(k, curr)) 917 return value[pos]; 918 } 919 } 920 921 public boolean containsKey(final Object k) { 922 if (k == null) 923 return containsNullKey; 924 K curr; 925 final K[] key = this.key; 926 int pos; 927 // The starting point. 928 if ((curr = key[pos = (hasher.hash(k)) & mask]) == null) 929 return false; 930 if (hasher.areEqual(k, curr)) 931 return true; 932 // There's always an unused entry. 933 while (true) { 934 if ((curr = key[pos = (pos + 1) & mask]) == null) 935 return false; 936 if (hasher.areEqual(k, curr)) 937 return true; 938 } 939 } 940 public boolean containsValue(final int v) { 941 return v >= 0 && v < size; 942 } 943 @Override 944 public boolean containsValue(final Object ov) { 945 return ov != null && containsValue(((Integer) ov).intValue()); 946 } 947 /* 948 * Removes all elements from this map. 949 * 950 * <P>To increase object reuse, this method does not change the table size. 951 * If you want to reduce the table size, you must use {@link #trim()}. 952 */ 953 public void clear() { 954 if (size == 0) 955 return; 956 size = 0; 957 containsNullKey = false; 958 Arrays.fill(key, null); 959 Arrays.fill(value, -1); 960 order.clear(); 961 } 962 963 public int size() { 964 return size; 965 } 966 967 public boolean isEmpty() { 968 return size == 0; 969 } 970 971 /** 972 * Returns an iterator over elements of type {@code T}. 973 * 974 * @return an Iterator. 975 */ 976 @Override 977 public Iterator<K> iterator() { 978 return new KeyIterator(); 979 } 980 981 /** 982 * The entry class for a hash map does not record key and value, but rather 983 * the position in the hash table of the corresponding entry. This is 984 * necessary so that calls to {@link java.util.Map.Entry#setValue(Object)} 985 * are reflected in the map 986 */ 987 final class MapEntry 988 implements 989 Map.Entry<K, Integer> { 990 // The table index this entry refers to, or -1 if this entry has been 991 // deleted. 992 int index; 993 MapEntry(final int index) { 994 this.index = index; 995 } 996 MapEntry() { 997 } 998 public K getKey() { 999 return key[index]; 1000 } 1001 /** 1002 * {@inheritDoc} 1003 * 1004 * @deprecated Please use the corresponding type-specific method 1005 * instead. 1006 */ 1007 @Deprecated 1008 public Integer getValue() { 1009 return value[index]; 1010 } 1011 public int getIntValue() { 1012 return value[index]; 1013 } 1014 public int setValue(final int v) { 1015 final int oldValue = value[index]; 1016 value[index] = v; 1017 return oldValue; 1018 } 1019 public Integer setValue(final Integer v) { 1020 return setValue(v.intValue()); 1021 } 1022 1023 @SuppressWarnings("unchecked") 1024 public boolean equals(final Object o) { 1025 if (!(o instanceof Map.Entry)) 1026 return false; 1027 Map.Entry<K, Integer> e = (Map.Entry<K, Integer>) o; 1028 return (key[index] == null 1029 ? e.getKey() == null 1030 : key[index].equals(e.getKey())) 1031 && (value[index] == e.getValue()); 1032 } 1033 public int hashCode() { 1034 return (key[index] == null ? 0 : hasher.hash(key[index])) 1035 ^ value[index]; 1036 } 1037 public String toString() { 1038 return key[index] + "=>" + value[index]; 1039 } 1040 } 1041 1042 /** 1043 * Modifies the link vector so that the given entry is removed. This method will complete in linear time. 1044 * 1045 * @param i the index of an entry. 1046 */ 1047 protected void fixOrder(final int i) { 1048 if (size == 0) { 1049 order.clear(); 1050 return; 1051 } 1052 order.removeValue(i); 1053 } 1054 1055 /** 1056 * Modifies the link vector for a shift from s to d. 1057 * <br> 1058 * This method will complete in logarithmic time or better. 1059 * 1060 * @param s the source position. 1061 * @param d the destination position. 1062 */ 1063 protected void fixOrder(int s, int d) { 1064 if(size == 0) 1065 return; 1066 if (size == 1 || order.items[0] == s) { 1067 order.set(0, d); 1068 } 1069 else if (order.items[order.size-1] == s) { 1070 order.set(order.size - 1, d); 1071 } 1072 else 1073 { 1074 int idx = order.indexOf(s); 1075 order.set(idx, d); 1076 } 1077 } 1078 1079 /** 1080 * Returns the first key of this map in iteration order. 1081 * 1082 * @return the first key in iteration order. 1083 */ 1084 public K firstKey() { 1085 if (size == 0) 1086 throw new NoSuchElementException(); 1087 return key[order.items[0]]; 1088 } 1089 /** 1090 * Returns the last key of this map in iteration order. 1091 * 1092 * @return the last key in iteration order. 1093 */ 1094 public K lastKey() { 1095 if (size == 0) 1096 throw new NoSuchElementException(); 1097 return key[order.items[order.size-1]]; 1098 } 1099 /** 1100 * Retains in this collection only elements from the given collection. 1101 * 1102 * @param c a collection. 1103 * @return <code>true</code> if this collection changed as a result of the 1104 * call. 1105 */ 1106 public boolean retainAll(Collection<?> c) { 1107 boolean retVal = false; 1108 int n = size; 1109 while (n-- != 0) { 1110 if (!c.contains(key[order.get(n)])) { 1111 removeAt(n); 1112 retVal = true; 1113 } 1114 } 1115 return retVal; 1116 } 1117 1118 public Comparator<? super K> comparator() { 1119 return null; 1120 } 1121 public SortedMap<K, Integer> tailMap(K from) { 1122 throw new UnsupportedOperationException(); 1123 } 1124 public SortedMap<K, Integer> headMap(K to) { 1125 throw new UnsupportedOperationException(); 1126 } 1127 public SortedMap<K, Integer> subMap(K from, K to) { 1128 throw new UnsupportedOperationException(); 1129 } 1130 /** 1131 * A list iterator over a Arrangement. 1132 * 1133 * <P> 1134 * This class provides a list iterator over a Arrangement. The 1135 * constructor runs in constant time. 1136 */ 1137 private class MapIterator { 1138 /** 1139 * The entry that will be returned by the next call to 1140 * {@link ListIterator#previous()} (or <code>null</code> if no 1141 * previous entry exists). 1142 */ 1143 int prev = -1; 1144 /** 1145 * The entry that will be returned by the next call to 1146 * {@link ListIterator#next()} (or <code>null</code> if no 1147 * next entry exists). 1148 */ 1149 int next; 1150 /** 1151 * The last entry that was returned (or -1 if we did not iterate or used 1152 * {@link Iterator#remove()}). 1153 */ 1154 int curr = -1; 1155 /** 1156 * The current index (in the sense of a {@link ListIterator}). 1157 * Note that this value is not meaningful when this iterator has been 1158 * created using the nonempty constructor. 1159 */ 1160 int index; 1161 private MapIterator() { 1162 next = size == 0 ? -1 : order.items[0]; 1163 index = 0; 1164 } 1165 /* 1166 private MapIterator(final K from) { 1167 if (((from) == null)) { 1168 if (containsNullKey) { 1169 next = (int) link[n]; 1170 prev = n; 1171 return; 1172 } else 1173 throw new NoSuchElementException("The key null" 1174 + " does not belong to this map."); 1175 } 1176 if (((key[last]) != null && (key[last]).equals(from))) { 1177 prev = last; 1178 index = size; 1179 return; 1180 } 1181 // The starting point. 1182 int pos = (((from).hashCode())) 1183 & mask; 1184 // There's always an unused entry. 1185 while (!((key[pos]) == null)) { 1186 if (((key[pos]).equals(from))) { 1187 // Note: no valid index known. 1188 next = (int) link[pos]; 1189 prev = pos; 1190 return; 1191 } 1192 pos = (pos + 1) & mask; 1193 } 1194 throw new NoSuchElementException("The key " + from 1195 + " does not belong to this map."); 1196 }*/ 1197 public boolean hasNext() { 1198 return next != -1; 1199 } 1200 public boolean hasPrevious() { 1201 return prev != -1; 1202 } 1203 private void ensureIndexKnown() { 1204 if (index >= 0) 1205 return; 1206 if (prev == -1) { 1207 index = 0; 1208 return; 1209 } 1210 if (next == -1) { 1211 index = size; 1212 return; 1213 } 1214 index = 0; 1215 /*while (pos != prev) { 1216 pos = (int) link[pos]; 1217 index++; 1218 }*/ 1219 } 1220 public int nextIndex() { 1221 ensureIndexKnown(); 1222 return index + 1; 1223 } 1224 public int previousIndex() { 1225 ensureIndexKnown(); 1226 return index - 1; 1227 } 1228 public int nextEntry() { 1229 if (!hasNext()) 1230 throw new NoSuchElementException(); 1231 curr = next; 1232 if(++index >= order.size) 1233 next = -1; 1234 else 1235 next = order.get(index);//(int) link[curr]; 1236 prev = curr; 1237 return curr; 1238 } 1239 public int previousEntry() { 1240 if (!hasPrevious()) 1241 throw new NoSuchElementException(); 1242 curr = prev; 1243 if(--index < 1) 1244 prev = -1; 1245 else 1246 prev = order.get(index - 1); 1247 //prev = (int) (link[curr] >>> 32); 1248 next = curr; 1249 return curr; 1250 } 1251 public void remove() { 1252 ensureIndexKnown(); 1253 if (curr == -1) 1254 throw new IllegalStateException(); 1255 if (curr == prev) { 1256 /* 1257 * If the last operation was a next(), we are removing an entry 1258 * that precedes the current index, and thus we must decrement 1259 * it. 1260 */ 1261 if(--index >= 1) 1262 prev = order.get(index - 1); //(int) (link[curr] >>> 32); 1263 else 1264 prev = -1; 1265 } else { 1266 if(index < order.size - 1) 1267 next = order.get(index + 1); 1268 else 1269 next = -1; 1270 } 1271 order.removeIndex(index); 1272 size--; 1273 int last, slot, pos = curr; 1274 curr = -1; 1275 if (pos == n) { 1276 containsNullKey = false; 1277 key[n] = null; 1278 } else { 1279 K curr; 1280 final K[] key = Arrangement.this.key; 1281 // We have to horribly duplicate the shiftKeys() code because we 1282 // need to update next/prev. 1283 for (;;) { 1284 pos = ((last = pos) + 1) & mask; 1285 for (;;) { 1286 if ((curr = key[pos]) == null) { 1287 key[last] = null; 1288 fixValues(index); 1289 return; 1290 } 1291 slot = (hasher.hash(curr)) & mask; 1292 if (last <= pos 1293 ? last >= slot || slot > pos 1294 : last >= slot && slot > pos) 1295 break; 1296 pos = (pos + 1) & mask; 1297 } 1298 key[last] = curr; 1299 if (next == pos) 1300 next = last; 1301 if (prev == pos) 1302 prev = last; 1303 fixOrder(pos, last); 1304 } 1305 } 1306 } 1307 public int skip(final int n) { 1308 int i = n; 1309 while (i-- != 0 && hasNext()) 1310 nextEntry(); 1311 return n - i - 1; 1312 } 1313 public int back(final int n) { 1314 int i = n; 1315 while (i-- != 0 && hasPrevious()) 1316 previousEntry(); 1317 return n - i - 1; 1318 } 1319 } 1320 private class EntryIterator extends MapIterator 1321 implements 1322 Iterator<Entry<K, Integer>>, Serializable { 1323 private static final long serialVersionUID = 0L; 1324 1325 private MapEntry entry; 1326 public EntryIterator() { 1327 } 1328 public MapEntry next() { 1329 return entry = new MapEntry(nextEntry()); 1330 } 1331 public MapEntry previous() { 1332 return entry = new MapEntry(previousEntry()); 1333 } 1334 @Override 1335 public void remove() { 1336 super.remove(); 1337 entry.index = -1; // You cannot use a deleted entry. 1338 } 1339 public void set(Entry<K, Integer> ok) { 1340 throw new UnsupportedOperationException(); 1341 } 1342 public void add(Entry<K, Integer> ok) { 1343 throw new UnsupportedOperationException(); 1344 } 1345 } 1346 1347 public class FastEntryIterator extends MapIterator implements ListIterator<MapEntry>, Serializable { 1348 private static final long serialVersionUID = 0L; 1349 1350 final MapEntry entry = new MapEntry(); 1351 1352 public FastEntryIterator() { 1353 } 1354 public MapEntry next() { 1355 entry.index = nextEntry(); 1356 return entry; 1357 } 1358 public MapEntry previous() { 1359 entry.index = previousEntry(); 1360 return entry; 1361 } 1362 public void set(MapEntry ok) { 1363 throw new UnsupportedOperationException(); 1364 } 1365 public void add(MapEntry ok) { 1366 throw new UnsupportedOperationException(); 1367 } 1368 } 1369 private final class MapEntrySet 1370 implements Cloneable, SortedSet<Entry<K, Integer>>, Set<Entry<K, Integer>>, Collection<Entry<K, Integer>>, Serializable { 1371 private static final long serialVersionUID = 0L; 1372 public EntryIterator iterator() { 1373 return new EntryIterator(); 1374 } 1375 public Comparator<? super Entry<K, Integer>> comparator() { 1376 return null; 1377 } 1378 public SortedSet<Entry<K, Integer>> subSet( 1379 Entry<K, Integer> fromElement, 1380 Entry<K, Integer> toElement) { 1381 throw new UnsupportedOperationException(); 1382 } 1383 public SortedSet<Entry<K, Integer>> headSet( 1384 Entry<K, Integer> toElement) { 1385 throw new UnsupportedOperationException(); 1386 } 1387 public SortedSet<Entry<K, Integer>> tailSet( 1388 Entry<K, Integer> fromElement) { 1389 throw new UnsupportedOperationException(); 1390 } 1391 public Entry<K, Integer> first() { 1392 if (size == 0) 1393 throw new NoSuchElementException(); 1394 return new MapEntry(order.items[0]); 1395 } 1396 public Entry<K, Integer> last() { 1397 if (size == 0) 1398 throw new NoSuchElementException(); 1399 return new MapEntry(order.items[order.size-1]); 1400 } 1401 @SuppressWarnings("unchecked") 1402 public boolean contains(final Object o) { 1403 if (!(o instanceof Map.Entry)) 1404 return false; 1405 final Entry<?, ?> e = (Entry<?, ?>) o; 1406 final K k = (K) e.getKey(); 1407 final int v = (Integer) e.getValue(); 1408 if (k == null) 1409 return containsNullKey 1410 && (value[n] == v); 1411 K curr; 1412 final K[] key = Arrangement.this.key; 1413 int pos; 1414 // The starting point. 1415 if ((curr = key[pos = (hasher.hash(k)) & mask]) == null) 1416 return false; 1417 if (hasher.areEqual(k, curr)) 1418 return value[pos] == v; 1419 // There's always an unused entry. 1420 while (true) { 1421 if ((curr = key[pos = (pos + 1) & mask]) == null) 1422 return false; 1423 if (hasher.areEqual(k, curr)) 1424 return value[pos] == v; 1425 } 1426 } 1427 @SuppressWarnings("unchecked") 1428 protected boolean rem(final Object o) { 1429 if (!(o instanceof Map.Entry)) 1430 return false; 1431 final Entry<?, ?> e = (Entry<?, ?>) o; 1432 final K k = (K) e.getKey(); 1433 final int v = (Integer) e.getValue(); 1434 if (k == null) { 1435 if (containsNullKey 1436 && value[n] == v) { 1437 removeNullEntry(); 1438 return true; 1439 } 1440 return false; 1441 } 1442 K curr; 1443 final K[] key = Arrangement.this.key; 1444 int pos; 1445 // The starting point. 1446 if ((curr = key[pos = (hasher.hash(k)) & mask]) == null) 1447 return false; 1448 if (hasher.areEqual(curr, k)) { 1449 if (value[pos] == v) { 1450 removeEntry(pos); 1451 return true; 1452 } 1453 return false; 1454 } 1455 while (true) { 1456 if ((curr = key[pos = (pos + 1) & mask]) == null) 1457 return false; 1458 if (hasher.areEqual(curr, k)) { 1459 if (value[pos] == v) { 1460 removeEntry(pos); 1461 return true; 1462 } 1463 } 1464 } 1465 } 1466 @Override 1467 public boolean remove(Object o) 1468 { 1469 return rem(o); 1470 } 1471 public int size() { 1472 return size; 1473 } 1474 public void clear() { 1475 Arrangement.this.clear(); 1476 } 1477 1478 public FastEntryIterator fastIterator() { 1479 return new FastEntryIterator(); 1480 } 1481 1482 @Override 1483 public boolean equals(final Object o) { 1484 if (o == this) 1485 return true; 1486 if (!(o instanceof Set)) 1487 return false; 1488 Set<?> s = (Set<?>) o; 1489 return s.size() == size() && containsAll(s); 1490 } 1491 1492 public Object[] toArray() { 1493 final Object[] a = new Object[size()]; 1494 objectUnwrap(iterator(), a); 1495 return a; 1496 } 1497 1498 @SuppressWarnings("unchecked") 1499 public <T> T[] toArray(T[] a) { 1500 if (a == null || a.length < size()) a = (T[]) new Object[size()]; 1501 objectUnwrap(iterator(), a); 1502 return a; 1503 } 1504 1505 /** 1506 * Unsupported. 1507 * 1508 * @param c ignored 1509 * @return nothing, throws UnsupportedOperationException 1510 * @throws UnsupportedOperationException always 1511 */ 1512 public boolean addAll(Collection<? extends Entry<K, Integer>> c) { 1513 throw new UnsupportedOperationException("addAll not supported"); 1514 } 1515 1516 /** 1517 * Unsupported. 1518 * 1519 * @param k ignored 1520 * @return nothing, throws UnsupportedOperationException 1521 * @throws UnsupportedOperationException always 1522 */ 1523 public boolean add(Entry<K, Integer> k) { 1524 throw new UnsupportedOperationException("add not supported"); 1525 } 1526 1527 /** 1528 * Checks whether this collection contains all elements from the given 1529 * collection. 1530 * 1531 * @param c a collection. 1532 * @return <code>true</code> if this collection contains all elements of the 1533 * argument. 1534 */ 1535 public boolean containsAll(Collection<?> c) { 1536 int n = c.size(); 1537 final Iterator<?> i = c.iterator(); 1538 while (n-- != 0) 1539 if (!contains(i.next())) 1540 return false; 1541 return true; 1542 } 1543 1544 /** 1545 * Retains in this collection only elements from the given collection. 1546 * 1547 * @param c a collection. 1548 * @return <code>true</code> if this collection changed as a result of the 1549 * call. 1550 */ 1551 public boolean retainAll(Collection<?> c) { 1552 boolean retVal = false; 1553 int n = size(); 1554 final Iterator<?> i = iterator(); 1555 while (n-- != 0) { 1556 if (!c.contains(i.next())) { 1557 i.remove(); 1558 retVal = true; 1559 } 1560 } 1561 return retVal; 1562 } 1563 1564 /** 1565 * Remove from this collection all elements in the given collection. If the 1566 * collection is an instance of this class, it uses faster iterators. 1567 * 1568 * @param c a collection. 1569 * @return <code>true</code> if this collection changed as a result of the 1570 * call. 1571 */ 1572 public boolean removeAll(Collection<?> c) { 1573 boolean retVal = false; 1574 int n = c.size(); 1575 final Iterator<?> i = c.iterator(); 1576 while (n-- != 0) 1577 if (remove(i.next())) 1578 retVal = true; 1579 return retVal; 1580 } 1581 1582 public boolean isEmpty() { 1583 return size() == 0; 1584 } 1585 1586 @Override 1587 public String toString() { 1588 final StringBuilder s = new StringBuilder(); 1589 final EntryIterator i = iterator(); 1590 int n = size(); 1591 MapEntry k; 1592 boolean first = true; 1593 s.append("{"); 1594 while (n-- != 0) { 1595 if (first) 1596 first = false; 1597 else 1598 s.append(", "); 1599 k = i.next(); 1600 s.append(this == key[k.index] 1601 ? "(this Arrangement)" 1602 : String.valueOf(key[k.index])) 1603 .append("=>").append(value[k.index]); 1604 } 1605 s.append("}"); 1606 return s.toString(); 1607 } 1608 1609 } 1610 1611 @Override 1612 public SortedSet<Entry<K, Integer>> entrySet() { 1613 if (entries == null) entries = new MapEntrySet(); 1614 return entries; 1615 } 1616 public MapEntrySet mapEntrySet() { 1617 if (entries == null) entries = new MapEntrySet(); 1618 return entries; 1619 } 1620 1621 /** 1622 * An iterator on keys. 1623 * <p> 1624 * <P>We simply override the {@link ListIterator#next()}/{@link ListIterator#previous()} methods (and possibly their type-specific counterparts) so that they return keys 1625 * instead of entries. 1626 */ 1627 public final class KeyIterator extends MapIterator implements Iterator<K>, Serializable { 1628 private static final long serialVersionUID = 0L; 1629 public K previous() { 1630 return key[previousEntry()]; 1631 } 1632 public void set(K k) { 1633 throw new UnsupportedOperationException(); 1634 } 1635 public void add(K k) { 1636 throw new UnsupportedOperationException(); 1637 } 1638 public KeyIterator() {} 1639 public K next() { 1640 return key[nextEntry()]; 1641 } 1642 public void remove() { super.remove(); } 1643 } 1644 1645 public final class KeySet implements SortedSet<K>, Serializable { 1646 private static final long serialVersionUID = 0L; 1647 1648 public KeyIterator iterator() { 1649 return new KeyIterator(); 1650 } 1651 1652 public int size() { 1653 return size; 1654 } 1655 1656 public void clear() { 1657 Arrangement.this.clear(); 1658 } 1659 1660 public K first() { 1661 if (size == 0) throw new NoSuchElementException(); 1662 return key[order.items[0]]; 1663 } 1664 1665 public K last() { 1666 if (size == 0) throw new NoSuchElementException(); 1667 return key[order.items[order.size-1]]; 1668 } 1669 1670 public Comparator<K> comparator() { 1671 return null; 1672 } 1673 1674 public final SortedSet<K> tailSet(K from) { 1675 throw new UnsupportedOperationException(); 1676 } 1677 1678 public final SortedSet<K> headSet(K to) { 1679 throw new UnsupportedOperationException(); 1680 } 1681 1682 public final SortedSet<K> subSet(K from, K to) { 1683 throw new UnsupportedOperationException(); 1684 } 1685 1686 @SuppressWarnings("unchecked") 1687 @Override 1688 public <T> T[] toArray(T[] a) { 1689 if (a == null || a.length < size()) a = (T[]) new Object[size()]; 1690 unwrap(iterator(), a); 1691 return a; 1692 } 1693 1694 /** 1695 * Always throws an UnsupportedOperationException 1696 */ 1697 public boolean remove(Object ok) { 1698 throw new UnsupportedOperationException("Cannot remove from the key set directly"); 1699 } 1700 1701 /** 1702 * Always throws an UnsupportedOperationException 1703 */ 1704 public boolean add(final K o) { 1705 throw new UnsupportedOperationException("Cannot add to the key set directly"); 1706 } 1707 1708 /** 1709 * Delegates to the corresponding type-specific method. 1710 */ 1711 public boolean contains(final Object o) { 1712 return containsKey(o); 1713 } 1714 1715 /** 1716 * Checks whether this collection contains all elements from the given type-specific collection. 1717 * 1718 * @param c a type-specific collection. 1719 * @return <code>true</code> if this collection contains all elements of the argument. 1720 */ 1721 public boolean containsAll(Collection<?> c) { 1722 final Iterator<?> i = c.iterator(); 1723 int n = c.size(); 1724 while (n-- != 0) 1725 if (!contains(i.next())) return false; 1726 return true; 1727 } 1728 1729 /** 1730 * Retains in this collection only elements from the given type-specific collection. 1731 * 1732 * @param c a type-specific collection. 1733 * @return <code>true</code> if this collection changed as a result of the call. 1734 */ 1735 public boolean retainAll(Collection<?> c) { 1736 throw new UnsupportedOperationException("Cannot remove from the key set directly"); 1737 } 1738 1739 /** 1740 * Remove from this collection all elements in the given type-specific collection. 1741 * 1742 * @param c a type-specific collection. 1743 * @return <code>true</code> if this collection changed as a result of the call. 1744 */ 1745 public boolean removeAll(Collection<?> c) { 1746 throw new UnsupportedOperationException("Cannot remove from the key set directly"); 1747 } 1748 1749 public Object[] toArray() { 1750 final Object[] a = new Object[size()]; 1751 objectUnwrap(iterator(), a); 1752 return a; 1753 } 1754 1755 /** 1756 * Always throws an UnsupportedOperationException. 1757 * @param c disregarded; always throws Exception 1758 * @return nothing; always throws Exception 1759 */ 1760 public boolean addAll(Collection<? extends K> c) { 1761 throw new UnsupportedOperationException("Cannot add to the key set directly"); 1762 } 1763 1764 @Override 1765 public boolean equals(final Object o) { 1766 if (o == this) 1767 return true; 1768 if (!(o instanceof Set)) 1769 return false; 1770 Set<?> s = (Set<?>) o; 1771 if (s.size() != size()) 1772 return false; 1773 return containsAll(s); 1774 } 1775 /** 1776 * Unwraps an iterator into an array starting at a given offset for a given number of elements. 1777 * <p> 1778 * <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 1779 * 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). 1780 * 1781 * @param i a type-specific iterator. 1782 * @param array an array to contain the output of the iterator. 1783 * @param offset the first element of the array to be returned. 1784 * @param max the maximum number of elements to unwrap. 1785 * @return the number of elements unwrapped. 1786 */ 1787 public int unwrap(final KeyIterator i, final Object[] array, int offset, final int max) { 1788 if (max < 0) throw new IllegalArgumentException("The maximum number of elements (" + max + ") is negative"); 1789 if (offset < 0 || offset + max > array.length) throw new IllegalArgumentException(); 1790 int j = max; 1791 while (j-- != 0 && i.hasNext()) 1792 array[offset++] = i.next(); 1793 return max - j - 1; 1794 } 1795 1796 /** 1797 * Unwraps an iterator into an array. 1798 * <p> 1799 * <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 1800 * of the array has been reached. 1801 * 1802 * @param i a type-specific iterator. 1803 * @param array an array to contain the output of the iterator. 1804 * @return the number of elements unwrapped. 1805 */ 1806 public int unwrap(final KeyIterator i, final Object[] array) { 1807 return unwrap(i, array, 0, array.length); 1808 } 1809 1810 public boolean isEmpty() { 1811 return size() == 0; 1812 } 1813 1814 @Override 1815 public String toString() { 1816 final StringBuilder s = new StringBuilder(); 1817 boolean first = true; 1818 K k; 1819 s.append("{"); 1820 for (int i = 0; i < size; i++) { 1821 if (first) first = false; 1822 else s.append(", "); 1823 k = keyAt(i); 1824 s.append(k == Arrangement.this ? "(this collection)" : String.valueOf(k)); 1825 } 1826 s.append("}"); 1827 return s.toString(); 1828 } 1829 } 1830 1831 public KeySet keySet() { 1832 if (keys == null) keys = new KeySet(); 1833 return keys; 1834 } 1835 1836 public OrderedSet<K> keysAsOrderedSet() 1837 { 1838 OrderedSet<K> os = new OrderedSet<K>(size, f, hasher); 1839 for (int i = 0; i < size; i++) { 1840 os.add(keyAt(i)); 1841 } 1842 return os; 1843 } 1844 1845 /** 1846 * An iterator on values. 1847 * <p> 1848 * <P>We simply override the {@link ListIterator#next()}/{@link ListIterator#previous()} methods (and possibly their type-specific counterparts) so that they return values 1849 * instead of entries. 1850 */ 1851 public final class ValueIterator extends MapIterator implements ListIterator<Integer>, Serializable { 1852 private static final long serialVersionUID = 0L; 1853 1854 public Integer previous() { 1855 return (index < 0) ? -1 : --index; 1856 } 1857 public int previousInt() { 1858 return (index < 0) ? -1 : --index; 1859 } 1860 public void set(Integer v) { 1861 throw new UnsupportedOperationException(); 1862 } 1863 public void add(Integer v) { 1864 throw new UnsupportedOperationException(); 1865 } 1866 public ValueIterator() {} 1867 public Integer next() { 1868 return (index >= size - 1) ? -1 : ++index; 1869 }public int nextInt() { 1870 return (index >= size - 1) ? -1 : ++index; 1871 } 1872 public void remove() { super.remove(); } 1873 } 1874 public final class ValueCollection extends AbstractCollection<Integer> implements Serializable 1875 { 1876 private static final long serialVersionUID = 0L; 1877 public ValueIterator iterator() { 1878 return new ValueIterator(); 1879 } 1880 public int size() { 1881 return size; 1882 } 1883 public boolean contains(Object v) { 1884 return containsValue(v); 1885 } 1886 public void clear() { 1887 Arrangement.this.clear(); 1888 } 1889 } 1890 public Collection<Integer> values() { 1891 if (values == null) values = new ValueCollection(); 1892 return values; 1893 } 1894 1895 public ArrayList<Integer> valuesAsList() 1896 { 1897 ArrayList<Integer> ls = new ArrayList<>(size); 1898 for (int i = 0; i < size; i++) { 1899 ls.add(i); 1900 } 1901 return ls; 1902 } 1903 1904 public IntVLA valuesAsIntVLA() 1905 { 1906 return new IntVLA(ArrayTools.range(size)); 1907 } 1908 public int[] valuesAsArray() 1909 { 1910 return ArrayTools.range(size); 1911 } 1912 1913 /** 1914 * Rehashes the map, making the table as small as possible. 1915 * <p> 1916 * <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. 1917 * <p> 1918 * <P>If the table size is already the minimum possible, this method does nothing. 1919 * 1920 * @return true if there was enough memory to trim the map. 1921 * @see #trim(int) 1922 */ 1923 public boolean trim() { 1924 final int l = arraySize(size, f); 1925 if (l >= n || size > maxFill(l, f)) return true; 1926 try { 1927 rehash(l); 1928 } catch (Exception cantDoIt) { 1929 return false; 1930 } 1931 return true; 1932 } 1933 1934 /** 1935 * Rehashes this map if the table is too large. 1936 * <p> 1937 * <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 1938 * <var>N</var>, this method does nothing. Otherwise, it rehashes this map in a table of size <var>N</var>. 1939 * <p> 1940 * <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 1941 * size to avoid keeping around a very large table just because of a few large transient maps. 1942 * 1943 * @param n the threshold for the trimming. 1944 * @return true if there was enough memory to trim the map. 1945 * @see #trim() 1946 */ 1947 public boolean trim(final int n) { 1948 final int l = HashCommon.nextPowerOfTwo((int) Math.ceil(n / f)); 1949 if (l >= n || size > maxFill(l, f)) return true; 1950 try { 1951 rehash(l); 1952 } catch (Exception cantDoIt) { 1953 return false; 1954 } 1955 return true; 1956 } 1957 1958 /** 1959 * Rehashes the map. 1960 * 1961 * <P> 1962 * This method implements the basic rehashing strategy, and may be overriden 1963 * by subclasses implementing different rehashing strategies (e.g., 1964 * disk-based rehashing). However, you should not override this method 1965 * unless you understand the internal workings of this class. 1966 * 1967 * @param newN 1968 * the new size 1969 */ 1970 1971 @SuppressWarnings("unchecked") 1972 protected void rehash(final int newN) { 1973 final K[] key = this.key; 1974 final int[] value = this.value; 1975 final int mask = newN - 1; // Note that this is used by the hashing macro 1976 final K[] newKey = (K[]) new Object[newN + 1]; 1977 final int[] newValue = new int[newN + 1]; 1978 final int sz = order.size; 1979 K k; 1980 int i, pos; 1981 final int[] oi = order.items; 1982 for (int q = 0; q < sz; q++) { 1983 i = oi[q]; 1984 if ((k = key[i]) == null) 1985 pos = newN; 1986 else { 1987 pos = (hasher.hash(k)) & mask; 1988 while (newKey[pos] != null) 1989 pos = (pos + 1) & mask; 1990 } 1991 newKey[pos] = k; 1992 newValue[pos] = value[i]; 1993 oi[q] = pos; 1994 } 1995 1996 n = newN; 1997 this.mask = mask; 1998 maxFill = maxFill(n, f); 1999 this.key = newKey; 2000 this.value = newValue; 2001 } 2002 /** 2003 * Returns a deep copy of this map. 2004 * 2005 * <P> 2006 * This method performs a deep copy of this Arrangement; the data stored in the 2007 * map, however, is not cloned. Note that this makes a difference only for 2008 * object keys. 2009 * 2010 * @return a deep copy of this map. 2011 */ 2012 @SuppressWarnings("unchecked") 2013 @GwtIncompatible 2014 public Arrangement<K> clone() { 2015 Arrangement<K> c; 2016 try { 2017 c = new Arrangement<>(hasher); 2018 c.key = (K[]) new Object[n + 1]; 2019 System.arraycopy(key, 0, c.key, 0, n + 1); 2020 c.value = new int[n + 1]; 2021 System.arraycopy(value, 0, c.value, 0, n + 1); 2022 c.order = (IntVLA) order.clone(); 2023 return c; 2024 } catch (Exception cantHappen) { 2025 throw new UnsupportedOperationException(cantHappen + (cantHappen.getMessage() != null ? 2026 "; " + cantHappen.getMessage() : "")); 2027 } 2028 } 2029 /** 2030 * Returns a hash code for this map. 2031 * 2032 * This method overrides the generic method provided by the superclass. 2033 * Since <code>equals()</code> is not overriden, it is important that the 2034 * value returned by this method is the same value as the one returned by 2035 * the overriden method. 2036 * 2037 * @return a hash code for this map. 2038 */ 2039 public int hashCode() { 2040 int h = 0; 2041 for (int j = realSize(), i = 0, t = 0; j-- != 0;) { 2042 while (key[i] == null) 2043 i++; 2044 if (this != key[i]) 2045 t = hasher.hash(key[i]); 2046 t ^= value[i]; 2047 h += t; 2048 i++; 2049 } 2050 // Zero / null keys have hash zero. 2051 if (containsNullKey) 2052 h += value[n]; 2053 return h; 2054 } 2055 public long hash64() 2056 { 2057 return 31L * CrossHash.hash64(key) + size; 2058 } 2059 2060 /** 2061 * Returns the maximum number of entries that can be filled before rehashing. 2062 * 2063 * @param n the size of the backing array. 2064 * @param f the load factor. 2065 * @return the maximum number of entries before rehashing. 2066 */ 2067 public static int maxFill(final int n, final float f) { 2068 /* We must guarantee that there is always at least 2069 * one free entry (even with pathological load factors). */ 2070 return Math.min((int) Math.ceil(n * f), n - 1); 2071 } 2072 2073 /** 2074 * Returns the maximum number of entries that can be filled before rehashing. 2075 * 2076 * @param n the size of the backing array. 2077 * @param f the load factor. 2078 * @return the maximum number of entries before rehashing. 2079 */ 2080 public static long maxFill(final long n, final float f) { 2081 /* We must guarantee that there is always at least 2082 * one free entry (even with pathological load factors). */ 2083 return Math.min((long) Math.ceil(n * f), n - 1); 2084 } 2085 2086 /** 2087 * 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>. 2088 * 2089 * @param expected the expected number of elements in a hash table. 2090 * @param f the load factor. 2091 * @return the minimum possible size for a backing array. 2092 * @throws IllegalArgumentException if the necessary size is larger than 2<sup>30</sup>. 2093 */ 2094 public static int arraySize(final int expected, final float f) { 2095 final long s = Math.max(2, HashCommon.nextPowerOfTwo((long) Math.ceil(expected / f))); 2096 if (s > (1 << 30)) 2097 throw new IllegalArgumentException("Too large (" + expected + " expected elements with load factor " + f + ")"); 2098 return (int) s; 2099 } 2100 2101 /** 2102 * Unwraps an iterator into an array starting at a given offset for a given number of elements. 2103 * <p> 2104 * <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 2105 * 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). 2106 * 2107 * @param i a type-specific iterator. 2108 * @param array an array to contain the output of the iterator. 2109 * @param offset the first element of the array to be returned. 2110 * @param max the maximum number of elements to unwrap. 2111 * @return the number of elements unwrapped. 2112 */ 2113 private int unwrap(final ValueIterator i, final Object[] array, int offset, final int max) { 2114 if (max < 0) throw new IllegalArgumentException("The maximum number of elements (" + max + ") is negative"); 2115 if (offset < 0 || offset + max > array.length) throw new IllegalArgumentException(); 2116 int j = max; 2117 while (j-- != 0 && i.hasNext()) 2118 array[offset++] = i.next(); 2119 return max - j - 1; 2120 } 2121 2122 /** 2123 * Unwraps an iterator into an array. 2124 * <p> 2125 * <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 2126 * of the array has been reached. 2127 * 2128 * @param i a type-specific iterator. 2129 * @param array an array to contain the output of the iterator. 2130 * @return the number of elements unwrapped. 2131 */ 2132 private int unwrap(final ValueIterator i, final Object[] array) { 2133 return unwrap(i, array, 0, array.length); 2134 } 2135 2136 2137 /** Unwraps an iterator into an array starting at a given offset for a given number of elements. 2138 * 2139 * <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 2140 * 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). 2141 * 2142 * @param i a type-specific iterator. 2143 * @param array an array to contain the output of the iterator. 2144 * @param offset the first element of the array to be returned. 2145 * @param max the maximum number of elements to unwrap. 2146 * @return the number of elements unwrapped. */ 2147 private static <K> int objectUnwrap(final Iterator<? extends K> i, final K[] array, int offset, final int max ) { 2148 if ( max < 0 ) throw new IllegalArgumentException( "The maximum number of elements (" + max + ") is negative" ); 2149 if ( offset < 0 || offset + max > array.length ) throw new IllegalArgumentException(); 2150 int j = max; 2151 while ( j-- != 0 && i.hasNext() ) 2152 array[ offset++ ] = i.next(); 2153 return max - j - 1; 2154 } 2155 2156 /** Unwraps an iterator into an array. 2157 * 2158 * <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 2159 * of the array has been reached. 2160 * 2161 * @param i a type-specific iterator. 2162 * @param array an array to contain the output of the iterator. 2163 * @return the number of elements unwrapped. */ 2164 private static <K> int objectUnwrap(final Iterator<? extends K> i, final K[] array) { 2165 return objectUnwrap(i, array, 0, array.length ); 2166 } 2167 2168 @Override 2169 public String toString() { 2170 final StringBuilder s = new StringBuilder(); 2171 boolean first = true; 2172 K k; 2173 s.append("Arrangement{"); 2174 for (int i = 0; i < size; i++) { 2175 if (first) first = false; 2176 else s.append(", "); 2177 k = keyAt(i); 2178 s.append(k == Arrangement.this ? "(this collection)" : String.valueOf(k)) 2179 .append("=>") 2180 .append(getAt(i)); 2181 } 2182 s.append("}"); 2183 return s.toString(); 2184 } 2185 @Override 2186 public boolean equals(Object o) { 2187 if (o == this) 2188 return true; 2189 if (!(o instanceof Map)) 2190 return false; 2191 Map<?, ?> m = (Map<?, ?>) o; 2192 if (m.size() != size()) 2193 return false; 2194 return entrySet().containsAll(m.entrySet()); 2195 } 2196 2197 @GwtIncompatible 2198 private void writeObject(java.io.ObjectOutputStream s) 2199 throws java.io.IOException { 2200 final K[] key = this.key; 2201 final int[] value = this.value; 2202 final MapIterator i = new MapIterator(); 2203 s.defaultWriteObject(); 2204 for (int j = size, e; j-- != 0;) { 2205 e = i.nextEntry(); 2206 s.writeObject(key[e]); 2207 s.writeInt(value[e]); 2208 } 2209 } 2210 @GwtIncompatible 2211 @SuppressWarnings("unchecked") 2212 private void readObject(java.io.ObjectInputStream s) 2213 throws java.io.IOException, ClassNotFoundException { 2214 s.defaultReadObject(); 2215 n = arraySize(size, f); 2216 maxFill = maxFill(n, f); 2217 mask = n - 1; 2218 final K[] key = this.key = (K[]) new Object[n + 1]; 2219 final int[] value = this.value = new int[n + 1]; 2220 final IntVLA order = this.order = new IntVLA(n + 1); 2221 K k; 2222 int v; 2223 for (int i = size, pos; i-- != 0;) { 2224 k = (K) s.readObject(); 2225 v = s.readInt(); 2226 if (k == null) { 2227 pos = n; 2228 containsNullKey = true; 2229 } else { 2230 pos = (hasher.hash(k)) 2231 & mask; 2232 while (!(key[pos] == null)) 2233 pos = (pos + 1) & mask; 2234 } 2235 2236 key[pos] = k; 2237 value[pos] = v; 2238 order.add(pos); 2239 } 2240 } 2241 2242 /** 2243 * Gets the value at the given index in the iteration order in constant time (random-access). 2244 * @param idx the index in the iteration order of the value to fetch 2245 * @return the value at the index, if the index is valid, otherwise the default return value 2246 */ 2247 public int getAt(final int idx) { 2248 int pos; 2249 if (idx < 0 || idx >= order.size) 2250 return defRetValue; 2251 // The starting point. 2252 if (key[pos = order.get(idx)] == null) 2253 return containsNullKey ? value[n] : defRetValue; 2254 return value[pos]; 2255 } 2256 /** 2257 * Gets the key at the given index in the iteration order in constant time (random-access). 2258 * @param idx the index in the iteration order of the key to fetch 2259 * @return the key at the index, if the index is valid, otherwise null 2260 */ 2261 public K keyAt(final int idx) { 2262 if (idx < 0 || idx >= order.size) 2263 return null; 2264 // The starting point. 2265 return key[order.get(idx)]; 2266 } 2267 2268 /** 2269 * Gets the key-value Map.Entry at the given index in the iteration order in constant time (random-access). 2270 * @param idx the index in the iteration order of the entry to fetch 2271 * @return the key-value entry at the index, if the index is valid, otherwise null 2272 */ 2273 public Entry<K, Integer> entryAt(final int idx) 2274 { 2275 if (idx < 0 || idx >= order.size) 2276 return null; 2277 return new MapEntry(order.get(idx)); 2278 } 2279 2280 /** 2281 * Removes the key and value at the given index in the iteration order in not-exactly constant time (though it still 2282 * should be efficient). 2283 * @param idx the index in the iteration order of the key and value to remove 2284 * @return the key removed, if there was anything removed, or null otherwise 2285 */ 2286 public K removeAt(final int idx) { 2287 2288 if (idx < 0 || idx >= order.size) 2289 return null; 2290 int pos = order.get(idx); 2291 K k; 2292 if ((k = key[pos]) == null) { 2293 if (containsNullKey) { 2294 removeNullEntry(); 2295 } 2296 return null; 2297 } 2298 removeEntry(pos); 2299 return k; 2300 } 2301 2302 /** 2303 * Equivalent to {@link #add(Object)}, except that it can place k at any point in the ordering (shifting up later 2304 * entries and changing their values to match their new positions in the ordering). 2305 * @param idx the position in the ordering to place k at; will not be used if negative or greater than the current size (it can be equal to the current size) 2306 * @param k the key to add into this Arrangement; its value will be idx 2307 * @return the previous position in the ordering that k had if already present, the previous size of the Arrangement if k was just added now, or -1 if idx is invalid 2308 */ 2309 public int addAt(final int idx, final K k) { 2310 if(idx < 0 || idx > size) 2311 return -1; 2312 final int pos = insertAt(k, idx), oldValue = value[pos]; 2313 fixValues(idx); 2314 return oldValue; 2315 } 2316 /** 2317 * Gets a random value from this Arrangement in constant time, using the given IRNG to generate a random number. 2318 * @param rng used to generate a random index for a value 2319 * @return a random value from this Arrangement, or -1 if this is empty 2320 */ 2321 public int randomValue(IRNG rng) 2322 { 2323 if(rng == null) 2324 return defRetValue; 2325 return getAt(rng.nextInt(order.size)); 2326 } 2327 2328 /** 2329 * Gets a random key from this Arrangement in constant time, using the given IRNG to generate a random number. 2330 * @param rng used to generate a random index for a key 2331 * @return a random key from this Arrangement, or null if this is empty 2332 */ 2333 public K randomKey(IRNG rng) 2334 { 2335 if(rng == null) 2336 return null; 2337 return keyAt(rng.nextInt(order.size)); 2338 } 2339 2340 /** 2341 * Gets a random entry from this Arrangement in constant time, using the given IRNG to generate a random number. 2342 * @param rng used to generate a random index for a entry 2343 * @return a random key-value entry from this Arrangement 2344 */ 2345 public Entry<K, Integer> randomEntry(IRNG rng) 2346 { 2347 return new MapEntry(order.getRandomElement(rng)); 2348 } 2349 2350 /** 2351 * Randomly alters the iteration order for this Arrangement using the given IRNG to shuffle. 2352 * @param rng used to generate a random ordering 2353 * @return this for chaining 2354 */ 2355 public Arrangement<K> shuffle(IRNG rng) 2356 { 2357 if(size < 2) 2358 return this; 2359 order.shuffle(rng); 2360 fixValues(0); 2361 return this; 2362 } 2363 2364 /** 2365 * Given an array or varargs of replacement indices for this Arrangement's iteration order, reorders this so the 2366 * first item in the returned version is the same as {@code getAt(ordering[0])} (with some care taken for negative 2367 * or too-large indices), the second item in the returned version is the same as {@code getAt(ordering[1])}, etc. 2368 * <br> 2369 * Negative indices are considered reversed distances from the end of ordering, so -1 refers to the same index as 2370 * {@code ordering[ordering.length - 1]}. If ordering is smaller than {@code size()}, only the indices up to the 2371 * length of ordering will be modified. If ordering is larger than {@code size()}, only as many indices will be 2372 * affected as {@code size()}, and reversed distances are measured from the end of this Map's entries instead of 2373 * the end of ordering. Duplicate values in ordering will produce duplicate values in the returned Map. 2374 * <br> 2375 * This method modifies this Arrangement in-place and also returns it for chaining. 2376 * @param ordering an array or varargs of int indices, where the nth item in ordering changes the nth item in this 2377 * Map to have the value currently in this Map at the index specified by the value in ordering 2378 * @return this for chaining, after modifying it in-place 2379 */ 2380 public Arrangement<K> reorder(int... ordering) 2381 { 2382 if(ordering == null || ordering.length <= 0) 2383 return this; 2384 order.reorder(ordering); 2385 fixValues(0); 2386 return this; 2387 } 2388 private int alterEntry(final int pos, final K replacement) { 2389 final int[] value = this.value; 2390 final int v = value[pos], op = order.indexOf(pos); 2391 shiftKeysValues(pos); 2392 2393 int rep; 2394 if (replacement == null) { 2395 if (containsNullKey) 2396 return v; 2397 rep = n; 2398 containsNullKey = true; 2399 } else { 2400 K curr; 2401 final K[] key = this.key; 2402 2403 // The starting point. 2404 if (!((curr = key[rep = (hasher.hash(replacement)) & mask]) == null)) { 2405 if (hasher.areEqual(curr, replacement)) 2406 return v; 2407 while (!((curr = key[rep = (rep + 1) & mask]) == null)) 2408 if (hasher.areEqual(curr, replacement)) 2409 return v; 2410 } 2411 key[rep] = replacement; 2412 value[rep] = v; 2413 } 2414 order.set(op, rep); 2415 return v; 2416 } 2417 private int alterNullEntry(final K replacement) { 2418 containsNullKey = false; 2419 final int[] value = this.value; 2420 int v = value[n]; 2421 value[n] = -1; 2422 2423 int rep; 2424 if (replacement == null) { 2425 rep = n; 2426 containsNullKey = true; 2427 } else { 2428 K curr; 2429 final K[] key = this.key; 2430 // The starting point. 2431 if ((curr = key[rep = (hasher.hash(replacement)) & mask]) != null) { 2432 if (hasher.areEqual(curr, replacement)) 2433 return v; 2434 while ((curr = key[rep = (rep + 1) & mask]) != null) 2435 if (hasher.areEqual(curr, replacement)) 2436 return v; 2437 } 2438 key[rep] = replacement; 2439 value[rep] = v; 2440 2441 } 2442 fixOrder(n, rep); 2443 return v; 2444 } 2445 2446 /** 2447 * Swaps a key, original, for another key, replacement, while keeping replacement at the same point in the iteration 2448 * order as original and keeping it associated with the same value (which also keeps its iteration index). 2449 * @param original the key to find and swap out 2450 * @param replacement the key to replace original with 2451 * @return the value associated with original before, and replacement now 2452 */ 2453 public int alter(final K original, final K replacement) { 2454 if (original == null) { 2455 if (containsNullKey) { 2456 return alterNullEntry(replacement); 2457 } 2458 else 2459 return add(replacement); 2460 } 2461 else if(hasher.areEqual(original, replacement)) 2462 return getInt(original); 2463 K curr; 2464 final K[] key = this.key; 2465 int pos; 2466 // The starting point. 2467 if ((curr = key[pos = (hasher.hash(original)) & mask]) == null) 2468 return add(replacement); 2469 if (hasher.areEqual(original, curr)) 2470 return alterEntry(pos, replacement); 2471 while (true) { 2472 if ((curr = key[pos = (pos + 1) & mask]) == null) 2473 return add(replacement); 2474 if (hasher.areEqual(original, curr)) 2475 return alterEntry(pos, replacement); 2476 } 2477 } 2478 2479 public int[] getArray(K[] keys) 2480 { 2481 if(keys == null) 2482 return new int[0]; 2483 int len = keys.length; 2484 int[] vals = new int[len]; 2485 for (int i = 0; i < len; i++) { 2486 vals[i] = getInt(keys[i]); 2487 } 2488 return vals; 2489 } 2490 2491 public int[] getArray(Collection<? extends K> keys) 2492 { 2493 if(keys == null) 2494 return new int[0]; 2495 int len = keys.size(), i = 0; 2496 int[] vals = new int[len]; 2497 for(K k : keys) 2498 { 2499 vals[i++] = getInt(k); 2500 } 2501 return vals; 2502 } 2503 2504 public IntVLA getMany(Iterable<? extends K> keys) 2505 { 2506 if(keys == null) 2507 return new IntVLA(); 2508 IntVLA vals = new IntVLA(); 2509 for(K k : keys) 2510 { 2511 vals.add(getInt(k)); 2512 } 2513 return vals; 2514 } 2515 2516 public OrderedSet<K> keysAt(int... positions) 2517 { 2518 if(keys == null || positions == null || positions.length <= 0) 2519 return new OrderedSet<K>(); 2520 OrderedSet<K> ks = new OrderedSet<>(positions.length); 2521 for(int i = 0; i < positions.length; i++) 2522 { 2523 ks.add(keyAt(positions[i])); 2524 } 2525 return ks; 2526 } 2527 public OrderedSet<K> keysAt(IntVLA positions) 2528 { 2529 if(keys == null || positions == null || positions.size <= 0) 2530 return new OrderedSet<K>(); 2531 OrderedSet<K> ks = new OrderedSet<>(positions.size); 2532 for(int i = 0; i < positions.size; i++) 2533 { 2534 ks.add(keyAt(positions.get(i))); 2535 } 2536 return ks; 2537 } 2538 2539 /** 2540 * Produces a copy of this Arrangement, but only using up to the given amount of items to take. Does a shallow copy 2541 * of individual keys, so the references will be shared. 2542 * @param amount the number of items to copy from this Arrangement; will copy all items if greater than size 2543 * @return a new Arrangement with up to amount items copied from this into it. 2544 */ 2545 public Arrangement<K> take(int amount) 2546 { 2547 amount = Math.min(size, Math.max(0, amount)); 2548 Arrangement<K> nx = new Arrangement<>(amount, f); 2549 for (int i = 0; i < amount; i++) { 2550 nx.add(keyAt(i)); 2551 } 2552 return nx; 2553 } 2554 protected int positionOf(final Object k) { 2555 if (k == null) 2556 { 2557 return (containsNullKey) ? n : -1; 2558 } 2559 K curr; 2560 final K[] key = this.key; 2561 int pos; 2562 // The starting point. 2563 if ((curr = key[pos = (hasher.hash(k)) & mask]) == null) 2564 return -1; 2565 if (hasher.areEqual(k, curr)) 2566 return pos; 2567 // There's always an unused entry. 2568 while (true) { 2569 if ((curr = key[pos = pos + 1 & mask]) == null) 2570 return -1; 2571 if (hasher.areEqual(k, curr)) 2572 return pos; 2573 } 2574 } 2575 2576 /** 2577 * Swaps the positions in the ordering for the given items, if they are both present. Returns true if the ordering 2578 * changed as a result of this call, or false if it stayed the same (which can be because left or right was not 2579 * present, or because left and right are the same reference (so swapping would do nothing)). 2580 * @param left an item that should be present in this OrderedSet 2581 * @param right an item that should be present in this OrderedSet 2582 * @return true if this OrderedSet changed in ordering as a result of this call, or false otherwise 2583 */ 2584 public boolean swap(final K left, final K right) 2585 { 2586 if(left == right) return false; 2587 int l = getInt(left); 2588 if(l < 0) return false; 2589 int r = getInt(right); 2590 if(r < 0) return false; 2591 int posL = order.get(l), posR = order.get(r); 2592 value[posL] = r; 2593 value[posR] = l; 2594 order.swap(l, r); 2595 return true; 2596 } 2597 /** 2598 * Swaps the given indices in the ordering, if they are both ints between 0 and size. Returns true if the ordering 2599 * changed as a result of this call, or false if it stayed the same (which can be because left or right referred to 2600 * an out-of-bounds index, or because left and right are equal (so swapping would do nothing)). 2601 * @param left an index of an item in this OrderedSet, at least 0 and less than {@link #size()} 2602 * @param right an index of an item in this OrderedSet, at least 0 and less than {@link #size()} 2603 * @return true if this OrderedSet changed in ordering as a result of this call, or false otherwise 2604 */ 2605 public boolean swapIndices(final int left, final int right) 2606 { 2607 if(left < 0 || right < 0 || left >= order.size || right >= order.size || left == right) return false; 2608 int posL = order.get(left), posR = order.get(right); 2609 value[posL] = right; 2610 value[posR] = left; 2611 order.swap(left, right); 2612 return true; 2613 } 2614 2615 /** 2616 * Changes the K at the given index to replacement while keeping replacement at the same point in the ordering. 2617 * 2618 * @param index an index to replace the K key at 2619 * @param replacement another K key that will replace the original at the remembered index 2620 * @return the int associated with the possibly-altered key; should be equal to index 2621 */ 2622 public int alterAt(int index, K replacement) 2623 { 2624 return alter(keyAt(index), replacement); 2625 } 2626 2627 2628 /** 2629 * Sorts this whole Arrangement using the supplied Comparator. 2630 * @param comparator a Comparator that can be used on the same type this uses for its keys (may need wildcards) 2631 */ 2632 public void sort(Comparator<? super K> comparator) 2633 { 2634 sort(comparator, 0, size); 2635 } 2636 2637 /** 2638 * Sorts a sub-range of this Arrangement from what is currently the index {@code start} up to (but not including) 2639 * the index {@code end}, using the supplied Comparator. 2640 * @param comparator a Comparator that can be used on the same type this uses for its keys (may need wildcards) 2641 * @param start the first index of a key to sort (the index can change after this) 2642 * @param end the exclusive bound on the indices to sort; often this is just {@link #size()} 2643 */ 2644 public void sort(Comparator<? super K> comparator, int start, int end) 2645 { 2646 TimSort.sort(key, order, start, end, comparator); 2647 final int[] indices = order.items; 2648 for (int i = start; i < end; i++) { 2649 value[indices[i]] = i; 2650 } 2651 } 2652 2653}