-
-
Notifications
You must be signed in to change notification settings - Fork 61
/
OrderedMap.ts
178 lines (174 loc) · 5.49 KB
/
OrderedMap.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
import TreeContainer from './Base';
import TreeIterator from './Base/TreeIterator';
import { TreeNode } from './Base/TreeNode';
import { initContainer, IteratorType } from '@/container/ContainerBase';
import $checkWithinAccessParams from '@/utils/checkParams.macro';
import { throwIteratorAccessError } from '@/utils/throwError';
class OrderedMapIterator<K, V> extends TreeIterator<K, V> {
container: OrderedMap<K, V>;
constructor(
node: TreeNode<K, V>,
header: TreeNode<K, V>,
container: OrderedMap<K, V>,
iteratorType?: IteratorType
) {
super(node, header, iteratorType);
this.container = container;
}
get pointer() {
if (this._node === this._header) {
throwIteratorAccessError();
}
const self = this;
return new Proxy(<[K, V]><unknown>[], {
get(target, prop: '0' | '1') {
if (prop === '0') return self._node._key!;
else if (prop === '1') return self._node._value!;
target[0] = self._node._key!;
target[1] = self._node._value!;
return target[prop];
},
set(_, prop: '1', newValue: V) {
if (prop !== '1') {
throw new TypeError('prop must be 1');
}
self._node._value = newValue;
return true;
}
});
}
copy() {
return new OrderedMapIterator<K, V>(
this._node,
this._header,
this.container,
this.iteratorType
);
}
// @ts-ignore
equals(iter: OrderedMapIterator<K, V>): boolean;
}
export type { OrderedMapIterator };
class OrderedMap<K, V> extends TreeContainer<K, V> {
/**
* @param container - The initialization container.
* @param cmp - The compare function.
* @param enableIndex - Whether to enable iterator indexing function.
* @example
* new OrderedMap();
* new OrderedMap([[0, 1], [2, 1]]);
* new OrderedMap([[0, 1], [2, 1]], (x, y) => x - y);
* new OrderedMap([[0, 1], [2, 1]], (x, y) => x - y, true);
*/
constructor(
container: initContainer<[K, V]> = [],
cmp?: (x: K, y: K) => number,
enableIndex?: boolean
) {
super(cmp, enableIndex);
const self = this;
container.forEach(function (el) {
self.setElement(el[0], el[1]);
});
}
begin() {
return new OrderedMapIterator<K, V>(this._header._left || this._header, this._header, this);
}
end() {
return new OrderedMapIterator<K, V>(this._header, this._header, this);
}
rBegin() {
return new OrderedMapIterator<K, V>(
this._header._right || this._header,
this._header,
this,
IteratorType.REVERSE
);
}
rEnd() {
return new OrderedMapIterator<K, V>(this._header, this._header, this, IteratorType.REVERSE);
}
front() {
if (this._length === 0) return;
const minNode = this._header._left!;
return <[K, V]>[minNode._key, minNode._value];
}
back() {
if (this._length === 0) return;
const maxNode = this._header._right!;
return <[K, V]>[maxNode._key, maxNode._value];
}
lowerBound(key: K) {
const resNode = this._lowerBound(this._root, key);
return new OrderedMapIterator<K, V>(resNode, this._header, this);
}
upperBound(key: K) {
const resNode = this._upperBound(this._root, key);
return new OrderedMapIterator<K, V>(resNode, this._header, this);
}
reverseLowerBound(key: K) {
const resNode = this._reverseLowerBound(this._root, key);
return new OrderedMapIterator<K, V>(resNode, this._header, this);
}
reverseUpperBound(key: K) {
const resNode = this._reverseUpperBound(this._root, key);
return new OrderedMapIterator<K, V>(resNode, this._header, this);
}
forEach(callback: (element: [K, V], index: number, map: OrderedMap<K, V>) => void) {
this._inOrderTraversal(function (node, index, map) {
callback(<[K, V]>[node._key, node._value], index, map);
});
}
/**
* @description Insert a key-value pair or set value by the given key.
* @param key - The key want to insert.
* @param value - The value want to set.
* @param hint - You can give an iterator hint to improve insertion efficiency.
* @return The size of container after setting.
* @example
* const mp = new OrderedMap([[2, 0], [4, 0], [5, 0]]);
* const iter = mp.begin();
* mp.setElement(1, 0);
* mp.setElement(3, 0, iter); // give a hint will be faster.
*/
setElement(key: K, value: V, hint?: OrderedMapIterator<K, V>) {
return this._set(key, value, hint);
}
getElementByPos(pos: number) {
$checkWithinAccessParams!(pos, 0, this._length - 1);
const node = this._inOrderTraversal(pos);
return <[K, V]>[node._key, node._value];
}
find(key: K) {
const curNode = this._getTreeNodeByKey(this._root, key);
return new OrderedMapIterator<K, V>(curNode, this._header, this);
}
/**
* @description Get the value of the element of the specified key.
* @param key - The specified key you want to get.
* @example
* const val = container.getElementByKey(1);
*/
getElementByKey(key: K) {
const curNode = this._getTreeNodeByKey(this._root, key);
return curNode._value;
}
union(other: OrderedMap<K, V>) {
const self = this;
other.forEach(function (el) {
self.setElement(el[0], el[1]);
});
return this._length;
}
* [Symbol.iterator]() {
const length = this._length;
const nodeList = this._inOrderTraversal();
for (let i = 0; i < length; ++i) {
const node = nodeList[i];
yield <[K, V]>[node._key, node._value];
}
}
// @ts-ignore
eraseElementByIterator(iter: OrderedMapIterator<K, V>): OrderedMapIterator<K, V>;
}
export default OrderedMap;