Skip to content

Commit 062b0c1

Browse files
committed
Various tweaks including new failing tests
I added new tests that use the new `getPairOrNextLower` method from PR #23 (and the new `getPairOrNextHigher` method in this commit) but the tests are failing. - Add public `getPairOrNextHigher` method - Add `as any` in places to avoid red squiggly errors - Change the second argument of `getPairOrNextHigher` and `getPairOrNextLower` to eliminate unnecessary indirection - Other tweaks
1 parent 63d84d9 commit 062b0c1

File tree

6 files changed

+156
-8026
lines changed

6 files changed

+156
-8026
lines changed

b+tree.d.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,9 @@ export default class BTree<K = any, V = any> implements ISortedMapF<K, V>, ISort
333333
* avoid creating a new array on every iteration.
334334
*/
335335
nextHigherPair(key: K | undefined, reusedArray?: [K, V]): [K, V] | undefined;
336-
/** Returns the next key larger than the specified key (or undefined if there is none) */
336+
/** Returns the next key larger than the specified key, or undefined if there is none.
337+
* Also, nextHigherKey(undefined) returns the lowest key.
338+
*/
337339
nextHigherKey(key: K | undefined): K | undefined;
338340
/** Returns the next pair whose key is smaller than the specified key (or undefined if there is none).
339341
* If key === undefined, this function returns the highest pair.
@@ -342,15 +344,26 @@ export default class BTree<K = any, V = any> implements ISortedMapF<K, V>, ISort
342344
* avoid creating a new array each time you call this method.
343345
*/
344346
nextLowerPair(key: K | undefined, reusedArray?: [K, V]): [K, V] | undefined;
345-
/** Returns the next key smaller than the specified key (or undefined if there is none) */
347+
/** Returns the next key smaller than the specified key, or undefined if there is none.
348+
* Also, nextLowerKey(undefined) returns the highest key.
349+
*/
346350
nextLowerKey(key: K | undefined): K | undefined;
347351
/** Returns the key-value pair associated with the supplied key if it exists
348-
* and the next lower pair otherwise (or undefined if there is none)
352+
* or the pair associated with the next lower pair otherwise. If there is no
353+
* next lower pair, undefined is returned.
349354
* @param key The key to search for.
350355
* @param reusedArray Optional array used repeatedly to store key-value pairs, to
351356
* avoid creating a new array each time you call this method.
352357
* */
353358
getPairOrNextLower(key: K, reusedArray?: [K, V]): [K, V] | undefined;
359+
/** Returns the key-value pair associated with the supplied key if it exists
360+
* or the pair associated with the next lower pair otherwise. If there is no
361+
* next lower pair, undefined is returned.
362+
* @param key The key to search for.
363+
* @param reusedArray Optional array used repeatedly to store key-value pairs, to
364+
* avoid creating a new array each time you call this method.
365+
* */
366+
getPairOrNextHigher(key: K, reusedArray?: [K, V]): [K, V] | undefined;
354367
/** Edits the value associated with a key in the tree, if it already exists.
355368
* @returns true if the key existed, false if not.
356369
*/

