1 /**
  2  * @fileOverview Tree Map implementation
  3  */
  4 var sys = require ('sys'),
  5     Map = require ('./map').Map;
  6 
  7 ///
  8 /// Tree Map implementation
  9 ///
 10 
 11 /**
 12  * Tree Map
 13  * 
 14  * @class
 15  * @author Sijie Guo <sijie0413@gmail.com>
 16  * @constructor
 17  *
 18  * @param {Function} comparator comparasion function
 19  */
 20 var TreeMap = function(comparator) {
 21   
 22   var that = this;
 23 
 24   /**@field comparator used to maintain order in tree map*/
 25   var _compareFunc = comparator;
 26   /**@field root entry*/
 27   var _root = null;
 28   /**@filed number of entries in the tree*/
 29   var _size = 0;
 30   var _modCnt = 0;
 31 
 32   /**@constant COLOR*/
 33   var COLOR = {};
 34   /**@constant RED COLOR*/
 35   COLOR.RED = 0;
 36   /**@constant BLACK COLOR*/
 37   COLOR.BLACK = 1;
 38   ///
 39   /// Private Class
 40   ///
 41   var Entry = function(key, value, parent) {
 42     this.key = key;
 43     this.value = value;
 44     this.left = null;
 45     this.right = null;
 46     this.parent = parent;
 47     this.color = COLOR.BLACK;
 48   };
 49 
 50   function keyOrNull(e) {
 51     return null === e ? null : e.key;
 52   }
 53 
 54   function key(e) {
 55     return e.key;
 56   }
 57 
 58   ///
 59   /// Private methods
 60   ///
 61 
 62   function getComparator() {
 63     return _compareFunc;
 64   }
 65 
 66   function size() {
 67     return _size;
 68   }
 69 
 70   /**
 71    * Return the map entry of the given key, or null if the map does not contain an entry for the key.
 72    * 
 73    * @param {Object} key given query key
 74    *
 75    * @return the map entry of the given key, or null if the map does not contain an entry for the key
 76    *
 77    * @public
 78    */
 79   function getEntry(key) {
 80     var p = _root;
 81     while (null !== p) {
 82       var cmp = _compareFunc(key, p.key);
 83       if (cmp < 0) {
 84         p = p.left;
 85       } else if (cmp > 0) {
 86         p = p.right;
 87       } else {
 88         return p;
 89       }
 90     }
 91     return null;
 92   }
 93 
 94   function getCeilingEntry(key) {
 95     var p = _root;
 96     while (null !== p) {
 97       var cmp = _compareFunc(key, p.key);
 98       if (cmp < 0) {
 99         if (null !== p.left) {
100           p = p.left;
101         } else {
102           return p;
103         }
104       } else if (cmp > 0) {
105         if (null !== p.right) {
106           p = p.right;
107         } else {
108           var parent = p.parent;
109           var ch = p;
110           while (null !== parent && ch === parent.right) {
111             ch = parent;
112             parent = parent.parent;
113           }
114           return parent;
115         }
116       } else {
117         return p;
118       }
119     }
120     return null;
121   }
122   this.getCeilingEntry = getCeilingEntry;
123 
124   function getFloorEntry(key) {
125     var p = _root;
126     while (null !== p) {
127       var cmp = _compareFunc(key, p.key);
128       if (cmp > 0) {
129         if (null !== p.right) {
130           p = p.right;
131         } else {
132           return p;
133         }
134       } else if (cmp < 0) {
135         if (null !== p.left) {
136           p = p.left;
137         } else {
138           var parent = p.parent;
139           var ch = p;
140           while (null !== parent && ch === parent.left) {
141             ch = parent;
142             parent = parent.parent;
143           }
144           return parent;
145         }
146       } else {
147         return p;
148       }
149     }
150     return null;
151   }
152   this.getFloorEntry = getFloorEntry;
153 
154   function getHigherEntry(key) {
155     var p = _root;
156     while (null !== p) {
157       var cmp = _compareFunc(key, p.key);
158       if (cmp < 0) {
159         if (null !== p.left) {
160           p = p.left;
161         } else {
162           return p;
163         }
164       } else {
165         if (null !== p.right) {
166           p = p.right;
167         } else {
168           var parent = p.parent;
169           var ch = p;
170           while (null !== parent && ch === parent.right) {
171             ch = parent;
172             parent = parent.parent;
173           }
174           return parent;
175         }
176       }
177     }
178     return null;
179   }
180   this.getHigherEntry = getHigherEntry;
181 
182   function getLowerEntry(key) {
183     var p = _root;
184     while (null !== p) {
185       var cmp = _compareFunc(key, p.key);
186       if (cmp > 0) {
187         if (null !== p.right) {
188           p = p.right;
189         } else {
190           return p;
191         }
192       } else {
193         if (null !== p.left) {
194           p = p.left;
195         } else {
196           var parent = p.parent;
197           var ch = p;
198           while (null !== parent && ch === parent.left) {
199             ch = parent;
200             parent = parent.parent;
201           }
202           return parent;
203         }
204       }
205     }
206     return null;
207   }
208   this.getLowerEntry = getLowerEntry;
209 
210   function put(key, value) {
211     if (!key) {
212       console.log("TreeMap doesn't support null key now.");
213       return;
214     }
215 
216     var t = _root;
217     if (null === t) {
218       _root = new Entry(key, value, null);
219       _size = 1;
220       ++_modCnt;
221       return null;
222     }
223 
224     var cmp, parent;
225     do {
226       parent = t;
227       cmp = _compareFunc(key, t.key);
228       if (cmp < 0) {
229         t = t.left;
230       } else if (cmp > 0) {
231         t = t.right;
232       } else {
233         var oldValue = t.value;
234         t.value = value;
235         return oldValue;
236       }
237     } while (null !== t);
238 
239     var e = new Entry(key, value, parent);
240     if (cmp < 0) {
241       parent.left = e;
242     } else {
243       parent.right = e;
244     }
245     fixAfterInsertion(e);
246     ++_size;
247     ++_modCnt;
248     return null;
249   }
250 
251 
252   function deleteEntry(p) {
253     ++_modCnt;
254     --_size;
255 
256     // copy successor's element to p and then make p point to successor
257     if (null !== p.left && null !== p.right) {
258       var s = successor(p);
259       p.key = s.key;
260       p.value = s.value;
261       p = s;
262     }
263 
264     var replacement = null !== p.left ? p.left : p.right;
265 
266     if (null !== replacement) {
267       replacement.parent = p.parent;
268       if (null === p.parent) {
269         _root = replacment;
270       } else if (p === p.parent.left) {
271         p.parent.left = replacement;
272       } else {
273         p.parent.right = replacement;
274       }
275 
276       p.left = p.right = p.parent = null;
277 
278       if (COLOR.BLACK === p.color) {
279         fixAfterDeletion(replacement);
280       }
281     } else if (null === p.parent) {
282       _root = null;
283     } else {
284       if (COLOR.BLACK === p.color) {
285         fixAfterDeletion(p);
286       }
287 
288       if (null !== p.parent) {
289         if (p === p.parent.left) {
290           p.parent.left = null;
291         } else if (p === p.parent.right) {
292           p.parent.right = null;
293         }
294         p.parent = null;
295       }
296     }
297   }
298   this.deleteEntry = deleteEntry;
299 
300   function clear() {
301     ++_modCnt;
302     _size = 0;
303     _root = null;
304   }
305 
306   ///
307   /// Red-Black-Tree Blance Operations
308   ///
309   
310   function colorOf(p) {
311     return null === p ? COLOR.BLACK : p.color;
312   }
313 
314   function setColor(p, color) {
315     if (null !== p) {
316       p.color = color;
317     }
318   }
319 
320   function parentOf(p) {
321     return null === p ? null : p.parent;
322   }
323 
324   function leftOf(p) {
325     return null === p ? null : p.left;
326   }
327 
328   function rightOf(p) {
329     return null === p ? null : p.right;
330   }
331 
332   function rotateLeft(p) {
333     if (null === p) {
334       return;
335     }
336     var r = p.right;
337     p.right = r.left;
338     if (null !== r.left) {
339       r.left.parent = p;
340     }
341     r.parent = p.parent;
342     if (null === p.parent) {
343       _root = r;
344     } else if (p.parent.left === p) {
345       p.parent.left = r;
346     } else {
347       p.parent.right = r;
348     }
349     r.left = p;
350     p.parent = r;
351   }
352 
353   function rotateRight(p) {
354     if (null === p) {
355       return;
356     }
357     var l = p.left;
358     p.left = l.right;
359     if (null !== l.right) {
360       l.right.parent = p;
361     }
362     l.parent = p.parent;
363     if (null === p.parent) {
364       _root = l;
365     } else if (p.parent.left === p) {
366       p.parent.left = l;
367     } else {
368       p.parent.right = l;
369     }
370     l.right = p;
371     p.parent = l;
372   }
373 
374   function fixAfterInsertion(x) {
375     x.color = COLOR.RED;
376 
377     var y;
378     while (null !== x && _root !== x && COLOR.RED == x.parent.color) {
379       if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
380         y = rightOf(parentOf(parentOf(x)));
381         if (COLOR.RED === colorOf(y)) {
382           setColor(parentOf(x), COLOR.BLACK);
383           setColor(y, COLOR.BLACK);
384           setColor(parentOf(parentOf(x)), COLOR.RED);
385           x = parentOf(parentOf(x));
386         } else {
387           if (rightOf(parent(x)) === x) {
388             x = parentOf(x);
389             rotateLeft(x);
390           }
391           setColor(parentOf(x), COLOR.BLACK);
392           setColor(parentOf(parentOf(x)), COLOR.RED);
393           rotateRight(parentOf(parentOf(x)));
394         }
395       } else {
396         y = leftOf(parentOf(parentOf(x)));
397         if (COLOR.RED === colorOf(y)) {
398           setColor(parentOf(x), COLOR.BLACK);
399           setColor(y, COLOR.BLACK);
400           setColor(parentOf(parentOf(x)), COLOR.RED);
401           x = parentOf(parentOf(x));
402         } else {
403           if (leftOf(parentOf(x)) === x) {
404             x = parentOf(x);
405             rotateRight(x);
406           }
407           setColor(parentOf(x), COLOR.BLACK);
408           setColor(parentOf(parentOf(x)), COLOR.RED);
409           rotateLeft(parentOf(parentOf(x)));
410         }
411       }
412     }
413     _root.color = COLOR.BLACK;
414   }
415 
416   function fixAfterDeletion(x) {
417     var sib;
418     while (_root !== x && COLOR.BLACK === colorOf(x)) {
419       if (leftOf(parentOf(x)) === x) {
420         sib = rightOf(parentOf(x));
421 
422         if (COLOR.RED === colorOf(sib)) {
423           setColor(sib, COLOR.BLACK);
424           setColor(parentOf(x), COLOR.RED);
425           rotateLeft(parentOf(x));
426           sib = rightOf(parentOf(x));
427         }
428 
429         if (COLOR.BLACK === colorOf(rightOf(sib)) &&
430             COLOR.BLACK === colorOf(leftOf(sib))) {
431           setColor(sib, COLOR.RED);
432           x = parentOf(x);
433         } else {
434           if (COLOR.BLACK === colorOf(rightOf(sib))) {
435             setColor(leftOf(sib), BLACK);
436             setColor(sib, COLOR.RED);
437             rotateRight(sib);
438             sib = rightOf(parentOf(x));
439           }
440 
441           setColor(sib, colorOf(parentOf(x)));
442           setColor(parentOf(x), COLOR.BLACK);
443           setColor(rightOf(sib), COLOR.BLACK);
444           rotateLeft(parentOf(x));
445           x = _root;
446         }
447       } else {
448         sib = leftOf(parentOf(x));
449 
450         if (COLOR.RED === colorOf(sib)) {
451           setColor(sib, COLOR.BLACK);
452           setColor(parentOf(x), COLOR.RED);
453           rotateRight(parentOf(x));
454           sib = leftOf(parentOf(x));
455         }
456 
457         if (COLOR.BLACK === colorOf(rightOf(sib)) &&
458             COLOR.BLACK === colorOf(leftOf(sib))) {
459           setColor(sib, COLOR.RED);
460           x = parentOf(x);
461         } else {
462           if (COLOR.BLACK === colorOf(leftOf(sib))) {
463             setColor(rightOf(sib), BLACK);
464             setColor(sib, COLOR.RED);
465             rotateLeft(sib);
466             sib = leftOf(parentOf(x));
467           }
468 
469           setColor(sib, colorOf(parentOf(x)));
470           setColor(parentOf(x), COLOR.BLACK);
471           setColor(leftOf(sib), COLOR.BLACK);
472           rotateRight(parentOf(x));
473           x = _root;
474         }
475       }
476     }
477 
478     setColor(x, COLOR.BLACK);
479   }
480 
481   ///
482   /// Navigation methods
483   ///
484 
485   function getFirstEntry() {
486     var p = _root;
487     if (null !== p) {
488       while (null !== p.left) {
489         p = p.left;
490       }
491     }
492     return p;
493   }
494   this.getFirstEntry = getFirstEntry;
495 
496   function getLastEntry() {
497     var p = _root;
498     if (null !== p) {
499       while (null !== p.right) {
500         p = p.right;
501       }
502     }
503     return p;
504   }
505   this.getLastEntry = getLastEntry;
506 
507   function successor(p) {
508     var t, ch;
509     if (null === p) {
510       return null;
511     } else if (null !== p.right) {
512       t = p.right;
513       while (null !== t.left) {
514         t = t.left;
515       }
516       return t;
517     } else {
518       t = p.parent;
519       ch = p;
520       while (null !== t && ch === t.right) {
521         ch = t;
522         t = t.parent;
523       }
524       return t;
525     }
526   }
527 
528   function predecessor(p) {
529     var t, ch;
530     if (null === p) {
531       return null;
532     } else if (null !== p.left) {
533       t = p.right;
534       while (null !== t.right) {
535         t = t.right;
536       }
537       return t;
538     } else {
539       t = p.parent;
540       ch = p;
541       while (null !== t && ch === t.left) {
542         ch = t;
543         t = t.parent;
544       }
545       return t;
546     }
547   }
548 
549   function exportEntry(p) {
550     if (null !== p) {
551       return new Map.Entry(p.key, p.value);
552     } else {
553       return null;
554     }
555   }
556 
557   ///
558   /// Privileged methods
559   ///
560 
561   /**
562    * Return the comparasion function used in this map
563    * @return comparasion function
564    */
565   this.comparator = getComparator;
566 
567   /**
568    * Return the number of key-value mapping in this map
569    * 
570    * @return number of key-value mapping
571    */
572   this.size = size;
573 
574   /**
575    * Associate the specified value with the specified key in this map.
576    * If the map previously contained a mapping entry for the key, the old value is replaced.
577    * 
578    * @param {object} key key with which the specified value is to be associated
579    * @param {object} value value to be associated with the specified key
580    *
581    * @return the previous value associated with key
582    */
583   this.put = put;
584 
585   /**
586    * Removes the mapping entry for this key from this map if present.
587    * 
588    * @param {Object} key key for which mapping should be removed
589    *
590    * @return the previous value associated with key, or null if there was no mapping entry for this key.
591    */
592   this.remove = function(key) {
593     var p = getEntry(key);
594     if (null === p) {
595       return p;
596     }
597 
598     var oldValue = p.value;
599     deleteEntry(p);
600     return oldValue;
601   };
602 
603   /**
604    * Remove all the mapping entries from this map.
605    * @return void
606    */
607   this.clear = clear;
608 
609   /**
610    * Returns true if this map contains a mapping entry for the given key
611    * 
612    * @param {Object} key whose presence in this map is to be tested
613    *
614    * @return true if this map contains a mapping entry for the given key
615    */
616   this.containsKey = function(key) {
617     return getEntry(key) !== null;
618   };
619 
620   /**
621    * Get the value to which the specified key is mapped,
622    * or null if this map contains no mapping for the key
623    * 
624    * @param {Object} key the query key
625    *
626    * @return the value or null
627    */
628   this.get = function(key) {
629     var p = getEntry(key);
630     return null === p ? null : p.value;
631   };
632 
633   /**
634    * Get the first key in this map
635    * @return the first key
636    */
637   this.firstKey = function() {
638     var e = getFirstEntry();
639     return null === e ? null : e.key;
640   };
641 
642   /**
643    * Get the last key in this map
644    * @return the last key
645    */
646   this.lastKey = function() {
647     var e = getLastEntry();
648     return null === e ? null : e.key;
649   };
650 
651   /**
652    * Get the first entry in this map
653    * @return the first entry
654    */
655   this.firstEntry = function() {
656     return exportEntry(getFirstEntry());
657   };
658 
659   /**
660    * Get the last entry in this map
661    * @return the last entry
662    */
663   this.lastEntry = function() {
664     return exportEntry(getLastEntry());
665   };
666  
667   /**
668    * Get the first entry and remove it
669    * @return the first entry
670    */
671   this.pollFirstEntry = function() {
672     var p = getFirstEntry();
673     var res = exportEntry(p);
674     if (null !== p) {
675       deleteEntry(p);
676     }
677     return res;
678   };
679 
680   /**
681    * Get the last entry and remove it
682    * @return the last entry
683    */
684   this.pollLastEntry = function() {
685     var p = getLastEntry();
686     var res = exportEntry(p);
687     if (null !== p) {
688       deleteEntry(p);
689     }
690     return res;
691   };
692 
693   /**
694    * Get the largest entry whose key is lower than the specified key.
695    * 
696    * @param {Object} key the specified key
697    *
698    * @return lower entry
699    */
700   this.lowerEntry = function(key) {
701     return exportEntry(getLowerEntry(key));
702   };
703 
704   /**
705    * Get the largest entry's whose key is lower than the specified key.
706    * 
707    * @param {Object} key the specfied key
708    *
709    * @return lower key
710    */
711   this.lowerKey = function(key) {
712     var e = getLowerEntry(key);
713     return null === e ? null : e.key;
714   };
715   
716   ///
717   /// views
718   ///
719 
720   var AscendingSubMap = function(m, fromStart, lo, loInclusive, toEnd, hi, hiInclusive) {
721     
722     var _asm = this;
723   
724     if (!fromStart && !toEnd) {
725       if (m.comparator()(lo, hi) > 0) {
726         throw new Error("fromKey > toKey");
727       }
728     } 
729 
730     /**
731      * Endpoints are represented as triples (fromStart, lo,   loInclusive) and (toEnd, hi, hiInclusive).
732      */
733     var _map = m;
734     var _fromStart = fromStart;
735     var _lo = lo;
736     var _loInclusive = loInclusive;
737     var _toEnd = toEnd;
738     var _hi = hi;
739     var _hiInclusive = hiInclusive;
740     var _compareFunc = m.comparator();
741 
742     this.comparator = _compareFunc;
743   
744     ///
745     /// Private methods
746     ///
747 
748     function tooLow(key) {
749       if (!_fromStart) {
750         var cmp = _asm.comparator(key, _lo);
751         if (cmp < 0 || (0 === cmp && !_loInclusive)) {
752           return true;
753         }
754       }
755       return false;
756     }
757 
758     function tooHigh(key) {
759       if (!_toEnd) {
760         var cmp = _asm.comparator(key, _hi);
761         if (cmp > 0 || (0 === cmp && !_hiInclusive)) {
762           return true;
763         }
764       }
765       return false;
766     }
767 
768     function inRange(key, inclusive) {
769       if (false === inclusive) {
770         return inClosedRange(key);
771       }
772       return !tooLow(key) && !tooHigh(key);
773     }
774 
775     function inClosedRange(key) {
776       return (_fromStart || _asm.comparator(key, _lo) >= 0) &&
777              (_toEnd || _asm.comparator(_hi, key) >= 0);
778     }
779 
780     function absLowest() {
781       var e = _fromStart ? _map.getFirstEntry() : (_loInclusive ? _map.getCeilingEntry(_lo) : _map.getHigherEntry(_lo));
782       return null === e || tooHigh(e.key) ? null : e;
783     }
784     this.absLowest = absLowest;
785 
786     function absHighest() {
787       var e = _toEnd ? _map.getLastEntry() : (_hiInclusive ? _map.getFloorEntry(_hi) : _map.getLowerEntry(_hi));
788       return null === e || tooLow(e.key) ? null : e;
789     }
790     this.absHighest = absHighest;
791 
792     function absCeiling(key) {
793       if (tooLow(key)) {
794         return absLowest();
795       }
796       var e = _map.getCeilingEntry(key);
797       return null === e || tooHigh(e.key) ? null : e;
798     }
799     this.absCeiling = absCeiling;
800 
801     function absHigher(key) {
802       if (tooLow(key)) {
803         return absLowest();
804       }
805       var e = _map.getHigherEntry(key);
806       return null === e || tooHigh(e.key) ? null : e;
807     }
808     this.absHigher = absHigher;
809 
810     function absFloor(key) {
811       if (tooHigh(key)) {
812         return absHighest();
813       }
814       var e = _map.getFloorEntry(key);
815       return null === e || tooLow(e.key) ? null : e;
816     }
817     this.absFloor = absFloor;
818 
819     function absLower(key) {
820       if (tooHigh(key)) {
821         return absHighest();
822       }
823       var e = _map.getLowerEntry(key);
824       return null === e || tooLow(e.key) ? null : e;
825     }
826     this.absLower = absLower;
827 
828     function absHighFence() {
829       return _toEnd ? null : (_hiInclusive ? _map.getHigherEntry(_hi) : _map.getCeilingEntry(_hi));
830     }
831     this.absHighFence = absHighFence;
832 
833     function absLowFence() {
834       return _fromStart ? null : (_loInclusive ? _map.getLowerEntry(_lo) : _map.getFloorEntry(_lo));
835     }
836     this.absLowFence = absLowFence;
837 
838     this.subLowest  = absLowest;
839     this.subHighest = absHighest;
840     this.subCeiling = absCeiling;
841     this.subHigher  = absHigher;
842     this.subFloor   = absFloor;
843     this.subLower   = absLower;
844 
845     this.ceilingEntry = function(key) {
846       return exportEntry(this.subCeiling(key));
847     };
848     this.ceilingKey = function(key) {
849       return keyOrNull(this.subCeiling(key));
850     };
851     this.higherEntry = function(key) {
852       return exportEntry(this.subHigher(key));
853     };
854     this.higherKey = function(key) {
855       return keyOrNull(this.subHigher(key));
856     };
857     this.floorEntry = function(key) {
858       return exportEntry(this.subFloor(key));
859     };
860     this.floorKey = function(key) {
861       return keyOrNull(this.subFloor(key));
862     };
863     this.lowerEntry = function(key) {
864       return exportEntry(this.subLower(key));
865     };
866     this.lowerKey = function(key) {
867       return keyOrNull(this.subLower(key));
868     };
869     this.firstKey = function() {
870       return key(this.subLowest());
871     };
872     this.lastKey = function() {
873       return key(this.subHighest());
874     };
875     this.firstEntry = function() {
876       return exportEntry(this.subLowest());
877     };
878     this.lastEntry = function() {
879       return exportEntry(this.subHighest());
880     };
881     this.pollFirstEntry = function() {
882       var e = this.subLowest();
883       var result = exportEntry(e);
884       if (null !== e) {
885         _map.deleteEntry(e);
886       }
887       return result;
888     };
889     this.pollLastEntry = function() {
890       var e = this.subHighest();
891       var result = exportEntry(e);
892       if (null !== e) {
893         _map.deleteEntry(e);
894       }
895       return result;
896     };
897 
898     function containsKey(key) {
899       return inRange(key) && _map.containsKey(key);
900     }
901     this.containsKey = containsKey;
902 
903     function put(key, value) {
904       if (inRange(key)) {
905         _map.put(key, value);
906       }
907     }
908     this.put = put;
909 
910     function get(key) {
911       return !inRange(key) ? null : _map.get(key);
912     }
913     this.get = get;
914 
915     function remove(key) {
916       return !inRange(key) ? null : _map.remove(key);
917     }
918     this.remove = remove;
919   
920   };
921   
922   var DescendingSubMap = function(m, fromStart, lo, loInclusive, toEnd, hi, hiInclusive) {
923     AscendingSubMap.apply(this, m, fromStart, lo, loInclusive, toEnd, hi, hiInclusive);
924 
925     var _compareFunc = m.comparator();
926     this.comparator = function(k1, k2) {
927       var res = _compareFunc(k1, k2);
928       return -res;
929     };
930 
931     this.subLowest  = this.absHighest;
932     this.subHighest = this.absLowest;
933     this.subCeiling = this.absFloor;
934     this.subHigher  = this.absLower;
935     this.subFloor   = this.absCeiling;
936     this.subLower   = this.absHigher;
937   
938   };
939 
940   sys.inherits(DescendingSubMap, AscendingSubMap);
941   
942   this.subMap = function(fromKey, fromInclusive, toKey, toInclusive) {
943     return new AscendingSubMap(that, false, fromKey, fromInclusive, false, toKey, toInclusive);
944   };
945 
946   this.headMap = function(toKey, toInclusive) {
947     return new AscendingSubMap(that, true, null, true, false, toKey, !toInclusive ? false : true);
948   };
949 
950   this.tailMap = function(fromKey, inclusive) {
951     return new AscendingSubMap(that, false, fromKey, !inclusive ? false : true, true, null, true);
952   };
953 
954 };
955 
956 exports.TreeMap = TreeMap;
957