@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
@@ -1 +1 @@
1
- {"version":3,"file":"trailing-zeros.js","sourceRoot":"","sources":["../../src/utils/trailing-zeros.ts"],"names":[],"mappings":"AACA,MAAM,iBAAiB,GAAa;IAClC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE;IACjC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;IAClC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE;IACpC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE;CACxB,CAAA;AAMD,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,OAAO,iBAAiB,CAAC,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,CAAA;AACjD,CAAC"}
1
+ {"version":3,"file":"trailing-zeros.js","sourceRoot":"","sources":["../../src/utils/trailing-zeros.ts"],"names":[],"mappings":"AACA,MAAM,iBAAiB,GAAa;IAClC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE;IACjC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;IAClC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE;IACpC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE;CACxB,CAAA;AAKD,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,OAAO,iBAAiB,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,CAAA;AACzD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blackglory/structures",
3
- "version": "0.14.15",
3
+ "version": "0.15.0",
4
4
  "description": "",
5
5
  "files": [
6
6
  "lib",
@@ -14,58 +14,55 @@
14
14
  "author": "BlackGlory <woshenmedoubuzhidao@blackglory.me>",
15
15
  "license": "MIT",
16
16
  "engines": {
17
- "node": ">=18.17.0"
17
+ "node": ">=22"
18
18
  },
19
19
  "scripts": {
20
- "prepare": "ts-patch install -s",
21
20
  "lint": "eslint --ext .js,.jsx,.ts,.tsx --quiet src __tests__",
22
21
  "test": "vitest --run",
23
- "prepublishOnly": "run-s prepare clean build",
22
+ "prepublishOnly": "run-s clean build",
24
23
  "clean": "rimraf lib",
25
- "build": "tsc --project tsconfig.build.json --outDir lib",
24
+ "build": "tsc --project tsconfig.build.json && tsc-alias --project tsconfig.build.json",
26
25
  "bench": "run-s bench:*",
27
26
  "bench:bit-set": "tsx benches/bit-set.ts",
28
27
  "bench:sparse-map": "tsx benches/sparse-map.ts",
29
28
  "bench:sparse-set": "tsx benches/sparse-set.ts",
29
+ "bench:resizable-array-buffer": "tsx benches/resizable-array-buffer.ts",
30
30
  "release": "standard-version"
31
31
  },
32
32
  "husky": {
33
33
  "hooks": {
34
- "pre-commit": "run-s prepare lint build test",
34
+ "pre-commit": "run-s lint build test",
35
35
  "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
36
36
  }
37
37
  },
38
38
  "devDependencies": {
39
- "@commitlint/cli": "^18.6.1",
40
- "@commitlint/config-conventional": "^18.6.2",
41
- "@types/node": "16",
42
- "@typescript-eslint/eslint-plugin": "^7.0.1",
43
- "@typescript-eslint/parser": "^7.0.1",
44
- "cross-env": "^7.0.3",
45
- "eslint": "^8.56.0",
46
- "extra-benchmark": "^0.2.3",
47
- "extra-generator": "^0.5.4",
48
- "extra-promise": "^6.2.0",
39
+ "@commitlint/cli": "^21.2.3",
40
+ "@commitlint/config-conventional": "^21.2.3",
41
+ "@eslint/js": "^10.0.1",
42
+ "cross-env": "^10.1.0",
43
+ "eslint": "^10.12.0",
44
+ "extra-benchmark": "^0.3.1",
45
+ "extra-generator": "^0.7.1",
46
+ "extra-promise": "^7.1.1",
49
47
  "husky": "^4.3.8",
50
48
  "npm-run-all": "^4.1.5",
51
- "return-style": "^3.0.1",
52
- "rimraf": "^5.0.5",
49
+ "return-style": "^4.0.0",
50
+ "rimraf": "^6.1.3",
53
51
  "standard-version": "^9.5.0",
54
- "ts-patch": "^3.1.2",
55
- "tslib": "^2.6.2",
56
- "tsx": "^4.7.1",
57
- "typescript": "5.3.3",
58
- "typescript-transform-paths": "^3.4.6",
59
- "vite": "^5.4.2",
60
- "vite-tsconfig-paths": "^5.0.1",
61
- "vitest": "^2.0.5"
52
+ "tsc-alias": "^1.9.7",
53
+ "tslib": "^2.8.1",
54
+ "tsx": "^4.23.15",
55
+ "typescript": "6",
56
+ "typescript-eslint": "^8.71.0",
57
+ "vite": "^8.3.2",
58
+ "vitest": "^5.0.3"
62
59
  },
63
60
  "dependencies": {
64
- "@blackglory/errors": "^3.0.3",
61
+ "@blackglory/errors": "^3.1.0",
65
62
  "@blackglory/go": "^2.0.0",
66
- "extra-timers": "^0.2.6",
67
- "extra-utils": "^5.6.0",
68
- "iterable-operator": "^5.0.0",
69
- "justypes": "^4.2.1"
63
+ "extra-timers": "^0.3.1",
64
+ "extra-utils": "^6.2.0",
65
+ "iterable-operator": "^6.0.0",
66
+ "justypes": "^4.5.0"
70
67
  }
71
68
  }
@@ -1,10 +1,14 @@
1
1
  import { assert } from '@blackglory/errors'
2
2
  import { trailingZeros } from '@utils/trailing-zeros.js'
3
3
 
4
- export class BitSet {
5
- private array: number[] = []
4
+ export class BitSet implements Iterable<number> {
5
+ private array: Array<number | undefined> = []
6
6
  private length = 0
7
- private _size = 0
7
+ #size = 0
8
+
9
+ private isBitsPerElementPowerOfTwo: boolean = false
10
+ private quotientShift = 0
11
+ private remainderMask = 0
8
12
 
9
13
  constructor(private bitsPerElement: number = 8) {
10
14
  assert(
@@ -15,11 +19,19 @@ export class BitSet {
15
19
  bitsPerElement > 0
16
20
  , 'The parameter bitsPerElement must be greater than 0'
17
21
  )
18
- // `31`是该数据结构中能够处理的最大值
19
22
  assert(
20
- bitsPerElement <= 31
21
- , 'The mask of bitsPerElement must be less than or equal to 31'
23
+ bitsPerElement <= 32
24
+ , 'The parameter bitsPerElement must be less than or equal to 32'
22
25
  )
26
+
27
+ // bitsPerElement为2的幂时, 进行性能优化.
28
+ this.isBitsPerElementPowerOfTwo = (
29
+ bitsPerElement & (bitsPerElement - 1)
30
+ ) === 0
31
+ if (this.isBitsPerElementPowerOfTwo) {
32
+ this.quotientShift = Math.log2(bitsPerElement)
33
+ this.remainderMask = bitsPerElement - 1
34
+ }
23
35
  }
24
36
 
25
37
  get [Symbol.toStringTag](): string {
@@ -27,7 +39,7 @@ export class BitSet {
27
39
  }
28
40
 
29
41
  get size(): number {
30
- return this._size
42
+ return this.#size
31
43
  }
32
44
 
33
45
  [Symbol.iterator](): IterableIterator<number> {
@@ -40,13 +52,12 @@ export class BitSet {
40
52
  const maxArrayLength = ~~(this.length / this.bitsPerElement) + 1
41
53
 
42
54
  for (let index = 0; index < maxArrayLength; index++) {
43
- let element = this.array[index]
44
- let offset = 0
45
- let indexOfBit: number
46
- while ((indexOfBit = trailingZeros(element)) !== 32) {
47
- yield index * this.bitsPerElement + offset + indexOfBit
48
- offset += indexOfBit + 1
49
- element >>= indexOfBit + 1
55
+ let element = this.array[index] ?? 0
56
+ while (element !== 0) {
57
+ const indexOfBit = trailingZeros(element)
58
+ yield index * this.bitsPerElement + indexOfBit
59
+ // 移除最低位置的1, 以推进下一个indexOfBit的获取.
60
+ element &= element - 1
50
61
  }
51
62
  }
52
63
  }
@@ -55,7 +66,7 @@ export class BitSet {
55
66
  _dumpBinaryStrings(): string[] {
56
67
  const result: string[] = []
57
68
  for (let i = 0; i < this.array.length; i++) {
58
- const binary = this.array[i].toString(2)
69
+ const binary = ((this.array[i] ?? 0) >>> 0).toString(2)
59
70
  if (binary.length < this.bitsPerElement) {
60
71
  result.push('0'.repeat(this.bitsPerElement - binary.length) + binary)
61
72
  } else {
@@ -72,39 +83,34 @@ export class BitSet {
72
83
  }
73
84
 
74
85
  add(value: number): boolean {
75
- assert(value >= 0, 'value must be greater than or equal to 0')
76
- if (value >= this.length) {
77
- this.length = value + 1
78
- }
79
-
80
86
  const [index, mask] = this.getPosition(value)
81
87
 
82
88
  const element = this.array[index] ?? 0
83
89
  this.array[index] = element | mask
84
90
 
85
91
  const added = (element & mask) !== mask
86
- if (added) {
87
- this._size++
88
- }
92
+ if (added) this.#size++
93
+
94
+ if (value >= this.length) this.length = value + 1
95
+
89
96
  return added
90
97
  }
91
98
 
92
99
  delete(value: number): boolean {
93
100
  const [index, mask] = this.getPosition(value)
94
101
 
95
- const element = (this.array[index] ?? 0)
102
+ const element = this.array[index] ?? 0
96
103
  this.array[index] = element & ~mask
97
104
 
98
105
  const deleted = (element & mask) === mask
99
- if (deleted) {
100
- this._size--
101
- }
106
+ if (deleted) this.#size--
102
107
 
103
108
  return deleted
104
109
  }
105
110
 
106
111
  clear(): void {
107
- this._size = 0
112
+ this.#size = 0
113
+ this.length = 0
108
114
  this.array.length = 0
109
115
  }
110
116
 
@@ -113,16 +119,26 @@ export class BitSet {
113
119
 
114
120
  clone.array = [...this.array]
115
121
  clone.length = this.length
116
- clone._size = this._size
122
+ clone.#size = this.#size
117
123
 
118
124
  return clone
119
125
  }
120
126
 
121
127
  private getPosition(value: number): [index: number, mask: number] {
122
- const remainder = value % this.bitsPerElement
123
- const quotient = (value - remainder) / this.bitsPerElement
128
+ let quotient: number
129
+ let remainder: number
130
+ if (this.isBitsPerElementPowerOfTwo) {
131
+ // 当bitsPerElement是2的幂时, 使用位运算版本.
132
+ remainder = value & this.remainderMask
133
+ quotient = value >>> this.quotientShift
134
+ } else {
135
+ remainder = value % this.bitsPerElement
136
+ quotient = (value - remainder) / this.bitsPerElement
137
+ }
138
+
124
139
  const index = quotient
125
140
  const mask = this.getMask(remainder)
141
+
126
142
  return [index, mask]
127
143
  }
128
144
 
@@ -0,0 +1,131 @@
1
+ import { UnsignedTypedArrayConstructor } from 'justypes'
2
+ import { assert } from '@blackglory/errors'
3
+ import { DynamicTypedArray } from '@src/dynamic-typed-array.js'
4
+ import { trailingZeros } from '@utils/trailing-zeros.js'
5
+
6
+ export class DynamicTypedBitSet implements Iterable<number> {
7
+ private bitsPerElement: number
8
+ private length = 0
9
+ #size = 0
10
+
11
+ private quotientShift = 0
12
+ private remainderMask = 0
13
+
14
+ get [Symbol.toStringTag](): string {
15
+ return this.constructor.name
16
+ }
17
+
18
+ get size(): number {
19
+ return this.#size
20
+ }
21
+
22
+ constructor(private array: DynamicTypedArray<UnsignedTypedArrayConstructor>) {
23
+ const bitsPerElement = array.BYTES_PER_ELEMENT * 8
24
+
25
+ assert(
26
+ Number.isInteger(bitsPerElement)
27
+ , 'The bitsPerElement must be an integer'
28
+ )
29
+ assert(
30
+ bitsPerElement > 0
31
+ , 'The bitsPerElement must be greater than 0'
32
+ )
33
+ assert(
34
+ bitsPerElement <= 32
35
+ , 'The bitsPerElement must be less than or equal to 31'
36
+ )
37
+
38
+ this.bitsPerElement = bitsPerElement
39
+ this.quotientShift = Math.log2(bitsPerElement)
40
+ this.remainderMask = bitsPerElement - 1
41
+ }
42
+
43
+ [Symbol.iterator](): IterableIterator<number> {
44
+ return this.values()
45
+ }
46
+
47
+ * values(): IterableIterator<number> {
48
+ if (this.length > 0) {
49
+ // maxArrayLength = Math.ceil(this.length / this.bitsPerElement)
50
+ const maxArrayLength = ~~(this.length / this.bitsPerElement) + 1
51
+
52
+ for (let index = 0; index < maxArrayLength; index++) {
53
+ let element = this.array.get(index) ?? 0
54
+ while (element !== 0) {
55
+ const indexOfBit = trailingZeros(element)
56
+ yield index * this.bitsPerElement + indexOfBit
57
+ // 移除最低位置的1, 以推进下一个indexOfBit的获取.
58
+ element &= element - 1
59
+ }
60
+ }
61
+ }
62
+ }
63
+
64
+ _dumpBinaryStrings(): string[] {
65
+ const result: string[] = []
66
+ for (let i = 0; i < this.array.length; i++) {
67
+ const binary = ((this.array.get(i) ?? 0) >>> 0).toString(2)
68
+ if (binary.length < this.bitsPerElement) {
69
+ result.push('0'.repeat(this.bitsPerElement - binary.length) + binary)
70
+ } else {
71
+ result.push(binary)
72
+ }
73
+ }
74
+ return result
75
+ }
76
+
77
+ has(value: number): boolean {
78
+ const [index, mask] = this.getPosition(value)
79
+
80
+ return ((this.array.get(index) ?? 0) & mask) === mask
81
+ }
82
+
83
+ add(value: number): boolean {
84
+ assert(value >= 0, 'value must be greater than or equal to 0')
85
+
86
+ const [index, mask] = this.getPosition(value)
87
+
88
+ const element = this.array.get(index) ?? 0
89
+ this.array.set(index, element | mask)
90
+
91
+ const added = (element & mask) !== mask
92
+ if (added) this.#size++
93
+
94
+ if (value >= this.length) this.length = value + 1
95
+
96
+ return added
97
+ }
98
+
99
+ delete(value: number): boolean {
100
+ const [index, mask] = this.getPosition(value)
101
+
102
+ const element = (this.array.get(index) ?? 0)
103
+ this.array.set(index, element & ~mask)
104
+
105
+ const deleted = (element & mask) === mask
106
+ if (deleted) this.#size--
107
+
108
+ return deleted
109
+ }
110
+
111
+ clear(): void {
112
+ this.#size = 0
113
+ this.array.clear()
114
+ }
115
+
116
+ private getPosition(value: number): [index: number, mask: number] {
117
+ const remainder = value & this.remainderMask
118
+ const quotient = value >>> this.quotientShift
119
+
120
+ const index = quotient
121
+ const mask = this.getMask(remainder)
122
+
123
+ return [index, mask]
124
+ }
125
+
126
+ // 输入一定是一个小于bitsPerElement的值, 取值范围是[0, bitsPerElement)
127
+ private getMask(value: number): number {
128
+ // return 2 ** value
129
+ return 1 << value
130
+ }
131
+ }
@@ -0,0 +1,4 @@
1
+ export * from './bit-set.js'
2
+ export * from './typed-bit-set.js'
3
+ export * from './dynamic-typed-bit-set.js'
4
+ export * from './resizable-typed-bit-set.js'
@@ -1,14 +1,25 @@
1
1
  import { UnsignedTypedArrayConstructor } from 'justypes'
2
2
  import { assert } from '@blackglory/errors'
3
- import { DynamicTypedArray } from './dynamic-typed-array.js'
3
+ import { ResizableTypedArray } from '@src/resizable-typed-array.js'
4
4
  import { trailingZeros } from '@utils/trailing-zeros.js'
5
5
 
6
- export class TypedBitSet<T extends UnsignedTypedArrayConstructor> {
6
+ export class ResizableTypedBitSet implements Iterable<number> {
7
7
  private bitsPerElement: number
8
8
  private length = 0
9
- private _size = 0
9
+ #size = 0
10
10
 
11
- constructor(private array: DynamicTypedArray<T>) {
11
+ private quotientShift = 0
12
+ private remainderMask = 0
13
+
14
+ get [Symbol.toStringTag](): string {
15
+ return this.constructor.name
16
+ }
17
+
18
+ get size(): number {
19
+ return this.#size
20
+ }
21
+
22
+ constructor(private array: ResizableTypedArray<UnsignedTypedArrayConstructor>) {
12
23
  const bitsPerElement = array.BYTES_PER_ELEMENT * 8
13
24
 
14
25
  assert(
@@ -21,19 +32,13 @@ export class TypedBitSet<T extends UnsignedTypedArrayConstructor> {
21
32
  )
22
33
  // `31`是该数据结构中能够处理的最大值
23
34
  assert(
24
- bitsPerElement <= 31
25
- , 'The mask of bitsPerElement must be less than or equal to 31'
35
+ bitsPerElement <= 32
36
+ , 'The bitsPerElement must be less than or equal to 31'
26
37
  )
27
38
 
28
39
  this.bitsPerElement = bitsPerElement
29
- }
30
-
31
- get [Symbol.toStringTag](): string {
32
- return this.constructor.name
33
- }
34
-
35
- get size(): number {
36
- return this._size
40
+ this.quotientShift = Math.log2(bitsPerElement)
41
+ this.remainderMask = bitsPerElement - 1
37
42
  }
38
43
 
39
44
  [Symbol.iterator](): IterableIterator<number> {
@@ -46,13 +51,12 @@ export class TypedBitSet<T extends UnsignedTypedArrayConstructor> {
46
51
  const maxArrayLength = ~~(this.length / this.bitsPerElement) + 1
47
52
 
48
53
  for (let index = 0; index < maxArrayLength; index++) {
49
- let element = this.array.internalTypedArray[index]
50
- let offset = 0
51
- let indexOfBit: number
52
- while ((indexOfBit = trailingZeros(element)) !== 32) {
53
- yield index * this.bitsPerElement + offset + indexOfBit
54
- offset += indexOfBit + 1
55
- element >>= indexOfBit + 1
54
+ let element = this.array.get(index) ?? 0
55
+ while (element !== 0) {
56
+ const indexOfBit = trailingZeros(element)
57
+ yield index * this.bitsPerElement + indexOfBit
58
+ // 移除最低位置的1, 以推进下一个indexOfBit的获取.
59
+ element &= element - 1
56
60
  }
57
61
  }
58
62
  }
@@ -61,7 +65,7 @@ export class TypedBitSet<T extends UnsignedTypedArrayConstructor> {
61
65
  _dumpBinaryStrings(): string[] {
62
66
  const result: string[] = []
63
67
  for (let i = 0; i < this.array.length; i++) {
64
- const binary = this.array.internalTypedArray[i].toString(2)
68
+ const binary = ((this.array.get(i) ?? 0) >>> 0).toString(2)
65
69
  if (binary.length < this.bitsPerElement) {
66
70
  result.push('0'.repeat(this.bitsPerElement - binary.length) + binary)
67
71
  } else {
@@ -78,20 +82,16 @@ export class TypedBitSet<T extends UnsignedTypedArrayConstructor> {
78
82
  }
79
83
 
80
84
  add(value: number): boolean {
81
- assert(value >= 0, 'value must be greater than or equal to 0')
82
- if (value >= this.length) {
83
- this.length = value + 1
84
- }
85
-
86
85
  const [index, mask] = this.getPosition(value)
87
86
 
88
87
  const element = this.array.get(index) ?? 0
89
88
  this.array.set(index, element | mask)
90
89
 
91
90
  const added = (element & mask) !== mask
92
- if (added) {
93
- this._size++
94
- }
91
+ if (added) this.#size++
92
+
93
+ if (value >= this.length) this.length = value + 1
94
+
95
95
  return added
96
96
  }
97
97
 
@@ -102,22 +102,24 @@ export class TypedBitSet<T extends UnsignedTypedArrayConstructor> {
102
102
  this.array.set(index, element & ~mask)
103
103
 
104
104
  const deleted = (element & mask) === mask
105
- if (deleted) {
106
- this._size--
107
- }
105
+ if (deleted) this.#size--
106
+
108
107
  return deleted
109
108
  }
110
109
 
111
110
  clear(): void {
112
- this._size = 0
111
+ this.#size = 0
112
+ this.length = 0
113
113
  this.array.clear()
114
114
  }
115
115
 
116
116
  private getPosition(value: number): [index: number, mask: number] {
117
- const remainder = value % this.bitsPerElement
118
- const quotient = (value - remainder) / this.bitsPerElement
117
+ const remainder = value & this.remainderMask
118
+ const quotient = value >>> this.quotientShift
119
+
119
120
  const index = quotient
120
121
  const mask = this.getMask(remainder)
122
+
121
123
  return [index, mask]
122
124
  }
123
125
 
@@ -0,0 +1,134 @@
1
+ import { UnsignedTypedArray } from 'justypes'
2
+ import { assert } from '@blackglory/errors'
3
+ import { trailingZeros } from '@utils/trailing-zeros.js'
4
+
5
+ export class TypedBitSet implements Iterable<number> {
6
+ private bitsPerElement: number
7
+ private length = 0
8
+ #size = 0
9
+
10
+ private quotientShift = 0
11
+ private remainderMask = 0
12
+
13
+ get [Symbol.toStringTag](): string {
14
+ return this.constructor.name
15
+ }
16
+
17
+ get capacity(): number {
18
+ return this.array.length * this.bitsPerElement
19
+ }
20
+
21
+ get size(): number {
22
+ return this.#size
23
+ }
24
+
25
+ constructor(private array: UnsignedTypedArray) {
26
+ const bitsPerElement = array.BYTES_PER_ELEMENT * 8
27
+
28
+ assert(
29
+ Number.isInteger(bitsPerElement)
30
+ , 'The bitsPerElement must be an integer'
31
+ )
32
+ assert(
33
+ bitsPerElement > 0
34
+ , 'The bitsPerElement must be greater than 0'
35
+ )
36
+ assert(
37
+ bitsPerElement <= 32
38
+ , 'The bitsPerElement must be less than or equal to 32'
39
+ )
40
+
41
+ this.bitsPerElement = bitsPerElement
42
+ this.quotientShift = Math.log2(bitsPerElement)
43
+ this.remainderMask = bitsPerElement - 1
44
+ }
45
+
46
+ [Symbol.iterator](): IterableIterator<number> {
47
+ return this.values()
48
+ }
49
+
50
+ * values(): IterableIterator<number> {
51
+ if (this.length > 0) {
52
+ // maxArrayLength = Math.ceil(this.length / this.bitsPerElement)
53
+ const maxArrayLength = ~~(this.length / this.bitsPerElement) + 1
54
+
55
+ for (let index = 0; index < maxArrayLength; index++) {
56
+ let element = this.array[index] ?? 0
57
+ while (element !== 0) {
58
+ const indexOfBit = trailingZeros(element)
59
+ yield index * this.bitsPerElement + indexOfBit
60
+ // 移除最低位置的1, 以推进下一个indexOfBit的获取.
61
+ element &= element - 1
62
+ }
63
+ }
64
+ }
65
+ }
66
+
67
+ _dumpBinaryStrings(): string[] {
68
+ const result: string[] = []
69
+ for (let i = 0; i < this.array.length; i++) {
70
+ const binary = ((this.array[i] ?? 0) >>> 0).toString(2)
71
+ if (binary.length < this.bitsPerElement) {
72
+ result.push('0'.repeat(this.bitsPerElement - binary.length) + binary)
73
+ } else {
74
+ result.push(binary)
75
+ }
76
+ }
77
+ return result
78
+ }
79
+
80
+ has(value: number): boolean {
81
+ const [index, mask] = this.getPosition(value)
82
+
83
+ return (this.array[index] & mask) === mask
84
+ }
85
+
86
+ add(value: number): boolean {
87
+ const [index, mask] = this.getPosition(value)
88
+ assert(index < this.capacity, `The array is not large enough`)
89
+
90
+ const element = this.array[index]
91
+ this.array[index] = element | mask
92
+
93
+ const added = (element & mask) !== mask
94
+ if (added) this.#size++
95
+
96
+ if (value >= this.length) this.length = value + 1
97
+
98
+ return added
99
+ }
100
+
101
+ delete(value: number): boolean {
102
+ const [index, mask] = this.getPosition(value)
103
+
104
+ const element = this.array[index]
105
+ this.array[index] = element & ~mask
106
+
107
+ const deleted = (element & mask) === mask
108
+ if (deleted) this.#size--
109
+
110
+ return deleted
111
+ }
112
+
113
+ clear(): void {
114
+ this.#size = 0
115
+ this.length = 0
116
+ this.array.fill(0)
117
+ }
118
+
119
+ private getPosition(value: number): [index: number, mask: number] {
120
+ const remainder = value & this.remainderMask
121
+ const quotient = value >>> this.quotientShift
122
+
123
+ const index = quotient
124
+ const mask = this.getMask(remainder)
125
+
126
+ return [index, mask]
127
+ }
128
+
129
+ // 输入一定是一个小于bitsPerElement的值, 取值范围是[0, bitsPerElement)
130
+ private getMask(value: number): number {
131
+ // return 2 ** value
132
+ return 1 << value
133
+ }
134
+ }