b+tree.js

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ var BTree = /** @class */ (function () {
553553
var valOther = otherLeaf.values[otherLevelIndices[otherLevelIndices.length - 1]];
554554
if (!Object.is(valThis, valOther)) {
555555
var result = different(thisCursor.currentKey, valThis, valOther);
556-
if (result && (result === null || result === void 0 ? void 0 : result.break))
556+
if (result && result.break)
557557
return result.break;
558558
}
559559
}
@@ -828,12 +828,14 @@ var BTree = /** @class */ (function () {
828828
if (key === undefined) {
829829
return this._root.minPair(reusedArray);
830830
}
831-
return this._root.getPairOrNextHigher(key, this, false, reusedArray);
831+
return this._root.getPairOrNextHigher(key, this._compare, false, reusedArray);
832832
};
833-
/** Returns the next key larger than the specified key (or undefined if there is none) */
833+
/** Returns the next key larger than the specified key, or undefined if there is none.
834+
* Also, nextHigherKey(undefined) returns the lowest key.
835+
*/
834836
BTree.prototype.nextHigherKey = function (key) {
835837
var p = this.nextHigherPair(key, ReusedArray);
836-
return p ? p[0] : p;
838+
return p && p[0];
837839
};
838840
/** Returns the next pair whose key is smaller than the specified key (or undefined if there is none).
839841
* If key === undefined, this function returns the highest pair.
@@ -846,21 +848,34 @@ var BTree = /** @class */ (function () {
846848
if (key === undefined) {
847849
return this._root.maxPair(reusedArray);
848850
}
849-
return this._root.getPairOrNextLower(key, this, false, reusedArray);
851+
return this._root.getPairOrNextLower(key, this._compare, false, reusedArray);
850852
};
851-
/** Returns the next key smaller than the specified key (or undefined if there is none) */
853+
/** Returns the next key smaller than the specified key, or undefined if there is none.
854+
* Also, nextLowerKey(undefined) returns the highest key.
855+
*/
852856
BTree.prototype.nextLowerKey = function (key) {
853857
var p = this.nextLowerPair(key, ReusedArray);
854-
return p ? p[0] : p;
858+
return p && p[0];
855859
};
856860
/** Returns the key-value pair associated with the supplied key if it exists
857-
* and the next lower pair otherwise (or undefined if there is none)
861+
* or the pair associated with the next lower pair otherwise. If there is no
862+
* next lower pair, undefined is returned.
858863
* @param key The key to search for.
859864
* @param reusedArray Optional array used repeatedly to store key-value pairs, to
860865
* avoid creating a new array each time you call this method.
861866
* */
862867
BTree.prototype.getPairOrNextLower = function (key, reusedArray) {
863-
return this._root.getPairOrNextLower(key, this, true, reusedArray || []);
868+
return this._root.getPairOrNextLower(key, this._compare, true, reusedArray || []);
869+
};
870+
/** Returns the key-value pair associated with the supplied key if it exists
871+
* or the pair associated with the next lower pair otherwise. If there is no
872+
* next lower pair, undefined is returned.
873+
* @param key The key to search for.
874+
* @param reusedArray Optional array used repeatedly to store key-value pairs, to
875+
* avoid creating a new array each time you call this method.
876+
* */
877+
BTree.prototype.getPairOrNextHigher = function (key, reusedArray) {
878+
return this._root.getPairOrNextHigher(key, this._compare, true, reusedArray || []);
864879
};
865880
/** Edits the value associated with a key in the tree, if it already exists.
866881
* @returns true if the key existed, false if not.
@@ -1179,8 +1194,8 @@ var BNode = /** @class */ (function () {
11791194
var i = this.indexOf(key, -1, tree._compare);
11801195
return i < 0 ? defaultValue : this.values[i];
11811196
};
1182-
BNode.prototype.getPairOrNextLower = function (key, tree, inclusive, reusedArray) {
1183-
var i = this.indexOf(key, -1, tree._compare);
1197+
BNode.prototype.getPairOrNextLower = function (key, compare, inclusive, reusedArray) {
1198+
var i = this.indexOf(key, -1, compare);
11841199
var indexOrLower = i < 0 ? ~i - 1 : (inclusive ? i : i - 1);
11851200
if (indexOrLower >= 0) {
11861201
reusedArray[0] = this.keys[indexOrLower];
@@ -1189,8 +1204,8 @@ var BNode = /** @class */ (function () {
11891204
}
11901205
return undefined;
11911206
};
1192-
BNode.prototype.getPairOrNextHigher = function (key, tree, inclusive, reusedArray) {
1193-
var i = this.indexOf(key, -1, tree._compare);
1207+
BNode.prototype.getPairOrNextHigher = function (key, compare, inclusive, reusedArray) {
1208+
var i = this.indexOf(key, -1, compare);
11941209
var indexOrLower = i < 0 ? ~i : (inclusive ? i : i + 1);
11951210
var keys = this.keys;
11961211
if (indexOrLower < keys.length) {
@@ -1404,21 +1419,21 @@ var BNodeInternal = /** @class */ (function (_super) {
14041419
var i = this.indexOf(key, 0, tree._compare), children = this.children;
14051420
return i < children.length ? children[i].get(key, defaultValue, tree) : undefined;
14061421
};
1407-
BNodeInternal.prototype.getPairOrNextLower = function (key, tree, inclusive, reusedArray) {
1408-
var i = this.indexOf(key, 0, tree._compare), children = this.children;
1422+
BNodeInternal.prototype.getPairOrNextLower = function (key, compare, inclusive, reusedArray) {
1423+
var i = this.indexOf(key, 0, compare), children = this.children;
14091424
if (i >= children.length)
14101425
return undefined;
1411-
var result = children[i].getPairOrNextLower(key, tree, inclusive, reusedArray);
1426+
var result = children[i].getPairOrNextLower(key, compare, inclusive, reusedArray);
14121427
if (result === undefined && i > 0) {
14131428
return children[i - 1].maxPair(reusedArray);
14141429
}
14151430
return result;
14161431
};
1417-
BNodeInternal.prototype.getPairOrNextHigher = function (key, tree, inclusive, reusedArray) {
1418-
var i = this.indexOf(key, 0, tree._compare), children = this.children, length = children.length;
1432+
BNodeInternal.prototype.getPairOrNextHigher = function (key, compare, inclusive, reusedArray) {
1433+
var i = this.indexOf(key, 0, compare), children = this.children, length = children.length;
14191434
if (i >= length)
14201435
return undefined;
1421-
var result = children[i].getPairOrNextHigher(key, tree, inclusive, reusedArray);
1436+
var result = children[i].getPairOrNextHigher(key, compare, inclusive, reusedArray);
14221437
if (result === undefined && i < length - 1) {
14231438
return children[i + 1].minPair(reusedArray);
14241439
}

b+tree.test.ts

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -421,27 +421,63 @@ function testBTree(maxNodeSize: number)
421421
});
422422
}
423423

424-
for (let size of [5, 10, 300]) {
425-
const tree = new BTree<number,number>(undefined, undefined, maxNodeSize);
426-
const pairs: [number,number][] = [];
427-
for (let i = 0; i < size; i++) {
428-
const value = randInt(size * 2);
429-
tree.set(i, value);
430-
pairs.push([i, value]);
431-
}
432-
test(`nextLowerPair/nextHigherPair for tree of size ${size}`, () => {
433-
expect(tree.nextHigherPair(undefined)).toEqual([tree.minKey()!, tree.get(tree.minKey()!)]);
424+
describe(`Next higher/lower methods`, () => {
425+
test(`nextLower/nextHigher methods return undefined in an empty tree`, () => {
426+
const tree = new BTree<number,number>(undefined, undefined, maxNodeSize);
427+
expect(tree.nextLowerPair(undefined)).toEqual(undefined);
428+
expect(tree.nextHigherPair(undefined)).toEqual(undefined);
429+
expect(tree.getPairOrNextLower(1)).toEqual(undefined);
430+
expect(tree.getPairOrNextHigher(2)).toEqual(undefined);
431+
432+
// This shouldn't make a difference
433+
tree.set(5, 55);
434+
tree.delete(5);
435+
436+
expect(tree.nextLowerPair(undefined)).toEqual(undefined);
437+
expect(tree.nextHigherPair(undefined)).toEqual(undefined);
438+
expect(tree.nextLowerPair(3)).toEqual(undefined);
439+
expect(tree.nextHigherPair(4)).toEqual(undefined);
440+
expect(tree.getPairOrNextLower(5)).toEqual(undefined);
441+
expect(tree.getPairOrNextHigher(6)).toEqual(undefined);
442+
});
443+
444+
for (let size of [5, 10, 300]) {
445+
// Build a tree and list with pairs whose keys are even numbers: 0, 2, 4, 6, 8, 10...
446+
const tree = new BTree<number,number>(undefined, undefined, maxNodeSize);
447+
const pairs: [number,number][] = [];
434448
for (let i = 0; i < size; i++) {
435-
if (i > 0) {
436-
expect(tree.nextLowerPair(i)).toEqual(pairs[i - 1]);
449+
const value = i;
450+
tree.set(i * 2, value);
451+
pairs.push([i * 2, value]);
452+
}
453+
454+
test(`nextLowerPair/nextHigherPair for tree of size ${size}`, () => {
455+
expect(tree.nextHigherPair(undefined)).toEqual([tree.minKey()!, tree.get(tree.minKey()!)]);
456+
expect(tree.nextHigherPair(tree.maxKey())).toEqual(undefined);
457+
for (let i = 0; i < size * 2; i++) {
458+
if (i > 0) {
459+
expect(tree.nextLowerPair(i)).toEqual(pairs[((i + 1) >> 1) - 1]);
460+
}
461+
if (i < size - 1) {
462+
expect(tree.nextHigherPair(i)).toEqual(pairs[(i >> 1) + 1]);
463+
}
437464
}
438-
if (i < size - 1) {
439-
expect(tree.nextHigherPair(i)).toEqual(pairs[i + 1]);
465+
expect(tree.nextLowerPair(undefined)).toEqual([tree.maxKey()!, tree.get(tree.maxKey()!)]);
466+
expect(tree.nextLowerPair(tree.minKey())).toEqual(undefined);
467+
})
468+
469+
test(`getPairOrNextLower/getPairOrNextHigher for tree of size ${size}`, () => {
470+
for (let i = 0; i < size * 2; i++) {
471+
if (i > 0) {
472+
expect(tree.getPairOrNextLower(i)).toEqual(pairs[i >> 1]);
473+
}
474+
if (i < size - 1) {
475+
expect(tree.getPairOrNextHigher(i)).toEqual(pairs[(i + 1) >> 1]);
476+
}
440477
}
441-
}
442-
expect(tree.nextLowerPair(undefined)).toEqual([tree.maxKey()!, tree.get(tree.maxKey()!)]);
443-
})
444-
}
478+
})
479+
}
480+
});
445481

446482
for (let size of [6, 36, 216]) {
447483
test(`setPairs & deleteRange [size ${size}]`, () => {

0 commit comments

Comments
 (0)