@blackglory/structures 0.14.14 → 0.15.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 (207) hide show
  1. package/README.md +661 -92
  2. package/lib/async-generator-emitter.js +2 -5
  3. package/lib/async-generator-emitter.js.map +1 -1
  4. package/lib/big-map.js +1 -3
  5. package/lib/big-map.js.map +1 -1
  6. package/lib/big-set.js +1 -3
  7. package/lib/big-set.js.map +1 -1
  8. package/lib/{bit-set.d.ts → bit-set/bit-set.d.ts} +5 -2
  9. package/lib/{bit-set.js → bit-set/bit-set.js} +43 -34
  10. package/lib/bit-set/bit-set.js.map +1 -0
  11. package/lib/{typed-bit-set.d.ts → bit-set/dynamic-typed-bit-set.d.ts} +6 -4
  12. package/lib/bit-set/dynamic-typed-bit-set.js +95 -0
  13. package/lib/bit-set/dynamic-typed-bit-set.js.map +1 -0
  14. package/lib/bit-set/index.d.ts +4 -0
  15. package/lib/bit-set/index.js +5 -0
  16. package/lib/bit-set/index.js.map +1 -0
  17. package/lib/bit-set/resizable-typed-bit-set.d.ts +22 -0
  18. package/lib/{typed-bit-set.js → bit-set/resizable-typed-bit-set.js} +37 -39
  19. package/lib/bit-set/resizable-typed-bit-set.js.map +1 -0
  20. package/lib/bit-set/typed-bit-set.d.ts +22 -0
  21. package/lib/bit-set/typed-bit-set.js +99 -0
  22. package/lib/bit-set/typed-bit-set.js.map +1 -0
  23. package/lib/box.js +1 -0
  24. package/lib/box.js.map +1 -1
  25. package/lib/disjoint-set.js +2 -4
  26. package/lib/disjoint-set.js.map +1 -1
  27. package/lib/dynamic-typed-array.d.ts +12 -9
  28. package/lib/dynamic-typed-array.js +51 -66
  29. package/lib/dynamic-typed-array.js.map +1 -1
  30. package/lib/emitter.js +3 -7
  31. package/lib/emitter.js.map +1 -1
  32. package/lib/expirable-map.js +9 -15
  33. package/lib/expirable-map.js.map +1 -1
  34. package/lib/generator-emitter.js +2 -5
  35. package/lib/generator-emitter.js.map +1 -1
  36. package/lib/hash-map.js +2 -1
  37. package/lib/hash-map.js.map +1 -1
  38. package/lib/hash-set.js +2 -1
  39. package/lib/hash-set.js.map +1 -1
  40. package/lib/index.d.ts +5 -7
  41. package/lib/index.js +5 -7
  42. package/lib/index.js.map +1 -1
  43. package/lib/lru-map.js +2 -1
  44. package/lib/lru-map.js.map +1 -1
  45. package/lib/queue.js +1 -3
  46. package/lib/queue.js.map +1 -1
  47. package/lib/radix-tree.js +6 -7
  48. package/lib/radix-tree.js.map +1 -1
  49. package/lib/resizable-typed-array.d.ts +32 -0
  50. package/lib/resizable-typed-array.js +127 -0
  51. package/lib/resizable-typed-array.js.map +1 -0
  52. package/lib/sorted-set.js +2 -1
  53. package/lib/sorted-set.js.map +1 -1
  54. package/lib/sparse-map/clean-sparse-map.d.ts +18 -0
  55. package/lib/sparse-map/clean-sparse-map.js +74 -0
  56. package/lib/sparse-map/clean-sparse-map.js.map +1 -0
  57. package/lib/sparse-map/dynamic-typed-clean-sparse-map-lite.d.ts +21 -0
  58. package/lib/sparse-map/dynamic-typed-clean-sparse-map-lite.js +87 -0
  59. package/lib/sparse-map/dynamic-typed-clean-sparse-map-lite.js.map +1 -0
  60. package/lib/sparse-map/dynamic-typed-sparse-map-lite.d.ts +21 -0
  61. package/lib/sparse-map/dynamic-typed-sparse-map-lite.js +94 -0
  62. package/lib/sparse-map/dynamic-typed-sparse-map-lite.js.map +1 -0
  63. package/lib/sparse-map/index.d.ts +10 -0
  64. package/lib/sparse-map/index.js +11 -0
  65. package/lib/sparse-map/index.js.map +1 -0
  66. package/lib/sparse-map/resizable-typed-clean-sparse-map-lite.d.ts +21 -0
  67. package/lib/sparse-map/resizable-typed-clean-sparse-map-lite.js +85 -0
  68. package/lib/sparse-map/resizable-typed-clean-sparse-map-lite.js.map +1 -0
  69. package/lib/sparse-map/resizable-typed-sparse-map-lite.d.ts +21 -0
  70. package/lib/sparse-map/resizable-typed-sparse-map-lite.js +92 -0
  71. package/lib/sparse-map/resizable-typed-sparse-map-lite.js.map +1 -0
  72. package/lib/{sparse-map.d.ts → sparse-map/sparse-map.d.ts} +6 -5
  73. package/lib/sparse-map/sparse-map.js +86 -0
  74. package/lib/sparse-map/sparse-map.js.map +1 -0
  75. package/lib/sparse-map/typed-clean-sparse-map-lite.d.ts +21 -0
  76. package/lib/sparse-map/typed-clean-sparse-map-lite.js +92 -0
  77. package/lib/sparse-map/typed-clean-sparse-map-lite.js.map +1 -0
  78. package/lib/sparse-map/typed-clean-sparse-map.d.ts +22 -0
  79. package/lib/sparse-map/typed-clean-sparse-map.js +117 -0
  80. package/lib/sparse-map/typed-clean-sparse-map.js.map +1 -0
  81. package/lib/sparse-map/typed-sparse-map-lite.d.ts +21 -0
  82. package/lib/sparse-map/typed-sparse-map-lite.js +109 -0
  83. package/lib/sparse-map/typed-sparse-map-lite.js.map +1 -0
  84. package/lib/sparse-map/typed-sparse-map.d.ts +21 -0
  85. package/lib/sparse-map/typed-sparse-map.js +130 -0
  86. package/lib/sparse-map/typed-sparse-map.js.map +1 -0
  87. package/lib/sparse-set/clean-sparse-set.d.ts +13 -0
  88. package/lib/sparse-set/clean-sparse-set.js +57 -0
  89. package/lib/sparse-set/clean-sparse-set.js.map +1 -0
  90. package/lib/{typed-sparse-set.d.ts → sparse-set/dynamic-typed-clean-sparse-set-lite.d.ts} +6 -6
  91. package/lib/sparse-set/dynamic-typed-clean-sparse-set-lite.js +51 -0
  92. package/lib/sparse-set/dynamic-typed-clean-sparse-set-lite.js.map +1 -0
  93. package/lib/sparse-set/dynamic-typed-clean-sparse-set.d.ts +16 -0
  94. package/lib/sparse-set/dynamic-typed-clean-sparse-set.js +82 -0
  95. package/lib/sparse-set/dynamic-typed-clean-sparse-set.js.map +1 -0
  96. package/lib/sparse-set/dynamic-typed-sparse-set-lite.d.ts +15 -0
  97. package/lib/sparse-set/dynamic-typed-sparse-set-lite.js +52 -0
  98. package/lib/sparse-set/dynamic-typed-sparse-set-lite.js.map +1 -0
  99. package/lib/sparse-set/dynamic-typed-sparse-set.d.ts +15 -0
  100. package/lib/sparse-set/dynamic-typed-sparse-set.js +75 -0
  101. package/lib/sparse-set/dynamic-typed-sparse-set.js.map +1 -0
  102. package/lib/sparse-set/index.d.ts +14 -0
  103. package/lib/sparse-set/index.js +15 -0
  104. package/lib/sparse-set/index.js.map +1 -0
  105. package/lib/sparse-set/resizable-typed-clean-sparse-set-lite.d.ts +15 -0
  106. package/lib/sparse-set/resizable-typed-clean-sparse-set-lite.js +51 -0
  107. package/lib/sparse-set/resizable-typed-clean-sparse-set-lite.js.map +1 -0
  108. package/lib/sparse-set/resizable-typed-clean-sparse-set.d.ts +16 -0
  109. package/lib/sparse-set/resizable-typed-clean-sparse-set.js +83 -0
  110. package/lib/sparse-set/resizable-typed-clean-sparse-set.js.map +1 -0
  111. package/lib/sparse-set/resizable-typed-sparse-set-lite.d.ts +15 -0
  112. package/lib/sparse-set/resizable-typed-sparse-set-lite.js +52 -0
  113. package/lib/sparse-set/resizable-typed-sparse-set-lite.js.map +1 -0
  114. package/lib/sparse-set/resizable-typed-sparse-set.d.ts +15 -0
  115. package/lib/sparse-set/resizable-typed-sparse-set.js +76 -0
  116. package/lib/sparse-set/resizable-typed-sparse-set.js.map +1 -0
  117. package/lib/{sparse-set.d.ts → sparse-set/sparse-set.d.ts} +3 -4
  118. package/lib/sparse-set/sparse-set.js +60 -0
  119. package/lib/sparse-set/sparse-set.js.map +1 -0
  120. package/lib/sparse-set/typed-clean-sparse-set-lite.d.ts +15 -0
  121. package/lib/sparse-set/typed-clean-sparse-set-lite.js +55 -0
  122. package/lib/sparse-set/typed-clean-sparse-set-lite.js.map +1 -0
  123. package/lib/sparse-set/typed-clean-sparse-set.d.ts +16 -0
  124. package/lib/sparse-set/typed-clean-sparse-set.js +80 -0
  125. package/lib/sparse-set/typed-clean-sparse-set.js.map +1 -0
  126. package/lib/sparse-set/typed-sparse-set-lite.d.ts +15 -0
  127. package/lib/sparse-set/typed-sparse-set-lite.js +60 -0
  128. package/lib/sparse-set/typed-sparse-set-lite.js.map +1 -0
  129. package/lib/sparse-set/typed-sparse-set.d.ts +15 -0
  130. package/lib/sparse-set/typed-sparse-set.js +81 -0
  131. package/lib/sparse-set/typed-sparse-set.js.map +1 -0
  132. package/lib/string-radix-tree.js +6 -7
  133. package/lib/string-radix-tree.js.map +1 -1
  134. package/lib/string-trie-map.js +3 -4
  135. package/lib/string-trie-map.js.map +1 -1
  136. package/lib/tlru-map.js +6 -6
  137. package/lib/tlru-map.js.map +1 -1
  138. package/lib/trie-map.js +3 -4
  139. package/lib/trie-map.js.map +1 -1
  140. package/lib/unique-queue.js +1 -3
  141. package/lib/unique-queue.js.map +1 -1
  142. package/lib/utils/compute-new-capacity.d.ts +1 -0
  143. package/lib/utils/compute-new-capacity.js +36 -0
  144. package/lib/utils/compute-new-capacity.js.map +1 -0
  145. package/lib/utils/get-max-value-of-unsigned-typed-array.d.ts +3 -0
  146. package/lib/utils/get-max-value-of-unsigned-typed-array.js +13 -0
  147. package/lib/utils/get-max-value-of-unsigned-typed-array.js.map +1 -0
  148. package/lib/utils/skip-list.js +11 -9
  149. package/lib/utils/skip-list.js.map +1 -1
  150. package/lib/utils/trailing-zeros.js +1 -1
  151. package/lib/utils/trailing-zeros.js.map +1 -1
  152. package/package.json +28 -31
  153. package/src/{bit-set.ts → bit-set/bit-set.ts} +47 -31
  154. package/src/bit-set/dynamic-typed-bit-set.ts +131 -0
  155. package/src/bit-set/index.ts +4 -0
  156. package/src/{typed-bit-set.ts → bit-set/resizable-typed-bit-set.ts} +38 -36
  157. package/src/bit-set/typed-bit-set.ts +134 -0
  158. package/src/dynamic-typed-array.ts +67 -82
  159. package/src/index.ts +5 -7
  160. package/src/radix-tree.ts +3 -3
  161. package/src/resizable-typed-array.ts +214 -0
  162. package/src/sparse-map/clean-sparse-map.ts +84 -0
  163. package/src/sparse-map/dynamic-typed-clean-sparse-map-lite.ts +109 -0
  164. package/src/sparse-map/dynamic-typed-sparse-map-lite.ts +124 -0
  165. package/src/sparse-map/index.ts +11 -0
  166. package/src/sparse-map/resizable-typed-clean-sparse-map-lite.ts +107 -0
  167. package/src/sparse-map/resizable-typed-sparse-map-lite.ts +122 -0
  168. package/src/sparse-map/sparse-map.ts +104 -0
  169. package/src/sparse-map/typed-clean-sparse-map-lite.ts +116 -0
  170. package/src/sparse-map/typed-clean-sparse-map.ts +149 -0
  171. package/src/sparse-map/typed-sparse-map-lite.ts +141 -0
  172. package/src/sparse-map/typed-sparse-map.ts +169 -0
  173. package/src/sparse-set/clean-sparse-set.ts +76 -0
  174. package/src/sparse-set/dynamic-typed-clean-sparse-set-lite.ts +64 -0
  175. package/src/sparse-set/dynamic-typed-clean-sparse-set.ts +101 -0
  176. package/src/sparse-set/dynamic-typed-sparse-set-lite.ts +67 -0
  177. package/src/sparse-set/dynamic-typed-sparse-set.ts +93 -0
  178. package/src/sparse-set/index.ts +15 -0
  179. package/src/sparse-set/resizable-typed-clean-sparse-set-lite.ts +64 -0
  180. package/src/sparse-set/resizable-typed-clean-sparse-set.ts +108 -0
  181. package/src/sparse-set/resizable-typed-sparse-set-lite.ts +67 -0
  182. package/src/sparse-set/resizable-typed-sparse-set.ts +97 -0
  183. package/src/sparse-set/sparse-set.ts +79 -0
  184. package/src/sparse-set/typed-clean-sparse-set-lite.ts +67 -0
  185. package/src/sparse-set/typed-clean-sparse-set.ts +100 -0
  186. package/src/sparse-set/typed-sparse-set-lite.ts +74 -0
  187. package/src/sparse-set/typed-sparse-set.ts +102 -0
  188. package/src/string-radix-tree.ts +3 -3
  189. package/src/utils/compute-new-capacity.ts +39 -0
  190. package/src/utils/get-max-value-of-unsigned-typed-array.ts +19 -0
  191. package/src/utils/skip-list.ts +1 -1
  192. package/src/utils/trailing-zeros.ts +2 -3
  193. package/lib/bit-set.js.map +0 -1
  194. package/lib/sparse-map.js +0 -76
  195. package/lib/sparse-map.js.map +0 -1
  196. package/lib/sparse-set.js +0 -63
  197. package/lib/sparse-set.js.map +0 -1
  198. package/lib/typed-bit-set.js.map +0 -1
  199. package/lib/typed-sparse-map.d.ts +0 -20
  200. package/lib/typed-sparse-map.js +0 -83
  201. package/lib/typed-sparse-map.js.map +0 -1
  202. package/lib/typed-sparse-set.js +0 -59
  203. package/lib/typed-sparse-set.js.map +0 -1
  204. package/src/sparse-map.ts +0 -82
  205. package/src/sparse-set.ts +0 -74
  206. package/src/typed-sparse-map.ts +0 -97
  207. package/src/typed-sparse-set.ts +0 -73
