@blackglory/structures 0.13.2 → 0.13.4

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 CHANGED
@@ -58,24 +58,18 @@ function truncateArrayRight<T>(arr: T[], num: number): void
58
58
  type Listener<Args extends unknown[]> = (...args: Args) => void
59
59
 
60
60
  class Emitter<
61
- EventToArgs extends Record<Key, unknown[]> = Record<
61
+ EventToArgs extends Record<Event, unknown[]> = Record<
62
62
  string | number | symbol
63
63
  , unknown[]
64
64
  >
65
- , Key extends string | number | symbol = keyof EventToArgs
65
+ , Event extends string | number | symbol = keyof EventToArgs
66
66
  > {
67
67
  get [Symbol.toStringTag](): string
68
68
 
69
- on<T extends Key>(
70
- event: T
71
- , listener: Listener<EventToArgs[T]>
72
- ): () => void
73
- once<T extends Key>(
74
- event: T
75
- , listener: Listener<EventToArgs[T]>
76
- ): () => void
77
-
78
- emit<T extends Key>(event: T, ...args: EventToArgs[T]): void
69
+ on<T extends Event>(event: T, listener: Listener<EventToArgs[T]>): () => void
70
+ once<T extends Event>(event: T, listener: Listener<EventToArgs[T]>): () => void
71
+ emit<T extends Event>(event: T, ...args: EventToArgs[T]): void
72
+ removeAllListeners<T extends Event>(event: T): void
79
73
  }
