1 dojo.provide("calitha.collections.TreeMap");
  2 dojo.require("calitha.collections.INavigableMap");
  3 dojo.require("calitha.collections.AbstractMap");
  4 dojo.require("calitha.collections.util");
  5 dojo.require("calitha.collections.treemap.AscendingSubMap");
  6 dojo.require("calitha.collections.treemap.DescendingSubMap");
  7 dojo.require("calitha.collections.treemap.Entry");
  8 dojo.require("calitha.collections.treemap.KeyIterator");
  9 dojo.require("calitha.collections.treemap.KeySet");
 10 dojo.require("calitha.collections.treemap.Values");
 11 dojo.require("calitha.collections.IComparable");
 12 dojo.require("calitha.collections.treemap.EntrySet");
 13 dojo.require("calitha.collections.imap.ImmutableEntry");
 14 dojo.require("calitha.exception.IllegalStateException");
 15 dojo.require("calitha.exception.NullPointerException");
 16 dojo.require("calitha.exception.IllegalArgumentException");
 17 
 18 dojo.declare("calitha.collections.TreeMap", [calitha.collections.INavigableMap, calitha.collections.AbstractMap],
 19 /** @lends calitha.collections.TreeMap# */
 20 {
 21     /**
 22      * @constructs
 23      * @param comparator optional comparator
 24      * @extends calitha.collections.INavigableMap
 25      * @extends calitha.collections.AbstractMap
 26      * @description A Red-Black tree based NavigableMap implementation.
 27      * <p>This class is similar to the
 28      * <a href="http://java.sun.com/javase/6/docs/api/java/util/TreeMap.html">Java TreeMap class</a>
 29      * <p>This map needs a comparator object or function, or all elements must be IComparable.
 30      * Take a look at the comparator functions in the {@link calitha.collections} namespace.
 31      */
 32     constructor: function(/**(calitha.collections.IComparator|Function)?*/ comparator)
 33     {
 34         if (calitha.collections.util.isObjectInstanceOf(comparator, calitha.collections.IComparator))
 35         {
 36             this._comparator = comparator;
 37         }
 38         else if (calitha.collections.util.isObjectInstanceOf(comparator, Function))
 39         {
 40             this._comparator = new calitha.collections.base.Comparator(comparator);
 41         }
 42         else
 43         {
 44             this._comparator = null;
 45         }
 46         this._root = null;
 47         this._size = 0;
 48         this._modCount = 0;
 49         this._entrySet = null;
 50         this._navigableKeySet = null;
 51         this._descendingMap = null;
 52     }
 53     ,
 54     ceilingEntry: function(/**Object*/ key)
 55     {
 56         return this._exportEntry(this._getCeilingEntry(key));
 57     }
 58     ,
 59     ceilingKey: function(/**Object*/ key)
 60     {
 61         return this._keyOrNull(this._getCeilingEntry(key));
 62     }
 63     ,
 64     clear: function()
 65     {
 66         this._modCount++;
 67         this._size = 0;
 68         this._root = null;
 69     }
 70     ,
 71     comparator: function()
 72     {
 73         return this._comparator;
 74     }
 75     ,
 76     containsKey: function(/**Object*/ key)
 77     {
 78         return this._getEntry(key) != null;
 79     }
 80     ,
 81     containsValue: function(/**Object*/ value)
 82     {
 83         var entry = this._getFirstEntry();
 84         while (entry != null)
 85         {
 86             if (calitha.collections.util.equals(entry.value, value))
 87             {
 88                 return true;
 89             }
 90             entry = this._successor(entry);
 91         }
 92         return false;
 93     }
 94     ,
 95     descendingKeySet: function()
 96     {
 97         return this.descendingMap().navigableKeySet();
 98     }
 99     ,
100     descendingMap: function()
101     {
102         if (this._descendingMap === null)
103         {
104             this._descendingMap = new calitha.collections.treemap.DescendingSubMap(this, true, null, true, true, null, true);
105         }
106         return this._descendingMap;
107     }
108     ,
109     entrySet: function()
110     {
111         if (this._entrySet === null)
112         {
113             this._entrySet = new calitha.collections.treemap.EntrySet(this);
114         }
115         return this._entrySet;
116     }
117     ,
118     firstKey: function()
119     {
120         return this._key(this._getFirstEntry());
121     }
122     ,
123     floorEntry: function(/**Object*/ key)
124     {
125         return this._exportEntry(this._getFloorEntry(key));
126     }
127     ,
128     get: function(key)
129     {
130         var p = this._getEntry(key);
131         return (p === null ? null : p.value);
132     }
133     ,
134     headMap: function(/**Object*/ toKey, /**Boolean*/ inclusive)
135     {
136         return new calitha.collections.treemap.AscendingSubMap(this,
137                                                              true,  null,  true,
138                                                              false, toKey, inclusive);
139     }
140     ,
141     higherEntry: function(/**Object*/ key)
142     {
143         return this._exportEntry(this._getHigherEntry(key));
144     }
145     ,
146     keyIterator: function()
147     {
148         return new calitha.collections.treemap.KeyIterator(this, this._getFirstEntry());
149     }
150     ,
151     keySet: function()
152     {
153         return this.navigableKeySet();
154     }
155     ,
156     lastKey: function()
157     {
158         return this._key(this._getLastEntry());
159     }
160     ,
161     lowerEntry: function(/**Object*/ key)
162     {
163         return this._exportEntry(this._getLowerEntry(key));
164     }
165     ,
166     navigableKeySet: function()
167     {
168         if (this._navigableKeySet === null)
169         {
170             this._navigableKeySet = new calitha.collections.treemap.KeySet(this);
171         }
172         return this._navigableKeySet;
173     }
174     ,
175     put: function(/**Object*/ key, /**Object*/ value)
176     {
177         if (this._root === null)
178         {
179             if (key === null)
180             {
181                 throw new calitha.exception.NullPointerException(Error());
182             }
183             this._root = new calitha.collections.treemap.Entry(key, value, null);
184             this._size = 1;
185             this._modCount++;
186             return null;
187         }
188         var node = this._root;
189         var compare;
190         var parent;
191 
192         // split comparator and comparable paths
193         if (this._comparator != null)
194         {
195             do
196             {
197                 parent = node;
198                 compare = this._comparator.compare(key, node.getKey());
199                 if (compare < 0)
200                 {
201                     node = node.getLeft();
202                 }
203                 else if (compare > 0)
204                 {
205                     node = node.getRight();
206                 }
207                 else
208                 {
209                     return node.setValue(value);
210                 }
211             } while (node != null);
212         }
213         else
214         {
215             if (!calitha.collections.util.isObjectInstanceOf(key, calitha.collections.IComparable))
216             {
217                 throw new calitha.exception.IllegalArgumentException(Error("key must be IComparable"));
218             }
219             do
220             {
221                 parent = node;
222                 compare = key.compareTo(node.getKey());
223                 if (compare < 0)
224                 {
225                     node = node.getLeft();
226                 }
227                 else if (compare > 0)
228                 {
229                     node = node.getRight();
230                 }
231                 else
232                 {
233                     return node.setValue(value);
234                 }
235             } while (node != null);
236         }
237         var entry = new calitha.collections.treemap.Entry(key, value, parent);
238         if (compare < 0)
239         {
240             parent.setLeft(entry);
241         }
242         else
243         {
244             parent.setRight(entry);
245         }
246         this._fixAfterInsertion(entry);
247         this._size++;
248         this._modCount++;
249         return null;
250     }
251     ,
252     remove: function(/**Object*/ key)
253     {
254         var node = this._getEntry(key);
255         if (node === null)
256         {
257             return null;
258         }
259 
260         var oldValue = node.getValue();
261         this._deleteEntry(node);
262         return oldValue;
263     },
264     size: function()
265     {
266         return this._size;
267     }
268     ,
269     subMap: function(/**Object*/ fromKey, /**Boolean*/ fromInclusive, /**Object*/ toKey, /**Boolean*/ toInclusive)
270     {
271         return new calitha.collections.treemap.AscendingSubMap(this,
272                                                              false, fromKey, fromInclusive,
273                                                              false, toKey, toInclusive);
274     }
275     ,
276     tailMap: function(/**Object*/ fromKey, /**Boolean*/ inclusive)
277     {
278         return new calitha.collections.treemap.AscendingSubMap(this,
279                                                              false, fromKey, inclusive,
280                                                              true, null, true);
281     }
282     ,
283     values: function() 
284     {
285         if (this._values === null)
286         {
287             this._values = new calitha.collections.treemap.Values(this);
288         }
289         return this._values;
290     }
291     ,
292     _colorOf: function(/**calitha.collections.treemap.Entry*/ node)
293     {
294         return (node === null ? calitha.collections.TreeMap._BLACK : node.getColor());
295     }
296     ,
297     _compare: function(/**Object*/ k1, /**Object*/ k2)
298     {
299         if (this._comparator === null)
300         {
301             if ((!calitha.collections.util.isObjectInstanceOf(k1, calitha.collections.IComparable)) || (!calitha.collections.util.isObjectInstanceOf(k2, calitha.collections.IComparable)))
302             {
303                 throw new calitha.exception.IllegalStateException(Error("No comparator available. Therefore key must be an IComparable instance."));
304             }
305             return k1.compareTo(k2);
306         }
307         else
308         {
309             return this._comparator.compare(k1, k2);
310         }
311     }
312     ,
313     _deleteEntry:function(/**calitha.collections.treemap.Entry*/ node)
314     {
315         var BLACK = calitha.collections.TreeMap._BLACK;
316 
317         this._modCount++;
318         this._size--;
319 
320         // If strictly internal, copy successor's element to node and then make node
321         // point to successor.
322         if (node.getLeft() != null && node.getRight() != null)
323         {
324             var s = this._successor(node);
325             node.setKey(s);
326             node.setValue(s.getValue());
327             node = s;
328         } // node has 2 children
329 
330         // Start fixup at replacement node, if it exists.
331         var replacement = (node.getLeft() != null ? node.getLeft() : node.getRight());
332 
333         if (replacement != null)
334         {
335             // Link replacement to parent
336             replacement.setParent(node.getParent());
337             if (node.getParent() === null)
338             {
339                 this._root = replacement;
340             }
341             else if (node === node.getParent().getLeft())
342             {
343                 node.getParent().getLeft()  = replacement;
344             }
345             else
346             {
347                 node.getParent().getRight() = replacement;
348             }
349 
350             // Null out links so they are OK to use by fixAfterDeletion.
351             node.setLeft(null);
352             node.setRight(null);
353             node.setParent(null);
354 
355             // Fix replacement
356             if (node.getColor() === BLACK)
357             {
358                 this._fixAfterDeletion(replacement);
359             }
360         }
361         else if (node.getParent() === null)
362         { // return if we are the only node.
363             this._root = null;
364         }
365         else
366         { //  No children. Use self as phantom replacement and unlink.
367             if (node.getColor() === BLACK)
368             {
369                 this._fixAfterDeletion(node);
370             }
371 
372             if (node.getParent() != null)
373             {
374                 if (node === node.getParent().getLeft())
375                 {
376                     node.getParent().setLeft(null);
377                 }
378                 else if (node === node.getParent().getRight())
379                 {
380                     node.getParent().setRight(null);
381                 }
382                 node.setParent(null);
383             }
384         }
385     }
386     ,
387     _exportEntry: function(/**calitha.collections.treemap.Entry*/ entry)
388     {
389         return entry === null ? null : calitha.collections.imap.ImmutableEntry.newInstance(entry);
390     }
391     ,
392     _fixAfterDeletion: function(/**calitha.collections.treemap.Entry*/ x)
393     {
394         var BLACK = calitha.collections.TreeMap._BLACK;
395         var RED = calitha.collections.TreeMap._RED;
396 
397         var sib;
398         while (x != this._root && this._colorOf(x) === BLACK)
399         {
400             if (x === this._leftOf(this._parentOf(x)))
401             {
402                 sib = this._rightOf(this._parentOf(x));
403 
404                 if (this._colorOf(sib) === RED)
405                 {
406                     this._setColor(sib, BLACK);
407                     this._setColor(this._parentOf(x), RED);
408                     this._rotateLeft(this._parentOf(x));
409                     sib = this._rightOf(this._parentOf(x));
410                 }
411 
412                 if (this._colorOf(this._leftOf(sib))  === BLACK &&
413                     this._colorOf(this._rightOf(sib)) === BLACK)
414                 {
415                     this._setColor(sib, RED);
416                     x = this._parentOf(x);
417                 }
418                 else
419                 {
420                     if (this._colorOf(this._rightOf(sib)) === BLACK)
421                     {
422                         this._setColor(this._leftOf(sib), BLACK);
423                         this._setColor(sib, RED);
424                         this._rotateRight(sib);
425                         sib = this._rightOf(this._parentOf(x));
426                     }
427                     this._setColor(sib, this._colorOf(this._parentOf(x)));
428                     this._setColor(this._parentOf(x), BLACK);
429                     this._setColor(this._rightOf(sib), BLACK);
430                     this._rotateLeft(this._parentOf(x));
431                     x = this._root;
432                 }
433             }
434             else
435             { // symmetric
436                 sib = this._leftOf(this._parentOf(x));
437 
438                 if (this._colorOf(sib) === RED)
439                 {
440                     this._setColor(sib, BLACK);
441                     this._setColor(this._parentOf(x), RED);
442                     this._rotateRight(this._parentOf(x));
443                     sib = this._leftOf(this._parentOf(x));
444                 }
445 
446                 if (this._colorOf(this._rightOf(sib)) === BLACK &&
447                     this._colorOf(this._leftOf(sib)) === BLACK)
448                 {
449                     this._setColor(sib, RED);
450                     x = this._parentOf(x);
451                 }
452                 else
453                 {
454                     if (this._colorOf(this._leftOf(sib)) === BLACK)
455                     {
456                         this._setColor(this._rightOf(sib), BLACK);
457                         this._setColor(sib, RED);
458                         this._rotateLeft(sib);
459                         sib = this._leftOf(this._parentOf(x));
460                     }
461                     this._setColor(sib, this._colorOf(this._parentOf(x)));
462                     this._setColor(this._parentOf(x), BLACK);
463                     this._setColor(this._leftOf(sib), BLACK);
464                     this._rotateRight(this._parentOf(x));
465                     x = this._root;
466                 }
467             }
468         }
469 
470         this._setColor(x, BLACK);
471     }
472     ,
473     _fixAfterInsertion: function(/**calitha.collections.treemap.Entry*/ x)
474     {
475         var BLACK = calitha.collections.TreeMap._BLACK;
476         var RED = calitha.collections.TreeMap._RED;
477         x.setColor(RED);
478         var y;
479         while (x != null && x != this._root && x.getParent().getColor() === RED)
480         {
481             if (this._parentOf(x) === this._leftOf(this._parentOf(this._parentOf(x))))
482             {
483                 y = this._rightOf(this._parentOf(this._parentOf(x)));
484                 if (this._colorOf(y) === RED)
485                 {
486                     this._setColor(this._parentOf(x), BLACK);
487                     this._setColor(y, BLACK);
488                     this._setColor(this._parentOf(this._parentOf(x)), RED);
489                     x = this._parentOf(this._parentOf(x));
490                 }
491                 else
492                 {
493                     if (x === this._rightOf(this._parentOf(x)))
494                     {
495                         x = this._parentOf(x);
496                         this._rotateLeft(x);
497                     }
498                     this._setColor(this._parentOf(x), BLACK);
499                     this._setColor(this._parentOf(this._parentOf(x)), RED);
500                     this._rotateRight(this._parentOf(this._parentOf(x)));
501                 }
502             }
503             else
504             {
505                 y = this._leftOf(this._parentOf(this._parentOf(x)));
506                 if (this._colorOf(y) === RED)
507                 {
508                     this._setColor(this._parentOf(x), BLACK);
509                     this._setColor(y, BLACK);
510                     this._setColor(this._parentOf(this._parentOf(x)), RED);
511                     x = this._parentOf(this._parentOf(x));
512                 }
513                 else
514                 {
515                     if (x === this._leftOf(this._parentOf(x)))
516                     {
517                         x = this._parentOf(x);
518                         this._rotateRight(x);
519                     }
520                     this._setColor(this._parentOf(x), BLACK);
521                     this._setColor(this._parentOf(this._parentOf(x)), RED);
522                     this._rotateLeft(this._parentOf(this._parentOf(x)));
523                 }
524             }
525         }
526         this._root.color = BLACK;
527     }
528     ,
529     _getCeilingEntry: function(/**Object*/ key)
530     {
531         var p = this._root;
532         while (p != null)
533         {
534             var cmp = this._compare(key, p.key);
535             if (cmp < 0)
536             {
537                 if (p.left != null)
538                 {
539                     p = p.left;
540                 }
541                 else
542                 {
543                     return p;
544                 }
545             }
546             else if (cmp > 0)
547             {
548                 if (p.right != null)
549                 {
550                     p = p.right;
551                 }
552                 else
553                 {
554                     var parent = p.parent;
555                     var ch = p;
556                     while (parent != null && ch === parent.right)
557                     {
558                         ch = parent;
559                         parent = parent.parent;
560                     }
561                     return parent;
562                 }
563             }
564             else
565             {
566                 return p;
567             }
568         }
569         return null;
570     }
571     ,
572     _getEntry: function(/**Object*/ key)
573     {
574         // Offload comparator-based version for sake of performance
575         if (this._comparator != null)
576         {
577             return this._getEntryUsingComparator(key);
578         }
579         if (key === null)
580         {
581             throw new calitha.exception.NullPointerException(Error());
582         }
583         var p = this._root;
584         while (p != null)
585         {
586             var cmp = key.compareTo(p.key);
587             if (cmp < 0)
588             {
589                 p = p.left;
590             }
591             else if (cmp > 0)
592             {
593                 p = p.right;
594             }
595             else
596             {
597                 return p;
598             }
599         }
600         return null;
601     }
602     ,
603     _getEntryUsingComparator: function(/**Object*/ key)
604     {
605         if (this._comparator != null)
606         {
607             var p = this._root;
608             while (p != null)
609             {
610                 var cmp = this._comparator.compare(key, p.key);
611                 if (cmp < 0)
612                 {
613                     p = p.left;
614                 }
615                 else if (cmp > 0)
616                 {
617                     p = p.right;
618                 }
619                 else
620                 {
621                     return p;
622                 }
623             }
624         }
625         return null;
626     }
627     ,
628     _getFirstEntry: function()
629     {
630         var p = this._root;
631         if (p != null)
632         {
633             while (p.left != null)
634             {
635                 p = p.left;
636             }
637         }
638         return p;
639     }
640     ,
641     _getFloorEntry: function(/**Object*/ key)
642     {
643         var p = this._root;
644         while (p != null)
645         {
646             var cmp = this._compare(key, p.key);
647             if (cmp > 0)
648             {
649                 if (p.right != null)
650                 {
651                     p = p.right;
652                 }
653                 else
654                 {
655                     return p;
656                 }
657             }
658             else if (cmp < 0)
659             {
660                 if (p.left != null)
661                 {
662                     p = p.left;
663                 }
664                 else
665                 {
666                     var parent = p.parent;
667                     var ch = p;
668                     while (parent != null && ch === parent.left)
669                     {
670                         ch = parent;
671                         parent = parent.parent;
672                     }
673                     return parent;
674                 }
675             }
676             else
677             {
678                 return p;
679             }
680         }
681         return null;
682     }
683     ,
684     _getHigherEntry: function(/**Object*/ key)
685     {
686         var p = this._root;
687         while (p != null)
688         {
689             var cmp = this._compare(key, p.key);
690             if (cmp < 0)
691             {
692                 if (p.left != null)
693                 {
694                     p = p.left;
695                 }
696                 else
697                 {
698                     return p;
699                 }
700             }
701             else
702             {
703                 if (p.right != null)
704                 {
705                     p = p.right;
706                 }
707                 else
708                 {
709                     var parent = p.parent;
710                     var ch = p;
711                     while (parent != null && ch === parent.right)
712                     {
713                         ch = parent;
714                         parent = parent.parent;
715                     }
716                     return parent;
717                 }
718             }
719         }
720         return null;
721     }
722     ,
723     _getLastEntry: function()
724     {
725         var p = this._root;
726         if (p != null)
727         {
728             while (p.right != null)
729             {
730                 p = p.right;
731             }
732         }
733         return p;
734     }
735     ,
736     _getLowerEntry: function(/**Object*/ key)
737     {
738         var p = this._root;
739         while (p != null)
740         {
741             var cmp = this._compare(key, p.key);
742             if (cmp > 0)
743             {
744                 if (p.right != null)
745                 {
746                     p = p.right;
747                 }
748                 else
749                 {
750                     return p;
751                 }
752             }
753             else
754             {
755                 if (p.left != null)
756                 {
757                     p = p.left;
758                 }
759                 else
760                 {
761                     var parent = p.parent;
762                     var ch = p;
763                     while (parent != null && ch === parent.left)
764                     {
765                         ch = parent;
766                         parent = parent.parent;
767                     }
768                     return parent;
769                 }
770             }
771         }
772         return null;
773     }
774     ,
775     _key: function(/**calitha.collections.treemap.Entry*/ entry)
776     {
777         if (entry === null)
778         {
779             throw new calitha.exception.NoSuchElementException(Error());
780         }
781         return entry.getKey();
782     }
783     ,
784     _keyOrNull: function(/**calitha.collections.treemap.Entry*/ entry)
785     {
786         return entry === null? null : entry.getKey();
787     }
788     ,
789     _leftOf: function(/**calitha.collections.treemap.Entry*/ node)
790     {
791         return (node === null) ? null: node.getLeft();
792     }
793     ,
794     _parentOf: function(/**calitha.collections.treemap.Entry*/ node)
795     {
796         return (node === null ? null: node.getParent());
797     }
798     ,
799     _predecessor: function(/**calitha.collections.treemap.Entry*/ t)
800     {
801         var p;
802         if (t === null)
803         {
804             return null;
805         }
806         else if (t.getLeft() != null)
807         {
808             p = t.getLeft();
809             while (p.getRight() != null)
810             {
811                 p = p.getRight();
812             }
813             return p;
814         }
815         else
816         {
817             p = t.getParent();
818             var ch = t;
819             while (p != null && ch === p.getLeft())
820             {
821                 ch = p;
822                 p = p.getParent();
823             }
824             return p;
825         }
826     }
827     ,
828     _rightOf: function(/**calitha.collections.treemap.Entry*/ node)
829     {
830         return (node === null) ? null: node.getRight();
831     }
832     ,
833     _rotateLeft: function(/**calitha.collections.treemap.Entry*/ node)
834     {
835         if (node != null)
836         {
837             var rightNode = node.getRight();
838             node.setRight(rightNode.getLeft());
839             if (rightNode.getLeft() != null)
840             {
841                 rightNode.getLeft().setParent(node);
842             }
843             rightNode.setParent(node.getParent());
844             if (node.getParent() === null)
845             {
846                 this._root = rightNode;
847             }
848             else if (node.getParent().getLeft() === node)
849             {
850                 node.getParent().setLeft(rightNode);
851             }
852             else
853             {
854                 node.getParent().setRight(rightNode);
855             }
856             rightNode.setLeft(node);
857             node.setParent(rightNode);
858         }
859     }
860     ,
861     _rotateRight: function(/**calitha.collections.treemap.Entry*/ node)
862     {
863         if (node != null)
864         {
865             var leftNode = node.getLeft();
866             node.setLeft(leftNode.getRight());
867             if (leftNode.getRight() != null)
868             {
869                 leftNode.getRight().setParent(node);
870             }
871             leftNode.setParent(node.getParent());
872             if (node.getParent() === null)
873             {
874                 this._root = leftNode;
875             }
876             else if (node.getParent().getRight() === node)
877             {
878                 node.getParent().setRight(leftNode);
879             }
880             else
881             {
882                 node.getParent().setLeft(leftNode);
883             }
884             leftNode.setRight(node);
885             node.setParent(leftNode);
886         }
887     }
888     ,
889     _setColor: function(/**calitha.collections.treemap.Entry*/ node, /**Number*/ color)
890     {
891         if (node != null)
892         {
893 	        node.setColor(color);
894         }
895     }
896     ,
897     _successor: function(/**calitha.collections.treemap.Entry*/ node)
898     {
899         if (node === null)
900         {
901             return null;
902         }
903         else if (node.getRight() != null)
904         {
905             node = node.getRight();
906             while (node.getLeft() != null)
907             {
908                 node = node.getLeft();
909             }
910             return node;
911         }
912         else
913         {
914             var parent = node.getParent();
915             while (parent != null && node === parent.getRight())
916             {
917                 node = parent;
918                 parent = parent.getParent();
919             }
920             return parent;
921         }
922     }
923     
924 });
925 
926 calitha.collections.TreeMap._RED = false;
927 calitha.collections.TreeMap._BLACK = true;
928