@@ -0,0 +1,169 @@
1
+ import { assert } from '@blackglory/errors'
2
+ import { go } from '@blackglory/go'
3
+ import { getMaxValueOfUnsignedTypedArray, getMaxValueOfUnsignedTypedArrayConstructor } from '@utils/get-max-value-of-unsigned-typed-array.js'
4
+ import { TypedArrayConstructor, UnsignedTypedArrayConstructor, TypedArrayOfConstructor, UnsignedTypedArray } from 'justypes'
5
+
6
+ export class TypedSparseMap<
7
+ K extends UnsignedTypedArrayConstructor
8
+ , V extends TypedArrayConstructor
9
+ > {
10
+ private denseKeys: TypedArrayOfConstructor<K>
11
+ private denseValues: TypedArrayOfConstructor<V>
12
+ private sparse: UnsignedTypedArray
13
+ #length = 0
14
+
15
+ readonly internalKeyArray: TypedArrayOfConstructor<K, ArrayBuffer>
16
+ readonly internalValueArray: TypedArrayOfConstructor<V, ArrayBuffer>
17
+
18
+ get [Symbol.toStringTag](): string {
19
+ return this.constructor.name
20
+ }
21
+
22
+ get size(): number {
23
+ return this.#length
24
+ }
25
+
26
+ constructor(
27
+ keys: TypedArrayOfConstructor<K, ArrayBuffer>
28
+ , values: TypedArrayOfConstructor<V, ArrayBuffer>
29
+ ) {
30
+ assert(!keys.buffer.resizable, 'The keys buffer must not be resizable')
31
+ assert(!values.buffer.resizable, 'The values buffer must not be resizable')
32
+ assert(
33
+ values.length >= keys.length
34
+ , 'The values.length must greater than or equal to keys.length'
35
+ )
36
+
37
+ this.denseKeys = keys
38
+ this.denseValues = values
39
+
40
+ this.internalKeyArray = keys
41
+ this.internalValueArray = values
42
+
43
+ const sparseConstructor = go(() => {
44
+ const maxIndex = Math.min(
45
+ keys.length - 1
46
+ , getMaxValueOfUnsignedTypedArray(keys) + 1
47
+ )
48
+ if (
49
+ maxIndex <=
50
+ getMaxValueOfUnsignedTypedArrayConstructor(Uint8Array)
51
+ ) {
52
+ return Uint8Array
53
+ } else if (
54
+ maxIndex <=
55
+ getMaxValueOfUnsignedTypedArrayConstructor(Uint16Array)
56
+ ) {
57
+ return Uint16Array
58
+ } else if (
59
+ maxIndex <=
60
+ getMaxValueOfUnsignedTypedArrayConstructor(Uint32Array)
61
+ ) {
62
+ return Uint32Array
63
+ } else {
64
+ throw new Error('The array is too large')
65
+ }
66
+ })
67
+ this.sparse = new sparseConstructor(getMaxValueOfUnsignedTypedArray(keys) + 1)
68
+ }
69
+
70
+ * entries(): IterableIterator<[key: number, value: number]> {
71
+ for (let i = 0; i < this.#length; i++) {
72
+ yield [
73
+ this.denseKeys[i]
74
+ , this.denseValues[i]
75
+ ]
76
+ }
77
+ }
78
+
79
+ * keys(): IterableIterator<number> {
80
+ for (let i = 0; i < this.#length; i++) {
81
+ yield this.denseKeys[i]
82
+ }
83
+ }
84
+
85
+ * values(): IterableIterator<number> {
86
+ for (let i = 0; i < this.#length; i++) {
87
+ yield this.denseValues[i]
88
+ }
89
+ }
90
+
91
+ getInternalIndexOfKey(key: number): number | undefined {
92
+ const index = this.sparse[key]
93
+ if (
94
+ index !== undefined &&
95
+ index < this.#length &&
96
+ index < this.denseKeys.length && // 用于改善JIT优化.
97
+ this.denseKeys[index] === key
98
+ ) {
99
+ return index
100
+ }
101
+ }
102
+
103
+ has(key: number): boolean {
104
+ const index = this.sparse[key]
105
+ return index !== undefined
106
+ && index < this.#length
107
+ && index < this.denseKeys.length // 用于改善JIT优化.
108
+ && this.denseKeys[index] === key
109
+ }
110
+
111
+ get(key: number): number | undefined {
112
+ const index = this.sparse[key]
113
+ if (
114
+ index !== undefined &&
115
+ index < this.#length &&
116
+ index < this.denseKeys.length && // 用于改善JIT优化.
117
+ this.denseKeys[index] === key
118
+ ) {
119
+ return this.denseValues[index]
120
+ } else {
121
+ return undefined
122
+ }
123
+ }
124
+
125
+ set(key: number, value: number): void {
126
+ const index = this.sparse[key]
127
+ if (
128
+ index !== undefined &&
129
+ index < this.#length &&
130
+ index < this.denseKeys.length && // 用于改善JIT优化.
131
+ this.denseKeys[index] === key
132
+ ) {
133
+ this.denseValues[index] = value
134
+ } else {
135
+ const index = this.#length++
136
+ this.denseKeys[index] = key
137
+ this.denseValues[index] = value
138
+ this.sparse[key] = index
139
+ }
140
+ }
141
+
142
+ delete(key: number): boolean {
143
+ const index = this.sparse[key]
144
+ if (
145
+ index !== undefined &&
146
+ index < this.#length &&
147
+ index < this.denseKeys.length && // 用于改善JIT优化.
148
+ this.denseKeys[index] === key
149
+ ) {
150
+ const lastIndex = --this.#length
151
+ const lastKey = this.denseKeys[lastIndex]
152
+ const lastValue = this.denseValues[lastIndex]
153
+ if (key !== lastKey) {
154
+ this.denseKeys[index] = lastKey
155
+ this.denseValues[index] = lastValue
156
+ this.sparse[lastKey] = index
157
+ }
158
+
159
+ return true
160
+ } else {
161
+ return false
162
+ }
163
+ }
164
+
165
+ clear(): void {
166
+ this.#length = 0
167
+ // 无需清空dense和sparse数组.
168
+ }
169
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * 稀疏集的干净sparse数组变体.
3
+ *
4
+ * `has()`和`add()`快于标准实现, `delete()`和`clear()`慢于标准实现.
5
+ */
6
+ export class CleanSparseSet implements Iterable<number> {
7
+ private dense: number[] = []
8
+ private sparse: Array<number | undefined> = []
9
+
10
+ get [Symbol.toStringTag](): string {
11
+ return this.constructor.name
12
+ }
13
+
14
+ get size(): number {
15
+ return this.dense.length
16
+ }
17
+
18
+ [Symbol.iterator](): IterableIterator<number> {
19
+ return this.values()
20
+ }
21
+
22
+ values(): IterableIterator<number> {
23
+ return this.dense.values()
24
+ }
25
+
26
+ has(value: number): boolean {
27
+ return this.sparse[value] !== undefined
28
+ }
29
+
30
+ add(value: number): void {
31
+ if (!this.has(value)) {
32
+ const index = this.dense.length
33
+ this.dense.push(value)
34
+ this.sparse[value] = index
35
+ }
36
+ }
37
+
38
+ delete(value: number): boolean {
39
+ const index = this.sparse[value]
40
+ if (index !== undefined) {
41
+ this.sparse[value] = undefined
42
+
43
+ const lastValue = this.dense.pop()!
44
+ if (value !== lastValue) {
45
+ this.dense[index] = lastValue
46
+ this.sparse[lastValue] = index
47
+ }
48
+
49
+ return true
50
+ } else {
51
+ return false
52
+ }
53
+ }
54
+
55
+ clear(): void {
56
+ this.dense.length = 0
57
+ this.sparse.length = 0
58
+ }
59
+
60
+ clone(): CleanSparseSet {
61
+ const clone = new CleanSparseSet()
62
+
63
+ const dense = [...this.dense]
64
+
65
+ // 由于`sparse`是稀疏的, 不应用`[...sparse]`复制.
66
+ const sparse: Array<number | undefined> = []
67
+ for (const [index, value] of dense.entries()) {
68
+ sparse[value] = index
69
+ }
70
+
71
+ clone.dense = dense
72
+ clone.sparse = sparse
73
+
74
+ return clone
75
+ }
76
+ }
@@ -0,0 +1,64 @@
1
+ import { DynamicTypedArray } from '@src/dynamic-typed-array.js'
2
+ import { assert } from '@blackglory/errors'
3
+ import { UnsignedTypedArrayConstructor } from 'justypes'
4
+
5
+ export class DynamicTypedCleanSparseSetLite implements Iterable<number> {
6
+ private dense: DynamicTypedArray<UnsignedTypedArrayConstructor>
7
+ private sparse: Array<number | undefined> = []
8
+
9
+ get [Symbol.toStringTag](): string {
10
+ return this.constructor.name
11
+ }
12
+
13
+ get size(): number {
14
+ return this.dense.length
15
+ }
16
+
17
+ constructor(array: DynamicTypedArray<UnsignedTypedArrayConstructor>) {
18
+ assert(array.length === 0, 'The array must be empty')
19
+
20
+ this.dense = array
21
+ }
22
+
23
+ [Symbol.iterator](): IterableIterator<number> {
24
+ return this.values()
25
+ }
26
+
27
+ values(): IterableIterator<number> {
28
+ return this.dense.values()
29
+ }
30
+
31
+ has(value: number): boolean {
32
+ return this.sparse[value] !== undefined
33
+ }
34
+
35
+ add(value: number): void {
36
+ if (!this.has(value)) {
37
+ const index = this.dense.length
38
+ this.dense.push(value)
39
+ this.sparse[value] = index
40
+ }
41
+ }
42
+
43
+ delete(value: number): boolean {
44
+ const index = this.sparse[value]
45
+ if (index !== undefined) {
46
+ this.sparse[value] = undefined
47
+
48
+ const lastValue = this.dense.pop()!
49
+ if (value !== lastValue) {
50
+ this.dense.internalTypedArray[index] = lastValue
51
+ this.sparse[lastValue] = index
52
+ }
53
+
54
+ return true
55
+ } else {
56
+ return false
57
+ }
58
+ }
59
+
60
+ clear(): void {
61
+ this.dense.clear()
62
+ this.sparse.length = 0
63
+ }
64
+ }
@@ -0,0 +1,101 @@
1
+ import { TypedArrayConstructor, UnsignedTypedArrayConstructor } from 'justypes'
2
+ import { DynamicTypedArray } from '@src/dynamic-typed-array.js'
3
+ import { assert } from '@blackglory/errors'
4
+ import { getMaxValueOfUnsignedTypedArray, getMaxValueOfUnsignedTypedArrayConstructor } from '@utils/get-max-value-of-unsigned-typed-array.js'
5
+ import { go } from '@blackglory/go'
6
+
7
+ export class DynamicTypedCleanSparseSet implements Iterable<number> {
8
+ private dense: DynamicTypedArray<TypedArrayConstructor>
9
+ private sparse: DynamicTypedArray<UnsignedTypedArrayConstructor>
10
+ private readonly NULL: number
11
+
12
+ get [Symbol.toStringTag](): string {
13
+ return this.constructor.name
14
+ }
15
+
16
+ get size(): number {
17
+ return this.dense.length
18
+ }
19
+
20
+ constructor(array: DynamicTypedArray<UnsignedTypedArrayConstructor>) {
21
+ assert(array.length === 0, 'The array must be empty')
22
+
23
+ this.dense = array
24
+
25
+ const NULL = getMaxValueOfUnsignedTypedArray(array.internalTypedArray)
26
+ + 1
27
+ this.NULL = NULL
28
+
29
+ const sparseInternalArrayConstructor = go(() => {
30
+ if (
31
+ NULL <=
32
+ getMaxValueOfUnsignedTypedArrayConstructor(Uint8Array)
33
+ ) {
34
+ return Uint8Array
35
+ } else if (
36
+ NULL <=
37
+ getMaxValueOfUnsignedTypedArrayConstructor(Uint16Array)
38
+ ) {
39
+ return Uint16Array
40
+ } else if (
41
+ NULL <=
42
+ getMaxValueOfUnsignedTypedArrayConstructor(Uint32Array)
43
+ ) {
44
+ return Uint32Array
45
+ } else {
46
+ throw new Error('The array is too large')
47
+ }
48
+ })
49
+ const sparse = new DynamicTypedArray(sparseInternalArrayConstructor, {
50
+ fillValue: NULL
51
+ })
52
+ this.sparse = sparse
53
+ }
54
+
55
+ [Symbol.iterator](): IterableIterator<number> {
56
+ return this.values()
57
+ }
58
+
59
+ values(): IterableIterator<number> {
60
+ return this.dense.values()
61
+ }
62
+
63
+ has(value: number): boolean {
64
+ const index = this.sparse.get(value)
65
+ return index !== undefined
66
+ && index !== this.NULL
67
+ }
68
+
69
+ add(value: number): void {
70
+ if (!this.has(value)) {
71
+ const index = this.dense.length
72
+ this.dense.push(value)
73
+ this.sparse.set(value, index)
74
+ }
75
+ }
76
+
77
+ delete(value: number): boolean {
78
+ const index = this.sparse.get(value)
79
+ if (
80
+ index !== undefined &&
81
+ index !== this.NULL
82
+ ) {
83
+ this.sparse.internalTypedArray[value] = this.NULL
84
+
85
+ const lastValue = this.dense.pop()!
86
+ if (value !== lastValue) {
87
+ this.dense.internalTypedArray[index] = lastValue
88
+ this.sparse.internalTypedArray[lastValue] = index
89
+ }
90
+
91
+ return true
92
+ } else {
93
+ return false
94
+ }
95
+ }
96
+
97
+ clear(): void {
98
+ this.dense.clear()
99
+ this.sparse.clear()
100
+ }
101
+ }
@@ -0,0 +1,67 @@
1
+ import { DynamicTypedArray } from '@src/dynamic-typed-array.js'
2
+ import { assert } from '@blackglory/errors'
3
+ import { UnsignedTypedArrayConstructor } from 'justypes'
4
+
5
+ export class DynamicTypedSparseSetLite implements Iterable<number> {
6
+ private dense: DynamicTypedArray<UnsignedTypedArrayConstructor>
7
+ private sparse: Array<number | undefined> = []
8
+
9
+ get [Symbol.toStringTag](): string {
10
+ return this.constructor.name
11
+ }
12
+
13
+ get size(): number {
14
+ return this.dense.length
15
+ }
16
+
17
+ constructor(array: DynamicTypedArray<UnsignedTypedArrayConstructor>) {
18
+ assert(array.length === 0, 'The array must be empty')
19
+
20
+ this.dense = array
21
+ }
22
+
23
+ [Symbol.iterator](): IterableIterator<number> {
24
+ return this.values()
25
+ }
26
+
27
+ values(): IterableIterator<number> {
28
+ return this.dense.values()
29
+ }
30
+
31
+ has(value: number): boolean {
32
+ const index = this.sparse[value]
33
+ return index !== undefined
34
+ && this.dense.get(index) === value
35
+ }
36
+
37
+ add(value: number): void {
38
+ if (!this.has(value)) {
39
+ const index = this.dense.length
40
+ this.dense.push(value)
41
+ this.sparse[value] = index
42
+ }
43
+ }
44
+
45
+ delete(value: number): boolean {
46
+ const index = this.sparse[value]
47
+ if (
48
+ index !== undefined &&
49
+ this.dense.get(index) === value
50
+ ) {
51
+ const lastValue = this.dense.pop()!
52
+ if (value !== lastValue) {
53
+ this.dense.internalTypedArray[index] = lastValue
54
+ this.sparse[lastValue] = index
55
+ }
56
+
57
+ return true
58
+ } else {
59
+ return false
60
+ }
61
+ }
62
+
63
+ clear(): void {
64
+ this.dense.clear()
65
+ // 无需清空sparse数组.
66
+ }
67
+ }
@@ -0,0 +1,93 @@
1
+ import { UnsignedTypedArrayConstructor } from 'justypes'
2
+ import { DynamicTypedArray } from '@src/dynamic-typed-array.js'
3
+ import { assert } from '@blackglory/errors'
4
+ import { go } from '@blackglory/go'
5
+ import { getMaxValueOfUnsignedTypedArray, getMaxValueOfUnsignedTypedArrayConstructor } from '@utils/get-max-value-of-unsigned-typed-array.js'
6
+
7
+ export class DynamicTypedSparseSet implements Iterable<number> {
8
+ private dense: DynamicTypedArray<UnsignedTypedArrayConstructor>
9
+ private sparse: DynamicTypedArray<UnsignedTypedArrayConstructor>
10
+
11
+ get [Symbol.toStringTag](): string {
12
+ return this.constructor.name
13
+ }
14
+
15
+ get size(): number {
16
+ return this.dense.length
17
+ }
18
+
19
+ constructor(array: DynamicTypedArray<UnsignedTypedArrayConstructor>) {
20
+ assert(array.length === 0, 'The array must be empty')
21
+
22
+ this.dense = array
23
+
24
+ const sparseInternalArrayConstructor = go(() => {
25
+ const maxIndex = getMaxValueOfUnsignedTypedArray(array.internalTypedArray)
26
+ + 1
27
+ if (
28
+ maxIndex <=
29
+ getMaxValueOfUnsignedTypedArrayConstructor(Uint8Array)
30
+ ) {
31
+ return Uint8Array
32
+ } else if (
33
+ maxIndex <=
34
+ getMaxValueOfUnsignedTypedArrayConstructor(Uint16Array)
35
+ ) {
36
+ return Uint16Array
37
+ } else if (
38
+ maxIndex <=
39
+ getMaxValueOfUnsignedTypedArrayConstructor(Uint32Array)
40
+ ) {
41
+ return Uint32Array
42
+ } else {
43
+ throw new Error('The array is too large')
44
+ }
45
+ })
46
+ this.sparse = new DynamicTypedArray(sparseInternalArrayConstructor)
47
+ }
48
+
49
+ [Symbol.iterator](): IterableIterator<number> {
50
+ return this.values()
51
+ }
52
+
53
+ values(): IterableIterator<number> {
54
+ return this.dense.values()
55
+ }
56
+
57
+ has(value: number): boolean {
58
+ const index = this.sparse.get(value)
59
+ return index !== undefined
60
+ && this.dense.get(index) === value
61
+ }
62
+
63
+ add(value: number): void {
64
+ if (!this.has(value)) {
65
+ const index = this.dense.length
66
+ this.dense.push(value)
67
+ this.sparse.set(value, index)
68
+ }
69
+ }
70
+
71
+ delete(value: number): boolean {
72
+ const index = this.sparse.get(value)
73
+ if (
74
+ index !== undefined &&
75
+ this.dense.get(index) === value
76
+ ) {
77
+ const lastValue = this.dense.pop()!
78
+ if (value !== lastValue) {
79
+ this.dense.internalTypedArray[index] = lastValue
80
+ this.sparse.set(lastValue, index)
81
+ }
82
+
83
+ return true
84
+ } else {
85
+ return false
86
+ }
87
+ }
88
+
89
+ clear(): void {
90
+ this.dense.clear()
91
+ // 无需清空sparse数组.
92
+ }
93
+ }
@@ -0,0 +1,15 @@
1
+ export * from './sparse-set.js'
2
+ export * from './typed-sparse-set.js'
3
+ export * from './typed-sparse-set-lite.js'
4
+ export * from './dynamic-typed-sparse-set.js'
5
+ export * from './dynamic-typed-sparse-set-lite.js'
6
+ export * from './resizable-typed-sparse-set.js'
7
+ export * from './resizable-typed-sparse-set-lite.js'
8
+
9
+ export * from './clean-sparse-set.js'
10
+ export * from './typed-clean-sparse-set.js'
11
+ export * from './typed-clean-sparse-set-lite.js'
12
+ export * from './dynamic-typed-clean-sparse-set.js'
13
+ export * from './dynamic-typed-clean-sparse-set-lite.js'
14
+ export * from './resizable-typed-clean-sparse-set.js'
15
+ export * from './resizable-typed-clean-sparse-set-lite.js'
@@ -0,0 +1,64 @@
1
+ import { UnsignedTypedArrayConstructor } from 'justypes'
2
+ import { ResizableTypedArray } from '@src/resizable-typed-array.js'
3
+ import { assert } from '@blackglory/errors'
4
+
5
+ export class ResizableTypedCleanSparseSetLite implements Iterable<number> {
6
+ private dense: ResizableTypedArray<UnsignedTypedArrayConstructor>
7
+ private sparse: Array<number | undefined> = []
8
+
9
+ get [Symbol.toStringTag](): string {
10
+ return this.constructor.name
11
+ }
12
+
13
+ get size(): number {
14
+ return this.dense.length
15
+ }
16
+
17
+ constructor(array: ResizableTypedArray<UnsignedTypedArrayConstructor>) {
18
+ assert(array.length === 0, 'The array must be empty')
19
+
20
+ this.dense = array
21
+ }
22
+
23
+ [Symbol.iterator](): IterableIterator<number> {
24
+ return this.values()
25
+ }
26
+
27
+ values(): IterableIterator<number> {
28
+ return this.dense.values()
29
+ }
30
+
31
+ has(value: number): boolean {
32
+ return this.sparse[value] !== undefined
33
+ }
34
+
35
+ add(value: number): void {
36
+ if (!this.has(value)) {
37
+ const index = this.dense.length
38
+ this.dense.push(value)
39
+ this.sparse[value] = index
40
+ }
41
+ }
42
+
43
+ delete(value: number): boolean {
44
+ const index = this.sparse[value]
45
+ if (index !== undefined) {
46
+ this.sparse[value] = undefined
47
+
48
+ const lastValue = this.dense.pop()!
49
+ if (value !== lastValue) {
50
+ this.dense.internalTypedArray[index] = lastValue
51
+ this.sparse[lastValue] = index
52
+ }
53
+
54
+ return true
55
+ } else {
56
+ return false
57
+ }
58
+ }
59
+
60
+ clear(): void {
61
+ this.dense.clear()
62
+ this.sparse.length = 0
63
+ }
64
+ }