@blackglory/structures 0.13.3 → 0.14.0

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.
Files changed (66) hide show
  1. package/lib/array.js.map +1 -1
  2. package/lib/big-map.js.map +1 -1
  3. package/lib/big-set.js.map +1 -1
  4. package/lib/bit-set.js.map +1 -1
  5. package/lib/box.js +3 -3
  6. package/lib/box.js.map +1 -1
  7. package/lib/cons.js.map +1 -1
  8. package/lib/dynamic-typed-array.js +10 -10
  9. package/lib/dynamic-typed-array.js.map +1 -1
  10. package/lib/emitter.d.ts +1 -1
  11. package/lib/emitter.js.map +1 -1
  12. package/lib/expirable-map.js.map +1 -1
  13. package/lib/hash-map.js +4 -4
  14. package/lib/hash-map.js.map +1 -1
  15. package/lib/hash-set.js +4 -4
  16. package/lib/hash-set.js.map +1 -1
  17. package/lib/lru-map.js +6 -6
  18. package/lib/lru-map.js.map +1 -1
  19. package/lib/queue.js.map +1 -1
  20. package/lib/radix-tree.js.map +1 -1
  21. package/lib/sorted-set.js +3 -3
  22. package/lib/sorted-set.js.map +1 -1
  23. package/lib/sparse-map.js.map +1 -1
  24. package/lib/sparse-set.js +9 -9
  25. package/lib/sparse-set.js.map +1 -1
  26. package/lib/string-radix-tree.js.map +1 -1
  27. package/lib/string-trie-map.js +1 -1
  28. package/lib/string-trie-map.js.map +1 -1
  29. package/lib/tlru-map.js +6 -6
  30. package/lib/tlru-map.js.map +1 -1
  31. package/lib/trie-map.js +1 -1
  32. package/lib/trie-map.js.map +1 -1
  33. package/lib/typed-bit-set.js.map +1 -1
  34. package/lib/typed-sparse-map.js +6 -6
  35. package/lib/typed-sparse-map.js.map +1 -1
  36. package/lib/typed-sparse-set.js.map +1 -1
  37. package/lib/utils/skip-list.js +3 -3
  38. package/lib/utils/skip-list.js.map +1 -1
  39. package/package.json +31 -31
  40. package/src/array.ts +19 -0
  41. package/src/big-map.ts +98 -0
  42. package/src/big-set.ts +72 -0
  43. package/src/bit-set.ts +124 -0
  44. package/src/box.ts +15 -0
  45. package/src/cons.ts +15 -0
  46. package/src/dynamic-typed-array.ts +201 -0
  47. package/src/emitter.ts +76 -0
  48. package/src/expirable-map.ts +122 -0
  49. package/src/hash-map.ts +34 -0
  50. package/src/hash-set.ts +38 -0
  51. package/src/index.ts +24 -0
  52. package/src/lru-map.ts +69 -0
  53. package/src/queue.ts +30 -0
  54. package/src/radix-tree.ts +264 -0
  55. package/src/sorted-set.ts +34 -0
  56. package/src/sparse-map.ts +83 -0
  57. package/src/sparse-set.ts +67 -0
  58. package/src/string-radix-tree.ts +263 -0
  59. package/src/string-trie-map.ts +102 -0
  60. package/src/tlru-map.ts +162 -0
  61. package/src/trie-map.ts +102 -0
  62. package/src/typed-bit-set.ts +129 -0
  63. package/src/typed-sparse-map.ts +97 -0
  64. package/src/typed-sparse-set.ts +71 -0
  65. package/src/utils/skip-list.ts +195 -0
  66. package/src/utils/trailing-zeros.ts +15 -0
