@calcit/ternary-tree 0.0.23 → 0.0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -4
- package/TESTING.md +155 -0
- package/lib/benchmark.d.mts +1 -0
- package/lib/benchmark.mjs +67 -0
- package/lib/list.d.mts +2 -0
- package/lib/list.mjs +178 -124
- package/lib/map.mjs +124 -101
- package/lib/test-list-detailed-perf.d.mts +1 -0
- package/lib/test-list-detailed-perf.mjs +165 -0
- package/lib/test-list-perf.d.mts +1 -0
- package/lib/test-list-perf.mjs +153 -0
- package/lib/test-list.mjs +202 -203
- package/lib/test-map-perf.d.mts +1 -0
- package/lib/test-map-perf.mjs +70 -0
- package/lib/test-map.mjs +201 -208
- package/lib/test-utils.d.mts +9 -5
- package/lib/test-utils.mjs +131 -18
- package/lib/{main.mjs → test.mjs} +5 -0
- package/package.json +13 -5
- /package/lib/{main.d.mts → test.d.mts} +0 -0
@@ -0,0 +1,153 @@
|
|
1
|
+
import { initTernaryTreeList, initTernaryTreeListFromRange, listGet, assocList, insert, listLen, indexOf, listToItems, prepend, append, concat, slice, reverse, listMapValues, } from "./list.mjs";
|
2
|
+
function createTestListData(size) {
|
3
|
+
const data = [];
|
4
|
+
for (let i = 0; i < size; i++) {
|
5
|
+
data.push(i);
|
6
|
+
}
|
7
|
+
return data;
|
8
|
+
}
|
9
|
+
function measureTime(name, fn) {
|
10
|
+
const start = performance.now();
|
11
|
+
const result = fn();
|
12
|
+
const end = performance.now();
|
13
|
+
console.log(`${name}: ${(end - start).toFixed(2)}ms`);
|
14
|
+
return result;
|
15
|
+
}
|
16
|
+
export function runListPerformanceTests() {
|
17
|
+
console.log("\n=== List Performance Tests ===");
|
18
|
+
const sizes = [100, 1000, 5000, 10000];
|
19
|
+
for (const size of sizes) {
|
20
|
+
console.log(`\n--- Testing with ${size} elements ---`);
|
21
|
+
const testData = createTestListData(size);
|
22
|
+
// Test list creation
|
23
|
+
const treeList = measureTime(`initTernaryTreeList(${size})`, () => {
|
24
|
+
return initTernaryTreeList(testData);
|
25
|
+
});
|
26
|
+
// Test range creation
|
27
|
+
measureTime(`initTernaryTreeListFromRange(${size})`, () => {
|
28
|
+
return initTernaryTreeListFromRange(testData, 0, size);
|
29
|
+
});
|
30
|
+
// Test random access (listGet)
|
31
|
+
const indices = Array.from({ length: Math.min(100, size) }, (_, i) => Math.floor(Math.random() * size));
|
32
|
+
measureTime(`Random access(${indices.length})`, () => {
|
33
|
+
for (const idx of indices) {
|
34
|
+
listGet(treeList, idx);
|
35
|
+
}
|
36
|
+
});
|
37
|
+
// Test sequential access
|
38
|
+
measureTime(`Sequential access(${size})`, () => {
|
39
|
+
for (let i = 0; i < size; i++) {
|
40
|
+
listGet(treeList, i);
|
41
|
+
}
|
42
|
+
});
|
43
|
+
// Test prepend operations
|
44
|
+
measureTime(`Prepend operations(100)`, () => {
|
45
|
+
let list = treeList;
|
46
|
+
for (let i = 0; i < 100; i++) {
|
47
|
+
list = prepend(list, i + size);
|
48
|
+
}
|
49
|
+
return list;
|
50
|
+
});
|
51
|
+
// Test append operations
|
52
|
+
measureTime(`Append operations(100)`, () => {
|
53
|
+
let list = treeList;
|
54
|
+
for (let i = 0; i < 100; i++) {
|
55
|
+
list = append(list, i + size);
|
56
|
+
}
|
57
|
+
return list;
|
58
|
+
});
|
59
|
+
// Test assoc operations
|
60
|
+
const assocIndices = Array.from({ length: Math.min(50, size) }, (_, i) => Math.floor(Math.random() * size));
|
61
|
+
measureTime(`Assoc operations(${assocIndices.length})`, () => {
|
62
|
+
let list = treeList;
|
63
|
+
for (const idx of assocIndices) {
|
64
|
+
list = assocList(list, idx, idx * 2);
|
65
|
+
}
|
66
|
+
return list;
|
67
|
+
});
|
68
|
+
// Test insert operations
|
69
|
+
const insertIndices = Array.from({ length: Math.min(25, size) }, (_, i) => Math.floor(Math.random() * (size + i)));
|
70
|
+
measureTime(`Insert operations(${insertIndices.length})`, () => {
|
71
|
+
let list = treeList;
|
72
|
+
for (let i = 0; i < insertIndices.length; i++) {
|
73
|
+
const idx = Math.min(insertIndices[i], listLen(list));
|
74
|
+
list = insert(list, idx, i + size);
|
75
|
+
}
|
76
|
+
return list;
|
77
|
+
});
|
78
|
+
// Test search operations
|
79
|
+
const searchValues = testData.slice(0, Math.min(50, size));
|
80
|
+
measureTime(`Search operations(${searchValues.length})`, () => {
|
81
|
+
for (const value of searchValues) {
|
82
|
+
indexOf(treeList, value);
|
83
|
+
}
|
84
|
+
});
|
85
|
+
// Test iteration
|
86
|
+
measureTime(`Iterator traversal(${size})`, () => {
|
87
|
+
let count = 0;
|
88
|
+
for (const item of listToItems(treeList)) {
|
89
|
+
count++;
|
90
|
+
}
|
91
|
+
return count;
|
92
|
+
});
|
93
|
+
// Test slice operations
|
94
|
+
const sliceCount = Math.min(10, size / 10);
|
95
|
+
measureTime(`Slice operations(${sliceCount})`, () => {
|
96
|
+
for (let i = 0; i < sliceCount; i++) {
|
97
|
+
const start = Math.floor((Math.random() * size) / 2);
|
98
|
+
const end = start + Math.floor((Math.random() * size) / 4);
|
99
|
+
slice(treeList, start, end);
|
100
|
+
}
|
101
|
+
});
|
102
|
+
// Test reverse operation
|
103
|
+
if (size <= 5000) {
|
104
|
+
// Only test reverse for smaller sizes as it can be expensive
|
105
|
+
measureTime(`Reverse(${size})`, () => {
|
106
|
+
return reverse(treeList);
|
107
|
+
});
|
108
|
+
}
|
109
|
+
// Test map operation
|
110
|
+
measureTime(`Map operation(${size})`, () => {
|
111
|
+
return listMapValues(treeList, (x) => x * 2);
|
112
|
+
});
|
113
|
+
}
|
114
|
+
// Concat performance test
|
115
|
+
console.log("\n=== Concat Performance Test ===");
|
116
|
+
const list1 = initTernaryTreeList(createTestListData(1000));
|
117
|
+
const list2 = initTernaryTreeList(createTestListData(1000));
|
118
|
+
const list3 = initTernaryTreeList(createTestListData(1000));
|
119
|
+
measureTime("Concat two lists(1000 each)", () => {
|
120
|
+
return concat(list1, list2);
|
121
|
+
});
|
122
|
+
measureTime("Concat three lists(1000 each)", () => {
|
123
|
+
return concat(concat(list1, list2), list3);
|
124
|
+
});
|
125
|
+
// Memory stress test
|
126
|
+
console.log("\n=== Memory Usage Test ===");
|
127
|
+
const largeData = createTestListData(25000);
|
128
|
+
measureTime("Large list creation(25k)", () => {
|
129
|
+
return initTernaryTreeList(largeData);
|
130
|
+
});
|
131
|
+
// Cascading operations test
|
132
|
+
console.log("\n=== Cascading Operations Test ===");
|
133
|
+
measureTime("Complex operations chain", () => {
|
134
|
+
let list = initTernaryTreeList(createTestListData(1000));
|
135
|
+
// Chain multiple operations
|
136
|
+
list = prepend(list, -1);
|
137
|
+
list = append(list, 1001);
|
138
|
+
list = assocList(list, 500, 9999);
|
139
|
+
list = insert(list, 250, 8888);
|
140
|
+
// Access and search
|
141
|
+
listGet(list, 100);
|
142
|
+
indexOf(list, 9999);
|
143
|
+
// Slice and iterate
|
144
|
+
const sliced = slice(list, 100, 200);
|
145
|
+
for (const item of listToItems(sliced)) {
|
146
|
+
// consume iterator
|
147
|
+
}
|
148
|
+
return list;
|
149
|
+
});
|
150
|
+
}
|
151
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
152
|
+
runListPerformanceTests();
|
153
|
+
}
|
package/lib/test-list.mjs
CHANGED
@@ -1,208 +1,207 @@
|
|
1
1
|
import { listToString, initTernaryTreeList, initTernaryTreeListFromRange, indexOf, findIndex, reverse, checkListStructure, slice, listToPairs, listToItems, formatListInline, sameListShape, assocBefore, concat, assocAfter, prepend, append, rest, butlast, first, assocList, dissocList, listGet, insert, initEmptyTernaryTreeList, last, listLen, forceListInplaceBalancing, listEqual, indexToItems, listMapValues, concat2, } from "./list.mjs";
|
2
|
-
import { test, check,
|
2
|
+
import { describe, test, check, checkEqual, checkArrayEqual } from "./test-utils.mjs";
|
3
3
|
export let runListTests = () => {
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
check(first(data11) === 1);
|
23
|
-
check(last(data11) === 11);
|
24
|
-
// assoc
|
25
|
-
let origin5 = [1, 2, 3, 4, 5];
|
26
|
-
let data5 = initTernaryTreeList(origin5);
|
27
|
-
let updated = assocList(data5, 3, 10);
|
28
|
-
check(listGet(updated, 3) === 10);
|
29
|
-
check(listGet(data5, 3) === 4);
|
30
|
-
check(listLen(updated) === listLen(data5));
|
31
|
-
for (let idx = 0; idx < listLen(data5); idx++) {
|
32
|
-
// echo data5.dissoc(idx).formatInline
|
33
|
-
check(listLen(dissocList(data5, idx)) === listLen(data5) - 1);
|
34
|
-
}
|
35
|
-
checkEqual(formatListInline(data5), "((1 2 _) 3 (4 5 _))");
|
36
|
-
checkEqual(formatListInline(dissocList(data5, 0)), "(2 3 (4 5 _))");
|
37
|
-
checkEqual(formatListInline(dissocList(data5, 1)), "(1 3 (4 5 _))");
|
38
|
-
checkEqual(formatListInline(dissocList(data5, 2)), "((1 2 _) (4 5 _) _)");
|
39
|
-
checkEqual(formatListInline(dissocList(data5, 3)), "((1 2 _) 3 5)");
|
40
|
-
checkEqual(formatListInline(dissocList(data5, 4)), "((1 2 _) 3 4)");
|
41
|
-
checkEqual(formatListInline(rest(initTernaryTreeList([1]))), "_");
|
42
|
-
checkEqual(formatListInline(rest(initTernaryTreeList([1, 2]))), "2");
|
43
|
-
checkEqual(formatListInline(rest(initTernaryTreeList([1, 2, 3]))), "(2 3 _)");
|
44
|
-
checkEqual(formatListInline(rest(initTernaryTreeList([1, 2, 3, 4]))), "((2 3 _) 4 _)");
|
45
|
-
checkEqual(formatListInline(rest(initTernaryTreeList([1, 2, 3, 4, 5]))), "(2 3 (4 5 _))");
|
46
|
-
checkEqual(formatListInline(butlast(initTernaryTreeList([1]))), "_");
|
47
|
-
checkEqual(formatListInline(butlast(initTernaryTreeList([1, 2]))), "1");
|
48
|
-
checkEqual(formatListInline(butlast(initTernaryTreeList([1, 2, 3]))), "(1 2 _)");
|
49
|
-
checkEqual(formatListInline(butlast(initTernaryTreeList([1, 2, 3, 4]))), "(1 (2 3 _) _)");
|
50
|
-
checkEqual(formatListInline(butlast(initTernaryTreeList([1, 2, 3, 4, 5]))), "((1 2 _) 3 4)");
|
51
|
-
});
|
52
|
-
test("list insertions", () => {
|
53
|
-
let origin5 = [1, 2, 3, 4, 5];
|
54
|
-
let data5 = initTernaryTreeList(origin5);
|
55
|
-
checkEqual(formatListInline(data5), "((1 2 _) 3 (4 5 _))");
|
56
|
-
checkEqual(formatListInline(insert(data5, 0, 10, false)), "(10 ((1 2 _) 3 (4 5 _)) _)");
|
57
|
-
checkEqual(formatListInline(insert(data5, 0, 10, true)), "((1 10 2) 3 (4 5 _))");
|
58
|
-
checkEqual(formatListInline(insert(data5, 1, 10, false)), "((1 10 2) 3 (4 5 _))");
|
59
|
-
checkEqual(formatListInline(insert(data5, 1, 10, true)), "((1 2 10) 3 (4 5 _))");
|
60
|
-
checkEqual(formatListInline(insert(data5, 2, 10, false)), "((1 2 _) (10 3 _) (4 5 _))");
|
61
|
-
checkEqual(formatListInline(insert(data5, 2, 10, true)), "((1 2 _) (3 10 _) (4 5 _))");
|
62
|
-
checkEqual(formatListInline(insert(data5, 3, 10, false)), "((1 2 _) 3 (10 4 5))");
|
63
|
-
checkEqual(formatListInline(insert(data5, 3, 10, true)), "((1 2 _) 3 (4 10 5))");
|
64
|
-
checkEqual(formatListInline(insert(data5, 4, 10, false)), "((1 2 _) 3 (4 10 5))");
|
65
|
-
checkEqual(formatListInline(insert(data5, 4, 10, true)), "(((1 2 _) 3 (4 5 _)) 10 _)");
|
66
|
-
let origin4 = [1, 2, 3, 4];
|
67
|
-
let data4 = initTernaryTreeList(origin4);
|
68
|
-
checkEqual(formatListInline(assocBefore(data4, 3, 10)), "(1 (2 3 _) (10 4 _))");
|
69
|
-
checkEqual(formatListInline(assocAfter(data4, 3, 10)), "(1 (2 3 _) (4 10 _))");
|
70
|
-
checkEqual(formatListInline(prepend(data4, 10)), "((10 1 _) (2 3 _) 4)");
|
71
|
-
checkEqual(formatListInline(append(data4, 10)), "(1 (2 3 _) (4 10 _))");
|
72
|
-
});
|
73
|
-
test("concat", () => {
|
74
|
-
let data1 = initTernaryTreeList([1, 2]);
|
75
|
-
let data2 = initTernaryTreeList([3, 4]);
|
76
|
-
let data3 = initTernaryTreeList([5, 6]);
|
77
|
-
let data4 = initTernaryTreeList([7, 8]);
|
78
|
-
check(formatListInline(concat(data1, data2)) === "(1 2 (3 4 _))");
|
79
|
-
check(formatListInline(concat(initTernaryTreeList([]), data1)) === "(1 2 _)");
|
80
|
-
check(formatListInline(concat(data1, data2, data3)) === "((1 2 _) (3 4 _) (5 6 _))");
|
81
|
-
check(formatListInline(concat(data1, data2, data3, data4)) === "((1 2 _) ((3 4 _) (5 6 _) _) (7 8 _))");
|
82
|
-
checkListStructure(concat(data1, data2));
|
83
|
-
checkListStructure(concat(data1, data2, data3));
|
84
|
-
checkListStructure(concat(data1, data2, data3, data4));
|
85
|
-
check(listLen(concat(data1, data2, data3, data4)) === 8);
|
86
|
-
});
|
87
|
-
test("check(equality", () => {
|
88
|
-
let origin4 = [1, 2, 3, 4];
|
89
|
-
let data4 = initTernaryTreeList(origin4);
|
90
|
-
let data4n = initTernaryTreeList(origin4);
|
91
|
-
let data4Made = prepend(initTernaryTreeList([2, 3, 4]), 1);
|
92
|
-
checkListStructure(data4);
|
93
|
-
checkListStructure(data4n);
|
94
|
-
checkListStructure(data4Made);
|
95
|
-
check(sameListShape(data4, data4) === true);
|
96
|
-
check(sameListShape(data4, data4n) === true);
|
97
|
-
check(sameListShape(data4, data4Made) === false);
|
98
|
-
check(listEqual(data4, data4n));
|
99
|
-
check(listEqual(data4, data4Made));
|
100
|
-
check(listEqual(data4n, data4Made));
|
101
|
-
check(data4 !== data4Made); // identical false
|
102
|
-
});
|
103
|
-
test("force balancing", () => {
|
104
|
-
var data = initTernaryTreeList([]);
|
105
|
-
for (let idx = 0; idx < 20; idx++) {
|
106
|
-
data = append(data, idx, true);
|
107
|
-
checkListStructure(data);
|
108
|
-
}
|
109
|
-
// echo data.formatInline
|
110
|
-
check(formatListInline(data) === "(((0 1 2) (3 4 5) (6 7 8)) ((9 10 11) (12 13 14) (15 16 17)) (18 19 _))");
|
111
|
-
forceListInplaceBalancing(data);
|
112
|
-
check(formatListInline(data) === "(((0 1 _) (2 3 4) (5 6 _)) ((7 8 _) (9 10 _) (11 12 _)) ((13 14 _) (15 16 17) (18 19 _)))");
|
113
|
-
// echo data.formatInline
|
114
|
-
});
|
115
|
-
test("iterator", () => {
|
116
|
-
let origin4 = [1, 2, 3, 4];
|
117
|
-
let data4 = initTernaryTreeList(origin4);
|
118
|
-
checkListStructure(data4);
|
119
|
-
var i = 0;
|
120
|
-
for (let item of listToItems(data4)) {
|
121
|
-
i = i + 1;
|
122
|
-
}
|
123
|
-
check(i === 4);
|
124
|
-
i = 0;
|
125
|
-
for (let [idx, item] of listToPairs(data4)) {
|
126
|
-
i = i + idx;
|
127
|
-
}
|
128
|
-
check(i === 6);
|
129
|
-
});
|
130
|
-
test("check structure", () => {
|
131
|
-
var data = initTernaryTreeList([]);
|
132
|
-
for (let idx = 0; idx < 20; idx++) {
|
133
|
-
data = append(data, idx, true);
|
134
|
-
checkListStructure(data);
|
135
|
-
}
|
136
|
-
check(checkListStructure(data));
|
137
|
-
for (let idx = 0; idx < 20; idx++) {
|
138
|
-
data = rest(data);
|
139
|
-
checkListStructure(data);
|
140
|
-
}
|
141
|
-
let origin11 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
|
142
|
-
let data11 = initTernaryTreeList(origin11);
|
143
|
-
check(checkListStructure(data11));
|
144
|
-
checkListStructure(prepend(initEmptyTernaryTreeList(), 1));
|
145
|
-
checkListStructure(prepend(null, 1));
|
146
|
-
});
|
147
|
-
test("slices", () => {
|
148
|
-
var data = initTernaryTreeList([]);
|
149
|
-
for (let idx = 0; idx < 40; idx++) {
|
150
|
-
data = append(data, idx, true);
|
151
|
-
}
|
152
|
-
var list40 = [];
|
153
|
-
for (let idx = 0; idx < 40; idx++) {
|
154
|
-
list40.push(idx);
|
155
|
-
}
|
156
|
-
for (let i = 0; i < 40; i++) {
|
157
|
-
for (let j = i; j < 40; j++) {
|
158
|
-
check(arrayEqual([...listToItems(slice(data, i, j))], list40.slice(i, j)));
|
159
|
-
checkListStructure(slice(data, i, j));
|
4
|
+
describe("TernaryTreeList Tests", () => {
|
5
|
+
test("should initialize list correctly", () => {
|
6
|
+
check(listToString(initTernaryTreeList([1, 2, 3, 4])) === "TernaryTreeList[4, ...]");
|
7
|
+
let origin11 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
|
8
|
+
let data11 = initTernaryTreeList(origin11);
|
9
|
+
check(checkListStructure(data11));
|
10
|
+
checkEqual(formatListInline(data11), "((1 (2 3 _) 4) (5 6 7) (8 (9 10 _) 11))");
|
11
|
+
checkArrayEqual([...listToItems(data11)], origin11);
|
12
|
+
checkArrayEqual([...listToItems(data11)], [...indexToItems(data11)]);
|
13
|
+
let emptyXs = new Array(0);
|
14
|
+
check(listEqual(initEmptyTernaryTreeList(), initTernaryTreeList(emptyXs)));
|
15
|
+
});
|
16
|
+
test("should perform basic list operations", () => {
|
17
|
+
let origin11 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
|
18
|
+
let data11 = initTernaryTreeList(origin11);
|
19
|
+
// get
|
20
|
+
for (let idx = 0; idx < origin11.length; idx++) {
|
21
|
+
check(origin11[idx] === listGet(data11, idx));
|
160
22
|
}
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
23
|
+
check(first(data11) === 1);
|
24
|
+
check(last(data11) === 11);
|
25
|
+
// assoc
|
26
|
+
let origin5 = [1, 2, 3, 4, 5];
|
27
|
+
let data5 = initTernaryTreeList(origin5);
|
28
|
+
let updated = assocList(data5, 3, 10);
|
29
|
+
check(listGet(updated, 3) === 10);
|
30
|
+
check(listGet(data5, 3) === 4);
|
31
|
+
check(listLen(updated) === listLen(data5));
|
32
|
+
for (let idx = 0; idx < listLen(data5); idx++) {
|
33
|
+
check(listLen(dissocList(data5, idx)) === listLen(data5) - 1);
|
34
|
+
}
|
35
|
+
checkEqual(formatListInline(data5), "((1 2 _) 3 (4 5 _))");
|
36
|
+
checkEqual(formatListInline(dissocList(data5, 0)), "(2 3 (4 5 _))");
|
37
|
+
checkEqual(formatListInline(dissocList(data5, 1)), "(1 3 (4 5 _))");
|
38
|
+
checkEqual(formatListInline(dissocList(data5, 2)), "((1 2 _) (4 5 _) _)");
|
39
|
+
checkEqual(formatListInline(dissocList(data5, 3)), "((1 2 _) 3 5)");
|
40
|
+
checkEqual(formatListInline(dissocList(data5, 4)), "((1 2 _) 3 4)");
|
41
|
+
checkEqual(formatListInline(rest(initTernaryTreeList([1]))), "_");
|
42
|
+
checkEqual(formatListInline(rest(initTernaryTreeList([1, 2]))), "2");
|
43
|
+
checkEqual(formatListInline(rest(initTernaryTreeList([1, 2, 3]))), "(2 3 _)");
|
44
|
+
checkEqual(formatListInline(rest(initTernaryTreeList([1, 2, 3, 4]))), "((2 3 _) 4 _)");
|
45
|
+
checkEqual(formatListInline(rest(initTernaryTreeList([1, 2, 3, 4, 5]))), "(2 3 (4 5 _))");
|
46
|
+
checkEqual(formatListInline(butlast(initTernaryTreeList([1]))), "_");
|
47
|
+
checkEqual(formatListInline(butlast(initTernaryTreeList([1, 2]))), "1");
|
48
|
+
checkEqual(formatListInline(butlast(initTernaryTreeList([1, 2, 3]))), "(1 2 _)");
|
49
|
+
checkEqual(formatListInline(butlast(initTernaryTreeList([1, 2, 3, 4]))), "(1 (2 3 _) _)");
|
50
|
+
checkEqual(formatListInline(butlast(initTernaryTreeList([1, 2, 3, 4, 5]))), "((1 2 _) 3 4)");
|
51
|
+
});
|
52
|
+
test("should handle list insertions", () => {
|
53
|
+
let origin5 = [1, 2, 3, 4, 5];
|
54
|
+
let data5 = initTernaryTreeList(origin5);
|
55
|
+
checkEqual(formatListInline(data5), "((1 2 _) 3 (4 5 _))");
|
56
|
+
checkEqual(formatListInline(insert(data5, 0, 10, false)), "(10 ((1 2 _) 3 (4 5 _)) _)");
|
57
|
+
checkEqual(formatListInline(insert(data5, 0, 10, true)), "((1 10 2) 3 (4 5 _))");
|
58
|
+
checkEqual(formatListInline(insert(data5, 1, 10, false)), "((1 10 2) 3 (4 5 _))");
|
59
|
+
checkEqual(formatListInline(insert(data5, 1, 10, true)), "((1 2 10) 3 (4 5 _))");
|
60
|
+
checkEqual(formatListInline(insert(data5, 2, 10, false)), "((1 2 _) (10 3 _) (4 5 _))");
|
61
|
+
checkEqual(formatListInline(insert(data5, 2, 10, true)), "((1 2 _) (3 10 _) (4 5 _))");
|
62
|
+
checkEqual(formatListInline(insert(data5, 3, 10, false)), "((1 2 _) 3 (10 4 5))");
|
63
|
+
checkEqual(formatListInline(insert(data5, 3, 10, true)), "((1 2 _) 3 (4 10 5))");
|
64
|
+
checkEqual(formatListInline(insert(data5, 4, 10, false)), "((1 2 _) 3 (4 10 5))");
|
65
|
+
checkEqual(formatListInline(insert(data5, 4, 10, true)), "(((1 2 _) 3 (4 5 _)) 10 _)");
|
66
|
+
let origin4 = [1, 2, 3, 4];
|
67
|
+
let data4 = initTernaryTreeList(origin4);
|
68
|
+
checkEqual(formatListInline(assocBefore(data4, 3, 10)), "(1 (2 3 _) (10 4 _))");
|
69
|
+
checkEqual(formatListInline(assocAfter(data4, 3, 10)), "(1 (2 3 _) (4 10 _))");
|
70
|
+
checkEqual(formatListInline(prepend(data4, 10)), "((10 1 _) (2 3 _) 4)");
|
71
|
+
checkEqual(formatListInline(append(data4, 10)), "(1 (2 3 _) (4 10 _))");
|
72
|
+
});
|
73
|
+
test("should handle list concatenation", () => {
|
74
|
+
let data1 = initTernaryTreeList([1, 2]);
|
75
|
+
let data2 = initTernaryTreeList([3, 4]);
|
76
|
+
let data3 = initTernaryTreeList([5, 6]);
|
77
|
+
let data4 = initTernaryTreeList([7, 8]);
|
78
|
+
check(formatListInline(concat(data1, data2)) === "(1 2 (3 4 _))");
|
79
|
+
check(formatListInline(concat(initTernaryTreeList([]), data1)) === "(1 2 _)");
|
80
|
+
check(formatListInline(concat(data1, data2, data3)) === "((1 2 _) (3 4 _) (5 6 _))");
|
81
|
+
check(formatListInline(concat(data1, data2, data3, data4)) === "((1 2 _) ((3 4 _) (5 6 _) _) (7 8 _))");
|
82
|
+
check(checkListStructure(concat(data1, data2)));
|
83
|
+
check(checkListStructure(concat(data1, data2, data3)));
|
84
|
+
check(checkListStructure(concat(data1, data2, data3, data4)));
|
85
|
+
check(listLen(concat(data1, data2, data3, data4)) === 8);
|
86
|
+
});
|
87
|
+
test("should check equality correctly", () => {
|
88
|
+
let origin4 = [1, 2, 3, 4];
|
89
|
+
let data4 = initTernaryTreeList(origin4);
|
90
|
+
let data4n = initTernaryTreeList(origin4);
|
91
|
+
let data4Made = prepend(initTernaryTreeList([2, 3, 4]), 1);
|
92
|
+
check(checkListStructure(data4));
|
93
|
+
check(checkListStructure(data4n));
|
94
|
+
check(checkListStructure(data4Made));
|
95
|
+
check(sameListShape(data4, data4) === true);
|
96
|
+
check(sameListShape(data4, data4n) === true);
|
97
|
+
check(sameListShape(data4, data4Made) === false);
|
98
|
+
check(listEqual(data4, data4n));
|
99
|
+
check(listEqual(data4, data4Made));
|
100
|
+
check(listEqual(data4n, data4Made));
|
101
|
+
check(data4 !== data4Made); // identical false
|
102
|
+
});
|
103
|
+
test("should force balancing correctly", () => {
|
104
|
+
var data = initTernaryTreeList([]);
|
105
|
+
for (let idx = 0; idx < 20; idx++) {
|
106
|
+
data = append(data, idx, true);
|
107
|
+
check(checkListStructure(data));
|
108
|
+
}
|
109
|
+
check(formatListInline(data) === "(((0 1 2) (3 4 5) (6 7 8)) ((9 10 11) (12 13 14) (15 16 17)) (18 19 _))");
|
110
|
+
forceListInplaceBalancing(data);
|
111
|
+
check(formatListInline(data) === "(((0 1 _) (2 3 4) (5 6 _)) ((7 8 _) (9 10 _) (11 12 _)) ((13 14 _) (15 16 17) (18 19 _)))");
|
112
|
+
});
|
113
|
+
test("should handle iteration correctly", () => {
|
114
|
+
let origin4 = [1, 2, 3, 4];
|
115
|
+
let data4 = initTernaryTreeList(origin4);
|
116
|
+
check(checkListStructure(data4));
|
117
|
+
var count = 0;
|
118
|
+
for (let item of listToItems(data4)) {
|
119
|
+
count = count + 1;
|
120
|
+
}
|
121
|
+
check(count === 4);
|
122
|
+
var indexSum = 0;
|
123
|
+
for (let [idx, item] of listToPairs(data4)) {
|
124
|
+
indexSum = indexSum + idx;
|
125
|
+
}
|
126
|
+
check(indexSum === 6);
|
127
|
+
});
|
128
|
+
test("should maintain structure integrity", () => {
|
129
|
+
var data = initTernaryTreeList([]);
|
130
|
+
for (let idx = 0; idx < 20; idx++) {
|
131
|
+
data = append(data, idx, true);
|
132
|
+
check(checkListStructure(data));
|
133
|
+
}
|
134
|
+
check(checkListStructure(data));
|
135
|
+
for (let idx = 0; idx < 20; idx++) {
|
136
|
+
data = rest(data);
|
137
|
+
check(checkListStructure(data));
|
138
|
+
}
|
139
|
+
let origin11 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
|
140
|
+
let data11 = initTernaryTreeList(origin11);
|
141
|
+
check(checkListStructure(data11));
|
142
|
+
check(checkListStructure(prepend(initEmptyTernaryTreeList(), 1)));
|
143
|
+
check(checkListStructure(prepend(null, 1)));
|
144
|
+
});
|
145
|
+
test("should handle slicing correctly", () => {
|
146
|
+
var data = initTernaryTreeList([]);
|
147
|
+
for (let idx = 0; idx < 40; idx++) {
|
148
|
+
data = append(data, idx, true);
|
149
|
+
}
|
150
|
+
var list40 = [];
|
151
|
+
for (let idx = 0; idx < 40; idx++) {
|
152
|
+
list40.push(idx);
|
153
|
+
}
|
154
|
+
for (let i = 0; i < 40; i++) {
|
155
|
+
for (let j = i; j < 40; j++) {
|
156
|
+
checkArrayEqual([...listToItems(slice(data, i, j))], list40.slice(i, j));
|
157
|
+
check(checkListStructure(slice(data, i, j)));
|
158
|
+
}
|
159
|
+
}
|
160
|
+
});
|
161
|
+
test("should reverse lists correctly", () => {
|
162
|
+
let data = initTernaryTreeList([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
|
163
|
+
let reversedData = reverse(data);
|
164
|
+
checkArrayEqual([...listToItems(reversedData)], [...listToItems(data)].reverse());
|
165
|
+
check(checkListStructure(reversedData));
|
166
|
+
});
|
167
|
+
test("should traverse lists correctly", () => {
|
168
|
+
var count = 0;
|
169
|
+
let data = initTernaryTreeList([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
|
170
|
+
check(checkListStructure(data));
|
171
|
+
for (let x of listToItems(data)) {
|
172
|
+
count = count + 1;
|
173
|
+
}
|
174
|
+
check(count === 10);
|
175
|
+
});
|
176
|
+
test("should find index correctly", () => {
|
177
|
+
let data = initTernaryTreeList([1, 2, 3, 4, 5, 6, 7, 8]);
|
178
|
+
check(indexOf(data, 2) === 1);
|
179
|
+
check(findIndex(data, (x) => x === 2) === 1);
|
180
|
+
check(indexOf(data, 9) === -1);
|
181
|
+
check(findIndex(data, (x) => x === 9) === -1);
|
182
|
+
});
|
183
|
+
test("should map values correctly", () => {
|
184
|
+
let data = initTernaryTreeList([1, 2, 3, 4]);
|
185
|
+
let data2 = initTernaryTreeList([1, 4, 9, 16]);
|
186
|
+
let data3 = listMapValues(data, (x) => x * x);
|
187
|
+
check(checkListStructure(data3));
|
188
|
+
check(listEqual(data2, data3));
|
189
|
+
check(formatListInline(data2) === formatListInline(data3));
|
190
|
+
});
|
191
|
+
test("should handle range initialization", () => {
|
192
|
+
let data1 = initTernaryTreeList([3, 4]);
|
193
|
+
let data2 = initTernaryTreeListFromRange([1, 2, 3, 4, 5, 6], 2, 4);
|
194
|
+
check(listEqual(data1, data2));
|
195
|
+
check(checkListStructure(data1));
|
196
|
+
check(checkListStructure(data2));
|
197
|
+
});
|
198
|
+
test("should handle concat loop stress test", () => {
|
199
|
+
let data1 = initTernaryTreeList([3, 4]);
|
200
|
+
let data2 = initTernaryTreeList([5]);
|
201
|
+
for (let i = 0; i < 100; i++) {
|
202
|
+
data1 = concat2(data1, data2);
|
203
|
+
}
|
204
|
+
console.log("concat into depth", formatListInline(data1));
|
205
|
+
});
|
207
206
|
});
|
208
207
|
};
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare function runPerformanceTests(): void;
|
@@ -0,0 +1,70 @@
|
|
1
|
+
import { initTernaryTreeMap, initTernaryTreeMapFromArray, assocMap, contains, mapGetDefault, dissocMap, toPairsArray, initEmptyTernaryTreeMap, } from "./map.mjs";
|
2
|
+
function createTestData(size) {
|
3
|
+
const data = [];
|
4
|
+
for (let i = 0; i < size; i++) {
|
5
|
+
data.push([i, `value_${i}`]);
|
6
|
+
}
|
7
|
+
return data;
|
8
|
+
}
|
9
|
+
function measureTime(name, fn) {
|
10
|
+
const start = performance.now();
|
11
|
+
const result = fn();
|
12
|
+
const end = performance.now();
|
13
|
+
console.log(`${name}: ${(end - start).toFixed(2)}ms`);
|
14
|
+
return result;
|
15
|
+
}
|
16
|
+
export function runPerformanceTests() {
|
17
|
+
console.log("\n=== Performance Tests ===");
|
18
|
+
const sizes = [100, 1000, 5000, 10000];
|
19
|
+
for (const size of sizes) {
|
20
|
+
console.log(`\n--- Testing with ${size} elements ---`);
|
21
|
+
const testData = createTestData(size);
|
22
|
+
const mapData = new Map(testData);
|
23
|
+
// Test initTernaryTreeMapFromArray
|
24
|
+
const treeFromArray = measureTime(`initTernaryTreeMapFromArray(${size})`, () => {
|
25
|
+
return initTernaryTreeMapFromArray(testData);
|
26
|
+
});
|
27
|
+
// Test initTernaryTreeMap
|
28
|
+
const treeFromMap = measureTime(`initTernaryTreeMap(${size})`, () => {
|
29
|
+
return initTernaryTreeMap(mapData);
|
30
|
+
});
|
31
|
+
// Test sequential assoc operations
|
32
|
+
measureTime(`Sequential assoc(${size})`, () => {
|
33
|
+
let tree = initEmptyTernaryTreeMap();
|
34
|
+
for (const [k, v] of testData) {
|
35
|
+
tree = assocMap(tree, k, v);
|
36
|
+
}
|
37
|
+
return tree;
|
38
|
+
});
|
39
|
+
// Test lookups
|
40
|
+
const lookupKeys = testData.slice(0, Math.min(100, size)).map(([k]) => k);
|
41
|
+
measureTime(`Lookups(${lookupKeys.length})`, () => {
|
42
|
+
for (const key of lookupKeys) {
|
43
|
+
contains(treeFromArray, key);
|
44
|
+
mapGetDefault(treeFromArray, key, "default");
|
45
|
+
}
|
46
|
+
});
|
47
|
+
// Test dissoc operations
|
48
|
+
const dissocKeys = testData.slice(0, Math.min(50, size)).map(([k]) => k);
|
49
|
+
measureTime(`Dissoc(${dissocKeys.length})`, () => {
|
50
|
+
let tree = treeFromArray;
|
51
|
+
for (const key of dissocKeys) {
|
52
|
+
tree = dissocMap(tree, key);
|
53
|
+
}
|
54
|
+
return tree;
|
55
|
+
});
|
56
|
+
// Test toPairsArray
|
57
|
+
measureTime(`toPairsArray(${size})`, () => {
|
58
|
+
return toPairsArray(treeFromArray);
|
59
|
+
});
|
60
|
+
}
|
61
|
+
console.log("\n=== Memory usage test ===");
|
62
|
+
const largeData = createTestData(50000);
|
63
|
+
console.log(`Testing with ${largeData.length} elements for memory efficiency`);
|
64
|
+
measureTime("Large dataset creation", () => {
|
65
|
+
return initTernaryTreeMapFromArray(largeData);
|
66
|
+
});
|
67
|
+
}
|
68
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
69
|
+
runPerformanceTests();
|
70
|
+
}
|