@vworlds/vecs 1.0.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/.claude/settings.json +12 -0
- package/.devcontainer/devcontainer.json +22 -0
- package/.github/workflows/publish.yml +32 -0
- package/README.md +464 -0
- package/dist/component.d.ts +135 -0
- package/dist/component.js +101 -0
- package/dist/component.js.map +1 -0
- package/dist/entity.d.ts +157 -0
- package/dist/entity.js +199 -0
- package/dist/entity.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/package.json +25 -0
- package/dist/phase.d.ts +47 -0
- package/dist/phase.js +23 -0
- package/dist/phase.js.map +1 -0
- package/dist/system.d.ts +361 -0
- package/dist/system.js +396 -0
- package/dist/system.js.map +1 -0
- package/dist/util/array_map.d.ts +58 -0
- package/dist/util/array_map.js +84 -0
- package/dist/util/array_map.js.map +1 -0
- package/dist/util/bitset.d.ts +117 -0
- package/dist/util/bitset.js +177 -0
- package/dist/util/bitset.js.map +1 -0
- package/dist/util/events.d.ts +27 -0
- package/dist/util/events.js +43 -0
- package/dist/util/events.js.map +1 -0
- package/dist/util/ordered_set.d.ts +17 -0
- package/dist/util/ordered_set.js +69 -0
- package/dist/util/ordered_set.js.map +1 -0
- package/dist/world.d.ts +279 -0
- package/dist/world.js +453 -0
- package/dist/world.js.map +1 -0
- package/package.json +25 -0
- package/src/component.ts +180 -0
- package/src/entity.ts +276 -0
- package/src/index.ts +6 -0
- package/src/phase.ts +49 -0
- package/src/system.ts +693 -0
- package/src/util/array_map.ts +93 -0
- package/src/util/bitset.ts +199 -0
- package/src/util/events.ts +95 -0
- package/src/util/ordered_set.ts +82 -0
- package/src/world.ts +534 -0
- package/tests/_helpers.ts +30 -0
- package/tests/array_map.test.ts +68 -0
- package/tests/bitset.test.ts +127 -0
- package/tests/component.test.ts +104 -0
- package/tests/entity.test.ts +179 -0
- package/tests/events.test.ts +48 -0
- package/tests/ordered_set.test.ts +153 -0
- package/tests/setup.ts +6 -0
- package/tests/system.test.ts +800 -0
- package/tests/world.test.ts +174 -0
- package/tsconfig.json +21 -0
- package/vitest.config.ts +9 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A `Map<number, T>` backed by a sparse JavaScript array.
|
|
3
|
+
*
|
|
4
|
+
* For small, dense integer key spaces this is significantly faster than
|
|
5
|
+
* `Map` because array index access avoids the hash-table overhead. Used
|
|
6
|
+
* internally to store per-entity component instances and per-type component
|
|
7
|
+
* metadata.
|
|
8
|
+
*
|
|
9
|
+
* Keys must be non-negative integers. Gaps in the key space are represented
|
|
10
|
+
* as `undefined` slots and do not count toward `size`.
|
|
11
|
+
*
|
|
12
|
+
* @typeParam T - The value type stored in the map.
|
|
13
|
+
*/
|
|
14
|
+
export class ArrayMap<T> {
|
|
15
|
+
private backend: (T | undefined)[];
|
|
16
|
+
private _size: number;
|
|
17
|
+
|
|
18
|
+
constructor() {
|
|
19
|
+
this.backend = [];
|
|
20
|
+
this._size = 0;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Store `value` at `key`, replacing any existing value.
|
|
25
|
+
*
|
|
26
|
+
* @param key - Non-negative integer key.
|
|
27
|
+
* @param value - Value to store.
|
|
28
|
+
*/
|
|
29
|
+
set(key: number, value: T): void {
|
|
30
|
+
if (this.backend[key] === undefined) {
|
|
31
|
+
this._size++;
|
|
32
|
+
}
|
|
33
|
+
this.backend[key] = value;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Return the value stored at `key`, or `undefined` if not present.
|
|
38
|
+
*
|
|
39
|
+
* @param key - Non-negative integer key.
|
|
40
|
+
*/
|
|
41
|
+
get(key: number): T | undefined {
|
|
42
|
+
return this.backend[key];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Remove the entry at `key`. Does nothing if `key` is not present.
|
|
47
|
+
*
|
|
48
|
+
* @param key - Non-negative integer key.
|
|
49
|
+
*/
|
|
50
|
+
delete(key: number): void {
|
|
51
|
+
if (this.backend[key] !== undefined) {
|
|
52
|
+
this.backend[key] = undefined;
|
|
53
|
+
this._size--;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Return `true` if an entry exists at `key`.
|
|
59
|
+
*
|
|
60
|
+
* @param key - Non-negative integer key.
|
|
61
|
+
*/
|
|
62
|
+
has(key: number): boolean {
|
|
63
|
+
return this.backend[key] !== undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Iterate over all present entries.
|
|
68
|
+
*
|
|
69
|
+
* Undefined slots are skipped; the callback is only called for keys that
|
|
70
|
+
* have an associated value.
|
|
71
|
+
*
|
|
72
|
+
* @param callback - Called with `(value, key, map)` for each entry.
|
|
73
|
+
*/
|
|
74
|
+
forEach(callback: (value: T, key: number, map: ArrayMap<T>) => void): void {
|
|
75
|
+
this.backend.forEach((value, index) => {
|
|
76
|
+
if (value !== undefined) {
|
|
77
|
+
callback(value, index, this);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Remove all entries and reset the size to zero.
|
|
84
|
+
*/
|
|
85
|
+
clear() {
|
|
86
|
+
this.backend.length = 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** The number of entries currently in the map. */
|
|
90
|
+
get size(): number {
|
|
91
|
+
return this._size;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A compact, growable set of non-negative integers backed by an array of
|
|
3
|
+
* 32-bit words.
|
|
4
|
+
*
|
|
5
|
+
* Used internally to represent entity archetypes (the set of component type
|
|
6
|
+
* ids attached to an entity) and system watchlists. Exposed in the public API
|
|
7
|
+
* so that component data can use it for bit-flag fields:
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* class Tags extends Component {
|
|
11
|
+
* tags = new Bitset();
|
|
12
|
+
* oldTags = new Bitset();
|
|
13
|
+
* }
|
|
14
|
+
*
|
|
15
|
+
* // Check a specific tag bit:
|
|
16
|
+
* if (tags.tags.has(TAG_VISIBLE)) { ... }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export class Bitset {
|
|
20
|
+
private bits: number[];
|
|
21
|
+
|
|
22
|
+
constructor() {
|
|
23
|
+
this.bits = [];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Return `true` if this bitset and `other` have exactly the same bits set.
|
|
28
|
+
*/
|
|
29
|
+
equal(other: Bitset) {
|
|
30
|
+
return (
|
|
31
|
+
this.bits.length === other.bits.length &&
|
|
32
|
+
this.bits.every((v, i) => other.bits[i] === v)
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* OR the given `bitmask` word into the word at position `arrayIndex`.
|
|
38
|
+
*
|
|
39
|
+
* @internal Low-level bulk operation; prefer {@link add} for single bits.
|
|
40
|
+
*/
|
|
41
|
+
addIndexBitmask(arrayIndex: number, bitmask: number) {
|
|
42
|
+
this.bits[arrayIndex] |= bitmask;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Replace the word at position `arrayIndex` with `bitmask`.
|
|
47
|
+
*
|
|
48
|
+
* @internal Used by network deserialization to set a whole word at once.
|
|
49
|
+
*/
|
|
50
|
+
setIndexBitmask(arrayIndex: number, bitmask: number) {
|
|
51
|
+
this.bits[arrayIndex] = bitmask;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Set the bit described by `bptr` (fast path using a pre-computed
|
|
56
|
+
* {@link BitPtr}).
|
|
57
|
+
*/
|
|
58
|
+
addBit(bptr: BitPtr) {
|
|
59
|
+
this.addIndexBitmask(bptr.arrayIndex, bptr.bitmask);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Set bit `n`.
|
|
64
|
+
*
|
|
65
|
+
* @param n - Non-negative integer bit index.
|
|
66
|
+
*/
|
|
67
|
+
add(n: number): void {
|
|
68
|
+
const arrayIndex = Math.floor(n / 32);
|
|
69
|
+
const bitmask = 1 << n % 32;
|
|
70
|
+
this.addIndexBitmask(arrayIndex, bitmask);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Clear bit `n`.
|
|
75
|
+
*
|
|
76
|
+
* Trailing zero words are trimmed so that the internal array stays compact.
|
|
77
|
+
*
|
|
78
|
+
* @param n - Non-negative integer bit index.
|
|
79
|
+
*/
|
|
80
|
+
delete(n: number): void {
|
|
81
|
+
const arrayIndex = Math.floor(n / 32);
|
|
82
|
+
const current = this.bits[arrayIndex];
|
|
83
|
+
if (current === undefined) {
|
|
84
|
+
return;
|
|
85
|
+
} else {
|
|
86
|
+
this.bits[arrayIndex] = current & ~(1 << n % 32);
|
|
87
|
+
}
|
|
88
|
+
while (this.bits.length && this.bits[this.bits.length - 1] === 0)
|
|
89
|
+
this.bits.pop();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Return `true` if the bit described by `bptr` is set (fast path).
|
|
94
|
+
*/
|
|
95
|
+
hasBit(bptr: BitPtr) {
|
|
96
|
+
return this.hasIndexBitmask(bptr.arrayIndex, bptr.bitmask);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Return `true` if bit `n` is set.
|
|
101
|
+
*
|
|
102
|
+
* @param n - Non-negative integer bit index.
|
|
103
|
+
*/
|
|
104
|
+
has(n: number): boolean {
|
|
105
|
+
const arrayIndex = Math.floor(n / 32);
|
|
106
|
+
if (arrayIndex >= this.bits.length) return false;
|
|
107
|
+
const bitIndex = n % 32;
|
|
108
|
+
const bitmask = 1 << bitIndex;
|
|
109
|
+
return this.hasIndexBitmask(arrayIndex, bitmask);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Return `true` if the given word-level bitmask is fully set at `arrayIndex`.
|
|
114
|
+
*
|
|
115
|
+
* @internal
|
|
116
|
+
*/
|
|
117
|
+
hasIndexBitmask(arrayIndex: number, bitmask: number) {
|
|
118
|
+
return (this.bits[arrayIndex] & bitmask) !== 0;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Return `true` if every bit set in `other` is also set in `this` (i.e.
|
|
123
|
+
* `other` is a subset of `this`).
|
|
124
|
+
*
|
|
125
|
+
* Used by the world to test whether an entity's archetype satisfies a
|
|
126
|
+
* system's `HAS` query.
|
|
127
|
+
*/
|
|
128
|
+
hasBitset(other: Bitset): boolean {
|
|
129
|
+
if (this.bits.length < other.bits.length) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
for (let i = 0; i < other.bits.length; i++) {
|
|
134
|
+
if ((this.bits[i] & other.bits[i]) !== (other.bits[i] || 0)) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Iterate over every set bit index in ascending order.
|
|
144
|
+
*
|
|
145
|
+
* @param callback - Called with each set bit index.
|
|
146
|
+
*/
|
|
147
|
+
forEach(callback: (n: number) => void): void {
|
|
148
|
+
this.bits.forEach((b, j) => {
|
|
149
|
+
for (let i = 0; i < 32; i++) {
|
|
150
|
+
if ((b & 1) !== 0) {
|
|
151
|
+
callback(i + j * 32);
|
|
152
|
+
}
|
|
153
|
+
b >>= 1;
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Return an array of all set bit indices in ascending order.
|
|
160
|
+
*
|
|
161
|
+
* @returns `number[]` of set bit positions.
|
|
162
|
+
*/
|
|
163
|
+
indices(): number[] {
|
|
164
|
+
const idx: number[] = [];
|
|
165
|
+
this.forEach((i) => idx.push(i));
|
|
166
|
+
return idx;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* A pre-computed pointer into a {@link Bitset}'s internal word array.
|
|
172
|
+
*
|
|
173
|
+
* Computing `arrayIndex` and `bitmask` from a raw bit index requires a floor
|
|
174
|
+
* division and a bitshift. `BitPtr` caches those values so that hot-path
|
|
175
|
+
* archetype checks ({@link Bitset.hasBit}, {@link Bitset.addBit}) avoid
|
|
176
|
+
* repeating the arithmetic on every entity update.
|
|
177
|
+
*
|
|
178
|
+
* A `BitPtr` is created once per component type and stored on
|
|
179
|
+
* {@link ComponentMeta.bitPtr}.
|
|
180
|
+
*/
|
|
181
|
+
export class BitPtr {
|
|
182
|
+
/** Index of the 32-bit word that contains this bit. */
|
|
183
|
+
public readonly arrayIndex: number;
|
|
184
|
+
/** Single-bit mask within that word. */
|
|
185
|
+
public readonly bitmask: number;
|
|
186
|
+
|
|
187
|
+
constructor(
|
|
188
|
+
/** The raw bit index this pointer refers to. */
|
|
189
|
+
public readonly value: number
|
|
190
|
+
) {
|
|
191
|
+
this.arrayIndex = Math.floor(value / 32);
|
|
192
|
+
this.bitmask = 1 << value % 32;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** Return `true` if both pointers refer to the same bit position. */
|
|
196
|
+
public equals(other: BitPtr) {
|
|
197
|
+
return this.arrayIndex == other.arrayIndex && this.bitmask == other.bitmask;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The following type declarations define an alternative typings interface for eventemitter3
|
|
3
|
+
* Inspired by typings in @yandeu/events https://github.com/yandeu/events
|
|
4
|
+
* Turns out those typings pretty much can be used directly on eventemitter3
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import eventEmitter3 from "eventemitter3";
|
|
8
|
+
const { EventEmitter } = eventEmitter3;
|
|
9
|
+
|
|
10
|
+
declare type ValidEventMap<T = any> = T extends {
|
|
11
|
+
[P in keyof T]: (...args: any[]) => void;
|
|
12
|
+
}
|
|
13
|
+
? T
|
|
14
|
+
: never;
|
|
15
|
+
declare type Handler<T extends any | ((...args: any[]) => R), R = any> = T;
|
|
16
|
+
export declare type EventListener<
|
|
17
|
+
T extends ValidEventMap,
|
|
18
|
+
K extends EventNames<T>
|
|
19
|
+
> = T extends string | symbol
|
|
20
|
+
? (...args: any[]) => void
|
|
21
|
+
: K extends keyof T
|
|
22
|
+
? Handler<T[K], void>
|
|
23
|
+
: never;
|
|
24
|
+
declare type EventArgs<
|
|
25
|
+
T extends ValidEventMap,
|
|
26
|
+
K extends EventNames<T>
|
|
27
|
+
> = Parameters<EventListener<T, K>>;
|
|
28
|
+
export declare type EventNames<T extends ValidEventMap> = T extends
|
|
29
|
+
| string
|
|
30
|
+
| symbol
|
|
31
|
+
? T
|
|
32
|
+
: keyof T;
|
|
33
|
+
class events<EventMap extends ValidEventMap = any> {
|
|
34
|
+
public on<T extends EventNames<EventMap>>(
|
|
35
|
+
event: T,
|
|
36
|
+
fn: EventListener<EventMap, T>,
|
|
37
|
+
context?: any
|
|
38
|
+
): events<EventMap> {
|
|
39
|
+
return 0 as any;
|
|
40
|
+
}
|
|
41
|
+
public emit<T extends EventNames<EventMap>>(
|
|
42
|
+
event: T,
|
|
43
|
+
...args: EventArgs<EventMap, T>
|
|
44
|
+
): boolean {
|
|
45
|
+
return 0 as any;
|
|
46
|
+
}
|
|
47
|
+
public once<T extends EventNames<EventMap>>(
|
|
48
|
+
event: T,
|
|
49
|
+
fn: EventListener<EventMap, T>,
|
|
50
|
+
context?: any
|
|
51
|
+
): events<EventMap> {
|
|
52
|
+
return 0 as any;
|
|
53
|
+
}
|
|
54
|
+
public eventNames(): EventNames<EventMap>[] {
|
|
55
|
+
return 0 as any;
|
|
56
|
+
}
|
|
57
|
+
public listeners(event: EventNames<EventMap>): any[] {
|
|
58
|
+
return 0 as any;
|
|
59
|
+
}
|
|
60
|
+
public listenerCount(event: EventNames<EventMap>): any {
|
|
61
|
+
return 0 as any;
|
|
62
|
+
}
|
|
63
|
+
public removeListener<T extends EventNames<EventMap>>(
|
|
64
|
+
event: T,
|
|
65
|
+
fn?: EventListener<EventMap, T>,
|
|
66
|
+
context?: any,
|
|
67
|
+
once?: boolean
|
|
68
|
+
): this {
|
|
69
|
+
return 0 as any;
|
|
70
|
+
}
|
|
71
|
+
removeAllListeners(event?: EventNames<EventMap>): this {
|
|
72
|
+
return 0 as any;
|
|
73
|
+
}
|
|
74
|
+
public off<T extends EventNames<EventMap>>(
|
|
75
|
+
event: T,
|
|
76
|
+
fn?: EventListener<EventMap, T> | undefined,
|
|
77
|
+
context?: any,
|
|
78
|
+
once?: boolean | undefined
|
|
79
|
+
): events<EventMap> {
|
|
80
|
+
return 0 as any;
|
|
81
|
+
}
|
|
82
|
+
public addListener<T extends EventNames<EventMap>>(
|
|
83
|
+
event: T,
|
|
84
|
+
fn: EventListener<EventMap, T>,
|
|
85
|
+
context?: any
|
|
86
|
+
): events<EventMap> {
|
|
87
|
+
return 0 as any;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
(events as any) = EventEmitter;
|
|
92
|
+
|
|
93
|
+
export class Events<
|
|
94
|
+
EventMap extends ValidEventMap = any
|
|
95
|
+
> extends events<EventMap> {}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export class OrderedSet<T> implements Set<T> {
|
|
2
|
+
private items: T[];
|
|
3
|
+
private readonly compare: (a: T, b: T) => number;
|
|
4
|
+
|
|
5
|
+
constructor(compare: (a: T, b: T) => number) {
|
|
6
|
+
this.items = [];
|
|
7
|
+
this.compare = compare;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
private bisect(value: T): number {
|
|
11
|
+
let lo = 0;
|
|
12
|
+
let hi = this.items.length;
|
|
13
|
+
while (lo < hi) {
|
|
14
|
+
const mid = (lo + hi) >>> 1;
|
|
15
|
+
if (this.compare(this.items[mid], value) < 0) {
|
|
16
|
+
lo = mid + 1;
|
|
17
|
+
} else {
|
|
18
|
+
hi = mid;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return lo;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
add(value: T): this {
|
|
25
|
+
const i = this.bisect(value);
|
|
26
|
+
if (i < this.items.length && this.compare(this.items[i], value) === 0) {
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
this.items.splice(i, 0, value);
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
has(value: T): boolean {
|
|
34
|
+
const i = this.bisect(value);
|
|
35
|
+
return i < this.items.length && this.compare(this.items[i], value) === 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
delete(value: T): boolean {
|
|
39
|
+
const i = this.bisect(value);
|
|
40
|
+
if (i < this.items.length && this.compare(this.items[i], value) === 0) {
|
|
41
|
+
this.items.splice(i, 1);
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
clear(): void {
|
|
48
|
+
this.items.length = 0;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get size(): number {
|
|
52
|
+
return this.items.length;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
forEach(callbackfn: (value: T, value2: T, set: Set<T>) => void, thisArg?: unknown): void {
|
|
56
|
+
for (const item of this.items) {
|
|
57
|
+
callbackfn.call(thisArg, item, item, this);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
[Symbol.iterator](): IterableIterator<T> {
|
|
62
|
+
return this.items[Symbol.iterator]();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
*entries(): IterableIterator<[T, T]> {
|
|
66
|
+
for (const item of this.items) {
|
|
67
|
+
yield [item, item];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
keys(): IterableIterator<T> {
|
|
72
|
+
return this.items[Symbol.iterator]();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
values(): IterableIterator<T> {
|
|
76
|
+
return this.items[Symbol.iterator]();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
get [Symbol.toStringTag](): string {
|
|
80
|
+
return "OrderedSet";
|
|
81
|
+
}
|
|
82
|
+
}
|