View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.collections4.trie;
18  
19  import java.io.IOException;
20  import java.io.ObjectInputStream;
21  import java.io.ObjectOutputStream;
22  import java.util.AbstractCollection;
23  import java.util.AbstractMap;
24  import java.util.AbstractSet;
25  import java.util.Collection;
26  import java.util.Collections;
27  import java.util.Comparator;
28  import java.util.ConcurrentModificationException;
29  import java.util.Iterator;
30  import java.util.Map;
31  import java.util.NoSuchElementException;
32  import java.util.Objects;
33  import java.util.Set;
34  import java.util.SortedMap;
35  
36  import org.apache.commons.collections4.OrderedMapIterator;
37  import org.apache.commons.collections4.Trie;
38  
39  /**
40   * This class implements the base PATRICIA algorithm and everything that
41   * is related to the {@link Map} interface.
42   *
43   * @param <K> the type of the keys in this map
44   * @param <V> the type of the values in this map
45   * @since 4.0
46   */
47  public abstract class AbstractPatriciaTrie<K, V> extends AbstractBitwiseTrie<K, V> {
48  
49      /**
50       * A range view of the {@link org.apache.commons.collections4.Trie}.
51       */
52      private abstract class AbstractRangeMap extends AbstractMap<K, V>
53              implements SortedMap<K, V> {
54  
55          /** The {@link #entrySet()} view. */
56          private transient volatile Set<Map.Entry<K, V>> entrySet;
57  
58          @Override
59          public Comparator<? super K> comparator() {
60              return AbstractPatriciaTrie.this.comparator();
61          }
62  
63          @Override
64          public boolean containsKey(final Object key) {
65              if (!inRange(castKey(key))) {
66                  return false;
67              }
68  
69              return AbstractPatriciaTrie.this.containsKey(key);
70          }
71  
72          /**
73           * Creates and returns an {@link #entrySet()} view of the {@link AbstractRangeMap}.
74           */
75          protected abstract Set<Map.Entry<K, V>> createEntrySet();
76  
77          /**
78           * Creates and returns a sub-range view of the current {@link AbstractRangeMap}.
79           */
80          protected abstract SortedMap<K, V> createRangeMap(K fromKey, boolean fromInclusive,
81                                                            K toKey, boolean toInclusive);
82  
83          @Override
84          public Set<Map.Entry<K, V>> entrySet() {
85              if (entrySet == null) {
86                  entrySet = createEntrySet();
87              }
88              return entrySet;
89          }
90  
91          @Override
92          public V get(final Object key) {
93              if (!inRange(castKey(key))) {
94                  return null;
95              }
96  
97              return AbstractPatriciaTrie.this.get(key);
98          }
99  
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 &amp; 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()} &amp; {@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 &amp; 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 &amp; root isEmpty, return null.
1965      *              - If it is root &amp; 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 &amp; L is smaller
2273      * than the XOR distance between D &amp; 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 &amp; L is smaller
2302      * than the XOR distance between D &amp; 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 &amp; L is smaller
2354      * than the XOR distance between D &amp; 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 }