1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package info.rolandkrueger.roklib.util;
26
27 import info.rolandkrueger.roklib.util.helper.CheckForNull;
28
29 import java.io.Serializable;
30 import java.util.AbstractCollection;
31 import java.util.AbstractMap;
32 import java.util.AbstractSet;
33 import java.util.Collection;
34 import java.util.Comparator;
35 import java.util.Iterator;
36 import java.util.Map;
37 import java.util.NoSuchElementException;
38 import java.util.Set;
39 import java.util.SortedMap;
40 import java.util.SortedSet;
41 import java.util.Stack;
42 import java.util.TreeSet;
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 public class TernarySearchTreeMap<V> extends AbstractMap<CharSequence, V> implements Serializable,
89 ITernarySearchTreeMap<V>
90 {
91 private static final long serialVersionUID = 8532235443989332299L;
92
93 private enum NodeType implements Serializable
94 {
95 NONE, LOKID, EQKID, HIKID
96 };
97
98 private TSTNode<V> mRootNode;
99 private TreeSet<CharSequence> mMatchingKeys;
100
101 private int mLengthTolerance;
102
103 private Comparator<? super CharSequence> mComparator;
104 private boolean mContainsEmptyStringKey = false;
105 private V mEmptyStringKeyValue = null;
106
107
108 private int mNodeCount;
109
110
111
112
113 public TernarySearchTreeMap ()
114 {
115 mRootNode = new TSTNode<V> ();
116 }
117
118 public TernarySearchTreeMap (Map<CharSequence, V> map)
119 {
120 this ();
121 putAll (map);
122 }
123
124 public TernarySearchTreeMap (SortedMap<CharSequence, V> map)
125 {
126 this ();
127
128 mComparator = map.comparator ();
129 putAll (map);
130 }
131
132 public String getMapStructureAsString ()
133 {
134 return mRootNode.toString ();
135 }
136
137 public void clear ()
138 {
139 mRootNode = new TSTNode<V> ();
140 mContainsEmptyStringKey = false;
141 mEmptyStringKeyValue = null;
142 }
143
144 public boolean containsKey (Object key)
145 {
146 return get (key) != null;
147 }
148
149 public boolean containsValue (Object value)
150 {
151 if (mContainsEmptyStringKey)
152 {
153 if (value == null && mEmptyStringKeyValue == null) return true;
154 if (mEmptyStringKeyValue != null && mEmptyStringKeyValue.equals (value)) return true;
155 }
156 for (Map.Entry<CharSequence, V> entry : entrySet ())
157 {
158 if (entry.getValue () == null && value == null) return true;
159 if (entry.getValue ().equals (value)) return true;
160 }
161 return false;
162 }
163
164 public boolean isEmpty ()
165 {
166 return (size () == 0);
167 }
168
169 private Iterator<Entry<CharSequence, V>> getIterator (CharSequence fromKey, CharSequence toKey)
170 {
171 return new TSTIterator (fromKey, toKey);
172 }
173
174 public Set<CharSequence> keySet ()
175 {
176 return new TSTKeySet ();
177 }
178
179 @SuppressWarnings ("unchecked")
180 private int compare (CharSequence firstKey, CharSequence secondKey)
181 {
182 return (mComparator == null ? ((Comparable<CharSequence>) firstKey).compareTo (secondKey)
183 : mComparator.compare (firstKey, secondKey));
184 }
185
186 public void putAll (Map<? extends CharSequence, ? extends V> t)
187 {
188 for (CharSequence element : t.keySet ())
189 {
190 put (element, t.get (element));
191 }
192 }
193
194 public V remove (Object key)
195 {
196 try
197 {
198 String keyString = ((CharSequence) key).toString ();
199 V oldValue;
200 if (keyString.equals ("") && mContainsEmptyStringKey)
201 {
202 mContainsEmptyStringKey = false;
203 oldValue = mEmptyStringKeyValue;
204 mEmptyStringKeyValue = null;
205 return oldValue;
206 }
207 Stack<TSTStackNode<V>> stack = new Stack<TSTStackNode<V>> ();
208 TSTNode<V> currentNode = mRootNode;
209 TSTStackNode<V> currentStackNode = null;
210 int charIndex = 0;
211 int keyStringLength = keyString.length ();
212
213 while (true)
214 {
215 if (currentNode == null)
216 {
217 return null;
218 } else
219 {
220 currentStackNode = new TSTStackNode<V> (currentNode);
221 }
222 stack.push (currentStackNode);
223 char splitChar = currentNode.mSplitChar;
224 char keyChar = keyString.charAt (charIndex);
225
226 if (keyChar == splitChar)
227 {
228 charIndex++;
229 if ((charIndex == keyStringLength) && (currentNode.mData != null))
230 {
231
232 oldValue = currentNode.mData;
233 currentNode.mData = null;
234 while ((currentNode.mLokid == null) && (currentNode.mEqkid == null)
235 && (currentNode.mHikid == null))
236 {
237
238 if ((stack.size () == 0) && (mRootNode.mData != null))
239 {
240
241
242 return oldValue;
243 } else if (stack.size () == 0)
244 {
245 mRootNode.mSplitChar = '\0';
246 return oldValue;
247 }
248 currentNode = stack.pop ().mNode;
249 currentNode.mSubarrayLength--;
250 charIndex--;
251
252
253
254 if (charIndex < 0) break;
255 if (keyChar == splitChar
256 && currentNode.mEqkid != null && currentNode.mEqkid.mSubarrayLength == 0)
257 currentNode.mEqkid = null;
258 else if (keyChar < splitChar
259 && currentNode.mLokid != null && currentNode.mLokid.mSubarrayLength == 0)
260 currentNode.mLokid = null;
261 else if (currentNode.mHikid != null && currentNode.mHikid.mSubarrayLength == 0)
262 currentNode.mHikid = null;
263 }
264 while (stack.size () > 0)
265 {
266 currentNode = stack.pop ().mNode;
267 currentNode.mSubarrayLength--;
268
269 }
270 return oldValue;
271 } else
272 {
273 currentNode = currentNode.mEqkid;
274 }
275 } else if (keyChar < splitChar)
276 {
277 currentNode = currentNode.mLokid;
278 } else
279 {
280 currentNode = currentNode.mHikid;
281 }
282 }
283 } finally
284 {
285 if (isEmpty ())
286 {
287 clear ();
288 }
289 }
290 }
291
292 public Collection<V> values ()
293 {
294 return new TSTValuesCollection ();
295 }
296
297 public Comparator<? super CharSequence> comparator ()
298 {
299 return mComparator;
300 }
301
302 public CharSequence firstKey ()
303 {
304 return getKeyAt (0);
305 }
306
307 public CharSequence lastKey ()
308 {
309 return getKeyAt (size () - 1);
310 }
311
312 public SortedMap<CharSequence, V> headMap (CharSequence toKey)
313 {
314 CheckForNull.check (toKey);
315 return new TSTSubMap (null, toKey);
316 }
317
318 public SortedMap<CharSequence, V> subMap (CharSequence fromKey, CharSequence toKey)
319 {
320 if (fromKey == null || toKey == null)
321 throw new NullPointerException ("One of the submap endpoints is null.");
322 return new TSTSubMap (fromKey, toKey);
323 }
324
325 public SortedMap<CharSequence, V> tailMap (CharSequence fromKey)
326 {
327 CheckForNull.check (fromKey);
328 return new TSTSubMap (fromKey, null);
329 }
330
331
332
333
334 public SortedSet<CharSequence> matchAlmost (CharSequence key, int distance, int lengthTolerance)
335 {
336 mMatchingKeys = new TreeSet<CharSequence> ();
337 this.mLengthTolerance = lengthTolerance;
338 matchAlmost (key.toString (), 0, mRootNode, distance, new StringBuilder (), key.toString ()
339 .length ());
340 TreeSet<CharSequence> result = mMatchingKeys;
341 mMatchingKeys = null;
342 return result;
343 }
344
345 private void matchAlmost (String key, int i, TSTNode<V> currentNode, int distance,
346 StringBuilder prefix, int keyLength)
347 {
348 int nextDist;
349 prefix.setLength (i);
350 if ((currentNode == null) || (distance < 0) || (i >= keyLength + mLengthTolerance))
351 {
352 return;
353 }
354
355 matchAlmost (key, i, currentNode.mLokid, distance, prefix, keyLength);
356
357 if (i < keyLength)
358 nextDist = (key.charAt (i) == currentNode.mSplitChar) ? distance : distance - 1;
359 else
360 nextDist = distance - 1;
361 if (distance < 0) return;
362 prefix.append (currentNode.mSplitChar);
363
364 if ((Math.abs (keyLength - i - 1) <= mLengthTolerance) && (nextDist >= 0)
365 && (currentNode.mData != null))
366 {
367 mMatchingKeys.add (prefix.toString ());
368 }
369
370 matchAlmost (key, i + 1, currentNode.mEqkid, nextDist, prefix, keyLength);
371 matchAlmost (key, i, currentNode.mHikid, distance, prefix, keyLength);
372 }
373
374 public V get (Object key)
375 {
376 Entry<CharSequence, V> result = getEntry (key);
377 if (result == null) return null;
378 return result.getValue ();
379 }
380
381
382
383
384 public Entry<CharSequence, V> getEntry (Object key)
385 {
386 CheckForNull.check (key);
387 String keyString = ((CharSequence) key).toString ();
388 if (keyString.equals ("") && mContainsEmptyStringKey)
389 return new TSTEntry<CharSequence, V> (keyString, mEmptyStringKeyValue);
390 else if (keyString.equals ("") && ! mContainsEmptyStringKey) return null;
391
392 Stack<TSTStackNode<V>> stack = new Stack<TSTStackNode<V>> ();
393 TSTStackNode<V> currentStackNode = null;
394 TSTNode<V> currentNode = mRootNode;
395 int charIndex = 0;
396 int keyStringLength = keyString.length ();
397 while (true)
398 {
399 if (currentNode == null)
400 {
401 return null;
402 } else
403 {
404 currentStackNode = new TSTStackNode<V> (currentNode);
405 }
406
407 stack.push (currentStackNode);
408 char splitChar = currentNode.mSplitChar;
409 char keyChar = keyString.charAt (charIndex);
410
411 if (keyChar == splitChar)
412 {
413 charIndex++;
414 if (charIndex == keyStringLength)
415 {
416 return currentNode.mData == null ? null : new TSTEntry<CharSequence, V> (keyString, currentNode.mData);
417 } else
418 {
419 currentNode = currentNode.mEqkid;
420 }
421 } else if (keyChar < splitChar)
422 {
423 currentNode = currentNode.mLokid;
424 } else
425 {
426 currentNode = currentNode.mHikid;
427 }
428 }
429 }
430
431
432
433
434 public V getValueAt (int index) throws IndexOutOfBoundsException
435 {
436 return getElementAt (index).getValue ();
437 }
438
439
440
441
442 public CharSequence getKeyAt (int index) throws IndexOutOfBoundsException
443 {
444 return getElementAt (index).getKey ();
445 }
446
447
448
449
450
451
452
453
454
455 private TSTEntry<CharSequence, V> getElementAt (int index) throws IndexOutOfBoundsException
456 {
457 if ((index < 0) || (index > this.size ())) throw new IndexOutOfBoundsException ();
458 if (mContainsEmptyStringKey && index == 0)
459 {
460 return new TSTEntry<CharSequence, V> ("", mEmptyStringKeyValue);
461 }
462
463 TSTNode<V> currentNode = mRootNode;
464 if (mContainsEmptyStringKey)
465 {
466 index--;
467 }
468
469 StringBuilder buf = new StringBuilder ();
470 int offset, loLength, eqLength, hiLength;
471
472 index++;
473 while (true)
474 {
475 offset = 0;
476
477 if (currentNode.mLokid != null)
478 loLength = currentNode.mLokid.mSubarrayLength;
479 else
480 loLength = 0;
481 if (currentNode.mEqkid != null)
482 eqLength = currentNode.mEqkid.mSubarrayLength;
483 else
484 eqLength = 0;
485 if (currentNode.mHikid != null)
486 hiLength = currentNode.mHikid.mSubarrayLength;
487 else
488 hiLength = 0;
489
490
491 if ((loLength + eqLength + hiLength == currentNode.mSubarrayLength - 1)
492 && (index - loLength == 1)) break;
493
494 if (currentNode.mData != null)
495 {
496
497
498
499 offset = 1;
500 }
501
502
503
504 if (loLength + offset >= index)
505 {
506 currentNode = currentNode.mLokid;
507 } else if (loLength + eqLength + offset >= index)
508 {
509
510 index -= loLength + offset;
511 buf.append (currentNode.mSplitChar);
512 currentNode = currentNode.mEqkid;
513 } else
514 {
515 index -= loLength + eqLength + offset;
516 currentNode = currentNode.mHikid;
517 }
518 }
519
520 return new TSTEntry<CharSequence, V> (buf.append (currentNode.mSplitChar).toString (),
521 currentNode.mData);
522 }
523
524
525
526
527 public int indexOf (CharSequence key)
528 {
529 String keyString = key.toString ();
530 if (mContainsEmptyStringKey && keyString.equals (""))
531 {
532 return 0;
533 }
534
535 TSTNode<V> currentNode = mRootNode;
536 int charIndex = 0;
537 int index = mContainsEmptyStringKey ? 1 : 0;
538 int keyStringLength = keyString.length ();
539 int offset, loLength, eqLength;
540
541 while (true)
542 {
543 if (currentNode == null) return - 1;
544 offset = 0;
545
546 if (currentNode.mLokid != null)
547 loLength = currentNode.mLokid.mSubarrayLength;
548 else
549 loLength = 0;
550 if (currentNode.mEqkid != null)
551 eqLength = currentNode.mEqkid.mSubarrayLength;
552 else
553 eqLength = 0;
554
555 if (currentNode.mData != null)
556 {
557
558
559
560 offset = 1;
561 }
562
563 if (keyString.charAt (charIndex) == currentNode.mSplitChar)
564 {
565 charIndex++;
566 if ((charIndex == keyStringLength) && (currentNode.mData != null))
567 {
568
569 return index;
570 } else if ((charIndex == keyStringLength) && (currentNode.mData == null))
571 {
572
573
574
575 return - 1;
576 } else
577 {
578 index += loLength + offset;
579 currentNode = currentNode.mEqkid;
580 }
581 } else if (keyString.charAt (charIndex) < currentNode.mSplitChar)
582 {
583 currentNode = currentNode.mLokid;
584 } else
585 {
586 index += loLength + eqLength + offset;
587 currentNode = currentNode.mHikid;
588 }
589 }
590 }
591
592
593
594
595 public Iterable<CharSequence> getKeysForPrefix (final CharSequence prefix)
596 {
597 return new Iterable<CharSequence> ()
598 {
599 public Iterator<CharSequence> iterator ()
600 {
601 return new Iterator<CharSequence> ()
602 {
603 Iterator<Entry<CharSequence, V>> it = getPrefixSubtreeIterator (prefix.toString ());
604
605 public boolean hasNext ()
606 {
607 return it.hasNext ();
608 }
609
610 public CharSequence next ()
611 {
612 return it.next ().getKey ();
613 }
614
615 public void remove ()
616 {
617 it.remove ();
618 }
619 };
620 }
621 };
622 }
623
624
625
626
627 public Iterator<Entry<CharSequence, V>> getPrefixSubtreeIterator (String prefix)
628 {
629 return getPrefixSubtreeIterator (prefix, false);
630 }
631
632
633
634
635 public Iterator<Entry<CharSequence, V>> getPrefixSubtreeIterator (String pPrefix,
636 boolean inverseSearch)
637 {
638 CheckForNull.check (pPrefix);
639 String prefix = pPrefix;
640 StringBuilder prefixBuilder = new StringBuilder ();
641 if (! inverseSearch && prefix.equals (""))
642 return new TSTIterator ();
643 else if (inverseSearch && prefix.equals ("")) return new TSTIterator (null, "", false, null, null);
644
645 TSTNode<V> currentNode = mRootNode;
646 int charIndex = 0;
647 int prefixLength = prefix.length ();
648
649 while (charIndex != prefixLength)
650 {
651 if (currentNode == null)
652 {
653 if (inverseSearch)
654 return new TSTIterator ();
655 else
656 return new TSTIterator (null, "", false, null, null);
657 }
658 char splitChar = currentNode.mSplitChar;
659 char currentChar = prefix.charAt (charIndex);
660
661 if (currentChar == splitChar)
662 {
663 charIndex++;
664 prefixBuilder.append (currentNode.mSplitChar);
665 if ((charIndex == prefixLength) && (currentNode.mData != null))
666 {
667 return new TSTIterator (currentNode, currentNode.mEqkid, prefixBuilder.toString (), inverseSearch, null, null);
668 } else if (charIndex == prefixLength)
669 {
670 return new TSTIterator (currentNode.mEqkid, prefixBuilder.toString (), inverseSearch, null, null);
671 } else
672 {
673 currentNode = currentNode.mEqkid;
674 }
675 } else if (currentChar < splitChar)
676 {
677 currentNode = currentNode.mLokid;
678 } else
679 {
680 currentNode = currentNode.mHikid;
681 }
682 }
683 if (inverseSearch)
684 return new TSTIterator ();
685 else
686 return new TSTIterator (null, "", inverseSearch, null, null);
687 }
688
689 public V put (CharSequence key, V value)
690 {
691 CheckForNull.check (key, value);
692 if (key.equals (""))
693 {
694 mEmptyStringKeyValue = value;
695 mContainsEmptyStringKey = true;
696 return value;
697 }
698 V prevValue = null;
699 TSTNode<V> currentNode = mRootNode;
700
701 TSTNode<V> prevNode = new TSTNode<V> ();
702
703 String keyString = key.toString ();
704 int keyStringLength = keyString.length ();
705
706 int charIndex = 0;
707
708 NodeType prevBranch = NodeType.NONE;
709 boolean keyAlreadyInList = containsKey (key);
710 char currentChar = keyString.charAt (charIndex);
711
712 while (true)
713 {
714 if ((currentNode == null) || (mRootNode.mSplitChar == '\0'))
715 {
716
717 if (currentNode == mRootNode)
718 {
719 mRootNode.mSplitChar = currentChar;
720 } else
721 {
722 currentNode = new TSTNode<V> (currentChar);
723 switch (prevBranch)
724 {
725 case HIKID:
726 prevNode.mHikid = currentNode;
727 break;
728 case EQKID:
729 prevNode.mEqkid = currentNode;
730 break;
731 case LOKID:
732 prevNode.mLokid = currentNode;
733 break;
734 default:
735 }
736 }
737 }
738 if (currentChar == currentNode.mSplitChar)
739 {
740 ++charIndex;
741 if (charIndex == keyStringLength)
742 {
743
744
745 if (prevValue == null)
746 {
747 prevValue = currentNode.mData;
748 }
749 currentNode.mData = value;
750 if (! keyAlreadyInList) ++currentNode.mSubarrayLength;
751
752
753
754 return prevValue;
755 } else
756 {
757 currentChar = keyString.charAt (charIndex);
758 if (! keyAlreadyInList) ++currentNode.mSubarrayLength;
759
760
761
762 prevNode = currentNode;
763 currentNode = currentNode.mEqkid;
764 prevBranch = NodeType.EQKID;
765 }
766 } else if (currentChar < currentNode.mSplitChar)
767 {
768 if (! keyAlreadyInList) ++currentNode.mSubarrayLength;
769
770
771
772 prevNode = currentNode;
773 currentNode = currentNode.mLokid;
774 prevBranch = NodeType.LOKID;
775 } else
776 {
777 if (! keyAlreadyInList) ++currentNode.mSubarrayLength;
778
779
780
781 prevNode = currentNode;
782 currentNode = currentNode.mHikid;
783 prevBranch = NodeType.HIKID;
784 }
785 }
786 }
787
788
789
790
791 public Entry<CharSequence, V> predecessor (Object keyObject)
792 {
793 CharSequence key = (CharSequence) keyObject;
794
795 if (key.equals ("")) return null;
796 SortedMap<CharSequence, V> headMap = headMap (key);
797 CharSequence prevKey = headMap.lastKey ();
798 return prevKey == null ? null : getEntry (prevKey);
799 }
800
801
802
803
804 public Entry<CharSequence, V> successor (Object keyObject)
805 {
806 CharSequence key = (CharSequence) keyObject;
807
808 Iterator<Map.Entry<CharSequence, V>> it = tailMap (key).entrySet ().iterator ();
809 if (containsKey (key))
810 {
811 it.next ();
812 }
813 return it.hasNext () ? it.next () : null;
814 }
815
816 public int size ()
817 {
818 if (mContainsEmptyStringKey) return mRootNode.mSubarrayLength + 1;
819 return mRootNode.mSubarrayLength;
820 }
821
822
823
824
825 public Set<Entry<CharSequence, V>> entrySet ()
826 {
827 return new TSTEntrySet (null, null);
828 }
829
830 private class TSTStackNode<NodeValue> implements Serializable
831 {
832 private static final long serialVersionUID = - 9203260538139494037L;
833
834 public TSTStackNode (TSTNode<NodeValue> node)
835 {
836 mNode = node;
837 }
838
839 public TSTNode<NodeValue> mNode;
840 public boolean mNeedsRecheck = false;
841 public int mCharIndex;
842 public boolean mRecheckHiKid = false;
843 }
844
845 private class TSTNode<NodeValue> implements Serializable
846 {
847 private static final long serialVersionUID = - 692198357972673845L;
848
849 public TSTNode<NodeValue> mLokid, mEqkid, mHikid;
850 public NodeValue mData;
851 public int mSubarrayLength = 0;
852
853
854
855
856 public char mSplitChar = '\0';
857
858 public TSTNode ()
859 {
860 super ();
861 }
862
863 public TSTNode (char splitChar)
864 {
865 mSplitChar = splitChar;
866 }
867
868 @Override
869 public String toString ()
870 {
871 return toString (0);
872 }
873
874 private String toString (int level)
875 {
876 StringBuilder indentBuf = new StringBuilder ();
877 for (int i = 0; i < level; ++i)
878 indentBuf.append (" ");
879 String indent = indentBuf.toString ();
880
881 return String.format ("{SL=%d; ch=%s; data=%s;\n%slo=%s,\n%seq=%s,\n%shi=%s}",
882 mSubarrayLength, mSplitChar, mData == null ? "" : mData.toString (), indent,
883 mLokid == null ? "0" : mLokid.toString (level + 1), indent,
884 mEqkid == null ? "0" : mEqkid.toString (level + 1), indent,
885 mHikid == null ? "0" : mHikid.toString (level + 1));
886 }
887 }
888
889 class TSTIterator implements Iterator<Entry<CharSequence, V>>, Serializable
890 {
891 private static final long serialVersionUID = - 7270329414991887561L;
892
893 private Stack<TSTItStackNode> mStack;
894 private String mPrefix;
895 private String mPrefixForInverseSearch;
896 private StringBuilder mBuffer;
897 private boolean mWentToNextItem = false;
898
899
900 private TSTNode<V> mFirstElement = null;
901 private String mPreviouslyReturnedKey;
902
903
904 private boolean mPrevKeyRemoved = false;
905 private boolean mProvideEmptyKeyValue = false;
906 private boolean mIteratorEmpty = false;
907 private boolean mInverseSearch;
908 private int mPrefixForInverseSearchLength;
909 private CharSequence mFromKey;
910 private CharSequence mExclusiveToKey;
911
912 public TSTIterator ()
913 {
914 this (null, null);
915 }
916
917 public TSTIterator (CharSequence fromKey, CharSequence toKey)
918 {
919 this (mRootNode, "", false, fromKey, toKey);
920 }
921
922 public TSTIterator (TSTNode<V> startNode, String prefix, boolean inverse, CharSequence fromKey, CharSequence toKey)
923 {
924 this (null, startNode, prefix, inverse, fromKey, toKey);
925 }
926
927 public TSTIterator (TSTNode<V> firstElement, TSTNode<V> startNode, String prefix,
928 boolean inverse, CharSequence fromKey, CharSequence toKey)
929 {
930 if (fromKey != null && toKey != null && compare (fromKey, toKey) > 0)
931 throw new IllegalArgumentException ("Invalid parameters: fromKey > toKey");
932
933 mFromKey = fromKey;
934 mExclusiveToKey = toKey;
935 if ("".equals (mExclusiveToKey)) mIteratorEmpty = true;
936 if (inverse)
937 {
938 mPrefixForInverseSearch = prefix;
939 mPrefixForInverseSearchLength = prefix.length ();
940 init (mRootNode, "");
941 } else
942 {
943 mFirstElement = firstElement;
944 init (startNode, prefix);
945 }
946 mInverseSearch = inverse;
947 }
948
949 private void init (TSTNode<V> startNode, String prefix)
950 {
951 mBuffer = new StringBuilder ();
952 mStack = new Stack<TSTItStackNode> ();
953 mPrefix = "";
954 if (startNode != null) mStack.push (new TSTItStackNode (startNode));
955 if (prefix != null) mPrefix = prefix;
956 if (mPrefix.equals ("") && mContainsEmptyStringKey)
957 {
958 if (mFromKey == null || (mFromKey != null && "".equals (mFromKey)))
959 {
960 mProvideEmptyKeyValue = true;
961 }
962 }
963 }
964
965 private void goToNextElement ()
966 {
967 TSTItStackNode currentNode;
968
969 currentNode = mStack.pop ();
970
971 while (true)
972 {
973 if ((currentNode.mNode.mData != null) && (currentNode.mReturned == false)
974 && (currentNode.mVisited == TSTItStackNode.LOKID))
975 {
976 mStack.push (currentNode);
977 if (! mInverseSearch || mBuffer.length () + 1 < mPrefixForInverseSearchLength) return;
978 if (! (mBuffer.toString () + currentNode.mNode.mSplitChar)
979 .startsWith (mPrefixForInverseSearch)) return;
980 }
981 if ((currentNode.mNode.mLokid != null) && (currentNode.mVisited == TSTItStackNode.NONE))
982 {
983 currentNode.mVisited = TSTItStackNode.LOKID;
984 mStack.push (currentNode);
985 currentNode = new TSTItStackNode (currentNode.mNode.mLokid);
986 } else if ((currentNode.mNode.mLokid == null)
987 && (currentNode.mVisited == TSTItStackNode.NONE))
988 currentNode.mVisited = TSTItStackNode.LOKID;
989 else if ((currentNode.mNode.mEqkid != null)
990 && (currentNode.mVisited < TSTItStackNode.LOEQKID))
991 {
992 mBuffer.append (currentNode.mNode.mSplitChar);
993 currentNode.mVisited = TSTItStackNode.LOEQKID;
994 mStack.push (currentNode);
995 currentNode = new TSTItStackNode (currentNode.mNode.mEqkid);
996 } else if ((currentNode.mNode.mEqkid == null)
997 && (currentNode.mVisited < TSTItStackNode.LOEQKID))
998 currentNode.mVisited = TSTItStackNode.LOEQKID;
999 else if ((currentNode.mNode.mHikid != null) && (currentNode.mVisited < TSTItStackNode.ALL))
1000 {
1001 currentNode.mVisited = TSTItStackNode.ALL;
1002 mStack.push (currentNode);
1003 currentNode = new TSTItStackNode (currentNode.mNode.mHikid);
1004 } else if ((currentNode.mNode.mHikid == null)
1005 && (currentNode.mVisited < TSTItStackNode.ALL))
1006 currentNode.mVisited = TSTItStackNode.ALL;
1007 else if (currentNode.mVisited == TSTItStackNode.ALL)
1008 {
1009 if (mStack.empty ()) return;
1010 currentNode = mStack.pop ();
1011 if (currentNode.mVisited == TSTItStackNode.LOEQKID)
1012 {
1013 mBuffer.setLength (mBuffer.length () - 1);
1014 }
1015 }
1016 }
1017 }
1018
1019 public TSTEntry<CharSequence, V> next ()
1020 {
1021 if (! hasNext ()) throw new NoSuchElementException ();
1022 mPrevKeyRemoved = false;
1023
1024 if (mProvideEmptyKeyValue)
1025 {
1026 mProvideEmptyKeyValue = false;
1027 mPreviouslyReturnedKey = "";
1028 return new TSTEntry<CharSequence, V> ("", mEmptyStringKeyValue);
1029 }
1030
1031 if (mFirstElement != null)
1032 {
1033 V dummy = mFirstElement.mData;
1034 mFirstElement = null;
1035 mPreviouslyReturnedKey = mPrefix;
1036 return new TSTEntry<CharSequence, V> (mPrefix, dummy);
1037 }
1038 if (! mWentToNextItem)
1039 {
1040 goToNextElement ();
1041 } else
1042 {
1043 mWentToNextItem = false;
1044 }
1045 TSTItStackNode stNode = mStack.peek ();
1046 String key = new StringBuilder ().append (mPrefix).append (mBuffer)
1047 .append (stNode.mNode.mSplitChar).toString ();
1048 stNode.mReturned = true;
1049 mPreviouslyReturnedKey = key;
1050 return new TSTEntry<CharSequence, V> (key, stNode.mNode.mData);
1051 }
1052
1053 public boolean hasNext ()
1054 {
1055 if (mIteratorEmpty) return false;
1056 if (mFirstElement != null || mProvideEmptyKeyValue) return true;
1057 if ((! mWentToNextItem) && (mStack.size () > 0))
1058 {
1059 goToNextElement ();
1060 mWentToNextItem = true;
1061 }
1062 mIteratorEmpty = mStack.isEmpty ();
1063 String currentKey = null;
1064 if (! mIteratorEmpty)
1065 {
1066 currentKey = new StringBuilder ().append (mPrefix).append (mBuffer)
1067 .append (mStack.peek ().mNode.mSplitChar).toString ();
1068 }
1069
1070 if (! mIteratorEmpty && mFromKey != null)
1071 {
1072 while (compare (mFromKey, currentKey) > 0)
1073 {
1074 goToNextElement ();
1075 mIteratorEmpty = mStack.isEmpty ();
1076 if (mIteratorEmpty) return false;
1077 mStack.peek ().mReturned = true;
1078 currentKey = new StringBuilder ().append (mPrefix).append (mBuffer)
1079 .append (mStack.peek ().mNode.mSplitChar).toString ();
1080 }
1081 }
1082
1083 if (! mIteratorEmpty && mExclusiveToKey != null)
1084 {
1085 if (compare (currentKey, mExclusiveToKey) >= 0)
1086 return false;
1087 }
1088 return ! mIteratorEmpty;
1089 }
1090
1091 public void remove () throws IllegalStateException
1092 {
1093 if (mIteratorEmpty) throw new NoSuchElementException ();
1094 if (! mPrevKeyRemoved)
1095 {
1096 if (mPreviouslyReturnedKey != null)
1097 {
1098 TernarySearchTreeMap.this.remove (mPreviouslyReturnedKey);
1099 } else
1100 throw new IllegalStateException (
1101 "Iterator.next() must be called prior to Iterator.remove().");
1102 } else
1103 throw new IllegalStateException (
1104 "Iterator's previously returned key has already been removed.");
1105 mPrevKeyRemoved = true;
1106 }
1107
1108 private class TSTItStackNode implements Serializable
1109 {
1110 private static final long serialVersionUID = - 5471137639654374101L;
1111
1112 public final static int NONE = 0;
1113 public final static int LOKID = 1;
1114 public final static int LOEQKID = 2;
1115 public final static int ALL = 3;
1116 public TSTNode<V> mNode;
1117 public int mVisited;
1118 public boolean mReturned;
1119
1120
1121 public TSTItStackNode (TSTNode<V> node)
1122 {
1123 this (node, NONE);
1124 }
1125
1126 public TSTItStackNode (TSTNode<V> node, int visited)
1127 {
1128 mReturned = false;
1129 mNode = node;
1130 mVisited = visited;
1131 }
1132 }
1133 }
1134
1135 private class TSTValuesCollection extends AbstractCollection<V> implements Serializable
1136 {
1137 private static final long serialVersionUID = 8889125197129391125L;
1138
1139 private CharSequence mFromKey;
1140 private CharSequence mExclusiveToKey;
1141
1142 public TSTValuesCollection ()
1143 {
1144 this (null, null);
1145 }
1146
1147 public TSTValuesCollection (CharSequence fromKey, CharSequence toKey)
1148 {
1149 if (fromKey != null && toKey != null && compare (fromKey, toKey) > 0)
1150 throw new IllegalArgumentException ("Invalid parameters: fromKey > toKey");
1151 mFromKey = fromKey;
1152 mExclusiveToKey = toKey;
1153 }
1154
1155 @Override
1156 public boolean add (V o)
1157 {
1158 throw new UnsupportedOperationException (
1159 "TernarySearchTree's value collection: add() not allowed!");
1160 }
1161
1162 @Override
1163 public boolean addAll (Collection<? extends V> c)
1164 {
1165 throw new UnsupportedOperationException (
1166 "TernarySearchTree's value collection: addAll() not allowed!");
1167 }
1168
1169 @Override
1170 public void clear ()
1171 {
1172 if (mFromKey == null && mExclusiveToKey == null)
1173 {
1174 TernarySearchTreeMap.this.clear ();
1175 } else
1176 {
1177 for (Iterator<Entry<CharSequence, V>> it = new TSTIterator (mFromKey, mExclusiveToKey); it.hasNext ();)
1178 {
1179 it.next ();
1180 it.remove ();
1181 }
1182 }
1183 }
1184
1185 @Override
1186 public boolean contains (Object o)
1187 {
1188 for (Map.Entry<CharSequence, V> entry : new TSTSubMap (mFromKey, mExclusiveToKey).entrySet ())
1189 {
1190 if (entry.getValue () == null && o == null) return true;
1191 if (entry.getValue ().equals (o)) return true;
1192 }
1193 return false;
1194 }
1195
1196 @Override
1197 public boolean containsAll (Collection<?> c)
1198 {
1199 for (Object o : c)
1200 {
1201 if (! contains (o)) return false;
1202 }
1203 return true;
1204 }
1205
1206 @SuppressWarnings ("rawtypes")
1207 @Override
1208 public boolean equals (Object obj)
1209 {
1210 if (this == obj) return true;
1211 if (! (obj instanceof Collection<?>)) return false;
1212 Collection other = (Collection) obj;
1213 if (other.size () != size ()) return false;
1214 for (Object o : other)
1215 {
1216 if (! contains (o)) return false;
1217 }
1218 return true;
1219 }
1220
1221 @Override
1222 public boolean isEmpty ()
1223 {
1224 return size () == 0;
1225 }
1226
1227 public Iterator<V> iterator ()
1228 {
1229 final Iterator<Entry<CharSequence, V>> entryIterator = new TSTIterator (mFromKey, mExclusiveToKey);
1230 return new Iterator<V> ()
1231 {
1232 public boolean hasNext ()
1233 {
1234 return entryIterator.hasNext ();
1235 }
1236
1237 public V next ()
1238 {
1239 return entryIterator.next ().getValue ();
1240 }
1241
1242 public void remove ()
1243 {
1244 entryIterator.remove ();
1245 }
1246 };
1247 }
1248
1249 @Override
1250 public boolean remove (Object o)
1251 {
1252 for (Iterator<V> it = iterator (); it.hasNext ();)
1253 {
1254 V value = it.next ();
1255 if (value.equals (o))
1256 {
1257 it.remove ();
1258 return true;
1259 }
1260 }
1261 return false;
1262 }
1263
1264 @Override
1265 public boolean removeAll (Collection<?> c)
1266 {
1267 boolean changed = false;
1268 for (Iterator<V> it = iterator (); it.hasNext ();)
1269 {
1270 V value = it.next ();
1271 if (c.contains (value))
1272 {
1273 it.remove ();
1274 changed = true;
1275 }
1276 }
1277 return changed;
1278 }
1279
1280 @Override
1281 public boolean retainAll (Collection<?> c)
1282 {
1283 boolean changed = false;
1284 for (Iterator<V> it = iterator (); it.hasNext ();)
1285 {
1286 V value = it.next ();
1287 if (! c.contains (value))
1288 {
1289 it.remove ();
1290 changed = true;
1291 }
1292 }
1293 return changed;
1294 }
1295
1296 public int size ()
1297 {
1298 if (mFromKey == null && mExclusiveToKey == null)
1299 {
1300 return TernarySearchTreeMap.this.size ();
1301 }
1302 else
1303 {
1304 int count = 0;
1305 for (Iterator<Entry<CharSequence, V>> it = new TSTIterator (mFromKey, mExclusiveToKey); it.hasNext ();)
1306 {
1307 it.next ();
1308 ++count;
1309 }
1310 return count;
1311 }
1312 }
1313 }
1314
1315 class TSTKeySet extends AbstractSet<CharSequence> implements Set<CharSequence>, Serializable
1316 {
1317 private static final long serialVersionUID = - 2892939426138635211L;
1318
1319 private CharSequence mFromKey;
1320 private CharSequence mExclusiveToKey;
1321
1322 public TSTKeySet ()
1323 {
1324 this (null, null);
1325 }
1326
1327 public TSTKeySet (CharSequence fromKey, CharSequence toKey)
1328 {
1329 assert (!(fromKey != null && toKey != null && compare (fromKey, toKey) > 0));
1330
1331 mFromKey = fromKey;
1332 mExclusiveToKey = toKey;
1333 }
1334
1335 public boolean add (CharSequence o)
1336 {
1337 throw new UnsupportedOperationException ("TernarySearchTree's key set: add() not allowed!");
1338 }
1339
1340 public boolean addAll (Collection<? extends CharSequence> c)
1341 {
1342 throw new UnsupportedOperationException ("TernarySearchTree's key set: addAll() not allowed!");
1343 }
1344
1345 public void clear ()
1346 {
1347 if (mFromKey == null && mExclusiveToKey == null)
1348 TernarySearchTreeMap.this.clear ();
1349 for (Iterator<Entry<CharSequence, V>> it = new TSTIterator (mFromKey, mExclusiveToKey); it.hasNext ();)
1350 {
1351 it.next ();
1352 it.remove ();
1353 }
1354 }
1355
1356 public boolean contains (Object o)
1357 {
1358 String key = ((CharSequence) o).toString ();
1359 if (mFromKey != null && compare (mFromKey, key) > 0) return false;
1360 if (mExclusiveToKey != null &&
1361 (compare (key, mExclusiveToKey) > 0 || compare (key, mExclusiveToKey) == 0)) return false;
1362
1363 return TernarySearchTreeMap.this.containsKey (o);
1364 }
1365
1366 public boolean containsAll (Collection<?> c)
1367 {
1368 for (Object o : c)
1369 {
1370 if (! contains (o)) return false;
1371 }
1372 return true;
1373 }
1374
1375 public boolean isEmpty ()
1376 {
1377 return size () == 0;
1378 }
1379
1380 public Iterator<CharSequence> iterator ()
1381 {
1382 final Iterator<Entry<CharSequence, V>> entryIterator = new TSTIterator (mFromKey, mExclusiveToKey);
1383 return new Iterator<CharSequence> ()
1384 {
1385 public boolean hasNext ()
1386 {
1387 return entryIterator.hasNext ();
1388 }
1389
1390 public CharSequence next ()
1391 {
1392 return entryIterator.next ().getKey ();
1393 }
1394
1395 public void remove ()
1396 {
1397 entryIterator.remove ();
1398 }
1399 };
1400 }
1401
1402 public boolean remove (Object o)
1403 {
1404 return contains (o) && TernarySearchTreeMap.this.remove (o) != null;
1405 }
1406
1407 public boolean removeAll (Collection<?> c)
1408 {
1409 boolean changed = false;
1410
1411 for (Object o : c)
1412 {
1413 if (contains (o) && remove (o)) changed = true;
1414 }
1415
1416 return changed;
1417 }
1418
1419 public boolean retainAll (Collection<?> c)
1420 {
1421 boolean changed = false;
1422
1423 for (Iterator<CharSequence> it = iterator (); it.hasNext ();)
1424 {
1425 CharSequence element = it.next ();
1426 if (! c.contains (element))
1427 {
1428 changed = true;
1429 remove (element);
1430 }
1431 }
1432
1433 return changed;
1434 }
1435
1436 public int size ()
1437 {
1438 if ("".equals (mExclusiveToKey)) return 0;
1439 if (mFromKey == null && mExclusiveToKey == null)
1440 {
1441 return TernarySearchTreeMap.this.size ();
1442 } else
1443 {
1444 int count = 0;
1445 for (Iterator<Entry<CharSequence, V>> it = new TSTIterator (mFromKey, mExclusiveToKey); it.hasNext ();)
1446 {
1447 it.next ();
1448 ++count;
1449 }
1450 return count;
1451 }
1452 }
1453 }
1454
1455 private class TSTEntrySet extends AbstractSet<Entry<CharSequence, V>> implements
1456 Set<Entry<CharSequence, V>>, Serializable
1457 {
1458 private static final long serialVersionUID = - 7845332141119069118L;
1459
1460 private CharSequence mFromKey;
1461 private CharSequence mExclusiveToKey;
1462
1463 public TSTEntrySet (CharSequence fromKey, CharSequence toKey)
1464 {
1465 if (fromKey != null && toKey != null && compare (fromKey, toKey) > 0)
1466 throw new IllegalArgumentException ("Invalid parameters: fromKey > toKey");
1467 mFromKey = fromKey;
1468 mExclusiveToKey = toKey;
1469 }
1470
1471 @Override
1472 public boolean addAll (Collection<? extends java.util.Map.Entry<CharSequence, V>> c)
1473 {
1474 throw new UnsupportedOperationException (new String ("TernarySearchTreeMap's entry set: addAll() not allowed!"));
1475 }
1476
1477 public boolean add (Entry<CharSequence, V> o)
1478 {
1479 throw new UnsupportedOperationException (new String (
1480 "TernarySearchTreeMap's entry set: add() not allowed!"));
1481 }
1482
1483 public void clear ()
1484 {
1485 for (Iterator<Entry<CharSequence, V>> it = iterator (); it.hasNext ();)
1486 {
1487 it.next ();
1488 it.remove ();
1489 }
1490 }
1491
1492 @SuppressWarnings ("unchecked")
1493 public boolean contains (Object entry)
1494 {
1495 if (! (entry instanceof Map.Entry<?, ?>))
1496 return false;
1497 else
1498 return containsEntry ((Map.Entry<CharSequence, V>) entry);
1499 }
1500
1501 private boolean containsEntry (Map.Entry<CharSequence, V> entry)
1502 {
1503 if (mFromKey != null && compare (mFromKey, entry.getKey ()) > 0) return false;
1504 if (mExclusiveToKey != null &&
1505 (compare (entry.getKey (), mExclusiveToKey) > 0 || compare (entry.getKey (), mExclusiveToKey) == 0)) return false;
1506 if ( ! containsKey (entry.getKey ())) return false;
1507 V value = TernarySearchTreeMap.this.get (entry.getKey ());
1508 if (value == null || ! value.equals (entry.getValue ())) return false;
1509 return true;
1510 }
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526 public Iterator<Entry<CharSequence, V>> iterator ()
1527 {
1528 return new TSTIterator (mFromKey, mExclusiveToKey);
1529 }
1530
1531 @SuppressWarnings ({ "rawtypes", "unchecked" })
1532 public boolean remove (Object o)
1533 {
1534 if (! (o instanceof Map.Entry)) return false;
1535 Map.Entry<CharSequence, V> entry = (Map.Entry<CharSequence, V>) o;
1536 if (mFromKey != null && compare (mFromKey, entry.getKey ()) > 0) return false;
1537 if (mExclusiveToKey != null &&
1538 (compare (entry.getKey (), mExclusiveToKey) > 0 || compare (entry.getKey (), mExclusiveToKey) == 0)) return false;
1539 Object key = ((Map.Entry) o).getKey ();
1540 Map.Entry mapEntry = getEntry (key);
1541 if (mapEntry == null) return false;
1542 if (! mapEntry.getValue ().equals (entry.getValue ())) return false;
1543 return TernarySearchTreeMap.this.remove (key) != null;
1544 }
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571 public int size ()
1572 {
1573 if (mFromKey == null && mExclusiveToKey == null)
1574 return TernarySearchTreeMap.this.size ();
1575 int count = 0;
1576 for (Iterator<Entry<CharSequence, V>> it = iterator (); it.hasNext ();)
1577 {
1578 it.next ();
1579 ++count;
1580 }
1581 return count;
1582 }
1583 }
1584
1585 private class TSTEntry<EntryK extends CharSequence, EntryV extends V> implements Map.Entry<EntryK, EntryV>, Serializable
1586 {
1587 private static final long serialVersionUID = - 5785604459208599077L;
1588
1589 private EntryK mKey;
1590 private EntryV mValue;
1591
1592 public TSTEntry (EntryK key, EntryV value)
1593 {
1594 mKey = key;
1595 mValue = value;
1596 }
1597
1598 @SuppressWarnings ("rawtypes")
1599 @Override
1600 public boolean equals (Object other)
1601 {
1602 if (! (other instanceof Map.Entry)) return false;
1603 Map.Entry entry = (Map.Entry) other;
1604 return (entry.getKey () == null ? getKey () == null : entry.getKey ().equals (getKey ()))
1605 && (entry.getValue () == null ? getValue () == null : entry.getValue ().equals (
1606 getValue ()));
1607 }
1608
1609 public EntryK getKey ()
1610 {
1611 return mKey;
1612 }
1613
1614 public EntryV getValue ()
1615 {
1616 return mValue;
1617 }
1618
1619 @Override
1620 public int hashCode ()
1621 {
1622 return (getKey () == null ? 0 : getKey ().hashCode ())
1623 ^ (getValue () == null ? 0 : getValue ().hashCode ());
1624 }
1625
1626 public EntryV setValue (EntryV value)
1627 {
1628 CheckForNull.check (value);
1629 EntryV oldValue = mValue;
1630 mValue = value;
1631 TernarySearchTreeMap.this.put (mKey, value);
1632 return oldValue;
1633 }
1634
1635 @Override
1636 public String toString ()
1637 {
1638 return mKey.toString () + "=" + mValue.toString ();
1639 }
1640 }
1641
1642 private class TSTSubMap extends AbstractMap<CharSequence, V> implements SortedMap<CharSequence, V>, Serializable
1643 {
1644 private static final long serialVersionUID = - 6603551293795525865L;
1645
1646 private CharSequence mFromKey;
1647 private CharSequence mExclusiveToKey;
1648
1649 public TSTSubMap (CharSequence fromKey, CharSequence toKey)
1650 {
1651 if (fromKey != null && toKey != null && compare (fromKey, toKey) > 0)
1652 throw new IllegalArgumentException ("Invalid parameters: fromKey > toKey");
1653
1654 mFromKey = fromKey;
1655 mExclusiveToKey = toKey;
1656 }
1657
1658 private boolean isInRange (Object keyObj)
1659 {
1660 CharSequence key = (CharSequence) keyObj;
1661 if (mContainsEmptyStringKey && "".equals (key.toString ()))
1662 {
1663 if ((mFromKey != null && ! "".equals (mFromKey)) ||
1664 (mExclusiveToKey != null && "".equals (mExclusiveToKey)))
1665 {
1666 return false;
1667 }
1668 if (mFromKey != null && "".equals (mFromKey))
1669 {
1670 return true;
1671 }
1672 }
1673 if (mFromKey != null && compare (key, mFromKey) < 0) return false;
1674 if (mExclusiveToKey == null) return true;
1675 if (compare (key, mExclusiveToKey) >= 0) return false;
1676 return true;
1677 }
1678
1679 public Comparator<? super CharSequence> comparator ()
1680 {
1681 return TernarySearchTreeMap.this.comparator ();
1682 }
1683
1684 public CharSequence firstKey ()
1685 {
1686 Iterator<Entry<CharSequence, V>> it = new TSTIterator (mFromKey, mExclusiveToKey);
1687 if (it.hasNext ())
1688 return it.next ().getKey ();
1689 return null;
1690 }
1691
1692 public CharSequence lastKey ()
1693 {
1694 return lastKey (true);
1695 }
1696
1697 private CharSequence lastKey (boolean throwException)
1698 {
1699 Iterator<Entry<CharSequence, V>> it = new TSTIterator (mFromKey, mExclusiveToKey);
1700 Entry<CharSequence, V> entry = null;
1701 while (it.hasNext ())
1702 {
1703 entry = it.next ();
1704 }
1705 return entry == null ? null : entry.getKey ();
1706 }
1707
1708 public SortedMap<CharSequence, V> headMap (CharSequence toKey)
1709 {
1710 if (mExclusiveToKey != null && compare (toKey, mExclusiveToKey) > 0)
1711 throw new IllegalArgumentException ("toKey out of range");
1712
1713 return new TSTSubMap (mFromKey, toKey);
1714 }
1715
1716 public SortedMap<CharSequence, V> subMap (CharSequence fromKey, CharSequence toKey)
1717 {
1718 if (mFromKey != null && compare (mFromKey, fromKey) > 0)
1719 throw new IllegalArgumentException ("fromKey out of range");
1720 if (mExclusiveToKey != null && compare (toKey, mExclusiveToKey) > 0)
1721 throw new IllegalArgumentException ("toKey out of range");
1722
1723 return new TSTSubMap (fromKey, toKey);
1724 }
1725
1726 public SortedMap<CharSequence, V> tailMap (CharSequence fromKey)
1727 {
1728 if (mFromKey != null && compare (mFromKey, fromKey) > 0)
1729 throw new IllegalArgumentException ("fromKey out of range");
1730 return new TSTSubMap (fromKey, mExclusiveToKey);
1731 }
1732
1733 public void clear ()
1734 {
1735 for (CharSequence key : this.keySet ())
1736 {
1737 TernarySearchTreeMap.this.remove (key);
1738 }
1739 }
1740
1741 public boolean containsKey (Object key)
1742 {
1743 if (! isInRange (key)) return false;
1744 return (TernarySearchTreeMap.this.containsKey (key));
1745 }
1746
1747 public boolean containsValue (Object value)
1748 {
1749 for (Map.Entry<CharSequence, V> entry : entrySet ())
1750 {
1751 if (entry.getValue ().equals (value)) return true;
1752 }
1753 return false;
1754 }
1755
1756 public V get (Object key)
1757 {
1758 if (! isInRange (key)) return null;
1759 return TernarySearchTreeMap.this.get (key);
1760 }
1761
1762 public boolean isEmpty ()
1763 {
1764 return size () == 0;
1765 }
1766
1767 public V put (CharSequence key, V value)
1768 {
1769 if (! isInRange (key))
1770 throw new IllegalArgumentException ("The key " + key
1771 + " is not within the bounds of this submap.");
1772 return TernarySearchTreeMap.this.put (key, value);
1773 }
1774
1775 public void putAll (Map<? extends CharSequence, ? extends V> t)
1776 {
1777 for (CharSequence key : t.keySet ())
1778 {
1779 put (key, t.get (key));
1780 }
1781 }
1782
1783 public V remove (Object key)
1784 {
1785 if (key == null) throw new NullPointerException ("key is null");
1786 if (! containsKey (key)) return null;
1787 return TernarySearchTreeMap.this.remove (key);
1788 }
1789
1790 public int size ()
1791 {
1792 if (TernarySearchTreeMap.this.isEmpty () || "".equals (mExclusiveToKey)) return 0;
1793 int count = 0;
1794 for (Iterator<Entry<CharSequence, V>> it = new TSTIterator (mFromKey, mExclusiveToKey); it.hasNext ();)
1795 {
1796 it.next ();
1797 ++count;
1798 }
1799 return count;
1800 }
1801
1802 public Set<Map.Entry<CharSequence, V>> entrySet ()
1803 {
1804 return new TSTEntrySet (mFromKey, mExclusiveToKey);
1805 }
1806
1807 public Set<CharSequence> keySet ()
1808 {
1809 return new TSTKeySet (mFromKey, mExclusiveToKey);
1810 }
1811
1812 public Collection<V> values ()
1813 {
1814 return new TSTValuesCollection (mFromKey, mExclusiveToKey);
1815 }
1816 }
1817 }
1818