@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.
- package/README.md +661 -92
- package/lib/async-generator-emitter.js +2 -5
- package/lib/async-generator-emitter.js.map +1 -1
- package/lib/big-map.js +1 -3
- package/lib/big-map.js.map +1 -1
- package/lib/big-set.js +1 -3
- package/lib/big-set.js.map +1 -1
- package/lib/{bit-set.d.ts → bit-set/bit-set.d.ts} +5 -2
- package/lib/{bit-set.js → bit-set/bit-set.js} +43 -34
- package/lib/bit-set/bit-set.js.map +1 -0
- package/lib/{typed-bit-set.d.ts → bit-set/dynamic-typed-bit-set.d.ts} +6 -4
- package/lib/bit-set/dynamic-typed-bit-set.js +95 -0
- package/lib/bit-set/dynamic-typed-bit-set.js.map +1 -0
- package/lib/bit-set/index.d.ts +4 -0
- package/lib/bit-set/index.js +5 -0
- package/lib/bit-set/index.js.map +1 -0
- package/lib/bit-set/resizable-typed-bit-set.d.ts +22 -0
- package/lib/{typed-bit-set.js → bit-set/resizable-typed-bit-set.js} +37 -39
- package/lib/bit-set/resizable-typed-bit-set.js.map +1 -0
- package/lib/bit-set/typed-bit-set.d.ts +22 -0
- package/lib/bit-set/typed-bit-set.js +99 -0
- package/lib/bit-set/typed-bit-set.js.map +1 -0
- package/lib/box.js +1 -0
- package/lib/box.js.map +1 -1
- package/lib/disjoint-set.js +2 -4
- package/lib/disjoint-set.js.map +1 -1
- package/lib/dynamic-typed-array.d.ts +12 -9
- package/lib/dynamic-typed-array.js +51 -66
- package/lib/dynamic-typed-array.js.map +1 -1
- package/lib/emitter.js +3 -7
- package/lib/emitter.js.map +1 -1
- package/lib/expirable-map.js +9 -15
- package/lib/expirable-map.js.map +1 -1
- package/lib/generator-emitter.js +2 -5
- package/lib/generator-emitter.js.map +1 -1
- package/lib/hash-map.js +2 -1
- package/lib/hash-map.js.map +1 -1
- package/lib/hash-set.js +2 -1
- package/lib/hash-set.js.map +1 -1
- package/lib/index.d.ts +5 -7
- package/lib/index.js +5 -7
- package/lib/index.js.map +1 -1
- package/lib/lru-map.js +2 -1
- package/lib/lru-map.js.map +1 -1
- package/lib/queue.js +1 -3
- package/lib/queue.js.map +1 -1
- package/lib/radix-tree.js +3 -4
- package/lib/radix-tree.js.map +1 -1
- package/lib/resizable-typed-array.d.ts +32 -0
- package/lib/resizable-typed-array.js +127 -0
- package/lib/resizable-typed-array.js.map +1 -0
- package/lib/sorted-set.js +2 -1
- package/lib/sorted-set.js.map +1 -1
- package/lib/sparse-map/clean-sparse-map.d.ts +18 -0
- package/lib/sparse-map/clean-sparse-map.js +74 -0
- package/lib/sparse-map/clean-sparse-map.js.map +1 -0
- package/lib/sparse-map/dynamic-typed-clean-sparse-map-lite.d.ts +21 -0
- package/lib/sparse-map/dynamic-typed-clean-sparse-map-lite.js +87 -0
- package/lib/sparse-map/dynamic-typed-clean-sparse-map-lite.js.map +1 -0
- package/lib/sparse-map/dynamic-typed-sparse-map-lite.d.ts +21 -0
- package/lib/sparse-map/dynamic-typed-sparse-map-lite.js +94 -0
- package/lib/sparse-map/dynamic-typed-sparse-map-lite.js.map +1 -0
- package/lib/sparse-map/index.d.ts +10 -0
- package/lib/sparse-map/index.js +11 -0
- package/lib/sparse-map/index.js.map +1 -0
- package/lib/sparse-map/resizable-typed-clean-sparse-map-lite.d.ts +21 -0
- package/lib/sparse-map/resizable-typed-clean-sparse-map-lite.js +85 -0
- package/lib/sparse-map/resizable-typed-clean-sparse-map-lite.js.map +1 -0
- package/lib/sparse-map/resizable-typed-sparse-map-lite.d.ts +21 -0
- package/lib/sparse-map/resizable-typed-sparse-map-lite.js +92 -0
- package/lib/sparse-map/resizable-typed-sparse-map-lite.js.map +1 -0
- package/lib/{sparse-map.d.ts → sparse-map/sparse-map.d.ts} +6 -5
- package/lib/sparse-map/sparse-map.js +86 -0
- package/lib/sparse-map/sparse-map.js.map +1 -0
- package/lib/sparse-map/typed-clean-sparse-map-lite.d.ts +21 -0
- package/lib/sparse-map/typed-clean-sparse-map-lite.js +92 -0
- package/lib/sparse-map/typed-clean-sparse-map-lite.js.map +1 -0
- package/lib/sparse-map/typed-clean-sparse-map.d.ts +22 -0
- package/lib/sparse-map/typed-clean-sparse-map.js +117 -0
- package/lib/sparse-map/typed-clean-sparse-map.js.map +1 -0
- package/lib/sparse-map/typed-sparse-map-lite.d.ts +21 -0
- package/lib/sparse-map/typed-sparse-map-lite.js +109 -0
- package/lib/sparse-map/typed-sparse-map-lite.js.map +1 -0
- package/lib/sparse-map/typed-sparse-map.d.ts +21 -0
- package/lib/sparse-map/typed-sparse-map.js +130 -0
- package/lib/sparse-map/typed-sparse-map.js.map +1 -0
- package/lib/sparse-set/clean-sparse-set.d.ts +13 -0
- package/lib/sparse-set/clean-sparse-set.js +57 -0
- package/lib/sparse-set/clean-sparse-set.js.map +1 -0
- package/lib/{typed-sparse-set.d.ts → sparse-set/dynamic-typed-clean-sparse-set-lite.d.ts} +6 -6
- package/lib/sparse-set/dynamic-typed-clean-sparse-set-lite.js +51 -0
- package/lib/sparse-set/dynamic-typed-clean-sparse-set-lite.js.map +1 -0
- package/lib/sparse-set/dynamic-typed-clean-sparse-set.d.ts +16 -0
- package/lib/sparse-set/dynamic-typed-clean-sparse-set.js +82 -0
- package/lib/sparse-set/dynamic-typed-clean-sparse-set.js.map +1 -0
- package/lib/sparse-set/dynamic-typed-sparse-set-lite.d.ts +15 -0
- package/lib/sparse-set/dynamic-typed-sparse-set-lite.js +52 -0
- package/lib/sparse-set/dynamic-typed-sparse-set-lite.js.map +1 -0
- package/lib/sparse-set/dynamic-typed-sparse-set.d.ts +15 -0
- package/lib/sparse-set/dynamic-typed-sparse-set.js +75 -0
- package/lib/sparse-set/dynamic-typed-sparse-set.js.map +1 -0
- package/lib/sparse-set/index.d.ts +14 -0
- package/lib/sparse-set/index.js +15 -0
- package/lib/sparse-set/index.js.map +1 -0
- package/lib/sparse-set/resizable-typed-clean-sparse-set-lite.d.ts +15 -0
- package/lib/sparse-set/resizable-typed-clean-sparse-set-lite.js +51 -0
- package/lib/sparse-set/resizable-typed-clean-sparse-set-lite.js.map +1 -0
- package/lib/sparse-set/resizable-typed-clean-sparse-set.d.ts +16 -0
- package/lib/sparse-set/resizable-typed-clean-sparse-set.js +83 -0
- package/lib/sparse-set/resizable-typed-clean-sparse-set.js.map +1 -0
- package/lib/sparse-set/resizable-typed-sparse-set-lite.d.ts +15 -0
- package/lib/sparse-set/resizable-typed-sparse-set-lite.js +52 -0
- package/lib/sparse-set/resizable-typed-sparse-set-lite.js.map +1 -0
- package/lib/sparse-set/resizable-typed-sparse-set.d.ts +15 -0
- package/lib/sparse-set/resizable-typed-sparse-set.js +76 -0
- package/lib/sparse-set/resizable-typed-sparse-set.js.map +1 -0
- package/lib/{sparse-set.d.ts → sparse-set/sparse-set.d.ts} +3 -4
- package/lib/sparse-set/sparse-set.js +60 -0
- package/lib/sparse-set/sparse-set.js.map +1 -0
- package/lib/sparse-set/typed-clean-sparse-set-lite.d.ts +15 -0
- package/lib/sparse-set/typed-clean-sparse-set-lite.js +55 -0
- package/lib/sparse-set/typed-clean-sparse-set-lite.js.map +1 -0
- package/lib/sparse-set/typed-clean-sparse-set.d.ts +16 -0
- package/lib/sparse-set/typed-clean-sparse-set.js +80 -0
- package/lib/sparse-set/typed-clean-sparse-set.js.map +1 -0
- package/lib/sparse-set/typed-sparse-set-lite.d.ts +15 -0
- package/lib/sparse-set/typed-sparse-set-lite.js +60 -0
- package/lib/sparse-set/typed-sparse-set-lite.js.map +1 -0
- package/lib/sparse-set/typed-sparse-set.d.ts +15 -0
- package/lib/sparse-set/typed-sparse-set.js +81 -0
- package/lib/sparse-set/typed-sparse-set.js.map +1 -0
- package/lib/string-radix-tree.js +3 -4
- package/lib/string-radix-tree.js.map +1 -1
- package/lib/string-trie-map.js +3 -4
- package/lib/string-trie-map.js.map +1 -1
- package/lib/tlru-map.js +6 -6
- package/lib/tlru-map.js.map +1 -1
- package/lib/trie-map.js +3 -4
- package/lib/trie-map.js.map +1 -1
- package/lib/unique-queue.js +1 -3
- package/lib/unique-queue.js.map +1 -1
- package/lib/utils/compute-new-capacity.d.ts +1 -0
- package/lib/utils/compute-new-capacity.js +36 -0
- package/lib/utils/compute-new-capacity.js.map +1 -0
- package/lib/utils/get-max-value-of-unsigned-typed-array.d.ts +3 -0
- package/lib/utils/get-max-value-of-unsigned-typed-array.js +13 -0
- package/lib/utils/get-max-value-of-unsigned-typed-array.js.map +1 -0
- package/lib/utils/skip-list.js +11 -9
- package/lib/utils/skip-list.js.map +1 -1
- package/lib/utils/trailing-zeros.js +1 -1
- package/lib/utils/trailing-zeros.js.map +1 -1
- package/package.json +28 -31
- package/src/{bit-set.ts → bit-set/bit-set.ts} +47 -31
- package/src/bit-set/dynamic-typed-bit-set.ts +131 -0
- package/src/bit-set/index.ts +4 -0
- package/src/{typed-bit-set.ts → bit-set/resizable-typed-bit-set.ts} +38 -36
- package/src/bit-set/typed-bit-set.ts +134 -0
- package/src/dynamic-typed-array.ts +67 -82
- package/src/index.ts +5 -7
- package/src/resizable-typed-array.ts +214 -0
- package/src/sparse-map/clean-sparse-map.ts +84 -0
- package/src/sparse-map/dynamic-typed-clean-sparse-map-lite.ts +109 -0
- package/src/sparse-map/dynamic-typed-sparse-map-lite.ts +124 -0
- package/src/sparse-map/index.ts +11 -0
- package/src/sparse-map/resizable-typed-clean-sparse-map-lite.ts +107 -0
- package/src/sparse-map/resizable-typed-sparse-map-lite.ts +122 -0
- package/src/sparse-map/sparse-map.ts +104 -0
- package/src/sparse-map/typed-clean-sparse-map-lite.ts +116 -0
- package/src/sparse-map/typed-clean-sparse-map.ts +149 -0
- package/src/sparse-map/typed-sparse-map-lite.ts +141 -0
- package/src/sparse-map/typed-sparse-map.ts +169 -0
- package/src/sparse-set/clean-sparse-set.ts +76 -0
- package/src/sparse-set/dynamic-typed-clean-sparse-set-lite.ts +64 -0
- package/src/sparse-set/dynamic-typed-clean-sparse-set.ts +101 -0
- package/src/sparse-set/dynamic-typed-sparse-set-lite.ts +67 -0
- package/src/sparse-set/dynamic-typed-sparse-set.ts +93 -0
- package/src/sparse-set/index.ts +15 -0
- package/src/sparse-set/resizable-typed-clean-sparse-set-lite.ts +64 -0
- package/src/sparse-set/resizable-typed-clean-sparse-set.ts +108 -0
- package/src/sparse-set/resizable-typed-sparse-set-lite.ts +67 -0
- package/src/sparse-set/resizable-typed-sparse-set.ts +97 -0
- package/src/sparse-set/sparse-set.ts +79 -0
- package/src/sparse-set/typed-clean-sparse-set-lite.ts +67 -0
- package/src/sparse-set/typed-clean-sparse-set.ts +100 -0
- package/src/sparse-set/typed-sparse-set-lite.ts +74 -0
- package/src/sparse-set/typed-sparse-set.ts +102 -0
- package/src/utils/compute-new-capacity.ts +39 -0
- package/src/utils/get-max-value-of-unsigned-typed-array.ts +19 -0
- package/src/utils/skip-list.ts +1 -1
- package/src/utils/trailing-zeros.ts +2 -3
- package/lib/bit-set.js.map +0 -1
- package/lib/sparse-map.js +0 -76
- package/lib/sparse-map.js.map +0 -1
- package/lib/sparse-set.js +0 -63
- package/lib/sparse-set.js.map +0 -1
- package/lib/typed-bit-set.js.map +0 -1
- package/lib/typed-sparse-map.d.ts +0 -20
- package/lib/typed-sparse-map.js +0 -83
- package/lib/typed-sparse-map.js.map +0 -1
- package/lib/typed-sparse-set.js +0 -59
- package/lib/typed-sparse-set.js.map +0 -1
- package/src/sparse-map.ts +0 -82
- package/src/sparse-set.ts +0 -74
- package/src/typed-sparse-map.ts +0 -97
- 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
|
+
}
|