@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
|
@@ -1,28 +1,30 @@
|
|
|
1
1
|
import { TypedArrayConstructor, TypedArrayOfConstructor } from 'justypes'
|
|
2
2
|
import { assert } from '@blackglory/errors'
|
|
3
|
+
import { computeNewCapacity } from '@utils/compute-new-capacity.js'
|
|
3
4
|
|
|
4
5
|
interface IDynamicTypedArrayOptions {
|
|
5
|
-
capacity?: number
|
|
6
6
|
growthFactor?: number
|
|
7
|
+
initialCapacity?: number
|
|
8
|
+
fillValue?: number
|
|
7
9
|
}
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
export class DynamicTypedArray<
|
|
12
|
+
T extends TypedArrayConstructor
|
|
13
|
+
> implements Iterable<number> {
|
|
11
14
|
private array: TypedArrayOfConstructor<T>
|
|
12
|
-
|
|
13
|
-
private initialCapacity: number
|
|
15
|
+
|
|
14
16
|
readonly growthFactor: number
|
|
17
|
+
readonly BYTES_PER_ELEMENT: number
|
|
18
|
+
readonly fillValue: number
|
|
15
19
|
|
|
16
|
-
|
|
17
|
-
return this.array
|
|
18
|
-
}
|
|
20
|
+
#length: number = 0
|
|
19
21
|
|
|
20
22
|
get [Symbol.toStringTag](): string {
|
|
21
23
|
return this.constructor.name
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
get
|
|
25
|
-
return this.
|
|
26
|
+
get internalTypedArray(): TypedArrayOfConstructor<T> {
|
|
27
|
+
return this.array
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
/**
|
|
@@ -36,23 +38,39 @@ export class DynamicTypedArray<T extends TypedArrayConstructor> {
|
|
|
36
38
|
* 数组逻辑上的长度, 总是小于或等于capacity.
|
|
37
39
|
*/
|
|
38
40
|
get length(): number {
|
|
39
|
-
return this
|
|
41
|
+
return this.#length
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
constructor(
|
|
43
45
|
private typedArrayConstructor: T
|
|
44
46
|
, {
|
|
45
|
-
|
|
46
|
-
,
|
|
47
|
+
growthFactor = 1.5
|
|
48
|
+
, initialCapacity = 0
|
|
49
|
+
, fillValue = 0
|
|
47
50
|
}: IDynamicTypedArrayOptions = {}
|
|
48
51
|
) {
|
|
49
|
-
assert(Number.isInteger(capacity), 'capacity must be an integer')
|
|
50
|
-
assert(capacity >= 0, 'capacity must be greater than or equal to 0')
|
|
51
52
|
assert(growthFactor >= 1, 'growthFactory must be greater than or equal to 1')
|
|
53
|
+
assert(Number.isInteger(initialCapacity), 'initialCapacity must be an integer')
|
|
54
|
+
assert(initialCapacity >= 0, 'initialCapacity must be greater than or equal to 0')
|
|
52
55
|
|
|
53
|
-
this.initialCapacity = capacity
|
|
54
|
-
this.array = new typedArrayConstructor(capacity) as TypedArrayOfConstructor<T>
|
|
55
56
|
this.growthFactor = growthFactor
|
|
57
|
+
this.fillValue = fillValue
|
|
58
|
+
|
|
59
|
+
const array = new typedArrayConstructor(initialCapacity) as TypedArrayOfConstructor<T>
|
|
60
|
+
if (fillValue !== 0) array.fill(fillValue)
|
|
61
|
+
this.array = array
|
|
62
|
+
|
|
63
|
+
this.BYTES_PER_ELEMENT = typedArrayConstructor.BYTES_PER_ELEMENT
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
[Symbol.iterator](): IterableIterator<number> {
|
|
67
|
+
return this.values()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
* values(): IterableIterator<number> {
|
|
71
|
+
for (let i = 0; i < this.#length; i++) {
|
|
72
|
+
yield this.array[i]
|
|
73
|
+
}
|
|
56
74
|
}
|
|
57
75
|
|
|
58
76
|
set(index: number, value: number): void {
|
|
@@ -65,38 +83,39 @@ export class DynamicTypedArray<T extends TypedArrayConstructor> {
|
|
|
65
83
|
this.resize(newCapacity)
|
|
66
84
|
}
|
|
67
85
|
|
|
68
|
-
if (index >= this
|
|
69
|
-
this
|
|
86
|
+
if (index >= this.#length) {
|
|
87
|
+
this.#length = index + 1
|
|
70
88
|
}
|
|
71
89
|
|
|
72
90
|
this.array[index] = value
|
|
73
91
|
}
|
|
74
92
|
|
|
75
|
-
setValues(index: number, values:
|
|
76
|
-
|
|
93
|
+
setValues(index: number, values: ArrayLike<number>): void {
|
|
94
|
+
const endIndex = index + values.length
|
|
95
|
+
if (endIndex > this.capacity) {
|
|
77
96
|
const newCapacity = computeNewCapacity(
|
|
78
97
|
this.capacity
|
|
79
|
-
,
|
|
98
|
+
, endIndex
|
|
80
99
|
, this.growthFactor
|
|
81
100
|
)
|
|
82
101
|
this.resize(newCapacity)
|
|
83
102
|
}
|
|
84
103
|
|
|
85
|
-
if (
|
|
86
|
-
this
|
|
104
|
+
if (endIndex > this.#length) {
|
|
105
|
+
this.#length = endIndex
|
|
87
106
|
}
|
|
88
107
|
|
|
89
|
-
this.
|
|
108
|
+
this.array.set(values, index)
|
|
90
109
|
}
|
|
91
110
|
|
|
92
111
|
get(index: number): number | undefined {
|
|
93
|
-
return index < this
|
|
112
|
+
return index < this.#length
|
|
94
113
|
? this.array[index]
|
|
95
114
|
: undefined
|
|
96
115
|
}
|
|
97
116
|
|
|
98
117
|
push(...values: number[]): void {
|
|
99
|
-
const newLength = this
|
|
118
|
+
const newLength = this.#length + values.length
|
|
100
119
|
if (newLength > this.capacity) {
|
|
101
120
|
const newCapacity = computeNewCapacity(
|
|
102
121
|
this.capacity
|
|
@@ -107,21 +126,14 @@ export class DynamicTypedArray<T extends TypedArrayConstructor> {
|
|
|
107
126
|
}
|
|
108
127
|
|
|
109
128
|
for (const value of values) {
|
|
110
|
-
this.array[this
|
|
129
|
+
this.array[this.#length++] = value
|
|
111
130
|
}
|
|
112
131
|
}
|
|
113
132
|
|
|
114
133
|
pop(): number | undefined {
|
|
115
|
-
if (this
|
|
116
|
-
const value = this.array[this
|
|
117
|
-
this
|
|
118
|
-
|
|
119
|
-
const newCapacity = computeNewCapacity(
|
|
120
|
-
this.capacity
|
|
121
|
-
, this.length
|
|
122
|
-
, this.growthFactor
|
|
123
|
-
)
|
|
124
|
-
this.resize(newCapacity)
|
|
134
|
+
if (this.#length > 0) {
|
|
135
|
+
const value = this.array[this.#length - 1]
|
|
136
|
+
this.#length--
|
|
125
137
|
|
|
126
138
|
return value
|
|
127
139
|
} else {
|
|
@@ -130,9 +142,16 @@ export class DynamicTypedArray<T extends TypedArrayConstructor> {
|
|
|
130
142
|
}
|
|
131
143
|
|
|
132
144
|
clear(): void {
|
|
133
|
-
this
|
|
134
|
-
|
|
135
|
-
|
|
145
|
+
this.#length = 0
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
shrink(): void {
|
|
149
|
+
const newCapacity = computeNewCapacity(
|
|
150
|
+
this.capacity
|
|
151
|
+
, this.length
|
|
152
|
+
, this.growthFactor
|
|
153
|
+
)
|
|
154
|
+
this.resize(newCapacity)
|
|
136
155
|
}
|
|
137
156
|
|
|
138
157
|
sort(compare?: (a: number, b: number) => number): void {
|
|
@@ -148,8 +167,14 @@ export class DynamicTypedArray<T extends TypedArrayConstructor> {
|
|
|
148
167
|
} else if (this.array.length < newCapacity) {
|
|
149
168
|
const newArray = new this.typedArrayConstructor(newCapacity)
|
|
150
169
|
newArray.set(this.array)
|
|
170
|
+
|
|
171
|
+
if (this.fillValue !== 0) {
|
|
172
|
+
const startIndex = this.array.length
|
|
173
|
+
newArray.fill(this.fillValue, startIndex)
|
|
174
|
+
}
|
|
175
|
+
|
|
151
176
|
this.array = newArray as TypedArrayOfConstructor<T>
|
|
152
|
-
} else if (this.array.length > newCapacity) {
|
|
177
|
+
} else /* if (this.array.length > newCapacity) */ {
|
|
153
178
|
const newArray = new this.typedArrayConstructor(newCapacity)
|
|
154
179
|
// 不需要的部分将被舍弃.
|
|
155
180
|
for (let i = newCapacity; i--;) {
|
|
@@ -159,43 +184,3 @@ export class DynamicTypedArray<T extends TypedArrayConstructor> {
|
|
|
159
184
|
}
|
|
160
185
|
}
|
|
161
186
|
}
|
|
162
|
-
|
|
163
|
-
export function computeNewCapacity(
|
|
164
|
-
oldCapacity: number
|
|
165
|
-
, targetLength: number
|
|
166
|
-
, growthFactor: number
|
|
167
|
-
): number {
|
|
168
|
-
if (growthFactor === 1) {
|
|
169
|
-
return targetLength
|
|
170
|
-
} else {
|
|
171
|
-
if (oldCapacity === targetLength) {
|
|
172
|
-
return targetLength
|
|
173
|
-
} else if (oldCapacity < targetLength) {
|
|
174
|
-
// 增加容量以适配targetLength
|
|
175
|
-
let newCapacity = Math.max(oldCapacity, 1)
|
|
176
|
-
while (newCapacity < targetLength) {
|
|
177
|
-
newCapacity *= growthFactor
|
|
178
|
-
}
|
|
179
|
-
return Math.floor(newCapacity)
|
|
180
|
-
} else {
|
|
181
|
-
// 尝试减少容量以适配targetLength
|
|
182
|
-
|
|
183
|
-
// `targetLength = 0`是特殊情况,
|
|
184
|
-
// 此时无论怎么将oldCapacity除以growthFactory几次, 都不可能得到比targetLength小的结果.
|
|
185
|
-
if (targetLength === 0) {
|
|
186
|
-
return 0
|
|
187
|
-
} else {
|
|
188
|
-
let newCapacity = oldCapacity
|
|
189
|
-
while (true) {
|
|
190
|
-
const temp = newCapacity / growthFactor
|
|
191
|
-
if (temp < targetLength) {
|
|
192
|
-
break
|
|
193
|
-
} else {
|
|
194
|
-
newCapacity = temp
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
return Math.floor(newCapacity)
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
package/src/index.ts
CHANGED
|
@@ -17,12 +17,10 @@ export * from './trie-map.js'
|
|
|
17
17
|
export * from './string-trie-map.js'
|
|
18
18
|
export { RadixTree } from './radix-tree.js'
|
|
19
19
|
export { StringRadixTree } from './string-radix-tree.js'
|
|
20
|
-
export * from './
|
|
21
|
-
export * from './
|
|
22
|
-
export * from './typed-sparse-map.js'
|
|
23
|
-
export * from './typed-sparse-set.js'
|
|
24
|
-
export { DynamicTypedArray } from './dynamic-typed-array.js'
|
|
20
|
+
export * from './dynamic-typed-array.js'
|
|
21
|
+
export * from './resizable-typed-array.js'
|
|
25
22
|
export * from './sorted-set.js'
|
|
26
|
-
export * from './bit-set.js'
|
|
27
|
-
export * from './typed-bit-set.js'
|
|
28
23
|
export * from './disjoint-set.js'
|
|
24
|
+
export * from './bit-set/index.js'
|
|
25
|
+
export * from './sparse-set/index.js'
|
|
26
|
+
export * from './sparse-map/index.js'
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { TypedArrayConstructor, TypedArrayOfConstructor } from 'justypes'
|
|
2
|
+
import { assert } from '@blackglory/errors'
|
|
3
|
+
import { computeNewCapacity } from '@utils/compute-new-capacity.js'
|
|
4
|
+
|
|
5
|
+
interface IResizableTypedArrayOptions {
|
|
6
|
+
maxCapacity: number
|
|
7
|
+
|
|
8
|
+
initialCapacity?: number
|
|
9
|
+
growthFactor?: number
|
|
10
|
+
|
|
11
|
+
fillValue?: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class ResizableTypedArray<
|
|
15
|
+
T extends TypedArrayConstructor
|
|
16
|
+
> implements Iterable<number> {
|
|
17
|
+
private array: TypedArrayOfConstructor<T, ArrayBuffer>
|
|
18
|
+
|
|
19
|
+
readonly maxCapacity: number
|
|
20
|
+
readonly growthFactor: number
|
|
21
|
+
readonly BYTES_PER_ELEMENT: number
|
|
22
|
+
readonly internalTypedArray: TypedArrayOfConstructor<T>
|
|
23
|
+
readonly fillValue: number
|
|
24
|
+
|
|
25
|
+
#length: number = 0
|
|
26
|
+
|
|
27
|
+
get [Symbol.toStringTag](): string {
|
|
28
|
+
return this.constructor.name
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 数组当前的容量.
|
|
33
|
+
*/
|
|
34
|
+
get capacity(): number {
|
|
35
|
+
return this.array.length
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 数组逻辑上的长度, 总是小于或等于capacity.
|
|
40
|
+
*/
|
|
41
|
+
get length(): number {
|
|
42
|
+
return this.#length
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
constructor(
|
|
46
|
+
typedArrayConstructor: T
|
|
47
|
+
, {
|
|
48
|
+
maxCapacity
|
|
49
|
+
, initialCapacity = 0
|
|
50
|
+
, growthFactor = 1.5
|
|
51
|
+
, fillValue = 0
|
|
52
|
+
}: IResizableTypedArrayOptions
|
|
53
|
+
) {
|
|
54
|
+
assert(growthFactor >= 1, 'growthFactory must be greater than or equal to 1')
|
|
55
|
+
assert(initialCapacity >= 0, 'initialCapacity must be greater than or equal to 0')
|
|
56
|
+
assert(Number.isInteger(initialCapacity), 'capacity must be an integer')
|
|
57
|
+
assert(initialCapacity >= 0, 'capacity must be greater than or equal to 0')
|
|
58
|
+
assert(Number.isInteger(maxCapacity), 'maxCapacity must be an integer')
|
|
59
|
+
assert(maxCapacity >= initialCapacity, 'maxCapacity must be greater than or equal to capacity')
|
|
60
|
+
|
|
61
|
+
this.growthFactor = growthFactor
|
|
62
|
+
this.maxCapacity = maxCapacity
|
|
63
|
+
this.fillValue = fillValue
|
|
64
|
+
|
|
65
|
+
const buffer = new ArrayBuffer(
|
|
66
|
+
initialCapacity * typedArrayConstructor.BYTES_PER_ELEMENT
|
|
67
|
+
, { maxByteLength: maxCapacity * typedArrayConstructor.BYTES_PER_ELEMENT }
|
|
68
|
+
)
|
|
69
|
+
const array = new typedArrayConstructor(buffer)
|
|
70
|
+
if (fillValue !== 0) array.fill(fillValue)
|
|
71
|
+
this.array = array as TypedArrayOfConstructor<T, ArrayBuffer>
|
|
72
|
+
|
|
73
|
+
this.internalTypedArray = array as TypedArrayOfConstructor<T, ArrayBuffer>
|
|
74
|
+
this.BYTES_PER_ELEMENT = typedArrayConstructor.BYTES_PER_ELEMENT
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
[Symbol.iterator](): IterableIterator<number> {
|
|
78
|
+
return this.values()
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
* values(): IterableIterator<number> {
|
|
82
|
+
for (let i = 0; i < this.#length; i++) {
|
|
83
|
+
yield this.array[i]
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
set(index: number, value: number): void {
|
|
88
|
+
if (index >= this.capacity) {
|
|
89
|
+
assert(index < this.maxCapacity, 'index must be less than maxCapacity')
|
|
90
|
+
|
|
91
|
+
const newCapacity = Math.min(
|
|
92
|
+
computeNewCapacity(
|
|
93
|
+
this.capacity
|
|
94
|
+
, index + 1
|
|
95
|
+
, this.growthFactor
|
|
96
|
+
)
|
|
97
|
+
, this.maxCapacity
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
this.resize(newCapacity)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (index >= this.#length) {
|
|
104
|
+
this.#length = index + 1
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
this.array[index] = value
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
setValues(index: number, values: ArrayLike<number>): void {
|
|
111
|
+
const endIndex = index + values.length
|
|
112
|
+
if (endIndex > this.capacity) {
|
|
113
|
+
assert(
|
|
114
|
+
endIndex <= this.maxCapacity
|
|
115
|
+
, 'endIndex must be less than or equal tomaxCapacity'
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
const newCapacity = Math.min(
|
|
119
|
+
computeNewCapacity(
|
|
120
|
+
this.capacity
|
|
121
|
+
, index + values.length
|
|
122
|
+
, this.growthFactor
|
|
123
|
+
)
|
|
124
|
+
, this.maxCapacity
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
this.resize(newCapacity)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (endIndex > this.#length) {
|
|
131
|
+
this.#length = endIndex
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
this.array.set(values, index)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
get(index: number): number | undefined {
|
|
138
|
+
return index < this.#length
|
|
139
|
+
? this.array[index]
|
|
140
|
+
: undefined
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
push(...values: number[]): void {
|
|
144
|
+
const newLength = this.#length + values.length
|
|
145
|
+
if (newLength > this.capacity) {
|
|
146
|
+
assert(
|
|
147
|
+
newLength <= this.maxCapacity
|
|
148
|
+
, 'newLength must be less than or equal to maxCapacity'
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
const newCapacity = Math.min(
|
|
152
|
+
computeNewCapacity(
|
|
153
|
+
this.capacity
|
|
154
|
+
, newLength
|
|
155
|
+
, this.growthFactor
|
|
156
|
+
)
|
|
157
|
+
, this.maxCapacity
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
this.resize(newCapacity)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
for (const value of values) {
|
|
164
|
+
this.array[this.#length++] = value
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
pop(): number | undefined {
|
|
169
|
+
if (this.#length > 0) {
|
|
170
|
+
const value = this.array[this.#length - 1]
|
|
171
|
+
this.#length--
|
|
172
|
+
|
|
173
|
+
return value
|
|
174
|
+
} else {
|
|
175
|
+
return undefined
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
clear(): void {
|
|
180
|
+
this.#length = 0
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
shrink(): void {
|
|
184
|
+
const newCapacity = computeNewCapacity(
|
|
185
|
+
this.capacity
|
|
186
|
+
, this.length
|
|
187
|
+
, this.growthFactor
|
|
188
|
+
)
|
|
189
|
+
this.resize(newCapacity)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
sort(compare?: (a: number, b: number) => number): void {
|
|
193
|
+
const capacity = this.capacity
|
|
194
|
+
this.resize(this.length)
|
|
195
|
+
this.array.sort(compare)
|
|
196
|
+
this.resize(capacity)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private resize(newCapacity: number): void {
|
|
200
|
+
if (this.array.length === newCapacity) {
|
|
201
|
+
return
|
|
202
|
+
} else if (this.array.length < newCapacity) {
|
|
203
|
+
if (this.fillValue === 0) {
|
|
204
|
+
this.array.buffer.resize(newCapacity * this.BYTES_PER_ELEMENT)
|
|
205
|
+
} else {
|
|
206
|
+
const startIndex = this.array.length
|
|
207
|
+
this.array.buffer.resize(newCapacity * this.BYTES_PER_ELEMENT)
|
|
208
|
+
this.array.fill(this.fillValue, startIndex)
|
|
209
|
+
}
|
|
210
|
+
} else /* if (this.array.length > newCapacity) */ {
|
|
211
|
+
this.array.buffer.resize(newCapacity * this.BYTES_PER_ELEMENT)
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
export class CleanSparseMap<T> {
|
|
2
|
+
private denseKeys: number[] = []
|
|
3
|
+
private denseValues: T[] = []
|
|
4
|
+
private sparse: Array<number | undefined> = []
|
|
5
|
+
|
|
6
|
+
get [Symbol.toStringTag](): string {
|
|
7
|
+
return this.constructor.name
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
get size(): number {
|
|
11
|
+
return this.denseKeys.length
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
readonly internalKeyArray: readonly number[] = this.denseKeys
|
|
15
|
+
readonly internalValueArray: T[] = this.denseValues
|
|
16
|
+
|
|
17
|
+
;* entries(): IterableIterator<[key: number, value: T]> {
|
|
18
|
+
for (let i = 0; i < this.denseKeys.length; i++) {
|
|
19
|
+
yield [this.denseKeys[i], this.denseValues[i]]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
keys(): IterableIterator<number> {
|
|
24
|
+
return this.denseKeys.values()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
values(): IterableIterator<T> {
|
|
28
|
+
return this.denseValues.values()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
getInternalIndexOfKey(key: number): number | undefined {
|
|
32
|
+
return this.sparse[key]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
has(key: number): boolean {
|
|
36
|
+
return this.sparse[key] !== undefined
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get(key: number): T | undefined {
|
|
40
|
+
const index = this.sparse[key]
|
|
41
|
+
if (index !== undefined) {
|
|
42
|
+
return this.denseValues[index]
|
|
43
|
+
} else {
|
|
44
|
+
return undefined
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
set(key: number, value: T): void {
|
|
49
|
+
const index = this.sparse[key]
|
|
50
|
+
if (index !== undefined) {
|
|
51
|
+
this.denseValues[index] = value
|
|
52
|
+
} else {
|
|
53
|
+
const index = this.denseKeys.length
|
|
54
|
+
this.denseKeys.push(key)
|
|
55
|
+
this.denseValues.push(value)
|
|
56
|
+
this.sparse[key] = index
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
delete(key: number): boolean {
|
|
61
|
+
const index = this.sparse[key]
|
|
62
|
+
if (index !== undefined) {
|
|
63
|
+
this.sparse[key] = undefined
|
|
64
|
+
|
|
65
|
+
const lastKey = this.denseKeys.pop()!
|
|
66
|
+
const lastValue = this.denseValues.pop()!
|
|
67
|
+
if (key !== lastKey) {
|
|
68
|
+
this.denseKeys[index] = lastKey
|
|
69
|
+
this.denseValues[index] = lastValue
|
|
70
|
+
this.sparse[lastKey] = index
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return true
|
|
74
|
+
} else {
|
|
75
|
+
return false
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
clear(): void {
|
|
80
|
+
this.denseKeys.length = 0
|
|
81
|
+
this.denseValues.length = 0
|
|
82
|
+
this.sparse.length = 0
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { assert } from '@blackglory/errors'
|
|
2
|
+
import { TypedArrayConstructor, UnsignedTypedArrayConstructor, TypedArrayOfConstructor } from 'justypes'
|
|
3
|
+
import { DynamicTypedArray } from '@src/dynamic-typed-array.js'
|
|
4
|
+
|
|
5
|
+
export class DynamicTypedCleanSparseMapLite<
|
|
6
|
+
K extends UnsignedTypedArrayConstructor
|
|
7
|
+
, V extends TypedArrayConstructor
|
|
8
|
+
> {
|
|
9
|
+
private denseKeys: DynamicTypedArray<K>
|
|
10
|
+
private denseValues: DynamicTypedArray<V>
|
|
11
|
+
private sparse: Array<number | undefined> = []
|
|
12
|
+
|
|
13
|
+
get [Symbol.toStringTag](): string {
|
|
14
|
+
return this.constructor.name
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get size(): number {
|
|
18
|
+
return this.denseKeys.length
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get internalKeyArray(): TypedArrayOfConstructor<K> {
|
|
22
|
+
return this.denseKeys.internalTypedArray
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
get internalValueArray(): TypedArrayOfConstructor<V> {
|
|
26
|
+
return this.denseValues.internalTypedArray
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
constructor(
|
|
30
|
+
keys: DynamicTypedArray<K>
|
|
31
|
+
, values: DynamicTypedArray<V>
|
|
32
|
+
) {
|
|
33
|
+
assert(keys.length === 0, 'keys must be empty')
|
|
34
|
+
|
|
35
|
+
this.denseKeys = keys
|
|
36
|
+
this.denseValues = values
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
* entries(): IterableIterator<[key: number, value: number]> {
|
|
40
|
+
for (let i = 0; i < this.denseKeys.length; i++) {
|
|
41
|
+
yield [
|
|
42
|
+
this.denseKeys.internalTypedArray[i]
|
|
43
|
+
, this.denseValues.internalTypedArray[i]
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
keys(): IterableIterator<number> {
|
|
49
|
+
return this.denseKeys.values()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
values(): IterableIterator<number> {
|
|
53
|
+
return this.denseValues.values()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
getInternalIndexOfKey(key: number): number | undefined {
|
|
57
|
+
return this.sparse[key]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
has(key: number): boolean {
|
|
61
|
+
return this.sparse[key] !== undefined
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
get(key: number): number | undefined {
|
|
65
|
+
const index = this.sparse[key]
|
|
66
|
+
if (index !== undefined) {
|
|
67
|
+
return this.denseValues.internalTypedArray[index]
|
|
68
|
+
} else {
|
|
69
|
+
return undefined
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
set(key: number, value: number): void {
|
|
74
|
+
const index = this.sparse[key]
|
|
75
|
+
if (index !== undefined) {
|
|
76
|
+
this.denseValues.internalTypedArray[index] = value
|
|
77
|
+
} else {
|
|
78
|
+
const index = this.denseKeys.length
|
|
79
|
+
this.denseKeys.push(key)
|
|
80
|
+
this.denseValues.push(value)
|
|
81
|
+
this.sparse[key] = index
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
delete(key: number): boolean {
|
|
86
|
+
const index = this.sparse[key]
|
|
87
|
+
if (index !== undefined) {
|
|
88
|
+
this.sparse[key] = undefined
|
|
89
|
+
|
|
90
|
+
const lastKey = this.denseKeys.pop()!
|
|
91
|
+
const lastValue = this.denseValues.pop()!
|
|
92
|
+
if (key !== lastKey) {
|
|
93
|
+
this.denseKeys.internalTypedArray[index] = lastKey
|
|
94
|
+
this.denseValues.internalTypedArray[index] = lastValue
|
|
95
|
+
this.sparse[lastKey] = index
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return true
|
|
99
|
+
} else {
|
|
100
|
+
return false
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
clear(): void {
|
|
105
|
+
this.denseKeys.clear()
|
|
106
|
+
this.denseValues.clear()
|
|
107
|
+
this.sparse.length = 0
|
|
108
|
+
}
|
|
109
|
+
}
|