Skip to content

Commit ce43424

Browse files
committed
feat(util): 🎸 improve AvlMap iteration strategies
1 parent 65af848 commit ce43424

File tree

2 files changed

+80
-7
lines changed

2 files changed

+80
-7
lines changed

src/util/trees/avl/AvlMap.ts

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -105,20 +105,38 @@ export class AvlMap<K, V> implements Printable {
105105
while ((curr = next(curr as HeadlessNode) as AvlNode<K, V> | undefined));
106106
}
107107

108-
public iterator(): Iterator<AvlNode<K, V>> {
108+
public first(): AvlNode<K, V> | undefined {
109109
const root = this.root;
110-
if (!root) return {next: () => ({done: true, value: undefined})};
111-
let curr = first(root);
110+
return root ? first(root) : undefined;
111+
}
112+
113+
public readonly next = next;
114+
115+
public iterator0(): (() => undefined | AvlNode<K, V>) {
116+
let curr = this.first();
117+
return () => {
118+
if (!curr) return undefined;
119+
const value = curr;
120+
curr = next(curr as HeadlessNode) as AvlNode<K, V> | undefined;
121+
return value;
122+
};
123+
}
124+
125+
public iterator(): Iterator<AvlNode<K, V>> {
126+
const iterator = this.iterator0();
112127
return {
113128
next: () => {
114-
if (!curr) return {done: true, value: undefined};
115-
const value = curr;
116-
curr = next(curr as HeadlessNode) as AvlNode<K, V> | undefined;
117-
return {done: false, value};
129+
const value = iterator();
130+
const res = <IteratorResult<AvlNode<K, V>>>{value, done: !value};
131+
return res;
118132
},
119133
};
120134
}
121135

136+
public entries(): IterableIterator<AvlNode<K, V>> {
137+
return <any>{[Symbol.iterator]: () => this.iterator()};
138+
}
139+
122140
public toString(tab: string): string {
123141
return this.constructor.name + printTree(tab, [(tab) => print(this.root, tab)]);
124142
}

src/util/trees/avl/__tests__/AvlMap.spec.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,47 @@ test('smoke test', () => {
1515
expect(keys).toEqual([1, 3, 4, 4.1, 44]);
1616
});
1717

18+
describe('.first()/next() iteration', () => {
19+
test('for empty map, returns finished iterator', () => {
20+
const tree = new AvlMap<string, number>();
21+
const entry = tree.first();
22+
expect(entry).toEqual(undefined);
23+
});
24+
25+
test('can iterate through map entries', () => {
26+
const tree = new AvlMap<string, number>();
27+
tree.set('a', 1);
28+
tree.set('b', 2);
29+
tree.set('c', 3);
30+
const list: [string, number][] = [];
31+
for (let entry = tree.first(); entry; entry = tree.next(entry)) {
32+
list.push([entry.k, entry.v]);
33+
}
34+
expect(list).toEqual([['a', 1], ['b', 2], ['c', 3]]);
35+
});
36+
});
37+
38+
describe('.iterator0()', () => {
39+
test('for empty map, returns finished iterator', () => {
40+
const tree = new AvlMap<string, number>();
41+
const iterator = tree.iterator0();
42+
const entry = iterator();
43+
expect(entry).toEqual(undefined);
44+
});
45+
46+
test('can iterate through map entries', () => {
47+
const tree = new AvlMap<string, number>();
48+
tree.set('a', 1);
49+
tree.set('b', 2);
50+
tree.set('c', 3);
51+
const list: [string, number][] = [];
52+
const iterator = tree.iterator0();
53+
for (let entry = iterator(); entry; entry = iterator()) {
54+
list.push([entry.k, entry.v]);
55+
}
56+
expect(list).toEqual([['a', 1], ['b', 2], ['c', 3]]);
57+
});
58+
});
1859

1960
describe('.iterator()', () => {
2061
test('for empty map, returns finished iterator', () => {
@@ -37,3 +78,17 @@ describe('.iterator()', () => {
3778
expect(list).toEqual([['a', 1], ['b', 2], ['c', 3]]);
3879
});
3980
});
81+
82+
describe('for...of iteration', () => {
83+
test('can iterate through map entries', () => {
84+
const tree = new AvlMap<string, number>();
85+
tree.set('a', 1);
86+
tree.set('b', 2);
87+
tree.set('c', 3);
88+
const list: [string, number][] = [];
89+
for (const entry of tree.entries()) {
90+
list.push([entry.k, entry.v]);
91+
}
92+
expect(list).toEqual([['a', 1], ['b', 2], ['c', 3]]);
93+
});
94+
});

0 commit comments

Comments
 (0)