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