Skip to content

Commit 60e42f0

Browse files
🚴 perf(split): Avoid creating temporary arrays.
We immediately instantiate a Digit or null. It's a win-win best deal ever: - If we need a Digit, it's there! - No need to branch on list.length! So we win even when we need a Tree. Also we use separate struct DigitSplit to store result of _splitDigit since member types are not the same as in a tree Split. Maybe should rename Split to TreeSplit later.
1 parent ff5d8f5 commit 60e42f0

File tree

13 files changed

+115
-116
lines changed

13 files changed

+115
-116
lines changed

src/0-core/_fast/_digit.js

Lines changed: 0 additions & 24 deletions
This file was deleted.

src/0-core/_fast/_from_digit.js

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/0-core/_fast/_from_small_list.js

Lines changed: 0 additions & 35 deletions
This file was deleted.

src/0-core/_fast/index.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
export * from './_append.js';
22
export * from './_deepL.js';
33
export * from './_deepR.js';
4-
export * from './_digit.js';
5-
export * from './_from_digit.js';
6-
export * from './_from_small_list.js';
74
export * from './_prepend.js';
85
export * from './fast-iterators/index.js';

src/0-core/split/DigitSplit.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import assert from 'assert';
2+
import {Digit} from '../../1-digit/0-Digit.js';
3+
4+
/**
5+
* DigitSplit.
6+
*
7+
* @param {Digit} left
8+
* @param {any} middle
9+
* @param {Digit} right
10+
*/
11+
export function DigitSplit(left, middle, right) {
12+
assert(left === null || left instanceof Digit);
13+
assert(right === null || right instanceof Digit);
14+
this._left = left;
15+
this._middle = middle;
16+
this._right = right;
17+
}

src/0-core/split/Split.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
1+
import assert from 'assert';
2+
import {Tree} from '../../3-tree/base/Tree.js';
3+
4+
/**
5+
* Split.
6+
*
7+
* @param {Tree} left
8+
* @param {any} middle
9+
* @param {Tree} right
10+
*/
111
export function Split(left, middle, right) {
12+
assert(left instanceof Tree);
13+
assert(right instanceof Tree);
214
this._left = left;
315
this._middle = middle;
416
this._right = right;

src/0-core/split/deepL.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
1-
import {Deep} from '../../3-tree/index.js';
1+
import assert from 'assert';
2+
3+
import {Digit} from '../../1-digit/0-Digit.js';
4+
import {Deep, Tree} from '../../3-tree/index.js';
25
import {delay} from '../../4-lazy/index.js';
3-
import {_from_digit, _digit} from '../_fast/index.js';
46

57
/**
6-
* @param {Measure} M
7-
* @param {Array} left
8-
* @param {FingerTree} middle
8+
* @param {any} M
9+
* @param {Digit|null} left
10+
* @param {Tree} middle
911
* @param {Digit} right
1012
*/
1113
export function deepL(M, left, middle, right) {
12-
if (left.length === 0) {
13-
if (middle.isEmpty()) return _from_digit(M, right);
14+
assert(left === null || left instanceof Digit);
15+
assert(middle instanceof Tree);
16+
assert(right instanceof Digit);
17+
18+
if (left === null) {
19+
if (middle.isEmpty()) return right._tree(M);
1420

1521
return new Deep(
1622
M,
@@ -20,5 +26,5 @@ export function deepL(M, left, middle, right) {
2026
);
2127
}
2228

23-
return new Deep(M, _digit(left), middle, right);
29+
return new Deep(M, left, middle, right);
2430
}

src/0-core/split/deepR.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
1-
import {Deep} from '../../3-tree/index.js';
1+
import assert from 'assert';
2+
3+
import {Digit} from '../../1-digit/0-Digit.js';
4+
import {Deep, Tree} from '../../3-tree/index.js';
25
import {delay} from '../../4-lazy/index.js';
3-
import {_from_digit, _digit} from '../_fast/index.js';
46

57
/**
6-
* @param {Measure} M
8+
* @param {any} M
79
* @param {Digit} left
8-
* @param {FingerTree} middle
9-
* @param {Array} right
10+
* @param {Tree} middle
11+
* @param {Digit|null} right
1012
*/
1113
export function deepR(M, left, middle, right) {
12-
if (right.length === 0) {
13-
if (middle.isEmpty()) return _from_digit(M, left);
14+
assert(left instanceof Digit);
15+
assert(middle instanceof Tree);
16+
assert(right === null || right instanceof Digit);
17+
18+
if (right === null) {
19+
if (middle.isEmpty()) return left._tree(M);
1420

1521
return new Deep(
1622
M,
@@ -20,5 +26,5 @@ export function deepR(M, left, middle, right) {
2026
);
2127
}
2228

23-
return new Deep(M, left, middle, _digit(right));
29+
return new Deep(M, left, middle, right);
2430
}

src/1-digit/1-One.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import assert from 'assert';
22
import {node2, node3} from '../2-node/index.js';
3-
import {Split} from '../0-core/index.js';
3+
import {DigitSplit} from '../0-core/split/DigitSplit.js';
4+
import {Single} from '../3-tree/implementations/1-Single.js';
45
import {Digit, Two, Three, Four} from './index.js';
56

67
export function One(a) {
@@ -43,12 +44,16 @@ One.prototype._node = function (_M) {
4344
throw new Error('cannot convert One to node');
4445
};
4546

47+
One.prototype._tree = function (M) {
48+
return new Single(M, this.a);
49+
};
50+
4651
/**
4752
* It is assumed that p(i+|this|) is true.
4853
*/
4954
One.prototype._splitDigit = function (p, i, M) {
5055
assert(p(M.plus(i, this.measure(M)))); // /!\ Potential Heisenbug generator.
51-
return new Split([], this.a, []);
56+
return new DigitSplit(null, this.a, null);
5257
};
5358

5459
One.prototype._nodes = function (M, other) {

src/1-digit/2-Two.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import assert from 'assert';
22
import {Node2, node2, node3} from '../2-node/index.js';
3-
import {Split} from '../0-core/index.js';
3+
import {DigitSplit} from '../0-core/split/DigitSplit.js';
4+
import {Empty} from '../3-tree/implementations/0-Empty.js';
5+
import {cache} from '../0-core/measure/cache.js';
6+
import {Deep} from '../3-tree/implementations/2-Deep.js';
47
import {Digit, One, Three, Four} from './index.js';
58

69
export function Two(a, b) {
@@ -44,14 +47,18 @@ Two.prototype._node = function (M) {
4447
return new Node2(this.measure(M), this.a, this.b);
4548
};
4649

50+
Two.prototype._tree = function (M) {
51+
return new Deep(M, new One(this.a), new Empty(cache(M)), new One(this.b));
52+
};
53+
4754
/**
4855
* It is assumed that p(i+|this|) is true.
4956
*/
5057
Two.prototype._splitDigit = function (p, i, M) {
5158
assert(p(M.plus(i, this.measure(M)))); // /!\ Potential Heisenbug generator.
5259
i = M.plus(i, M.measure(this.a));
53-
if (p(i)) return new Split([], this.a, [this.b]);
54-
return new Split([this.a], this.b, []);
60+
if (p(i)) return new DigitSplit(null, this.a, new One(this.b));
61+
return new DigitSplit(new One(this.a), this.b, null);
5562
};
5663

5764
Two.prototype._nodes = function (M, other) {

0 commit comments

Comments
 (0)