80
74
  ```
81
75
 
package/lib/emitter.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  declare type Listener<Args extends unknown[]> = (...args: Args) => void;
2
- export declare class Emitter<EventToArgs extends Record<Key, unknown[]> = Record<string | number | symbol, unknown[]>, Key extends string | number | symbol = keyof EventToArgs> {
2
+ export declare class Emitter<EventToArgs extends Record<Event, unknown[]> = Record<string | number | symbol, unknown[]>, Event extends string | number | symbol = keyof EventToArgs> {
3
3
  private map;
4
4
  get [Symbol.toStringTag](): string;
5
- on<T extends Key>(event: T, listener: Listener<EventToArgs[T]>): () => void;
6
- once<T extends Key>(event: T, listener: Listener<EventToArgs[T]>): () => void;
7
- emit<T extends Key>(event: T, ...args: EventToArgs[T]): void;
5
+ on<T extends Event>(event: T, listener: Listener<EventToArgs[T]>): () => void;
6
+ once<T extends Event>(event: T, listener: Listener<EventToArgs[T]>): () => void;
7
+ emit<T extends Event>(event: T, ...args: EventToArgs[T]): void;
8
+ removeAllListeners<T extends Event>(event: T): void;
8
9
  }
9
10
  export {};
package/lib/emitter.js CHANGED
@@ -43,5 +43,9 @@ export class Emitter {
43
43
  var _a;
44
44
  (_a = this.map.get(event)) === null || _a === void 0 ? void 0 : _a.forEach(cb => cb(...args));
45
45
  }
46
+ removeAllListeners(event) {
47
+ var _a;
48
+ (_a = this.map.get(event)) === null || _a === void 0 ? void 0 : _a.clear();
49
+ }
46
50
  }
47
51
  //# sourceMappingURL=emitter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"emitter.js","sourceRoot":"","sources":["../src/emitter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAA;AAInC,MAAM,OAAO,OAAO;IAApB;QAOU,QAAG,GAAG,IAAI,GAAG,EAGlB,CAAA;IAyDL,CAAC;IAvDC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;QACtB,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAA;IAC9B,CAAC;IAED,EAAE,CACA,KAAQ,EACR,QAAkC;QAElC,MAAM,GAAG,GAAG,EAAE,CAAC,GAAG,EAAE;YAClB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YAC/B,IAAI,GAAG,EAAE;gBACP,OAAO,GAAG,CAAA;aACX;iBAAM;gBACL,MAAM,GAAG,GAAG,IAAI,GAAG,EAA4C,CAAA;gBAC/D,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;gBACxB,OAAO,GAAG,CAAA;aACX;QACH,CAAC,CAAC,CAAA;QACF,GAAG,CAAC,GAAG,CAAC,OAAqC,CAAC,CAAA;QAE9C,OAAO,GAAG,EAAE;YACV,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YACpC,IAAI,QAAQ,EAAE;gBACZ,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAC7B,OAAqC,CACtC,CAAA;gBACD,IAAI,OAAO,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,EAAE;oBAClC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;iBACvB;aACF;QACH,CAAC,CAAA;QAED,SAAS,OAAO,CAAC,GAAG,IAA0C;YAC5D,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAA;QACnB,CAAC;IACH,CAAC;IAED,IAAI,CACF,KAAQ,EACR,QAAkC;QAElC,MAAM,cAAc,GAAG,IAAI,CAAC,EAAE,CAC5B,KAAK,EACL,CAAC,GAAG,IAA0C,EAAE,EAAE;YAChD,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAA;YACjB,cAAc,EAAE,CAAA;QAClB,CAAC,CACF,CAAA;QAED,OAAO,cAAc,CAAA;IACvB,CAAC;IAED,IAAI,CAAgB,KAAQ,EAAE,GAAG,IAAoB;;QACnD,MAAA,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,0CAAE,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAA;IACjD,CAAC;CACF"}
1
+ {"version":3,"file":"emitter.js","sourceRoot":"","sources":["../src/emitter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAA;AAInC,MAAM,OAAO,OAAO;IAApB;QAOU,QAAG,GAAG,IAAI,GAAG,EAGlB,CAAA;IA6DL,CAAC;IA3DC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;QACtB,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAA;IAC9B,CAAC;IAED,EAAE,CACA,KAAQ,EACR,QAAkC;QAElC,MAAM,GAAG,GAAG,EAAE,CAAC,GAAG,EAAE;YAClB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YAC/B,IAAI,GAAG,EAAE;gBACP,OAAO,GAAG,CAAA;aACX;iBAAM;gBACL,MAAM,GAAG,GAAG,IAAI,GAAG,EAA4C,CAAA;gBAC/D,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;gBACxB,OAAO,GAAG,CAAA;aACX;QACH,CAAC,CAAC,CAAA;QACF,GAAG,CAAC,GAAG,CAAC,OAAuC,CAAC,CAAA;QAEhD,OAAO,GAAG,EAAE;YACV,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YACpC,IAAI,QAAQ,EAAE;gBACZ,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAC7B,OAAuC,CACxC,CAAA;gBACD,IAAI,OAAO,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,EAAE;oBAClC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;iBACvB;aACF;QACH,CAAC,CAAA;QAED,SAAS,OAAO,CAAC,GAAG,IAA0C;YAC5D,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAA;QACnB,CAAC;IACH,CAAC;IAED,IAAI,CACF,KAAQ,EACR,QAAkC;QAElC,MAAM,cAAc,GAAG,IAAI,CAAC,EAAE,CAC5B,KAAK,EACL,CAAC,GAAG,IAA0C,EAAE,EAAE;YAChD,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAA;YACjB,cAAc,EAAE,CAAA;QAClB,CAAC,CACF,CAAA;QAED,OAAO,cAAc,CAAA;IACvB,CAAC;IAED,IAAI,CAAkB,KAAQ,EAAE,GAAG,IAAoB;;QACrD,MAAA,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,0CAAE,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAA;IACjD,CAAC;IAED,kBAAkB,CAAkB,KAAQ;;QAC1C,MAAA,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,0CAAE,KAAK,EAAE,CAAA;IAC9B,CAAC;CACF"}
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@blackglory/structures",
3
- "version": "0.13.2",
3
+ "version": "0.13.4",
4
4
  "description": "",
5
5
  "files": [
6
- "lib"
6
+ "lib",
7
+ "src"
7
8
  ],
8
9
  "type": "module",
9
10
  "main": "lib/index.js",
package/src/array.ts ADDED
@@ -0,0 +1,19 @@
1
+ export function sliceArrayLeft<T>(arr: T[], num: number): T[] {
2
+ return arr.slice(0, num)
3
+ }
4
+
5
+ export function sliceArrayRight<T>(arr: T[], num: number): T[] {
6
+ const startIndex = arr.length - num
7
+ return arr.slice(startIndex >= 0 ? startIndex : 0)
8
+ }
9
+
10
+ export function truncateArrayLeft<T>(arr: T[], num: number): void {
11
+ if (arr.length > num) {
12
+ arr.length = num
13
+ }
14
+ }
15
+
16
+ export function truncateArrayRight<T>(arr: T[], num: number): void {
17
+ const startIndex = arr.length - num
18
+ arr.splice(0, startIndex)
19
+ }
package/src/big-map.ts ADDED
@@ -0,0 +1,98 @@
1
+ /**
2
+ * A `Map` that supports unlimited elements.
3
+ *
4
+ * Note that `BigMap` cannot preserve the insertion order of elements.
5
+ */
6
+ export class BigMap<K, V> implements Iterable<[K, V]> {
7
+ _maps: Array<Map<K, V>> = []
8
+
9
+ get [Symbol.toStringTag](): string {
10
+ return this.constructor.name
11
+ }
12
+
13
+ get size(): number {
14
+ return this._maps
15
+ .map(map => map.size)
16
+ .reduce((acc, cur) => acc + cur, 0)
17
+ }
18
+
19
+ * [Symbol.iterator](): IterableIterator<[K, V]> {
20
+ for (const map of this._maps) {
21
+ yield* map[Symbol.iterator]()
22
+ }
23
+ }
24
+
25
+ set(key: K, value: V): void {
26
+ {
27
+ const map = this._maps.find(map => map.has(key))
28
+ if (map) {
29
+ map.set(key, value)
30
+ return
31
+ }
32
+ }
33
+
34
+ for (const map of this._maps) {
35
+ try {
36
+ map.set(key, value)
37
+ return
38
+ } catch (e) {
39
+ if (e instanceof RangeError) continue
40
+ throw e
41
+ }
42
+ }
43
+
44
+ const map = new Map<K, V>()
45
+ map.set(key, value)
46
+ this._maps.push(map)
47
+ }
48
+
49
+ has(key: K): boolean {
50
+ return this._maps.some(set => set.has(key))
51
+ }
52
+
53
+ get(key: K): V | undefined {
54
+ for (const map of this._maps) {
55
+ if (map.has(key)) {
56
+ return map.get(key)!
57
+ }
58
+ }
59
+ }
60
+
61
+ delete(key: K): boolean {
62
+ for (const [index, map] of this._maps.entries()) {
63
+ if (map.has(key)) {
64
+ map.delete(key)
65
+
66
+ if (map.size === 0) {
67
+ this._maps.splice(index, 1)
68
+ }
69
+
70
+ return true
71
+ }
72
+ }
73
+
74
+ return false
75
+ }
76
+
77
+ clear(): void {
78
+ this._maps = []
79
+ }
80
+
81
+ * entries(): IterableIterator<[K, V]> {
82
+ for (const map of this._maps) {
83
+ yield* map.entries()
84
+ }
85
+ }
86
+
87
+ * keys(): IterableIterator<K> {
88
+ for (const map of this._maps) {
89
+ yield* map.keys()
90
+ }
91
+ }
92
+
93
+ * values(): IterableIterator<V> {
94
+ for (const map of this._maps) {
95
+ yield* map.values()
96
+ }
97
+ }
98
+ }
package/src/big-set.ts ADDED
@@ -0,0 +1,72 @@
1
+ /**
2
+ * A `Set` that supports unlimited elements.
3
+ *
4
+ * Note that `BigSet` cannot preserve the insertion order of elements.
5
+ */
6
+ export class BigSet<T> implements Iterable<T> {
7
+ _sets: Array<Set<T>> = []
8
+
9
+ get [Symbol.toStringTag](): string {
10
+ return this.constructor.name
11
+ }
12
+
13
+ get size(): number {
14
+ return this._sets
15
+ .map(set => set.size)
16
+ .reduce((acc, cur) => acc + cur, 0)
17
+ }
18
+
19
+ * [Symbol.iterator](): IterableIterator<T> {
20
+ for (const set of this._sets) {
21
+ yield* set[Symbol.iterator]()
22
+ }
23
+ }
24
+
25
+ add(value: T): void {
26
+ if (this._sets.some(set => set.has(value))) return
27
+
28
+ for (const set of this._sets) {
29
+ try {
30
+ set.add(value)
31
+ return
32
+ } catch (e) {
33
+ if (e instanceof RangeError) continue
34
+ throw e
35
+ }
36
+ }
37
+
38
+ const set = new Set<T>()
39
+ set.add(value)
40
+ this._sets.push(set)
41
+ }
42
+
43
+ has(value: T): boolean {
44
+ return this._sets.some(set => set.has(value))
45
+ }
46
+
47
+ delete(value: T): boolean {
48
+ for (const [index, set] of this._sets.entries()) {
49
+ if (set.has(value)) {
50
+ set.delete(value)
51
+
52
+ if (set.size === 0) {
53
+ this._sets.splice(index, 1)
54
+ }
55
+
56
+ return true
57
+ }
58
+ }
59
+
60
+ return false
61
+ }
62
+
63
+ clear(): void {
64
+ this._sets = []
65
+ }
66
+
67
+ * values(): IterableIterator<T> {
68
+ for (const set of this._sets) {
69
+ yield* set.values()
70
+ }
71
+ }
72
+ }
package/src/bit-set.ts ADDED
@@ -0,0 +1,124 @@
1
+ import { assert } from '@blackglory/errors'
2
+ import { trailingZeros } from '@utils/trailing-zeros.js'
3
+
4
+ export class BitSet {
5
+ private array: number[] = []
6
+ private length = 0
7
+ private _size = 0
8
+
9
+ constructor(private bitsPerElement: number = 8) {
10
+ assert(
11
+ Number.isInteger(bitsPerElement)
12
+ , 'The parameter bitsPerElement must be an integer'
13
+ )
14
+ assert(
15
+ bitsPerElement > 0
16
+ , 'The parameter bitsPerElement must be greater than 0'
17
+ )
18
+ // `31`是该数据结构中能够处理的最大值
19
+ assert(
20
+ bitsPerElement <= 31
21
+ , 'The mask of bitsPerElement must be less than or equal to 31'
22
+ )
23
+ }
24
+
25
+ get [Symbol.toStringTag](): string {
26
+ return this.constructor.name
27
+ }
28
+
29
+ get size(): number {
30
+ return this._size
31
+ }
32
+
33
+ [Symbol.iterator](): IterableIterator<number> {
34
+ return this.values()
35
+ }
36
+
37
+ * values(): IterableIterator<number> {
38
+ if (this.length > 0) {
39
+ // maxArrayLength = Math.ceil(this.length / this.bitsPerElement)
40
+ const maxArrayLength = ~~(this.length / this.bitsPerElement) + 1
41
+
42
+ 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
50
+ }
51
+ }
52
+ }
53
+ }
54
+
55
+ _dumpBinaryStrings(): string[] {
56
+ const result: string[] = []
57
+ for (let i = 0; i < this.array.length; i++) {
58
+ const binary = this.array[i].toString(2)
59
+ if (binary.length < this.bitsPerElement) {
60
+ result.push('0'.repeat(this.bitsPerElement - binary.length) + binary)
61
+ } else {
62
+ result.push(binary)
63
+ }
64
+ }
65
+ return result
66
+ }
67
+
68
+ has(value: number): boolean {
69
+ const [index, mask] = this.getPosition(value)
70
+
71
+ return ((this.array[index] ?? 0) & mask) === mask
72
+ }
73
+
74
+ 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
+ const [index, mask] = this.getPosition(value)
81
+
82
+ const element = this.array[index] ?? 0
83
+ this.array[index] = element | mask
84
+
85
+ const added = (element & mask) !== mask
86
+ if (added) {
87
+ this._size++
88
+ }
89
+ return added
90
+ }
91
+
92
+ delete(value: number): boolean {
93
+ const [index, mask] = this.getPosition(value)
94
+
95
+ const element = (this.array[index] ?? 0)
96
+ this.array[index] = element & ~mask
97
+
98
+ const deleted = (element & mask) === mask
99
+ if (deleted) {
100
+ this._size--
101
+ }
102
+
103
+ return deleted
104
+ }
105
+
106
+ clear(): void {
107
+ this._size = 0
108
+ this.array.length = 0
109
+ }
110
+
111
+ private getPosition(value: number): [index: number, mask: number] {
112
+ const remainder = value % this.bitsPerElement
113
+ const quotient = (value - remainder) / this.bitsPerElement
114
+ const index = quotient
115
+ const mask = this.getMask(remainder)
116
+ return [index, mask]
117
+ }
118
+
119
+ // 输入一定是一个小于bitsPerElement的值, 取值范围是[0, bitsPerElement)
120
+ private getMask(value: number): number {
121
+ // return 2 ** value
122
+ return 1 << value
123
+ }
124
+ }
package/src/box.ts ADDED
@@ -0,0 +1,15 @@
1
+ export class Box<T> {
2
+ get [Symbol.toStringTag](): string {
3
+ return this.constructor.name
4
+ }
5
+
6
+ constructor(private value: T) {}
7
+
8
+ set(value: T): void {
9
+ this.value = value
10
+ }
11
+
12
+ get(): T {
13
+ return this.value
14
+ }
15
+ }
package/src/cons.ts ADDED
@@ -0,0 +1,15 @@
1
+ import { isNull } from 'extra-utils'
2
+ import { Cons } from 'justypes'
3
+ export { Cons } from 'justypes'
4
+
5
+ export function convertConsToArray<T>([value, next]: Cons<T>): T[] {
6
+ if (isNull(next)) {
7
+ return [value]
8
+ } else {
9
+ return [value, ...convertConsToArray(next)]
10
+ }
11
+ }
12
+
13
+ export function convertArrayToCons<T>([value, ...next]: T[]): Cons<T> {
14
+ return [value, next.length ? convertArrayToCons(next) : null]
15
+ }
@@ -0,0 +1,201 @@
1
+ import { TypedArrayConstructor, TypedArrayOfConstructor } from 'justypes'
2
+ import { assert } from '@blackglory/errors'
3
+
4
+ interface IDynamicTypedArrayOptions {
5
+ capacity?: number
6
+ growthFactor?: number
7
+ }
8
+
9
+ // 相关提案: https://github.com/tc39/proposal-resizablearraybuffer
10
+ export class DynamicTypedArray<T extends TypedArrayConstructor> {
11
+ private array: TypedArrayOfConstructor<T>
12
+ private _length: number = 0
13
+ private initialCapacity: number
14
+ readonly growthFactor: number
15
+
16
+ get internalTypedArray(): TypedArrayOfConstructor<T> {
17
+ return this.array
18
+ }
19
+
20
+ get [Symbol.toStringTag](): string {
21
+ return this.constructor.name
22
+ }
23
+
24
+ get BYTES_PER_ELEMENT(): number {
25
+ return this.typedArrayConstructor.BYTES_PER_ELEMENT
26
+ }
27
+
28
+ /**
29
+ * 数组当前的容量.
30
+ */
31
+ get capacity(): number {
32
+ return this.array.length
33
+ }
34
+
35
+ /**
36
+ * 数组逻辑上的长度, 总是小于或等于capacity.
37
+ */
38
+ get length(): number {
39
+ return this._length
40
+ }
41
+
42
+ constructor(
43
+ private typedArrayConstructor: T
44
+ , {
45
+ capacity = 0
46
+ , growthFactor = 1.5
47
+ }: IDynamicTypedArrayOptions = {}
48
+ ) {
49
+ assert(Number.isInteger(capacity), 'capacity must be an integer')
50
+ assert(capacity >= 0, 'capacity must be greater than or equal to 0')
51
+ assert(growthFactor >= 1, 'growthFactory must be greater than or equal to 1')
52
+
53
+ this.initialCapacity = capacity
54
+ this.array = new typedArrayConstructor(capacity) as TypedArrayOfConstructor<T>
55
+ this.growthFactor = growthFactor
56
+ }
57
+
58
+ set(index: number, value: number): void {
59
+ if (index >= this.capacity) {
60
+ const newCapacity = computeNewCapacity(
61
+ this.capacity
62
+ , index + 1
63
+ , this.growthFactor
64
+ )
65
+ this.resize(newCapacity)
66
+ }
67
+
68
+ if (index >= this._length) {
69
+ this._length = index + 1
70
+ }
71
+
72
+ this.array[index] = value
73
+ }
74
+
75
+ setValues(index: number, values: TypedArrayOfConstructor<T>): void {
76
+ if (index + values.length >= this.capacity) {
77
+ const newCapacity = computeNewCapacity(
78
+ this.capacity
79
+ , index + values.length
80
+ , this.growthFactor
81
+ )
82
+ this.resize(newCapacity)
83
+ }
84
+
85
+ if (index + values.length > this._length) {
86
+ this._length = index + values.length
87
+ }
88
+
89
+ this.internalTypedArray.set(values, index)
90
+ }
91
+
92
+ get(index: number): number | undefined {
93
+ return index < this._length
94
+ ? this.array[index]
95
+ : undefined
96
+ }
97
+
98
+ push(...values: number[]): void {
99
+ const newLength = this._length + values.length
100
+ if (newLength > this.capacity) {
101
+ const newCapacity = computeNewCapacity(
102
+ this.capacity
103
+ , newLength
104
+ , this.growthFactor
105
+ )
106
+ this.resize(newCapacity)
107
+ }
108
+
109
+ for (const value of values) {
110
+ this.array[this._length++] = value
111
+ }
112
+ }
113
+
114
+ pop(): number | undefined {
115
+ if (this._length > 0) {
116
+ const value = this.array[this._length - 1]
117
+ this._length--
118
+
119
+ const newCapacity = computeNewCapacity(
120
+ this.capacity
121
+ , this.length
122
+ , this.growthFactor
123
+ )
124
+ this.resize(newCapacity)
125
+
126
+ return value
127
+ } else {
128
+ return undefined
129
+ }
130
+ }
131
+
132
+ clear(): void {
133
+ this._length = 0
134
+ const newArray = new this.typedArrayConstructor(this.initialCapacity)
135
+ this.array = newArray as TypedArrayOfConstructor<T>
136
+ }
137
+
138
+ sort(compare?: (a: number, b: number) => number): void {
139
+ const capacity = this.capacity
140
+ this.resize(this.length)
141
+ this.array.sort(compare)
142
+ this.resize(capacity)
143
+ }
144
+
145
+ private resize(newCapacity: number): void {
146
+ if (this.array.length === newCapacity) {
147
+ return
148
+ } else if (this.array.length < newCapacity) {
149
+ const newArray = new this.typedArrayConstructor(newCapacity)
150
+ newArray.set(this.array)
151
+ this.array = newArray as TypedArrayOfConstructor<T>
152
+ } else if (this.array.length > newCapacity) {
153
+ const newArray = new this.typedArrayConstructor(newCapacity)
154
+ // 不需要的部分将被舍弃.
155
+ for (let i = newCapacity; i--;) {
156
+ newArray[i] = this.array[i]
157
+ }
158
+ this.array = newArray as TypedArrayOfConstructor<T>
159
+ }
160
+ }
161
+ }
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
+ }