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