@@ -0,0 +1,264 @@
1
+ import { toArray, first, map, find } from 'iterable-operator'
2
+ import { isntUndefined } from 'extra-utils'
3
+
4
+ class TreeNode<T, U> {
5
+ children = new Map<T[], TreeNode<T, U>>()
6
+
7
+ constructor(public value?: U) {}
8
+ }
9
+
10
+ export class RadixTree<K extends Iterable<T>, V, T = unknown> {
11
+ private root = new TreeNode<T, V>()
12
+
13
+ get [Symbol.toStringTag](): string {
14
+ return this.constructor.name
15
+ }
16
+
17
+ entries(): IterableIterator<[key: T[], value: V]> {
18
+ return dfs(this.root, [])
19
+
20
+ function* dfs(
21
+ node: TreeNode<T, V>
22
+ , path: T[]
23
+ ): IterableIterator<[key: T[], value: V]> {
24
+ for (const [prefix, childNode] of node.children) {
25
+ const newPath = [...path, ...prefix]
26
+ if (isntUndefined(childNode.value)) {
27
+ yield [newPath, childNode.value]
28
+ }
29
+
30
+ yield* dfs(childNode, newPath)
31
+ }
32
+ }
33
+ }
34
+
35
+ keys(): IterableIterator<T[]> {
36
+ return map(this.entries(), ([key]) => key)
37
+ }
38
+
39
+ values(): IterableIterator<V> {
40
+ return map(this.entries(), ([, value]) => value)
41
+ }
42
+
43
+ set(key: K, value: V): this {
44
+ set(toArray(key), value, this.root)
45
+ return this
46
+
47
+ function set(key: T[], value: V, node: TreeNode<T, V>): void {
48
+ const commonPrefix = findCommonPrefix(node.children.keys(), key)
49
+ if (isntUndefined(commonPrefix)) {
50
+ const { prefix, commonPartLength } = commonPrefix
51
+ if (prefix.length === commonPartLength) {
52
+ // 现有节点的前缀整个都被使用的情况, 不需要在这一级创建新的前缀节点.
53
+ const prefixNode = node.children.get(prefix)!
54
+
55
+ if (key.length === prefix.length) {
56
+ // 前缀节点就是目标节点.
57
+ prefixNode.value = value
58
+ } else {
59
+ // 前缀节点不是目标节点
60
+ const newKey = key.slice(prefix.length)
61
+ set(newKey, value, prefixNode)
62
+ }
63
+ } else {
64
+ // 并非整个现有节点的前缀都被使用, 说明需要在这一级创建新的前缀节点,
65
+ // 并将原前缀节点作为子节点接在新前缀节点之后.
66
+ const oldPrefixNode = node.children.get(prefix)!
67
+ const commonPrefix = prefix.slice(0, commonPartLength)
68
+ const newPrefixNode = new TreeNode<T, V>()
69
+ node.children.set(commonPrefix, newPrefixNode)
70
+ newPrefixNode.children.set(prefix.slice(commonPartLength), oldPrefixNode)
71
+ newPrefixNode.children.set(key.slice(commonPartLength), new TreeNode<T, V>(value))
72
+ node.children.delete(prefix)
73
+ }
74
+ } else {
75
+ node.children.set(key, new TreeNode(value))
76
+ }
77
+ }
78
+ }
79
+
80
+ has(key: K): boolean {
81
+ return has(toArray(key), this.root)
82
+
83
+ function has(key: T[], node: TreeNode<T, V>): boolean {
84
+ const matchedPrefix = matchPrefix(node.children.keys(), key)
85
+ if (isntUndefined(matchedPrefix)) {
86
+ const restKey = key.slice(matchedPrefix.length)
87
+ if (restKey.length === 0) {
88
+ return true
89
+ } else {
90
+ return has(restKey, node.children.get(matchedPrefix)!)
91
+ }
92
+ } else {
93
+ return false
94
+ }
95
+ }
96
+ }
97
+
98
+ get(key: K): V | undefined {
99
+ return get(toArray(key), this.root)
100
+
101
+ function get(key: T[], node: TreeNode<T, V>): V | undefined {
102
+ const matchedPrefix = matchPrefix(node.children.keys(), key)
103
+ if (isntUndefined(matchedPrefix)) {
104
+ const restKey = key.slice(matchedPrefix.length)
105
+ const nextNode = node.children.get(matchedPrefix)!
106
+ if (restKey.length === 0) {
107
+ return nextNode.value
108
+ } else {
109
+ return get(restKey, nextNode)
110
+ }
111
+ } else {
112
+ return undefined
113
+ }
114
+ }
115
+ }
116
+
117
+ delete(key: K): boolean {
118
+ return _delete(toArray(key), this.root)
119
+
120
+ function _delete(key: T[], node: TreeNode<T, V>): boolean {
121
+ const matchedPrefix = matchPrefix(node.children.keys(), key)
122
+ if (isntUndefined(matchedPrefix)) {
123
+ if (key.length === matchedPrefix.length) {
124
+ // 下一个子节点就是目标节点.
125
+ const targetNode = node.children.get(matchedPrefix)!
126
+ if (targetNode.children.size === 0) {
127
+ // 要删除的目标节点不是一个父节点, 可以直接删除.
128
+ // 与目标节点共享相同前缀的其他节点可能会因此这次的删除而导致发生与父节点的合并.
129
+ node.children.delete(matchedPrefix)
130
+ } else {
131
+ // 要删除的目标节点是一个父节点, 首先删除目标节点包含的值, 然后检查它的子节点是否只有一个.
132
+ delete node.value
133
+ if (targetNode.children.size === 1) {
134
+ // 如果子节点只有一个, 说明目标节点的子节点可以与目标节点合并.
135
+ // 即`(prefix, child)`合并为`(prefixchild)`.
136
+ const [key, value] = first(targetNode.children.entries())!
137
+ node.children.set([...matchedPrefix, ...key], value)
138
+ node.children.delete(matchedPrefix)
139
+ }
140
+ }
141
+ return true
142
+ } else {
143
+ // 下一个子节点不是目标节点.
144
+ const nextNode = node.children.get(matchedPrefix)!
145
+ const nextKey = key.slice(matchedPrefix.length)
146
+ const deleted = _delete(nextKey, nextNode)
147
+ if (deleted) {
148
+ // 最终找到了目标节点并删除了它, 现在执行与nextNode有关的合并操作, 以删除不必要的节点.
149
+ if (!('value' in nextNode)) {
150
+ // 只有在nextNode自身不具有值的情况下, nextNode才是能够被合并的.
151
+ switch (nextNode.children.size) {
152
+ case 0: {
153
+ // 自身没有值的nextNode节点是不必要的, 因为它不是一个父节点.
154
+ node.children.delete(matchedPrefix)
155
+ break
156
+ }
157
+ case 1: {
158
+ // 自身没有值的nextNode节点是不必要的, 虽然它是一个父节点, 但它只有一个子节点.
159
+ // 这说明nextNode的子节点可以与nextNode合并, 替代nextNode当前的位置.
160
+ // 即`(prefix, child)`合并为`(prefixchild)`.
161
+ const [key, value] = first(nextNode.children.entries())!
162
+ node.children.set([...matchedPrefix, ...key], value)
163
+ node.children.delete(matchedPrefix)
164
+ break
165
+ }
166
+ default: {
167
+ // 自身没有值, 但起前缀作用的nextNode节点是必要的,
168
+ // 但在有后代被删除的情况下, 可能会需要合并子节点的前缀.
169
+ // 在此检查子节点的前缀, 如果子节点具有共同前缀, 则合并前缀.
170
+ const entries = toArray(nextNode.children.entries())
171
+ const keys = entries.map(([key]) => key)
172
+ const commonPrefix = getCommonPrefix(keys)
173
+ if (commonPrefix) {
174
+ const newPrefix = [...matchedPrefix, ...commonPrefix]
175
+ const childNode = new TreeNode<T, V>()
176
+ for (const [key, value] of entries) {
177
+ childNode.children.set(key.slice(commonPrefix.length), value)
178
+ }
179
+ node.children.set(newPrefix, childNode)
180
+ node.children.delete(matchedPrefix)
181
+ }
182
+ }
183
+ }
184
+ }
185
+ return true
186
+ } else {
187
+ // 最终没有找到目标节点.
188
+ return false
189
+ }
190
+ }
191
+ } else {
192
+ return false
193
+ }
194
+ }
195
+ }
196
+ }
197
+
198
+ /**
199
+ * 查找prefixes里与path的前缀匹配的项目.
200
+ *
201
+ * @param prefixes 所有前缀都不能在首部有重合.
202
+ */
203
+ export function matchPrefix<T>(prefixes: Iterable<T[]>, path: T[]): T[] | undefined {
204
+ return find(prefixes, prefix => path[0] === prefix[0])
205
+ }
206
+
207
+ /**
208
+ * 查找prefixes与path的共同前缀, 结果可能是其中一整个prefix, 或者其中一个prefix的前缀部分.
209
+ *
210
+ * @param prefixes 所有前缀都不能在首部有重合.
211
+ */
212
+ export function findCommonPrefix<T>(prefixes: Iterable<T[]>, path: T[]): {
213
+ prefix: T[]
214
+ commonPartLength: number
215
+ } | undefined {
216
+ for (const prefix of prefixes) {
217
+ let commonPartLength = 0
218
+ for (let i = 0; i < prefix.length; i++) {
219
+ if (path[i] === prefix[i]) {
220
+ commonPartLength++
221
+ } else {
222
+ if (commonPartLength > 0) {
223
+ return { prefix, commonPartLength }
224
+ }
225
+ }
226
+ }
227
+ if (commonPartLength > 0) {
228
+ return { prefix, commonPartLength }
229
+ }
230
+ }
231
+ }
232
+
233
+
234
+ /**
235
+ * 返回一组可迭代值的共同前缀.
236
+ */
237
+ export function getCommonPrefix<T>(paths: T[][]): T[] {
238
+ if (paths.length > 0) {
239
+ const commonPrefix: T[] = []
240
+
241
+ loop: for (
242
+ let elementIndex = 0, firstPathLength = paths[0].length
243
+ ; elementIndex < firstPathLength
244
+ ; elementIndex++
245
+ ) {
246
+ const element = paths[0][elementIndex]
247
+ for (let pathIndex = 1; pathIndex < paths.length; pathIndex++) {
248
+ const path = paths[pathIndex]
249
+ if (elementIndex < path.length) {
250
+ if (path[elementIndex] !== element) {
251
+ break loop
252
+ }
253
+ } else {
254
+ break loop
255
+ }
256
+ }
257
+ commonPrefix.push(element)
258
+ }
259
+
260
+ return commonPrefix
261
+ } else {
262
+ return []
263
+ }
264
+ }
@@ -0,0 +1,34 @@
1
+ import { SkipList } from '@utils/skip-list.js'
2
+ import { map } from 'iterable-operator'
3
+
4
+ export class SortedSet<T> implements Iterable<T> {
5
+ private skipList: SkipList<T>
6
+
7
+ get [Symbol.toStringTag](): string {
8
+ return this.constructor.name
9
+ }
10
+
11
+ [Symbol.iterator](): IterableIterator<T> {
12
+ return this.values()
13
+ }
14
+
15
+ constructor(compare: (a: T, b: T) => number) {
16
+ this.skipList = new SkipList(compare)
17
+ }
18
+
19
+ values(): IterableIterator<T> {
20
+ return map(this.skipList.elements(), node => node.value!)
21
+ }
22
+
23
+ has(value: T): boolean {
24
+ return this.skipList.has(value)
25
+ }
26
+
27
+ add(value: T): void {
28
+ this.skipList.add(value)
29
+ }
30
+
31
+ delete(value: T): void {
32
+ this.skipList.delete(value)
33
+ }
34
+ }
@@ -0,0 +1,83 @@
1
+ export class SparseMap<T> {
2
+ private keyToIndex: Array<number | undefined> = []
3
+ private indexToKey: number[] = []
4
+ private indexToValue: T[] = []
5
+
6
+ get [Symbol.toStringTag](): string {
7
+ return this.constructor.name
8
+ }
9
+
10
+ get size(): number {
11
+ return this.indexToKey.length
12
+ }
13
+
14
+ get internalArray(): T[] {
15
+ return this.indexToValue
16
+ }
17
+
18
+ * entries(): IterableIterator<[key: number, value: T]> {
19
+ for (let i = 0; i < this.indexToKey.length; i++) {
20
+ yield [this.indexToKey[i], this.indexToValue[i]]
21
+ }
22
+ }
23
+
24
+ keys(): IterableIterator<number> {
25
+ return this.indexToKey.values()
26
+ }
27
+
28
+ values(): IterableIterator<T> {
29
+ return this.indexToValue.values()
30
+ }
31
+
32
+ getInternalIndexOfKey(key: number): number | undefined {
33
+ return this.keyToIndex[key]
34
+ }
35
+
36
+ has(key: number): boolean {
37
+ // 跟一般的稀疏集实现不同, 不需要访问values数组.
38
+ return key in this.keyToIndex
39
+ }
40
+
41
+ get(key: number): T | undefined {
42
+ if (this.has(key)) {
43
+ const index = this.keyToIndex[key]!
44
+ return this.indexToValue[index]
45
+ } else {
46
+ return undefined
47
+ }
48
+ }
49
+
50
+ set(key: number, value: T): void {
51
+ if (this.has(key)) {
52
+ const index = this.keyToIndex[key]!
53
+ this.indexToValue[index] = value
54
+ } else {
55
+ const index = this.indexToKey.length
56
+ this.indexToKey.push(key)
57
+ this.indexToValue.push(value)
58
+ this.keyToIndex[key] = index
59
+ }
60
+ }
61
+
62
+ delete(key: number): void {
63
+ if (this.has(key)) {
64
+ const lastKey = this.indexToKey.pop()!
65
+ const lastValue = this.indexToValue.pop()!
66
+ if (key === lastKey) {
67
+ delete this.keyToIndex[key]
68
+ } else {
69
+ const index = this.keyToIndex[key]!
70
+ this.indexToKey[index] = lastKey
71
+ this.indexToValue[index] = lastValue
72
+ this.keyToIndex[lastKey] = index
73
+ delete this.keyToIndex[key]
74
+ }
75
+ }
76
+ }
77
+
78
+ clear(): void {
79
+ this.keyToIndex.length = 0
80
+ this.indexToKey.length = 0
81
+ this.indexToValue.length = 0
82
+ }
83
+ }
@@ -0,0 +1,67 @@
1
+ export class SparseSet implements Iterable<number> {
2
+ private indexToValue: number[] = []
3
+ private valueToIndex: Array<number | undefined>
4
+
5
+ get [Symbol.toStringTag](): string {
6
+ return this.constructor.name
7
+ }
8
+
9
+ [Symbol.iterator](): IterableIterator<number> {
10
+ return this.indexToValue[Symbol.iterator]()
11
+ }
12
+
13
+ get size(): number {
14
+ return this.indexToValue.length
15
+ }
16
+
17
+ constructor(array: number[] = []) {
18
+ const valueToIndex: Array<number | undefined> = []
19
+ if (array.length > 0) {
20
+ for (const [index, value] of array.entries()) {
21
+ valueToIndex[value] = index
22
+ }
23
+ }
24
+
25
+ this.valueToIndex = valueToIndex
26
+ }
27
+
28
+ values(): IterableIterator<number> {
29
+ return this.indexToValue[Symbol.iterator]()
30
+ }
31
+
32
+ has(value: number): boolean {
33
+ // 跟一般的实现不同, 不需要访问values数组.
34
+ return value in this.valueToIndex
35
+ }
36
+
37
+ add(value: number): void {
38
+ if (!this.has(value)) {
39
+ const index = this.indexToValue.length
40
+ this.indexToValue.push(value)
41
+ this.valueToIndex[value] = index
42
+ }
43
+ }
44
+
45
+ delete(value: number): boolean {
46
+ if (this.has(value)) {
47
+ const lastValue = this.indexToValue.pop()!
48
+ if (value === lastValue) {
49
+ delete this.valueToIndex[value]
50
+ } else {
51
+ const index = this.valueToIndex[value]!
52
+ this.indexToValue[index] = lastValue
53
+ this.valueToIndex[lastValue] = index
54
+ // 跟一般的实现不同, 直接删除值的索引.
55
+ delete this.valueToIndex[value]
56
+ }
57
+ return true
58
+ } else {
59
+ return false
60
+ }
61
+ }
62
+
63
+ clear(): void {
64
+ this.indexToValue.length = 0
65
+ this.valueToIndex.length = 0
66
+ }
67
+ }