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