@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,108 @@
1
+ import { UnsignedTypedArrayConstructor } from 'justypes'
2
+ import { ResizableTypedArray } from '@src/resizable-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 ResizableTypedCleanSparseSet implements Iterable<number> {
8
+ private dense: ResizableTypedArray<UnsignedTypedArrayConstructor>
9
+ private sparse: ResizableTypedArray<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: ResizableTypedArray<UnsignedTypedArrayConstructor>) {
21
+ assert(array.length === 0, 'The array must be empty')
22
+
23
+ this.dense = array
24
+
25
+ const NULL = Math.min(
26
+ array.maxCapacity
27
+ , getMaxValueOfUnsignedTypedArray(array.internalTypedArray) + 1
28
+ )
29
+ this.NULL = NULL
30
+
31
+ const sparseInternalArrayConstructor = go(() => {
32
+ if (
33
+ NULL <=
34
+ getMaxValueOfUnsignedTypedArrayConstructor(Uint8Array)
35
+ ) {
36
+ return Uint8Array
37
+ } else if (
38
+ NULL <=
39
+ getMaxValueOfUnsignedTypedArrayConstructor(Uint16Array)
40
+ ) {
41
+ return Uint16Array
42
+ } else if (
43
+ NULL <=
44
+ getMaxValueOfUnsignedTypedArrayConstructor(Uint32Array)
45
+ ) {
46
+ return Uint32Array
47
+ } else {
48
+ throw new Error('The array is too large')
49
+ }
50
+ })
51
+ const sparse = new ResizableTypedArray(
52
+ sparseInternalArrayConstructor
53
+ , {
54
+ maxCapacity: getMaxValueOfUnsignedTypedArray(array.internalTypedArray)
55
+ + 1
56
+ , fillValue: NULL
57
+ }
58
+ )
59
+ this.sparse = sparse
60
+ }
61
+
62
+ [Symbol.iterator](): IterableIterator<number> {
63
+ return this.values()
64
+ }
65
+
66
+ values(): IterableIterator<number> {
67
+ return this.dense.values()
68
+ }
69
+
70
+ has(value: number): boolean {
71
+ const index = this.sparse.get(value)
72
+ return index !== undefined
73
+ && index !== this.NULL
74
+ }
75
+
76
+ add(value: number): void {
77
+ if (!this.has(value)) {
78
+ const index = this.dense.length
79
+ this.dense.push(value)
80
+ this.sparse.set(value, index)
81
+ }
82
+ }
83
+
84
+ delete(value: number): boolean {
85
+ const index = this.sparse.get(value)
86
+ if (
87
+ index !== undefined &&
88
+ index !== this.NULL
89
+ ) {
90
+ this.sparse.internalTypedArray[value] = this.NULL
91
+
92
+ const lastValue = this.dense.pop()!
93
+ if (value !== lastValue) {
94
+ this.dense.internalTypedArray[index] = lastValue
95
+ this.sparse.internalTypedArray[lastValue] = index
96
+ }
97
+
98
+ return true
99
+ } else {
100
+ return false
101
+ }
102
+ }
103
+
104
+ clear(): void {
105
+ this.dense.clear()
106
+ this.sparse.clear()
107
+ }
108
+ }
@@ -0,0 +1,67 @@
1
+ import { UnsignedTypedArrayConstructor } from 'justypes'
2
+ import { ResizableTypedArray } from '@src/resizable-typed-array.js'
3
+ import { assert } from '@blackglory/errors'
4
+
5
+ export class ResizableTypedSparseSetLite 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
+ 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,97 @@
1
+ import { UnsignedTypedArrayConstructor } from 'justypes'
2
+ import { ResizableTypedArray } from '@src/resizable-typed-array.js'
3
+ import { getMaxValueOfUnsignedTypedArray, getMaxValueOfUnsignedTypedArrayConstructor } from '@utils/get-max-value-of-unsigned-typed-array.js'
4
+ import { go } from '@blackglory/go'
5
+ import { assert } from '@blackglory/errors'
6
+
7
+ export class ResizableTypedSparseSet implements Iterable<number> {
8
+ private dense: ResizableTypedArray<UnsignedTypedArrayConstructor>
9
+ private sparse: ResizableTypedArray<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: ResizableTypedArray<UnsignedTypedArrayConstructor>) {
20
+ assert(array.length === 0, 'The array must be empty')
21
+
22
+ this.dense = array
23
+
24
+ const sparseInternalArrayConstructor = go(() => {
25
+ const maxIndex = Math.min(
26
+ array.maxCapacity - 1
27
+ , getMaxValueOfUnsignedTypedArray(array.internalTypedArray) + 1
28
+ )
29
+ if (
30
+ maxIndex <=
31
+ getMaxValueOfUnsignedTypedArrayConstructor(Uint8Array)
32
+ ) {
33
+ return Uint8Array
34
+ } else if (
35
+ maxIndex <=
36
+ getMaxValueOfUnsignedTypedArrayConstructor(Uint16Array)
37
+ ) {
38
+ return Uint16Array
39
+ } else if (
40
+ maxIndex <=
41
+ getMaxValueOfUnsignedTypedArrayConstructor(Uint32Array)
42
+ ) {
43
+ return Uint32Array
44
+ } else {
45
+ throw new Error('The array is too large')
46
+ }
47
+ })
48
+ this.sparse = new ResizableTypedArray(sparseInternalArrayConstructor, {
49
+ maxCapacity: getMaxValueOfUnsignedTypedArray(array.internalTypedArray) + 1
50
+ })
51
+ }
52
+
53
+ [Symbol.iterator](): IterableIterator<number> {
54
+ return this.values()
55
+ }
56
+
57
+ values(): IterableIterator<number> {
58
+ return this.dense.values()
59
+ }
60
+
61
+ has(value: number): boolean {
62
+ const index = this.sparse.get(value)
63
+ return index !== undefined
64
+ && this.dense.get(index) === value
65
+ }
66
+
67
+ add(value: number): void {
68
+ if (!this.has(value)) {
69
+ const index = this.dense.length
70
+ this.dense.push(value)
71
+ this.sparse.set(value, index)
72
+ }
73
+ }
74
+
75
+ delete(value: number): boolean {
76
+ const index = this.sparse.get(value)
77
+ if (
78
+ index !== undefined &&
79
+ this.dense.get(index) === value
80
+ ) {
81
+ const lastValue = this.dense.pop()!
82
+ if (value !== lastValue) {
83
+ this.dense.internalTypedArray[index] = lastValue
84
+ this.sparse.set(lastValue, index)
85
+ }
86
+
87
+ return true
88
+ } else {
89
+ return false
90
+ }
91
+ }
92
+
93
+ clear(): void {
94
+ this.dense.clear()
95
+ // 无需清空sparse数组.
96
+ }
97
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * 稀疏集的标准实现.
3
+ */
4
+ export class SparseSet implements Iterable<number> {
5
+ private dense: number[] = []
6
+ private sparse: Array<number | undefined> = []
7
+
8
+ get [Symbol.toStringTag](): string {
9
+ return this.constructor.name
10
+ }
11
+
12
+ get size(): number {
13
+ return this.dense.length
14
+ }
15
+
16
+ [Symbol.iterator](): IterableIterator<number> {
17
+ return this.values()
18
+ }
19
+
20
+ values(): IterableIterator<number> {
21
+ return this.dense.values()
22
+ }
23
+
24
+ has(value: number): boolean {
25
+ const index = this.sparse[value]
26
+ return index !== undefined
27
+ && index < this.dense.length // 用于改善JIT优化.
28
+ && this.dense[index] === value
29
+ }
30
+
31
+ add(value: number): void {
32
+ if (!this.has(value)) {
33
+ const index = this.dense.length
34
+ this.dense.push(value)
35
+ this.sparse[value] = index
36
+ }
37
+ }
38
+
39
+ delete(value: number): boolean {
40
+ const index = this.sparse[value]
41
+ if (
42
+ index !== undefined &&
43
+ index < this.dense.length && // 用于改善JIT优化.
44
+ this.dense[index] === value
45
+ ) {
46
+ const lastValue = this.dense.pop()!
47
+ if (value !== lastValue) {
48
+ this.dense[index] = lastValue
49
+ this.sparse[lastValue] = index
50
+ }
51
+
52
+ return true
53
+ } else {
54
+ return false
55
+ }
56
+ }
57
+
58
+ clear(): void {
59
+ this.dense.length = 0
60
+ // 无需清空sparse数组.
61
+ }
62
+
63
+ clone(): SparseSet {
64
+ const clone = new SparseSet()
65
+
66
+ const dense = [...this.dense]
67
+
68
+ // 由于`sparse`是稀疏的, 不应用`[...sparse]`复制.
69
+ const sparse: Array<number | undefined> = []
70
+ for (const [index, value] of dense.entries()) {
71
+ sparse[value] = index
72
+ }
73
+
74
+ clone.dense = dense
75
+ clone.sparse = sparse
76
+
77
+ return clone
78
+ }
79
+ }
@@ -0,0 +1,67 @@
1
+ import { assert } from '@blackglory/errors'
2
+ import { UnsignedTypedArray } from 'justypes'
3
+
4
+ export class TypedCleanSparseSetLite implements Iterable<number> {
5
+ private dense: UnsignedTypedArray
6
+ private sparse: Array<number | undefined> = []
7
+ #length = 0
8
+
9
+ get [Symbol.toStringTag](): string {
10
+ return this.constructor.name
11
+ }
12
+
13
+ get size(): number {
14
+ return this.#length
15
+ }
16
+
17
+ constructor(array: UnsignedTypedArray<ArrayBuffer>) {
18
+ assert(!array.buffer.resizable, 'The array buffer must not be resizable')
19
+
20
+ this.dense = array
21
+ }
22
+
23
+ [Symbol.iterator](): IterableIterator<number> {
24
+ return this.values()
25
+ }
26
+
27
+ * values(): IterableIterator<number> {
28
+ for (let i = 0; i < this.#length; i++) {
29
+ yield this.dense[i]
30
+ }
31
+ }
32
+
33
+ has(value: number): boolean {
34
+ return this.sparse[value] !== undefined
35
+ }
36
+
37
+ add(value: number): void {
38
+ if (!this.has(value)) {
39
+ const index = this.#length++
40
+ this.dense[index] = value
41
+ this.sparse[value] = index
42
+ }
43
+ }
44
+
45
+ delete(value: number): boolean {
46
+ const index = this.sparse[value]
47
+ if (index !== undefined) {
48
+ this.sparse[value] = undefined
49
+
50
+ const lastIndex = --this.#length
51
+ const lastValue = this.dense[lastIndex]
52
+ if (value !== lastValue) {
53
+ this.dense[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.#length = 0
65
+ this.sparse.length = 0
66
+ }
67
+ }
@@ -0,0 +1,100 @@
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 { UnsignedTypedArray } from 'justypes'
5
+
6
+ export class TypedCleanSparseSet implements Iterable<number> {
7
+ private dense: UnsignedTypedArray
8
+ private sparse: UnsignedTypedArray
9
+ private readonly NULL: number
10
+ #length = 0
11
+
12
+ get [Symbol.toStringTag](): string {
13
+ return this.constructor.name
14
+ }
15
+
16
+ get size(): number {
17
+ return this.#length
18
+ }
19
+
20
+ constructor(array: UnsignedTypedArray<ArrayBuffer>) {
21
+ assert(!array.buffer.resizable, 'The array buffer must not be resizable')
22
+
23
+ this.dense = array
24
+
25
+ const NULL = Math.min(
26
+ array.length
27
+ , getMaxValueOfUnsignedTypedArray(array) + 1
28
+ )
29
+ this.NULL = NULL
30
+
31
+ const sparseConstructor = go(() => {
32
+ if (
33
+ NULL <=
34
+ getMaxValueOfUnsignedTypedArrayConstructor(Uint8Array)
35
+ ) {
36
+ return Uint8Array
37
+ } else if (
38
+ NULL <=
39
+ getMaxValueOfUnsignedTypedArrayConstructor(Uint16Array)
40
+ ) {
41
+ return Uint16Array
42
+ } else if (
43
+ NULL <=
44
+ getMaxValueOfUnsignedTypedArrayConstructor(Uint32Array)
45
+ ) {
46
+ return Uint32Array
47
+ } else {
48
+ throw new Error('The array is too large')
49
+ }
50
+ })
51
+ const sparse = new sparseConstructor(getMaxValueOfUnsignedTypedArray(array) + 1)
52
+ sparse.fill(NULL)
53
+ this.sparse = sparse
54
+ }
55
+
56
+ [Symbol.iterator](): IterableIterator<number> {
57
+ return this.values()
58
+ }
59
+
60
+ * values(): IterableIterator<number> {
61
+ for (let i = 0; i < this.#length; i++) {
62
+ yield this.dense[i]
63
+ }
64
+ }
65
+
66
+ has(value: number): boolean {
67
+ return this.sparse[value] !== this.NULL
68
+ }
69
+
70
+ add(value: number): void {
71
+ if (!this.has(value)) {
72
+ const index = this.#length++
73
+ this.dense[index] = value
74
+ this.sparse[value] = index
75
+ }
76
+ }
77
+
78
+ delete(value: number): boolean {
79
+ const index = this.sparse[value]
80
+ if (index !== this.NULL) {
81
+ this.sparse[value] = this.NULL
82
+
83
+ const lastIndex = --this.#length
84
+ const lastValue = this.dense[lastIndex]
85
+ if (value !== lastValue) {
86
+ this.dense[index] = lastValue
87
+ this.sparse[lastValue] = index
88
+ }
89
+
90
+ return true
91
+ } else {
92
+ return false
93
+ }
94
+ }
95
+
96
+ clear(): void {
97
+ this.#length = 0
98
+ this.sparse.fill(this.NULL)
99
+ }
100
+ }
@@ -0,0 +1,74 @@
1
+ import { assert } from '@blackglory/errors'
2
+ import { UnsignedTypedArray } from 'justypes'
3
+
4
+ export class TypedSparseSetLite implements Iterable<number> {
5
+ private dense: UnsignedTypedArray
6
+ private sparse: Array<number | undefined> = []
7
+ #length = 0
8
+
9
+ get [Symbol.toStringTag](): string {
10
+ return this.constructor.name
11
+ }
12
+
13
+ get size(): number {
14
+ return this.#length
15
+ }
16
+
17
+ constructor(array: UnsignedTypedArray<ArrayBuffer>) {
18
+ assert(!array.buffer.resizable, 'The array buffer must not be resizable')
19
+
20
+ this.dense = array
21
+ }
22
+
23
+ [Symbol.iterator](): IterableIterator<number> {
24
+ return this.values()
25
+ }
26
+
27
+ * values(): IterableIterator<number> {
28
+ for (let i = 0; i < this.#length; i++) {
29
+ yield this.dense[i]
30
+ }
31
+ }
32
+
33
+ has(value: number): boolean {
34
+ const index = this.sparse[value]
35
+ return index !== undefined
36
+ && index < this.#length
37
+ && index < this.dense.length // 用于改善JIT优化.
38
+ && this.dense[index] === value
39
+ }
40
+
41
+ add(value: number): void {
42
+ if (!this.has(value)) {
43
+ const index = this.#length++
44
+ this.dense[index] = value
45
+ this.sparse[value] = index
46
+ }
47
+ }
48
+
49
+ delete(value: number): boolean {
50
+ const index = this.sparse[value]
51
+ if (
52
+ index !== undefined &&
53
+ index < this.#length &&
54
+ index < this.dense.length && // 用于改善JIT优化.
55
+ this.dense[index] === value
56
+ ) {
57
+ const lastIndex = --this.#length
58
+ const lastValue = this.dense[lastIndex]
59
+ if (value !== lastValue) {
60
+ this.dense[index] = lastValue
61
+ this.sparse[lastValue] = index
62
+ }
63
+
64
+ return true
65
+ } else {
66
+ return false
67
+ }
68
+ }
69
+
70
+ clear(): void {
71
+ this.#length = 0
72
+ // 无需清空dense和sparse数组.
73
+ }
74
+ }
@@ -0,0 +1,102 @@
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 { UnsignedTypedArray } from 'justypes'
5
+
6
+ export class TypedSparseSet implements Iterable<number> {
7
+ private dense: UnsignedTypedArray
8
+ private sparse: UnsignedTypedArray
9
+ #length = 0
10
+
11
+ get [Symbol.toStringTag](): string {
12
+ return this.constructor.name
13
+ }
14
+
15
+ get size(): number {
16
+ return this.#length
17
+ }
18
+
19
+ constructor(array: UnsignedTypedArray<ArrayBuffer>) {
20
+ assert(!array.buffer.resizable, 'The array buffer must not be resizable')
21
+
22
+ this.dense = array
23
+
24
+ const sparseConstructor = go(() => {
25
+ const maxIndex = Math.min(
26
+ array.length - 1
27
+ , getMaxValueOfUnsignedTypedArray(array) + 1
28
+ )
29
+ if (
30
+ maxIndex <=
31
+ getMaxValueOfUnsignedTypedArrayConstructor(Uint8Array)
32
+ ) {
33
+ return Uint8Array
34
+ } else if (
35
+ maxIndex <=
36
+ getMaxValueOfUnsignedTypedArrayConstructor(Uint16Array)
37
+ ) {
38
+ return Uint16Array
39
+ } else if (
40
+ maxIndex <=
41
+ getMaxValueOfUnsignedTypedArrayConstructor(Uint32Array)
42
+ ) {
43
+ return Uint32Array
44
+ } else {
45
+ throw new Error('The array is too large')
46
+ }
47
+ })
48
+ this.sparse = new sparseConstructor(getMaxValueOfUnsignedTypedArray(array) + 1)
49
+ }
50
+
51
+ [Symbol.iterator](): IterableIterator<number> {
52
+ return this.values()
53
+ }
54
+
55
+ * values(): IterableIterator<number> {
56
+ for (let i = 0; i < this.#length; i++) {
57
+ yield this.dense[i]
58
+ }
59
+ }
60
+
61
+ has(value: number): boolean {
62
+ const index = this.sparse[value]
63
+ return index !== undefined
64
+ && index < this.#length
65
+ && index < this.dense.length // 用于改善JIT优化.
66
+ && this.dense[index] === value
67
+ }
68
+
69
+ add(value: number): void {
70
+ if (!this.has(value)) {
71
+ const index = this.#length++
72
+ this.dense[index] = value
73
+ this.sparse[value] = index
74
+ }
75
+ }
76
+
77
+ delete(value: number): boolean {
78
+ const index = this.sparse[value]
79
+ if (
80
+ index !== undefined &&
81
+ index < this.#length &&
82
+ index < this.dense.length && // 用于改善JIT优化.
83
+ this.dense[index] === value
84
+ ) {
85
+ const lastIndex = --this.#length
86
+ const lastValue = this.dense[lastIndex]
87
+ if (value !== lastValue) {
88
+ this.dense[index] = lastValue
89
+ this.sparse[lastValue] = index
90
+ }
91
+
92
+ return true
93
+ } else {
94
+ return false
95
+ }
96
+ }
97
+
98
+ clear(): void {
99
+ this.#length = 0
100
+ // 无需清空dense和sparse数组.
101
+ }
102
+ }