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