001 /* 002 * $Id: PatriciaTrie.java,v 1.3 2012/02/19 17:35:51 davep Exp $ 003 * 004 * This file is part of McIDAS-V 005 * 006 * Copyright 2007-2012 007 * Space Science and Engineering Center (SSEC) 008 * University of Wisconsin - Madison 009 * 1225 W. Dayton Street, Madison, WI 53706, USA 010 * https://www.ssec.wisc.edu/mcidas 011 * 012 * All Rights Reserved 013 * 014 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and 015 * some McIDAS-V source code is based on IDV and VisAD source code. 016 * 017 * McIDAS-V is free software; you can redistribute it and/or modify 018 * it under the terms of the GNU Lesser Public License as published by 019 * the Free Software Foundation; either version 3 of the License, or 020 * (at your option) any later version. 021 * 022 * McIDAS-V is distributed in the hope that it will be useful, 023 * but WITHOUT ANY WARRANTY; without even the implied warranty of 024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 025 * GNU Lesser Public License for more details. 026 * 027 * You should have received a copy of the GNU Lesser Public License 028 * along with this program. If not, see http://www.gnu.org/licenses. 029 */ 030 package edu.wisc.ssec.mcidasv.util.trie; 031 032 import java.io.Serializable; 033 import java.util.AbstractCollection; 034 import java.util.AbstractMap; 035 import java.util.AbstractSet; 036 import java.util.Collection; 037 import java.util.Comparator; 038 import java.util.ConcurrentModificationException; 039 import java.util.Iterator; 040 import java.util.Map; 041 import java.util.NoSuchElementException; 042 import java.util.Set; 043 import java.util.SortedMap; 044 045 /** 046 * A PATRICIA Trie. 047 * <p> 048 * PATRICIA = Practical Algorithm to Retrieve Information Coded in Alphanumeric 049 * <p> 050 * A PATRICIA Trie is a compressed Trie. Instead of storing all data at the 051 * edges of the Trie (and having empty internal nodes), PATRICIA stores data 052 * in every node. This allows for very efficient traversal, insert, delete, 053 * predecessor, successor, prefix, range, and 'select' operations. All operations 054 * are performed at worst in O(K) time, where K is the number of bits in the 055 * largest item in the tree. In practice, operations actually take O(A(K)) 056 * time, where A(K) is the average number of bits of all items in the tree. 057 * <p> 058 * Most importantly, PATRICIA requires very few comparisons to keys while 059 * doing any operation. While performing a lookup, each comparison 060 * (at most K of them, described above) will perform a single bit comparison 061 * against the given key, instead of comparing the entire key to another key. 062 * <p> 063 * The Trie can return operations in lexicographical order using the 'traverse', 064 * 'prefix', 'submap', or 'iterator' methods. The Trie can also scan for items 065 * that are 'bitwise' (using an XOR metric) by the 'select' method. Bitwise 066 * closeness is determined by the {@link KeyAnalyzer} returning true or 067 * false for a bit being set or not in a given key. 068 * <p> 069 * This PATRICIA Trie supports both variable length & fixed length keys. 070 * Some methods, such as <code>getPrefixedBy(...)</code> are suited only to 071 * variable length keys, whereas <code>getPrefixedByBits(...)</code> is suited 072 * to fixed-size keys. 073 * <p> 074 * Additionally see <a 075 * href="http://www.csse.monash.edu.au/~lloyd/tildeAlgDS/Tree/PATRICIA/">PATRICIA</a> 076 * for more information. 077 * <p> 078 * Any methods here that take an <code>Object</code> may throw a 079 * <code>ClassCastException<code> if the method is expecting an instance of K 080 * (and it isn't K). 081 * 082 * <pre> 083 PatriciaTrie<String, String> trie = new PatriciaTrie<String, String> 084 (new CharSequenceKeyAnalyzer()); 085 086 trie.put("Lime", "Lime"); 087 trie.put("LimeWire", "LimeWire"); 088 trie.put("LimeRadio", "LimeRadio"); 089 trie.put("Lax", "Lax"); 090 trie.put("Lake", "Lake"); 091 trie.put("Lovely", "Lovely"); 092 093 System.out.println(trie.select("Lo")); 094 System.out.println(trie.select("Lime")); 095 096 System.out.println(trie.getPrefixedBy("La").toString()); 097 098 Output: 099 Lovely 100 Lime 101 {Lake=Lake, Lax=Lax} 102 103 * </pre> 104 * @author Roger Kapsi 105 * @author Sam Berlin 106 107 */ 108 public class PatriciaTrie<K, V> extends AbstractMap<K, V> implements Trie<K, V>, Serializable { 109 110 private static final long serialVersionUID = 110232526181493307L; 111 112 /** The root element of the Trie. */ 113 private final TrieEntry<K, V> root = new TrieEntry<K, V>(null, null, -1); 114 115 /** The current size (total number of elements) of the Trie. */ 116 private int size = 0; 117 118 /** The number of times this has been modified (to fail-fast the iterators). */ 119 private transient int modCount = 0; 120 121 /** The keyAnalyzer used to analyze bit values of keys. */ 122 private final KeyAnalyzer<? super K> keyAnalyzer; 123 124 /** Constructs a new PatriciaTrie using the given keyAnalyzer. */ 125 public PatriciaTrie(KeyAnalyzer<? super K> keyAnalyzer) { 126 this.keyAnalyzer = keyAnalyzer; 127 } 128 129 /** Returns the KeyAnalyzer that constructed the trie. */ 130 public KeyAnalyzer<? super K> getKeyAnalyzer() { 131 return keyAnalyzer; 132 } 133 134 /** Returns the KeyAnalyzer as a comparator. */ 135 public Comparator<? super K> comparator() { 136 return keyAnalyzer; 137 } 138 139 /** Clears the Trie (i.e. removes all elements). */ 140 public void clear() { 141 root.key = null; 142 root.bitIndex = -1; 143 root.value = null; 144 145 root.parent = null; 146 root.left = root; 147 root.right = null; 148 root.predecessor = root; 149 150 size = 0; 151 incrementModCount(); 152 } 153 154 /** Returns true if the Trie is empty */ 155 public boolean isEmpty() { 156 return size == 0; 157 } 158 159 /** Returns the number items in the Trie */ 160 public int size() { 161 return size; 162 } 163 164 /** Increments both the size and mod counter. */ 165 private void incrementSize() { 166 size++; 167 incrementModCount(); 168 } 169 170 /** Decrements the size and increments the mod counter. */ 171 private void decrementSize() { 172 size--; 173 incrementModCount(); 174 } 175 176 /** Increments the mod counter. */ 177 private void incrementModCount() { 178 modCount++; 179 } 180 181 /** 182 * Adds a new <key, value> pair to the Trie and if a pair already 183 * exists it will be replaced. In the latter case it will return 184 * the old value. 185 */ 186 public V put(K key, V value) { 187 if (key == null) { 188 throw new NullPointerException("Key cannot be null"); 189 } 190 191 int keyLength = length(key); 192 193 // The only place to store a key with a length 194 // of zero bits is the root node 195 if (keyLength == 0) { 196 if (root.isEmpty()) { 197 incrementSize(); 198 } else { 199 incrementModCount(); 200 } 201 return root.setKeyValue(key, value); 202 } 203 204 TrieEntry<K, V> found = getNearestEntryForKey(key, keyLength); 205 if (key.equals(found.key)) { 206 if (found.isEmpty()) { // <- must be the root 207 incrementSize(); 208 } else { 209 incrementModCount(); 210 } 211 return found.setKeyValue(key, value); 212 } 213 214 int bitIndex = bitIndex(key, found.key); 215 if (isValidBitIndex(bitIndex)) { // in 99.999...9% the case 216 /* NEW KEY+VALUE TUPLE */ 217 TrieEntry<K, V> t = new TrieEntry<K, V>(key, value, bitIndex); 218 addEntry(t, keyLength); 219 incrementSize(); 220 return null; 221 } else if (isNullBitKey(bitIndex)) { 222 // A bits of the Key are zero. The only place to 223 // store such a Key is the root Node! 224 225 /* NULL BIT KEY */ 226 if (root.isEmpty()) { 227 incrementSize(); 228 } else { 229 incrementModCount(); 230 } 231 return root.setKeyValue(key, value); 232 233 } else if (isEqualBitKey(bitIndex)) { 234 // This is a very special and rare case. 235 236 /* REPLACE OLD KEY+VALUE */ 237 if (found != root) { 238 incrementModCount(); 239 return found.setKeyValue(key, value); 240 } 241 } 242 243 throw new IndexOutOfBoundsException("Failed to put: " + key + " -> " + value + ", " + bitIndex); 244 } 245 246 /** Adds the given entry into the Trie. */ 247 private TrieEntry<K, V> addEntry(TrieEntry<K, V> toAdd, int keyLength) { 248 TrieEntry<K, V> current = root.left; 249 TrieEntry<K, V> path = root; 250 while(true) { 251 if(current.bitIndex >= toAdd.bitIndex || current.bitIndex <= path.bitIndex) { 252 toAdd.predecessor = toAdd; 253 254 if (!isBitSet(toAdd.key, keyLength, toAdd.bitIndex)) { 255 toAdd.left = toAdd; 256 toAdd.right = current; 257 } else { 258 toAdd.left = current; 259 toAdd.right = toAdd; 260 } 261 262 toAdd.parent = path; 263 if (current.bitIndex >= toAdd.bitIndex) { 264 current.parent = toAdd; 265 } 266 267 // if we inserted an uplink, set the predecessor on it 268 if(current.bitIndex <= path.bitIndex) { 269 current.predecessor = toAdd; 270 } 271 272 if (path == root || !isBitSet(toAdd.key, keyLength, path.bitIndex)) 273 path.left = toAdd; 274 else 275 path.right = toAdd; 276 return toAdd; 277 } 278 279 path = current; 280 if(!isBitSet(toAdd.key, keyLength, current.bitIndex)) 281 current = current.left; 282 else 283 current = current.right; 284 } 285 } 286 287 @Override 288 public Set<Map.Entry<K,V>> entrySet() { 289 Set<Map.Entry<K,V>> es = entrySet; 290 return (es != null ? es : (entrySet = new EntrySet())); 291 } 292 293 /** 294 * Returns the Value whose Key equals our lookup Key 295 * or null if no such key exists. 296 */ 297 public V get(Object k) { 298 TrieEntry<K, V> entry = getEntry(k); 299 return entry != null ? entry.getValue() : null; 300 } 301 302 /** 303 * Returns the entry associated with the specified key in the 304 * PatriciaTrie. Returns null if the map contains no mapping 305 * for this key. 306 * 307 * This may throw ClassCastException if the object is not of type K. 308 */ 309 TrieEntry<K,V> getEntry(Object k) { 310 K key = asKey(k); 311 if(key == null) 312 return null; 313 314 int keyLength = length(key); 315 TrieEntry<K,V> entry = getNearestEntryForKey(key, keyLength); 316 return !entry.isEmpty() && key.equals(entry.key) ? entry : null; 317 } 318 319 /** Gets the key as a 'K'. */ 320 @SuppressWarnings("unchecked") 321 protected final K asKey(Object key) { 322 try { 323 return (K)key; 324 } catch(ClassCastException cce) { 325 // Because the type is erased, the cast & return are 326 // actually doing nothing, making this CCE impossible. 327 // However, it's still here on the off-chance it may 328 // work. 329 return null; 330 } 331 } 332 333 /** 334 * Returns the nearest entry for a given key. This is useful 335 * for finding knowing if a given key exists (and finding the value 336 * for it), or for inserting the key. 337 * 338 * The actual get implementation. This is very similar to 339 * selectR but with the exception that it might return the 340 * root Entry even if it's empty. 341 */ 342 private TrieEntry<K, V> getNearestEntryForKey(K key, int keyLength) { 343 TrieEntry<K, V> current = root.left; 344 TrieEntry<K, V> path = root; 345 while(true) { 346 if(current.bitIndex <= path.bitIndex) 347 return current; 348 349 path = current; 350 if(!isBitSet(key, keyLength, current.bitIndex)) 351 current = current.left; 352 else 353 current = current.right; 354 } 355 } 356 357 /** 358 * Returns the Value whose Key has the longest prefix 359 * in common with our lookup key. 360 */ 361 @SuppressWarnings("unchecked") 362 public V select(K key) { 363 int keyLength = length(key); 364 TrieEntry[] result = new TrieEntry[1]; 365 if (!selectR(root.left, -1, key, keyLength, result)) { 366 TrieEntry<K, V> e = result[0]; 367 return e.getValue(); 368 } 369 return null; 370 } 371 372 /** 373 * This is equivalent to the other selectR() method but without 374 * its overhead because we're selecting only one best matching 375 * Entry from the Trie. 376 */ 377 private boolean selectR(TrieEntry<K, V> h, int bitIndex, 378 final K key, final int keyLength, final TrieEntry[] result) { 379 380 if (h.bitIndex <= bitIndex) { 381 // If we hit the root Node and it is empty 382 // we have to look for an alternative best 383 // matching node. 384 if (!h.isEmpty()) { 385 result[0] = h; 386 return false; 387 } 388 return true; 389 } 390 391 if (!isBitSet(key, keyLength, h.bitIndex)) { 392 if (selectR(h.left, h.bitIndex, key, keyLength, result)) { 393 return selectR(h.right, h.bitIndex, key, keyLength, result); 394 } 395 } else { 396 if (selectR(h.right, h.bitIndex, key, keyLength, result)) { 397 return selectR(h.left, h.bitIndex, key, keyLength, result); 398 } 399 } 400 return false; 401 } 402 403 @SuppressWarnings("unchecked") 404 public Map.Entry<K,V> select(K key, Cursor<? super K, ? super V> cursor) { 405 int keyLength = length(key); 406 TrieEntry[] result = new TrieEntry[]{ null }; 407 selectR(root.left, -1, key, keyLength, cursor, result); 408 return result[0]; 409 } 410 411 private boolean selectR(TrieEntry<K,V> h, int bitIndex, 412 final K key, 413 final int keyLength, 414 final Cursor<? super K, ? super V> cursor, 415 final TrieEntry[] result) { 416 417 if (h.bitIndex <= bitIndex) { 418 if(!h.isEmpty()) { 419 Cursor.SelectStatus ret = cursor.select(h); 420 switch(ret) { 421 case REMOVE: 422 throw new UnsupportedOperationException("cannot remove during select"); 423 case EXIT: 424 result[0] = h; 425 return false; // exit 426 case REMOVE_AND_EXIT: 427 TrieEntry<K, V> entry = new TrieEntry<K, V>(h.getKey(), h.getValue(), -1); 428 result[0] = entry; 429 removeEntry(h); 430 return false; 431 case CONTINUE: 432 // fall through. 433 } 434 } 435 return true; // continue 436 } 437 438 if (!isBitSet(key, keyLength, h.bitIndex)) { 439 if (selectR(h.left, h.bitIndex, key, keyLength, cursor, result)) { 440 return selectR(h.right, h.bitIndex, key, keyLength, cursor, result); 441 } 442 } else { 443 if (selectR(h.right, h.bitIndex, key, keyLength, cursor, result)) { 444 return selectR(h.left, h.bitIndex, key, keyLength, cursor, result); 445 } 446 } 447 448 return false; 449 } 450 451 /** 452 * Returns a view of this Trie of all elements that are 453 * prefixed by the given key. 454 * 455 * In a fixed-keysize Trie, this is essentially a 'get' operation. 456 * 457 * For example, if the trie contains 'Lime', 'LimeWire', 458 * 'LimeRadio', 'Lax', 'Later', 'Lake', and 'Lovely', then 459 * a lookup of 'Lime' would return 'Lime', 'LimeRadio', and 'LimeWire'. 460 * 461 * The view that this returns is optimized to have a very efficient 462 * Iterator. The firstKey, lastKey & size methods must iterate 463 * over all possible values in order to determine the results. This 464 * information is cached until the Patricia tree changes. All other 465 * methods (except Iterator) must compare the given key to the prefix 466 * to ensure that it is within the range of the view. The Iterator's 467 * remove method must also relocate the subtree that contains the 468 * prefixes if the entry holding the subtree is removed or changes. 469 * Changing the subtree takes O(K) time. 470 * 471 * @param key 472 */ 473 public SortedMap<K, V> getPrefixedBy(K key) { 474 return getPrefixedByBits(key, 0, keyAnalyzer.length(key)); 475 } 476 477 /** 478 * Returns a view of this Trie of all elements that are 479 * prefixed by the length of the key. 480 * 481 * Fixed-keysize Tries will not support this operation 482 * (because all keys will be the same length). 483 * 484 * For example, if the trie contains 'Lime', 'LimeWire', 485 * 'LimeRadio', 'Lax', 'Later', 'Lake', and 'Lovely', then 486 * a lookup of 'LimePlastics' with a length of 4 would 487 * return 'Lime', 'LimeRadio', and 'LimeWire'. 488 * 489 * The view that this returns is optimized to have a very efficient 490 * Iterator. The firstKey, lastKey & size methods must iterate 491 * over all possible values in order to determine the results. This 492 * information is cached until the Patricia tree changes. All other 493 * methods (except Iterator) must compare the given key to the prefix 494 * to ensure that it is within the range of the view. The Iterator's 495 * remove method must also relocate the subtree that contains the 496 * prefixes if the entry holding the subtree is removed or changes. 497 * Changing the subtree takes O(K) time. 498 * 499 * @param key 500 * @param length 501 */ 502 public SortedMap<K, V> getPrefixedBy(K key, int length) { 503 return getPrefixedByBits(key, 0, length * keyAnalyzer.bitsPerElement()); 504 } 505 506 /** 507 * Returns a view of this Trie of all elements that are prefixed 508 * by the key, starting at the given offset and for the given length. 509 * 510 * Fixed-keysize Tries will not support this operation 511 * (because all keys are the same length). 512 * 513 * For example, if the trie contains 'Lime', 'LimeWire', 514 * 'LimeRadio', 'Lax', 'Later', 'Lake', and 'Lovely', then 515 * a lookup of 'The Lime Plastics' with an offset of 4 and a 516 * length of 4 would return 'Lime', 'LimeRadio', and 'LimeWire'. 517 * 518 * The view that this returns is optimized to have a very efficient 519 * Iterator. The firstKey, lastKey & size methods must iterate 520 * over all possible values in order to determine the results. This 521 * information is cached until the Patricia tree changes. All other 522 * methods (except Iterator) must compare the given key to the prefix 523 * to ensure that it is within the range of the view. The Iterator's 524 * remove method must also relocate the subtree that contains the 525 * prefixes if the entry holding the subtree is removed or changes. 526 * Changing the subtree takes O(K) time. 527 * 528 * @param key 529 * @param offset 530 * @param length 531 */ 532 public SortedMap<K, V> getPrefixedBy(K key, int offset, int length) { 533 return getPrefixedByBits(key, offset * keyAnalyzer.bitsPerElement(), length * keyAnalyzer.bitsPerElement()); 534 } 535 536 /** 537 * Returns a view of this Trie of all elements that are prefixed 538 * by the number of bits in the given Key. 539 * 540 * Fixed-keysize Tries can support this operation as a way to do 541 * lookups of partial keys. That is, if the Trie is storing IP 542 * addresses, you can lookup all addresses that begin with 543 * '192.168' by providing the key '192.168.X.X' and a length of 16 544 * would return all addresses that begin with '192.168'. 545 * 546 * The view that this returns is optimized to have a very efficient 547 * Iterator. The firstKey, lastKey & size methods must iterate 548 * over all possible values in order to determine the results. This 549 * information is cached until the Patricia tree changes. All other 550 * methods (except Iterator) must compare the given key to the prefix 551 * to ensure that it is within the range of the view. The Iterator's 552 * remove method must also relocate the subtree that contains the 553 * prefixes if the entry holding the subtree is removed or changes. 554 * Changing the subtree takes O(K) time. 555 * 556 * @param key 557 * @param bitLength 558 */ 559 public SortedMap<K, V> getPrefixedByBits(K key, int bitLength) { 560 return getPrefixedByBits(key, 0, bitLength); 561 } 562 563 /** 564 * Returns a view of this map, with entries containing only those that 565 * are prefixed by a value whose bits matches the bits between 'offset' 566 * and 'length' in the given key. 567 * 568 * The view that this returns is optimized to have a very efficient 569 * Iterator. The firstKey, lastKey & size methods must iterate 570 * over all possible values in order to determine the results. This 571 * information is cached until the Patricia tree changes. All other 572 * methods (except Iterator) must compare the given key to the prefix 573 * to ensure that it is within the range of the view. The Iterator's 574 * remove method must also relocate the subtree that contains the 575 * prefixes if the entry holding the subtree is removed or changes. 576 * Changing the subtree takes O(K) time. 577 * 578 * @param key 579 * @param offset 580 * @param length 581 */ 582 private SortedMap<K, V> getPrefixedByBits(K key, int offset, int length) { 583 int offsetLength = offset + length; 584 if (offsetLength > length(key)) { 585 throw new IllegalArgumentException(offset + " + " + length + " > " + length(key)); 586 } 587 588 if(offsetLength == 0) 589 return this; 590 591 return new PrefixSubMap(key, offset, length); 592 } 593 594 /** 595 * Returns true if this trie contains the specified Key 596 * 597 * This may throw ClassCastException if the object is not 598 * of type K. 599 */ 600 public boolean containsKey(Object k) { 601 K key = asKey(k); 602 if(key == null) 603 return false; 604 605 int keyLength = length(key); 606 TrieEntry entry = getNearestEntryForKey(key, keyLength); 607 return !entry.isEmpty() && key.equals(entry.key); 608 } 609 610 /** Returns true if this Trie contains the specified value. */ 611 public boolean containsValue(Object o) { 612 for(V v : values()) 613 if(valEquals(v, o)) 614 return true; 615 return false; 616 } 617 618 619 /** 620 * Removes a Key from the Trie if one exists 621 * 622 * This may throw ClassCastException if the object is not of type K. 623 * 624 * @param k the Key to delete 625 * @return Returns the deleted Value 626 */ 627 public V remove(Object k) { 628 K key = asKey(k); 629 if(key == null) 630 return null; 631 632 int keyLength = length(key); 633 TrieEntry<K, V> current = root.left; 634 TrieEntry<K, V> path = root; 635 while(true) { 636 if(current.bitIndex <= path.bitIndex) { 637 if(!current.isEmpty() && key.equals(current.key)) 638 return removeEntry(current); 639 else 640 return null; 641 } 642 643 path = current; 644 if(!isBitSet(key, keyLength, current.bitIndex)) 645 current = current.left; 646 else 647 current = current.right; 648 } 649 } 650 651 /** 652 * Removes a single entry from the Trie. 653 * 654 * If we found a Key (Entry h) then figure out if it's 655 * an internal (hard to remove) or external Entry (easy 656 * to remove) 657 */ 658 private V removeEntry(TrieEntry<K, V> h) { 659 if (h != root) { 660 if (h.isInternalNode()) { 661 removeInternalEntry(h); 662 } else { 663 removeExternalEntry(h); 664 } 665 } 666 667 decrementSize(); 668 return h.setKeyValue(null, null); 669 } 670 671 /** 672 * Removes an external entry from the Trie. 673 * 674 * If it's an external Entry then just remove it. 675 * This is very easy and straight forward. 676 */ 677 private void removeExternalEntry(TrieEntry<K, V> h) { 678 if (h == root) { 679 throw new IllegalArgumentException("Cannot delete root Entry!"); 680 } else if (!h.isExternalNode()) { 681 throw new IllegalArgumentException(h + " is not an external Entry!"); 682 } 683 684 TrieEntry<K, V> parent = h.parent; 685 TrieEntry<K, V> child = (h.left == h) ? h.right : h.left; 686 687 if (parent.left == h) { 688 parent.left = child; 689 } else { 690 parent.right = child; 691 } 692 693 // either the parent is changing, or the predecessor is changing. 694 if (child.bitIndex > parent.bitIndex) { 695 child.parent = parent; 696 } else { 697 child.predecessor = parent; 698 } 699 700 } 701 702 /** 703 * Removes an internal entry from the Trie. 704 * 705 * If it's an internal Entry then "good luck" with understanding 706 * this code. The Idea is essentially that Entry p takes Entry h's 707 * place in the trie which requires some re-wiring. 708 */ 709 private void removeInternalEntry(TrieEntry<K, V> h) { 710 if (h == root) { 711 throw new IllegalArgumentException("Cannot delete root Entry!"); 712 } else if (!h.isInternalNode()) { 713 throw new IllegalArgumentException(h + " is not an internal Entry!"); 714 } 715 716 TrieEntry<K, V> p = h.predecessor; 717 718 // Set P's bitIndex 719 p.bitIndex = h.bitIndex; 720 721 // Fix P's parent, predecessor and child Nodes 722 { 723 TrieEntry<K, V> parent = p.parent; 724 TrieEntry<K, V> child = (p.left == h) ? p.right : p.left; 725 726 // if it was looping to itself previously, 727 // it will now be pointed from it's parent 728 // (if we aren't removing it's parent -- 729 // in that case, it remains looping to itself). 730 // otherwise, it will continue to have the same 731 // predecessor. 732 if(p.predecessor == p && p.parent != h) 733 p.predecessor = p.parent; 734 735 if (parent.left == p) { 736 parent.left = child; 737 } else { 738 parent.right = child; 739 } 740 741 if (child.bitIndex > parent.bitIndex) { 742 child.parent = parent; 743 } 744 }; 745 746 // Fix H's parent and child Nodes 747 { 748 // If H is a parent of its left and right child 749 // then change them to P 750 if (h.left.parent == h) { 751 h.left.parent = p; 752 } 753 754 if (h.right.parent == h) { 755 h.right.parent = p; 756 } 757 758 // Change H's parent 759 if (h.parent.left == h) { 760 h.parent.left = p; 761 } else { 762 h.parent.right = p; 763 } 764 }; 765 766 // Copy the remaining fields from H to P 767 //p.bitIndex = h.bitIndex; 768 p.parent = h.parent; 769 p.left = h.left; 770 p.right = h.right; 771 772 // Make sure that if h was pointing to any uplinks, 773 // p now points to them. 774 if(isValidUplink(p.left, p)) 775 p.left.predecessor = p; 776 if(isValidUplink(p.right, p)) 777 p.right.predecessor = p; 778 779 } 780 781 /** 782 * Returns the node lexicographically before the given node (or null if none). 783 * 784 * This follows four simple branches: 785 * - If the uplink that returned us was a right uplink: 786 * - If predecessor's left is a valid uplink from predecessor, return it. 787 * - Else, follow the right path from the predecessor's left. 788 * - If the uplink that returned us was a left uplink: 789 * - Loop back through parents until we encounter a node where 790 * node != node.parent.left. 791 * - If node.parent.left is uplink from node.parent: 792 * - If node.parent.left is not root, return it. 793 * - If it is root & root isEmpty, return null. 794 * - If it is root & root !isEmpty, return root. 795 * - If node.parent.left is not uplink from node.parent: 796 * - Follow right path for first right child from node.parent.left 797 * 798 * @param start 799 */ 800 private TrieEntry<K, V> previousEntry(TrieEntry<K, V> start) { 801 if(start.predecessor == null) 802 throw new IllegalArgumentException("must have come from somewhere!"); 803 804 if(start.predecessor.right == start) { 805 if(isValidUplink(start.predecessor.left, start.predecessor)) { 806 return start.predecessor.left; 807 } else { 808 return followRight(start.predecessor.left); 809 } 810 } else { 811 TrieEntry<K, V> node = start.predecessor; 812 while(node.parent != null && node == node.parent.left) 813 node = node.parent; 814 if(node.parent == null) // can be null if we're looking up root. 815 return null; 816 if(isValidUplink(node.parent.left, node.parent)) { 817 if(node.parent.left == root) { 818 if(root.isEmpty()) 819 return null; 820 else 821 return root; 822 } else { 823 return node.parent.left; 824 } 825 } else { 826 return followRight(node.parent.left); 827 } 828 } 829 } 830 831 /** 832 * Returns the entry lexicographically after the given entry. 833 * If the given entry is null, returns the first node. 834 */ 835 private TrieEntry<K, V> nextEntry(TrieEntry<K, V> node) { 836 if(node == null) { 837 return firstEntry(); 838 } else { 839 return nextEntryImpl(node.predecessor, node, null); 840 } 841 } 842 843 /** 844 * Returns the entry lexicographically after the given entry. 845 * If the given entry is null, returns the first node. 846 * 847 * This will traverse only within the subtree. If the given node 848 * is not within the subtree, this will have undefined results. 849 */ 850 private TrieEntry<K, V> nextEntryInSubtree(TrieEntry<K, V> node, TrieEntry<K, V> parentOfSubtree) { 851 if(node == null) { 852 return firstEntry(); 853 } else { 854 return nextEntryImpl(node.predecessor, node, parentOfSubtree); 855 } 856 } 857 858 /** 859 * Scans for the next node, starting at the specified point, and using 'previous' 860 * as a hint that the last node we returned was 'previous' (so we know not to return 861 * it again). If 'tree' is non-null, this will limit the search to the given tree. 862 * 863 * The basic premise is that each iteration can follow the following steps: 864 * 865 * 1) Scan all the way to the left. 866 * a) If we already started from this node last time, proceed to Step 2. 867 * b) If a valid uplink is found, use it. 868 * c) If the result is an empty node (root not set), break the scan. 869 * d) If we already returned the left node, break the scan. 870 * 871 * 2) Check the right. 872 * a) If we already returned the right node, proceed to Step 3. 873 * b) If it is a valid uplink, use it. 874 * c) Do Step 1 from the right node. 875 * 876 * 3) Back up through the parents until we encounter find a parent 877 * that we're not the right child of. 878 * 879 * 4) If there's no right child of that parent, the iteration is finished. 880 * Otherwise continue to Step 5. 881 * 882 * 5) Check to see if the right child is a valid uplink. 883 * a) If we already returned that child, proceed to Step 6. 884 * Otherwise, use it. 885 * 886 * 6) If the right child of the parent is the parent itself, we've 887 * already found & returned the end of the Trie, so exit. 888 * 889 * 7) Do Step 1 on the parent's right child. 890 */ 891 private TrieEntry<K, V> nextEntryImpl(TrieEntry<K, V> start, TrieEntry<K, V> previous, TrieEntry<K, V> tree) { 892 TrieEntry<K, V> current = start; 893 894 // Only look at the left if this was a recursive or 895 // the first check, otherwise we know we've already looked 896 // at the left. 897 if(previous == null || start != previous.predecessor) { 898 while(!current.left.isEmpty()) { 899 // stop traversing if we've already 900 // returned the left of this node. 901 if(previous == current.left) { 902 break; 903 } 904 905 if(isValidUplink(current.left, current)) { 906 return current.left; 907 } 908 909 current = current.left; 910 } 911 } 912 913 // If there's no data at all, exit. 914 if(current.isEmpty()) { 915 return null; 916 } 917 918 // If we've already returned the left, 919 // and the immediate right is null, 920 // there's only one entry in the Trie 921 // which is stored at the root. 922 // 923 // / ("") <-- root 924 // \_/ \ 925 // null <-- 'current' 926 // 927 if(current.right == null) 928 return null; 929 930 // If nothing valid on the left, try the right. 931 if(previous != current.right) { 932 // See if it immediately is valid. 933 if(isValidUplink(current.right, current)) { 934 return current.right; 935 } 936 937 // Must search on the right's side if it wasn't initially valid. 938 return nextEntryImpl(current.right, previous, tree); 939 } 940 941 // Neither left nor right are valid, find the first parent 942 // whose child did not come from the right & traverse it. 943 while(current == current.parent.right) { 944 // If we're going to traverse to above the subtree, stop. 945 if(current == tree) 946 return null; 947 948 current = current.parent; 949 } 950 951 // If we're on the top of the subtree, we can't go any higher. 952 if(current == tree) 953 return null; 954 955 956 // If there's no right, the parent must be root, so we're done. 957 if(current.parent.right == null) { 958 return null; 959 } 960 961 962 // If the parent's right points to itself, we've found one. 963 if(previous != current.parent.right && isValidUplink(current.parent.right, current.parent)) { 964 return current.parent.right; 965 } 966 967 // If the parent's right is itself, there can't be any more nodes. 968 if(current.parent.right == current.parent) { 969 return null; 970 } 971 972 // We need to traverse down the parent's right's path. 973 return nextEntryImpl(current.parent.right, previous, tree); 974 } 975 976 /** Returns each entry as a string. */ 977 public String toString() { 978 StringBuilder buffer = new StringBuilder(); 979 buffer.append("Trie[").append(size()).append("]={\n"); 980 for(Iterator<Map.Entry<K, V>> i = newEntryIterator(); i.hasNext(); ) { 981 buffer.append(" ").append(i.next().toString()).append("\n"); 982 } 983 buffer.append("}\n"); 984 return buffer.toString(); 985 } 986 987 public Map.Entry<K, V> traverse(Cursor<? super K, ? super V> cursor) { 988 TrieEntry<K, V> entry = nextEntry(null); 989 while(entry != null) { 990 TrieEntry<K, V> current = entry; 991 Cursor.SelectStatus ret = cursor.select(current); 992 entry = nextEntry(current); 993 switch(ret) { 994 case EXIT: 995 return current; 996 case REMOVE: 997 removeEntry(current); 998 break; // out of switch, stay in while loop 999 case REMOVE_AND_EXIT: 1000 Map.Entry<K, V> value = new TrieEntry<K, V>(current.getKey(), current.getValue(), -1); 1001 removeEntry(current); 1002 return value; 1003 case CONTINUE: // do nothing. 1004 } 1005 } 1006 1007 return null; 1008 } 1009 1010 /** Returns true if 'next' is a valid uplink coming from 'from'. */ 1011 private boolean isValidUplink(TrieEntry<K, V> next, TrieEntry<K, V> from) { 1012 return next != null && next.bitIndex <= from.bitIndex && !next.isEmpty(); 1013 } 1014 1015 /** Returns true if bitIndex is a valid index */ 1016 private static boolean isValidBitIndex(int bitIndex) { 1017 return 0 <= bitIndex && bitIndex <= Integer.MAX_VALUE; 1018 } 1019 1020 /** Returns true if bitIndex is a NULL_BIT_KEY */ 1021 private static boolean isNullBitKey(int bitIndex) { 1022 return bitIndex == KeyAnalyzer.NULL_BIT_KEY; 1023 } 1024 1025 /** Returns true if bitIndex is a EQUAL_BIT_KEY */ 1026 private static boolean isEqualBitKey(int bitIndex) { 1027 return bitIndex == KeyAnalyzer.EQUAL_BIT_KEY; 1028 } 1029 1030 /** Returns the length of the key, or 0 if the key is null. */ 1031 private int length(K key) { 1032 if (key == null) { 1033 return 0; 1034 } 1035 1036 return keyAnalyzer.length(key); 1037 } 1038 1039 /** 1040 * Returns whether or not the given bit on the 1041 * key is set, or false if the key is null 1042 */ 1043 private boolean isBitSet(K key, int keyLength, int bitIndex) { 1044 if (key == null) { // root's might be null! 1045 return false; 1046 } 1047 return keyAnalyzer.isBitSet(key, keyLength, bitIndex); 1048 } 1049 1050 /** 1051 * Utility method for calling 1052 * keyAnalyzer.bitIndex(key, 0, length(key), foundKey, 0, length(foundKey)) 1053 */ 1054 private int bitIndex(K key, K foundKey) { 1055 return keyAnalyzer.bitIndex(key, 0, length(key), foundKey, 0, length(foundKey)); 1056 } 1057 1058 /** The actual Trie nodes. */ 1059 private static class TrieEntry<K,V> implements Map.Entry<K,V>, Serializable { 1060 1061 private static final long serialVersionUID = 4596023148184140013L; 1062 1063 private K key; 1064 private V value; 1065 1066 /** The index this entry is comparing. */ 1067 private int bitIndex; 1068 1069 /** The parent of this entry. */ 1070 private TrieEntry<K,V> parent; 1071 /** The left child of this entry. */ 1072 private TrieEntry<K,V> left; 1073 /** The right child of this entry. */ 1074 private TrieEntry<K,V> right; 1075 /** The entry who uplinks to this entry. */ 1076 private TrieEntry<K,V> predecessor; 1077 1078 private TrieEntry(K key, V value, int bitIndex) { 1079 this.key = key; 1080 this.value = value; 1081 1082 this.bitIndex = bitIndex; 1083 1084 this.parent = null; 1085 this.left = this; 1086 this.right = null; 1087 this.predecessor = this; 1088 } 1089 1090 public boolean equals(Object o) { 1091 if(o == this) { 1092 return true; 1093 } else if(o instanceof Map.Entry) { 1094 Map.Entry e = (Map.Entry)o; 1095 Object k1 = getKey(); 1096 Object k2 = e.getKey(); 1097 if (k1 == k2 || (k1 != null && k1.equals(k2))) { 1098 Object v1 = getValue(); 1099 Object v2 = e.getValue(); 1100 if (v1 == v2 || (v1 != null && v1.equals(v2))) 1101 return true; 1102 } 1103 return false; 1104 } else { 1105 return false; 1106 } 1107 } 1108 1109 /** 1110 * Whether or not the entry is storing a key. 1111 * Only the root can potentially be empty, all other 1112 * nodes must have a key. 1113 */ 1114 public boolean isEmpty() { 1115 return key == null; 1116 } 1117 1118 public K getKey() { 1119 return key; 1120 } 1121 1122 public V getValue() { 1123 return value; 1124 } 1125 1126 public V setValue(V value) { 1127 V o = this.value; 1128 this.value = value; 1129 return o; 1130 } 1131 1132 /** 1133 * Replaces the old key and value with the new ones. 1134 * Returns the old vlaue. 1135 */ 1136 private V setKeyValue(K key, V value) { 1137 this.key = key; 1138 return setValue(value); 1139 } 1140 1141 /** Neither the left nor right child is a loopback */ 1142 private boolean isInternalNode() { 1143 return left != this && right != this; 1144 } 1145 1146 /** Either the left or right child is a loopback */ 1147 private boolean isExternalNode() { 1148 return !isInternalNode(); 1149 } 1150 1151 public String toString() { 1152 StringBuilder buffer = new StringBuilder(); 1153 1154 if (bitIndex == -1) { 1155 buffer.append("RootEntry("); 1156 } else { 1157 buffer.append("Entry("); 1158 } 1159 1160 buffer.append("key=").append(getKey()).append(" [").append(bitIndex).append("], "); 1161 buffer.append("value=").append(getValue()).append(", "); 1162 //buffer.append("bitIndex=").append(bitIndex).append(", "); 1163 1164 if (parent != null) { 1165 if (parent.bitIndex == -1) { 1166 buffer.append("parent=").append("ROOT"); 1167 } else { 1168 buffer.append("parent=").append(parent.getKey()).append(" [").append(parent.bitIndex).append("]"); 1169 } 1170 } else { 1171 buffer.append("parent=").append("null"); 1172 } 1173 buffer.append(", "); 1174 1175 if (left != null) { 1176 if (left.bitIndex == -1) { 1177 buffer.append("left=").append("ROOT"); 1178 } else { 1179 buffer.append("left=").append(left.getKey()).append(" [").append(left.bitIndex).append("]"); 1180 } 1181 } else { 1182 buffer.append("left=").append("null"); 1183 } 1184 buffer.append(", "); 1185 1186 if (right != null) { 1187 if (right.bitIndex == -1) { 1188 buffer.append("right=").append("ROOT"); 1189 } else { 1190 buffer.append("right=").append(right.getKey()).append(" [").append(right.bitIndex).append("]"); 1191 } 1192 } else { 1193 buffer.append("right=").append("null"); 1194 } 1195 buffer.append(", "); 1196 1197 if(predecessor != null) { 1198 if(predecessor.bitIndex == -1) { 1199 buffer.append("predecessor=").append("ROOT"); 1200 } else { 1201 buffer.append("predecessor=").append(predecessor.getKey()).append(" [").append(predecessor.bitIndex).append("]"); 1202 } 1203 } 1204 1205 buffer.append(")"); 1206 return buffer.toString(); 1207 } 1208 } 1209 1210 /** 1211 * Defines the interface to analyze {@link Trie} keys on a bit 1212 * level. <code>KeyAnalyzer</code>'s 1213 * methods return the length of the key in bits, whether or not a bit is 1214 * set, and bits per element in the key. 1215 * <p> 1216 * Additionally, a method determines if a key is a prefix of another key and 1217 * returns the bit index where one key is different from another key (if 1218 * the key and found key are equal than the return value is EQUAL_BIT_KEY). 1219 * <p> 1220 * <code>KeyAnalyzer</code> defines:<br> 1221 * <table cellspace="5"> 1222 * <tr><td>NULL_BIT_KEY</td><td>When key's bits are all zero</td></tr> 1223 * <tr><td> EQUAL_BIT_KEY </td><td>When keys are the same </td></tr> 1224 * </table> 1225 */ 1226 public static interface KeyAnalyzer<K> extends Comparator<K>, Serializable { 1227 1228 /** Returned by bitIndex if key's bits are all 0 */ 1229 public static final int NULL_BIT_KEY = -1; 1230 1231 /** 1232 * Returned by bitIndex if key and found key are 1233 * equal. This is a very very specific case and 1234 * shouldn't happen on a regular basis 1235 */ 1236 public static final int EQUAL_BIT_KEY = -2; 1237 1238 /** 1239 * Returns the length of the Key in bits. 1240 */ 1241 public int length(K key); 1242 1243 /** Returns whether or not a bit is set */ 1244 public boolean isBitSet(K key, int keyLength, int bitIndex); 1245 1246 /** 1247 * Returns the n-th different bit between key and found. 1248 * This starts the comparison in key at 'keyStart' and goes 1249 * for 'keyLength' bits, and compares to the found key 1250 * starting at 'foundStart' and going for 'foundLength' bits. 1251 */ 1252 public int bitIndex(K key, int keyStart, int keyLength, 1253 K found, int foundStart, int foundLength); 1254 1255 /** 1256 * Returns the number of bits per element in the key. 1257 * This is only useful for variable-length keys, such as Strings. 1258 */ 1259 public int bitsPerElement(); 1260 1261 /** 1262 * Determines whether or not the given prefix (from offset to length) 1263 * is a prefix of the given key. 1264 */ 1265 public boolean isPrefix(K prefix, int offset, int length, K key); 1266 } 1267 1268 /** An iterator that stores a single TrieEntry. */ 1269 private class SingletonIterator implements Iterator<Map.Entry<K, V>> { 1270 private final TrieEntry<K, V> entry; 1271 private int hit = 0; 1272 1273 public SingletonIterator(TrieEntry<K, V> entry) { 1274 this.entry = entry; 1275 } 1276 1277 public boolean hasNext() { 1278 return hit == 0; 1279 } 1280 1281 public Map.Entry<K, V> next() { 1282 if(hit != 0) 1283 throw new NoSuchElementException(); 1284 hit++; 1285 return entry; 1286 } 1287 1288 public void remove() { 1289 if(hit != 1) 1290 throw new IllegalStateException(); 1291 hit++; 1292 PatriciaTrie.this.removeEntry(entry); 1293 } 1294 1295 } 1296 1297 /** An iterator for the entries. */ 1298 private abstract class NodeIterator<E> implements Iterator<E> { 1299 protected int expectedModCount = modCount; // For fast-fail 1300 protected TrieEntry<K, V> next; // the next node to return 1301 protected TrieEntry<K, V> current; // the current entry we're on 1302 1303 // Starts iteration from the beginning. 1304 protected NodeIterator() { 1305 next = PatriciaTrie.this.nextEntry(null); 1306 } 1307 1308 // Starts iteration at the given entry. 1309 protected NodeIterator(TrieEntry<K, V> firstEntry) { 1310 next = firstEntry; 1311 } 1312 1313 public boolean hasNext() { 1314 return next != null; 1315 } 1316 1317 TrieEntry<K,V> nextEntry() { 1318 if (modCount != expectedModCount) 1319 throw new ConcurrentModificationException(); 1320 TrieEntry<K,V> e = next; 1321 if (e == null) 1322 throw new NoSuchElementException(); 1323 1324 next = findNext(e); 1325 current = e; 1326 return e; 1327 } 1328 1329 protected TrieEntry<K, V> findNext(TrieEntry<K, V> prior) { 1330 return PatriciaTrie.this.nextEntry(prior); 1331 } 1332 1333 public void remove() { 1334 if (current == null) 1335 throw new IllegalStateException(); 1336 if (modCount != expectedModCount) 1337 throw new ConcurrentModificationException(); 1338 1339 TrieEntry<K, V> node = current; 1340 current = null; 1341 PatriciaTrie.this.removeEntry(node); 1342 1343 expectedModCount = modCount; 1344 } 1345 } 1346 1347 private class ValueIterator extends NodeIterator<V> { 1348 public V next() { 1349 return nextEntry().value; 1350 } 1351 } 1352 1353 private class KeyIterator extends NodeIterator<K> { 1354 public K next() { 1355 return nextEntry().getKey(); 1356 } 1357 } 1358 1359 private class EntryIterator extends NodeIterator<Map.Entry<K,V>> { 1360 public Map.Entry<K,V> next() { 1361 return nextEntry(); 1362 } 1363 } 1364 1365 /** An iterator for iterating over a prefix search. */ 1366 private class PrefixEntryIterator extends NodeIterator<Map.Entry<K, V>> { 1367 // values to reset the subtree if we remove it. 1368 protected final K prefix; 1369 protected final int offset; 1370 protected final int length; 1371 protected boolean lastOne; 1372 1373 protected TrieEntry<K, V> subtree; // the subtree to search within 1374 1375 // Starts iteration at the given entry & search only within the given subtree. 1376 PrefixEntryIterator(TrieEntry<K, V> startScan, K prefix, int offset, int length) { 1377 subtree = startScan; 1378 next = PatriciaTrie.this.followLeft(startScan); 1379 this.prefix = prefix; 1380 this.offset = offset; 1381 this.length = length; 1382 } 1383 1384 public Map.Entry<K,V> next() { 1385 Map.Entry<K, V> entry = nextEntry(); 1386 if(lastOne) 1387 next = null; 1388 return entry; 1389 } 1390 1391 @Override 1392 protected TrieEntry<K, V> findNext(TrieEntry<K, V> prior) { 1393 return PatriciaTrie.this.nextEntryInSubtree(prior, subtree); 1394 } 1395 1396 @Override 1397 public void remove() { 1398 // If the current entry we're removing is the subtree 1399 // then we need to find a new subtree parent. 1400 boolean needsFixing = false; 1401 int bitIdx = subtree.bitIndex; 1402 if(current == subtree) 1403 needsFixing = true; 1404 1405 super.remove(); 1406 1407 // If the subtree changed its bitIndex or we 1408 // removed the old subtree, get a new one. 1409 if(bitIdx != subtree.bitIndex || needsFixing) 1410 subtree = subtree(prefix, offset, length); 1411 1412 // If the subtree's bitIndex is less than the 1413 // length of our prefix, it's the last item 1414 // in the prefix tree. 1415 if(length >= subtree.bitIndex) 1416 lastOne = true; 1417 } 1418 1419 } 1420 1421 /** An iterator for submaps. */ 1422 private class SubMapEntryIterator extends NodeIterator<Map.Entry<K,V>> { 1423 private final K firstExcludedKey; 1424 1425 SubMapEntryIterator(TrieEntry<K,V> first, TrieEntry<K,V> firstExcluded) { 1426 super(first); 1427 firstExcludedKey = 1428 (firstExcluded == null ? null : firstExcluded.key); 1429 } 1430 1431 public boolean hasNext() { 1432 return next != null && next.key != firstExcludedKey; 1433 } 1434 1435 public Map.Entry<K,V> next() { 1436 if (next == null || next.key == firstExcludedKey) 1437 throw new NoSuchElementException(); 1438 return nextEntry(); 1439 } 1440 } 1441 1442 Iterator<K> newKeyIterator() { 1443 return new KeyIterator(); 1444 } 1445 1446 Iterator<V> newValueIterator() { 1447 return new ValueIterator(); 1448 } 1449 1450 Iterator<Map.Entry<K,V>> newEntryIterator() { 1451 return new EntryIterator(); 1452 } 1453 1454 /** 1455 * Each of these fields are initialized to contain an instance of the 1456 * appropriate view the first time this view is requested. The views are 1457 * stateless, so there's no reason to create more than one of each. 1458 */ 1459 private transient volatile Set<K> keySet = null; 1460 private transient volatile Collection<V> values = null; 1461 private transient volatile Set<Map.Entry<K,V>> entrySet = null; 1462 1463 private class EntrySet extends AbstractSet<Map.Entry<K,V>> { 1464 public Iterator<Map.Entry<K,V>> iterator() { 1465 return newEntryIterator(); 1466 } 1467 1468 public boolean contains(Object o) { 1469 if (!(o instanceof Map.Entry)) 1470 return false; 1471 1472 TrieEntry<K,V> candidate = getEntry(((Map.Entry)o).getKey()); 1473 return candidate != null && candidate.equals(o); 1474 } 1475 1476 public boolean remove(Object o) { 1477 int size = size(); 1478 PatriciaTrie.this.remove(o); 1479 return size != size(); 1480 } 1481 1482 public int size() { 1483 return size; 1484 } 1485 1486 public void clear() { 1487 PatriciaTrie.this.clear(); 1488 } 1489 } 1490 1491 /** 1492 * Returns a set view of the keys contained in this map. The set is 1493 * backed by the map, so changes to the map are reflected in the set, and 1494 * vice-versa. The set supports element removal, which removes the 1495 * corresponding mapping from this map, via the <tt>Iterator.remove</tt>, 1496 * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and 1497 * <tt>clear</tt> operations. It does not support the <tt>add</tt> or 1498 * <tt>addAll</tt> operations. 1499 * 1500 * @return a set view of the keys contained in this map. 1501 */ 1502 public Set<K> keySet() { 1503 Set<K> ks = keySet; 1504 return (ks != null ? ks : (keySet = new KeySet())); 1505 } 1506 1507 private class KeySet extends AbstractSet<K> { 1508 public Iterator<K> iterator() { 1509 return newKeyIterator(); 1510 } 1511 public int size() { 1512 return size; 1513 } 1514 public boolean contains(Object o) { 1515 return containsKey(o); 1516 } 1517 public boolean remove(Object o) { 1518 int size = size(); 1519 PatriciaTrie.this.remove(o); 1520 return size != size(); 1521 } 1522 public void clear() { 1523 PatriciaTrie.this.clear(); 1524 } 1525 } 1526 1527 /** 1528 * Returns a collection view of the values contained in this map. The 1529 * collection is backed by the map, so changes to the map are reflected in 1530 * the collection, and vice-versa. The collection supports element 1531 * removal, which removes the corresponding mapping from this map, via the 1532 * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>, 1533 * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations. 1534 * It does not support the <tt>add</tt> or <tt>addAll</tt> operations. 1535 * 1536 * @return a collection view of the values contained in this map. 1537 */ 1538 public Collection<V> values() { 1539 Collection<V> vs = values; 1540 return (vs != null ? vs : (values = new Values())); 1541 } 1542 1543 /** Test two values for equality. Works with null values. */ 1544 private static boolean valEquals(Object o1, Object o2) { 1545 return (o1==null ? o2==null : o1.equals(o2)); 1546 } 1547 1548 private class Values extends AbstractCollection<V> { 1549 public Iterator<V> iterator() { 1550 return newValueIterator(); 1551 } 1552 public int size() { 1553 return size; 1554 } 1555 public boolean contains(Object o) { 1556 return containsValue(o); 1557 } 1558 public void clear() { 1559 PatriciaTrie.this.clear(); 1560 } 1561 public boolean remove(Object o) { 1562 for(Iterator<V> i = iterator(); i.hasNext(); ) { 1563 V v = i.next(); 1564 if(valEquals(v, o)) { 1565 i.remove(); 1566 return true; 1567 } 1568 } 1569 return false; 1570 } 1571 } 1572 1573 /** 1574 * Returns the first entry the Trie is storing. 1575 * 1576 * This is implemented by going always to the left until 1577 * we encounter a valid uplink. That uplink is the first key. 1578 */ 1579 private TrieEntry<K, V> firstEntry() { 1580 // if Trie is empty, no first node. 1581 if(isEmpty()) 1582 return null; 1583 1584 return followLeft(root); 1585 } 1586 1587 /** Goes left through the tree until it finds a valid node. */ 1588 private TrieEntry<K, V> followLeft(TrieEntry<K, V> node) { 1589 while(true) { 1590 TrieEntry<K, V> child = node.left; 1591 // if we hit root and it didn't have a node, go right instead. 1592 if(child.isEmpty()) 1593 child = node.right; 1594 1595 if(child.bitIndex <= node.bitIndex) 1596 return child; 1597 1598 node = child; 1599 } 1600 } 1601 1602 /** 1603 * Returns the last entry the Trie is storing. 1604 * <p> 1605 * This is implemented by going always to the right until 1606 * we encounter a valid uplink. That uplink is the last key. 1607 */ 1608 private TrieEntry<K, V> lastEntry() { 1609 return followRight(root.left); 1610 } 1611 1612 /** Traverses down the right path until it finds an uplink. */ 1613 protected TrieEntry<K, V> followRight(TrieEntry<K, V> node) { 1614 // if Trie is empty, no last entry. 1615 if(node.right == null) 1616 return null; 1617 1618 // Go as far right as possible, until we encounter an uplink. 1619 while(node.right.bitIndex > node.bitIndex) 1620 node = node.right; 1621 1622 return node.right; 1623 } 1624 1625 public K firstKey() { 1626 return firstEntry().getKey(); 1627 } 1628 1629 public SortedMap<K, V> headMap(K toKey) { 1630 return new SubMap(null, toKey); 1631 } 1632 1633 public K lastKey() { 1634 TrieEntry<K, V> entry = lastEntry(); 1635 if(entry != null) 1636 return entry.getKey(); 1637 else 1638 return null; 1639 } 1640 1641 1642 public SortedMap<K, V> subMap(K fromKey, K toKey) { 1643 return new SubMap(fromKey, toKey); 1644 } 1645 1646 public SortedMap<K, V> tailMap(K fromKey) { 1647 return new SubMap(fromKey, null); 1648 } 1649 1650 /** 1651 * Returns an entry strictly higher than the given key, 1652 * or null if no such entry exists. 1653 */ 1654 protected TrieEntry<K,V> higherEntry(K key) { 1655 // TODO: Cleanup so that we don't actually have to add/remove from the 1656 // tree. (We do it here because there are other well-defined 1657 // functions to perform the search.) 1658 int keyLength = length(key); 1659 1660 if (keyLength == 0) { 1661 if(!root.isEmpty()) { 1662 // If data in root, and more after -- return it. 1663 if(size() > 1) { 1664 return nextEntry(root); 1665 } else { // If no more after, no higher entry. 1666 return null; 1667 } 1668 } else { 1669 // Root is empty & we want something after empty, return first. 1670 return firstEntry(); 1671 } 1672 } 1673 1674 TrieEntry<K, V> found = getNearestEntryForKey(key, keyLength); 1675 if (key.equals(found.key)) 1676 return nextEntry(found); 1677 1678 int bitIndex = bitIndex(key, found.key); 1679 if (isValidBitIndex(bitIndex)) { 1680 TrieEntry<K, V> added = new TrieEntry<K, V>(key, null, bitIndex); 1681 addEntry(added, keyLength); 1682 incrementSize(); // must increment because remove will decrement 1683 TrieEntry<K, V> ceil = nextEntry(added); 1684 removeEntry(added); 1685 modCount -= 2; // we didn't really modify it. 1686 return ceil; 1687 } else if (isNullBitKey(bitIndex)) { 1688 if (!root.isEmpty()) 1689 return firstEntry(); 1690 else if(size() > 1) 1691 return nextEntry(firstEntry()); 1692 else 1693 return null; 1694 } else if (isEqualBitKey(bitIndex)) { 1695 return nextEntry(found); 1696 } 1697 1698 // we should have exited above. 1699 throw new IllegalStateException("invalid lookup: " + key); 1700 } 1701 1702 /** 1703 * Returns a key-value mapping associated with the least key greater 1704 * than or equal to the given key, or null if there is no such key. 1705 */ 1706 protected TrieEntry<K,V> ceilingEntry(K key) { 1707 // Basically: 1708 // Follow the steps of adding an entry, but instead... 1709 // 1710 // - If we ever encounter a situation where we found an equal 1711 // key, we return it immediately. 1712 // 1713 // - If we hit an empty root, return the first iterable item. 1714 // 1715 // - If we have to add a new item, we temporarily add it, 1716 // find the successor to it, then remove the added item. 1717 // 1718 // These steps ensure that the returned value is either the 1719 // entry for the key itself, or the first entry directly after 1720 // the key. 1721 1722 // TODO: Cleanup so that we don't actually have to add/remove from the 1723 // tree. (We do it here because there are other well-defined 1724 // functions to perform the search.) 1725 int keyLength = length(key); 1726 1727 if (keyLength == 0) { 1728 if(!root.isEmpty()) 1729 return root; 1730 else 1731 return firstEntry(); 1732 } 1733 1734 TrieEntry<K, V> found = getNearestEntryForKey(key, keyLength); 1735 if (key.equals(found.key)) 1736 return found; 1737 1738 int bitIndex = bitIndex(key, found.key); 1739 if (isValidBitIndex(bitIndex)) { 1740 TrieEntry<K, V> added = new TrieEntry<K, V>(key, null, bitIndex); 1741 addEntry(added, keyLength); 1742 incrementSize(); // must increment because remove will decrement 1743 TrieEntry<K, V> ceil = nextEntry(added); 1744 removeEntry(added); 1745 modCount -= 2; // we didn't really modify it. 1746 return ceil; 1747 } else if (isNullBitKey(bitIndex)) { 1748 if (!root.isEmpty()) 1749 return root; 1750 else 1751 return firstEntry(); 1752 } else if (isEqualBitKey(bitIndex)) { 1753 return found; 1754 } 1755 1756 // we should have exited above. 1757 throw new IllegalStateException("invalid lookup: " + key); 1758 } 1759 1760 /** 1761 * Returns a key-value mapping associated with the greatest key 1762 * strictly less than the given key, or null if there is no such key. 1763 */ 1764 protected TrieEntry<K,V> lowerEntry(K key) { 1765 // Basically: 1766 // Follow the steps of adding an entry, but instead... 1767 // 1768 // - If we ever encounter a situation where we found an equal 1769 // key, we return it's previousEntry immediately. 1770 // 1771 // - If we hit root (empty or not), return null. 1772 // 1773 // - If we have to add a new item, we temporarily add it, 1774 // find the previousEntry to it, then remove the added item. 1775 // 1776 // These steps ensure that the returned value is always just before 1777 // the key or null (if there was nothing before it). 1778 1779 // TODO: Cleanup so that we don't actually have to add/remove from the 1780 // tree. (We do it here because there are other well-defined 1781 // functions to perform the search.) 1782 int keyLength = length(key); 1783 1784 if (keyLength == 0) { 1785 return null; // there can never be anything before root. 1786 } 1787 1788 TrieEntry<K, V> found = getNearestEntryForKey(key, keyLength); 1789 if (key.equals(found.key)) 1790 return previousEntry(found); 1791 1792 int bitIndex = bitIndex(key, found.key); 1793 if (isValidBitIndex(bitIndex)) { 1794 TrieEntry<K, V> added = new TrieEntry<K, V>(key, null, bitIndex); 1795 addEntry(added, keyLength); 1796 incrementSize(); // must increment because remove will decrement 1797 TrieEntry<K, V> prior = previousEntry(added); 1798 removeEntry(added); 1799 modCount -= 2; // we didn't really modify it. 1800 return prior; 1801 } else if (isNullBitKey(bitIndex)) { 1802 return null; 1803 } else if (isEqualBitKey(bitIndex)) { 1804 return previousEntry(found); 1805 } 1806 1807 // we should have exited above. 1808 throw new IllegalStateException("invalid lookup: " + key); 1809 } 1810 1811 /** 1812 * Returns a key-value mapping associated with the greatest key 1813 * less than or equal to the given key, or null if there is no such key. 1814 */ 1815 protected TrieEntry<K,V> floorEntry(K key) { 1816 // TODO: Cleanup so that we don't actually have to add/remove from the 1817 // tree. (We do it here because there are other well-defined 1818 // functions to perform the search.) 1819 int keyLength = length(key); 1820 1821 if (keyLength == 0) { 1822 if(!root.isEmpty()) 1823 return root; 1824 else 1825 return null; 1826 } 1827 1828 TrieEntry<K, V> found = getNearestEntryForKey(key, keyLength); 1829 if (key.equals(found.key)) 1830 return found; 1831 1832 int bitIndex = bitIndex(key, found.key); 1833 if (isValidBitIndex(bitIndex)) { 1834 TrieEntry<K, V> added = new TrieEntry<K, V>(key, null, bitIndex); 1835 addEntry(added, keyLength); 1836 incrementSize(); // must increment because remove will decrement 1837 TrieEntry<K, V> floor = previousEntry(added); 1838 removeEntry(added); 1839 modCount -= 2; // we didn't really modify it. 1840 return floor; 1841 } else if (isNullBitKey(bitIndex)) { 1842 if (!root.isEmpty()) 1843 return root; 1844 else 1845 return null; 1846 } else if (isEqualBitKey(bitIndex)) { 1847 return found; 1848 } 1849 1850 // we should have exited above. 1851 throw new IllegalStateException("invalid lookup: " + key); 1852 } 1853 1854 1855 /** 1856 * Finds the subtree that contains the prefix. 1857 * 1858 * This is very similar to getR but with the difference that 1859 * we stop the lookup if h.bitIndex > keyLength. 1860 */ 1861 private TrieEntry<K, V> subtree(K prefix, int offset, int length) { 1862 TrieEntry<K, V> current = root.left; 1863 TrieEntry<K, V> path = root; 1864 while(true) { 1865 if(current.bitIndex <= path.bitIndex || length < current.bitIndex) 1866 break; 1867 1868 path = current; 1869 if(!isBitSet(prefix, length+offset, current.bitIndex+offset)) { 1870 current = current.left; 1871 } else { 1872 current = current.right; 1873 } 1874 } 1875 1876 // Make sure the entry is valid for a subtree. 1877 TrieEntry<K, V> entry = current.isEmpty() ? path : current; 1878 1879 // If entry is root, it can't be empty. 1880 if (entry.isEmpty()) 1881 return null; 1882 1883 int offsetLength = offset + length; 1884 1885 // if root && length of root is less than length of lookup, 1886 // there's nothing. 1887 // (this prevents returning the whole subtree if root has an empty 1888 // string and we want to lookup things with "\0") 1889 if(entry == root && length(entry.getKey()) < offsetLength) 1890 return null; 1891 1892 // Found key's length-th bit differs from our key 1893 // which means it cannot be the prefix... 1894 if(isBitSet(prefix, offsetLength, offsetLength) != 1895 isBitSet(entry.key, length(entry.key), length)) { 1896 return null; 1897 } 1898 1899 // ... or there are less than 'length' equal bits 1900 int bitIndex = keyAnalyzer.bitIndex(prefix, offset, length, 1901 entry.key, 0, length(entry.getKey())); 1902 if (bitIndex >= 0 && bitIndex < length) 1903 return null; 1904 1905 return entry; 1906 } 1907 1908 /** A submap used for prefix views over the Trie. */ 1909 private class PrefixSubMap extends SubMap { 1910 protected final K prefix; 1911 protected final int offset; 1912 protected final int length; 1913 private transient int keyModCount = 0; 1914 protected int size; 1915 1916 PrefixSubMap(K prefix, int offset, int length) { 1917 this.prefix = prefix; 1918 this.offset = offset; 1919 this.length = length; 1920 fromInclusive = false; 1921 } 1922 1923 public K firstKey() { 1924 fixup(); 1925 TrieEntry<K,V> e; 1926 if(fromKey == null) { 1927 e = firstEntry(); 1928 } else { 1929 e = higherEntry(fromKey); 1930 } 1931 1932 K first = e != null ? e.getKey() : null; 1933 if (e == null || !keyAnalyzer.isPrefix(prefix, offset, length, first)) 1934 throw new NoSuchElementException(); 1935 return first; 1936 } 1937 1938 public K lastKey() { 1939 fixup(); 1940 TrieEntry<K,V> e; 1941 if(toKey == null) { 1942 e = lastEntry(); 1943 } else { 1944 e = lowerEntry(toKey); 1945 } 1946 1947 K last = e != null ? e.getKey() : null; 1948 if (e == null || !keyAnalyzer.isPrefix(prefix, offset, length, last)) 1949 throw new NoSuchElementException(); 1950 return last; 1951 } 1952 1953 protected boolean inRange(K key) { 1954 return keyAnalyzer.isPrefix(prefix, offset, length, key); 1955 } 1956 1957 protected boolean inRange2(K key) { 1958 return keyAnalyzer.isPrefix(prefix, offset, length, key); 1959 } 1960 1961 protected boolean inToRange(K key, boolean forceInclusive) { 1962 return keyAnalyzer.isPrefix(prefix, offset, length, key); 1963 } 1964 1965 protected boolean inFromRange(K key, boolean forceInclusive) { 1966 return keyAnalyzer.isPrefix(prefix, offset, length, key); 1967 } 1968 1969 private void fixup() { 1970 // The trie has changed since we last 1971 // found our toKey / fromKey 1972 if(modCount != keyModCount) { 1973 Iterator<Map.Entry<K, V>> iter = entrySet().iterator(); 1974 size = 0; 1975 1976 Map.Entry<K, V> entry = null; 1977 if(iter.hasNext()) { 1978 entry = iter.next(); 1979 size = 1; 1980 } 1981 1982 fromKey = entry == null ? null : entry.getKey(); 1983 if(fromKey != null) { 1984 TrieEntry<K, V> prior = previousEntry((TrieEntry<K, V>)entry); 1985 fromKey = prior == null ? null : prior.getKey(); 1986 } 1987 1988 toKey = fromKey; 1989 1990 while(iter.hasNext()) { 1991 size++; 1992 entry = iter.next(); 1993 } 1994 1995 toKey = entry == null ? null : entry.getKey(); 1996 1997 if(toKey != null) { 1998 entry = nextEntry((TrieEntry<K, V>)entry); 1999 toKey = entry == null ? null : entry.getKey(); 2000 } 2001 2002 keyModCount = modCount; 2003 } 2004 } 2005 2006 protected Set<Map.Entry<K, V>> newSubMapEntrySet() { 2007 return new PrefixEntrySetView(); 2008 } 2009 2010 private class PrefixEntrySetView extends SubMap.EntrySetView { 2011 private TrieEntry<K, V> prefixStart; 2012 private int iterModCount = 0; 2013 2014 public int size() { 2015 fixup(); 2016 return PrefixSubMap.this.size; 2017 } 2018 2019 @SuppressWarnings("unchecked") 2020 public Iterator<Map.Entry<K,V>> iterator() { 2021 if(modCount != iterModCount) { 2022 prefixStart = subtree(prefix, offset, length); 2023 iterModCount = modCount; 2024 } 2025 2026 if(prefixStart == null) { 2027 return new EmptyIterator(); 2028 } else if(length >= prefixStart.bitIndex){ 2029 return new SingletonIterator(prefixStart); 2030 } else { 2031 return new PrefixEntryIterator(prefixStart, prefix, offset, length); 2032 } 2033 } 2034 } 2035 } 2036 2037 private class SubMap extends AbstractMap<K,V> implements SortedMap<K,V>, java.io.Serializable { 2038 2039 // TODO: add serialVersionUID 2040 2041 /** The key to start from, null if the beginning. */ 2042 protected K fromKey; 2043 2044 /** The key to end at, null if till the end. */ 2045 protected K toKey; 2046 2047 /** Whether or not the 'from' is inclusive. */ 2048 protected boolean fromInclusive; 2049 2050 /** Whether or not the 'to' is inclusive. */ 2051 protected boolean toInclusive; 2052 2053 /** 2054 * Constructs a blank SubMap -- this should ONLY be used 2055 * by subclasses that wish to lazily construct their 2056 * fromKey or toKey 2057 */ 2058 protected SubMap() {} 2059 2060 SubMap(K fromKey, K toKey) { 2061 if(fromKey == null && toKey == null) 2062 throw new IllegalArgumentException("must have a from or to!"); 2063 if(fromKey != null && toKey != null && keyAnalyzer.compare(fromKey, toKey) > 0) 2064 throw new IllegalArgumentException("fromKey > toKey"); 2065 this.fromKey = fromKey; 2066 this.toKey = toKey; 2067 fromInclusive = true; 2068 } 2069 2070 public boolean isEmpty() { 2071 return entrySet().isEmpty(); 2072 } 2073 2074 @SuppressWarnings("unchecked") 2075 public boolean containsKey(Object key) { 2076 return inRange((K) key) && PatriciaTrie.this.containsKey(key); 2077 } 2078 2079 @SuppressWarnings("unchecked") 2080 public V remove(Object key) { 2081 if(!inRange((K)key)) 2082 return null; 2083 return PatriciaTrie.this.remove(key); 2084 } 2085 2086 @SuppressWarnings("unchecked") 2087 public V get(Object key) { 2088 if (!inRange((K) key)) 2089 return null; 2090 return PatriciaTrie.this.get(key); 2091 } 2092 2093 public V put(K key, V value) { 2094 if (!inRange(key)) 2095 throw new IllegalArgumentException("key out of range"); 2096 return PatriciaTrie.this.put(key, value); 2097 } 2098 2099 public Comparator<? super K> comparator() { 2100 return keyAnalyzer; 2101 } 2102 2103 public K firstKey() { 2104 TrieEntry<K,V> e; 2105 if(fromKey == null) { 2106 e = firstEntry(); 2107 } else { 2108 if(fromInclusive) 2109 e = ceilingEntry(fromKey); 2110 else 2111 e = higherEntry(fromKey); 2112 } 2113 2114 K first = e != null ? e.getKey() : null; 2115 if (e == null || toKey != null && !inToRange(first, false)) 2116 throw new NoSuchElementException(); 2117 return first; 2118 } 2119 2120 public K lastKey() { 2121 TrieEntry<K,V> e; 2122 if(toKey == null) { 2123 e = lastEntry(); 2124 } else { 2125 if(toInclusive) 2126 e = floorEntry(toKey); 2127 else 2128 e = lowerEntry(toKey); 2129 } 2130 2131 K last = e != null ? e.getKey() : null; 2132 if (e == null || fromKey != null && !inFromRange(last, false)) 2133 throw new NoSuchElementException(); 2134 return last; 2135 } 2136 2137 private transient Set<Map.Entry<K,V>> entrySet; 2138 2139 public Set<Map.Entry<K,V>> entrySet() { 2140 if(entrySet == null) 2141 entrySet = newSubMapEntrySet(); 2142 return entrySet; 2143 } 2144 2145 protected Set<Map.Entry<K, V>> newSubMapEntrySet() { 2146 return new EntrySetView(); 2147 } 2148 2149 class EntrySetView extends AbstractSet<Map.Entry<K,V>> { 2150 private transient int size = -1, sizeModCount; 2151 2152 public int size() { 2153 if (size == -1 || sizeModCount != PatriciaTrie.this.modCount) { 2154 size = 0; sizeModCount = PatriciaTrie.this.modCount; 2155 Iterator i = iterator(); 2156 while (i.hasNext()) { 2157 size++; 2158 i.next(); 2159 } 2160 } 2161 return size; 2162 } 2163 2164 public boolean isEmpty() { 2165 return !iterator().hasNext(); 2166 } 2167 2168 @SuppressWarnings("unchecked") 2169 public boolean contains(Object o) { 2170 if (!(o instanceof Map.Entry)) 2171 return false; 2172 Map.Entry<K,V> entry = (Map.Entry<K,V>) o; 2173 K key = entry.getKey(); 2174 if (!inRange(key)) 2175 return false; 2176 TrieEntry<K, V> node = getEntry(key); 2177 return node != null && 2178 valEquals(node.getValue(), entry.getValue()); 2179 } 2180 2181 @SuppressWarnings("unchecked") 2182 public boolean remove(Object o) { 2183 if (!(o instanceof Map.Entry)) 2184 return false; 2185 Map.Entry<K,V> entry = (Map.Entry<K,V>) o; 2186 K key = entry.getKey(); 2187 if (!inRange(key)) 2188 return false; 2189 TrieEntry<K,V> node = getEntry(key); 2190 if (node!=null && valEquals(node.getValue(),entry.getValue())){ 2191 removeEntry(node); 2192 return true; 2193 } 2194 return false; 2195 } 2196 2197 public Iterator<Map.Entry<K,V>> iterator() { 2198 return new SubMapEntryIterator( 2199 (fromKey == null ? firstEntry() : ceilingEntry(fromKey)), 2200 (toKey == null ? null : ceilingEntry(toKey))); 2201 } 2202 } 2203 2204 public SortedMap<K,V> subMap(K fromKey, K toKey) { 2205 if (!inRange2(fromKey)) 2206 throw new IllegalArgumentException("fromKey out of range"); 2207 if (!inRange2(toKey)) 2208 throw new IllegalArgumentException("toKey out of range"); 2209 return new SubMap(fromKey, toKey); 2210 } 2211 2212 public SortedMap<K,V> headMap(K toKey) { 2213 if (!inRange2(toKey)) 2214 throw new IllegalArgumentException("toKey out of range"); 2215 return new SubMap(fromKey, toKey); 2216 } 2217 2218 public SortedMap<K,V> tailMap(K fromKey) { 2219 if (!inRange2(fromKey)) 2220 throw new IllegalArgumentException("fromKey out of range"); 2221 return new SubMap(fromKey, toKey); 2222 } 2223 2224 protected boolean inRange(K key) { 2225 return (fromKey == null || inFromRange(key, false)) && 2226 (toKey == null || inToRange(key, false)); 2227 } 2228 2229 // This form allows the high endpoint (as well as all legit keys) 2230 protected boolean inRange2(K key) { 2231 return (fromKey == null || inFromRange(key, false)) && 2232 (toKey == null || inToRange(key, true)); 2233 } 2234 2235 protected boolean inToRange(K key, boolean forceInclusive) { 2236 int ret = keyAnalyzer.compare(key, toKey); 2237 if(toInclusive || forceInclusive) 2238 return ret <= 0; 2239 else 2240 return ret < 0; 2241 } 2242 2243 protected boolean inFromRange(K key, boolean forceInclusive) { 2244 int ret = keyAnalyzer.compare(key, fromKey); 2245 if (fromInclusive || forceInclusive) 2246 return ret >= 0; 2247 else 2248 return ret > 0; 2249 } 2250 } 2251 2252 private static class EmptyIterator implements Iterator { 2253 public boolean hasNext() { 2254 return false; 2255 } 2256 2257 public Object next() { 2258 throw new NoSuchElementException(); 2259 } 2260 2261 public void remove() { 2262 throw new IllegalStateException(); 2263 } 2264 2265 } 2266 }