@rhombus-toolkit/collections 0.0.0-placeholder.0 → 2.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/LICENSE +21 -0
- package/dist/bundle/index.d.ts +51 -0
- package/dist/bundle/index.js +118 -0
- package/package.json +24 -5
- package/README.md +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 rhombus-toolkit
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extending answers a new list sharing everything already there, so whoever holds one reads
|
|
3
|
+
* exactly what it held however much is added or removed afterwards.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* Both ends are known. {@link push} adds at the head and shares the whole list after it, which
|
|
7
|
+
* leaves the tail the same link it already was — so a list knows what it ends with without ever
|
|
8
|
+
* walking to find out. {@link tailToHead} is settled once per list and answered from then on, which
|
|
9
|
+
* is what lets a list be read from its tail as often as wanted without paying to reverse it.
|
|
10
|
+
*/
|
|
11
|
+
declare class ImmutableLinkedList<T> implements Iterable<T> {
|
|
12
|
+
#private;
|
|
13
|
+
/** How many values the list holds. */
|
|
14
|
+
readonly size: number;
|
|
15
|
+
private constructor();
|
|
16
|
+
/** A list of `T` with nothing in it. */
|
|
17
|
+
static empty<T>(): ImmutableLinkedList<T>;
|
|
18
|
+
/** The value at the head, absent where the list holds nothing. */
|
|
19
|
+
get head(): T | undefined;
|
|
20
|
+
/** The value at the tail, absent where the list holds nothing. */
|
|
21
|
+
get tail(): T | undefined;
|
|
22
|
+
/** This list with `value` at the head, everything already here shared. */
|
|
23
|
+
push(value: T): ImmutableLinkedList<T>;
|
|
24
|
+
/**
|
|
25
|
+
* This list without the first value `matches` answers for, everything after it shared; the list
|
|
26
|
+
* itself where nothing matches.
|
|
27
|
+
*/
|
|
28
|
+
remove(matches: (value: T) => boolean): ImmutableLinkedList<T>;
|
|
29
|
+
/** The values from the head to the tail. */
|
|
30
|
+
[Symbol.iterator](): Iterator<T>;
|
|
31
|
+
/** The values from the tail to the head. */
|
|
32
|
+
tailToHead(): readonly T[];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
declare class KindaWeakMap<K, V extends object> {
|
|
36
|
+
#private;
|
|
37
|
+
set(key: K, value: V): this;
|
|
38
|
+
delete(key: K): boolean;
|
|
39
|
+
get(key: K): V | undefined;
|
|
40
|
+
has(key: K): boolean;
|
|
41
|
+
clear(): void;
|
|
42
|
+
forEach(callbackfn: (value: V, key: K, map: this) => void, thisArg?: any): void;
|
|
43
|
+
get size(): number;
|
|
44
|
+
entries(): MapIterator<[K, V]>;
|
|
45
|
+
keys(): MapIterator<K>;
|
|
46
|
+
values(): MapIterator<V | undefined>;
|
|
47
|
+
[Symbol.iterator](): MapIterator<[K, V]>;
|
|
48
|
+
readonly [Symbol.toStringTag]: "KindaWeakMap";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export { ImmutableLinkedList, KindaWeakMap };
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// src/ImmutableLinkedList.ts
|
|
2
|
+
class ImmutableLinkedList {
|
|
3
|
+
static #nothing = new ImmutableLinkedList(undefined, undefined, 0);
|
|
4
|
+
#head;
|
|
5
|
+
#tail;
|
|
6
|
+
#reversed;
|
|
7
|
+
size;
|
|
8
|
+
constructor(head, tail, size) {
|
|
9
|
+
this.#head = head;
|
|
10
|
+
this.#tail = tail;
|
|
11
|
+
this.size = size;
|
|
12
|
+
}
|
|
13
|
+
static empty() {
|
|
14
|
+
return ImmutableLinkedList.#nothing;
|
|
15
|
+
}
|
|
16
|
+
get head() {
|
|
17
|
+
return this.#head?.value;
|
|
18
|
+
}
|
|
19
|
+
get tail() {
|
|
20
|
+
return this.#tail?.value;
|
|
21
|
+
}
|
|
22
|
+
push(value) {
|
|
23
|
+
const head = { value, next: this.#head };
|
|
24
|
+
return new ImmutableLinkedList(head, this.#tail ?? head, this.size + 1);
|
|
25
|
+
}
|
|
26
|
+
remove(matches) {
|
|
27
|
+
const head = removed(this.#head, matches);
|
|
28
|
+
if (head === this.#head) {
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
return new ImmutableLinkedList(head, tailOf(head), this.size - 1);
|
|
32
|
+
}
|
|
33
|
+
*[Symbol.iterator]() {
|
|
34
|
+
for (let link = this.#head;link !== undefined; link = link.next) {
|
|
35
|
+
yield link.value;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
tailToHead() {
|
|
39
|
+
this.#reversed ??= [...this].reverse();
|
|
40
|
+
return this.#reversed;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function removed(link, matches) {
|
|
44
|
+
if (link === undefined) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (matches(link.value)) {
|
|
48
|
+
return link.next;
|
|
49
|
+
}
|
|
50
|
+
const next = removed(link.next, matches);
|
|
51
|
+
return next === link.next ? link : { value: link.value, next };
|
|
52
|
+
}
|
|
53
|
+
function tailOf(link) {
|
|
54
|
+
let tail = link;
|
|
55
|
+
while (tail?.next !== undefined) {
|
|
56
|
+
tail = tail.next;
|
|
57
|
+
}
|
|
58
|
+
return tail;
|
|
59
|
+
}
|
|
60
|
+
// src/KindaWeakMap.ts
|
|
61
|
+
class KindaWeakMap {
|
|
62
|
+
#map = new Map;
|
|
63
|
+
#registry = new FinalizationRegistry((key) => {
|
|
64
|
+
if (this.#map.get(key)?.deref() === undefined) {
|
|
65
|
+
this.#map.delete(key);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
set(key, value) {
|
|
69
|
+
if (this.has(key)) {
|
|
70
|
+
this.delete(key);
|
|
71
|
+
}
|
|
72
|
+
this.#registry.register(value, key, value);
|
|
73
|
+
this.#map.set(key, new WeakRef(value));
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
delete(key) {
|
|
77
|
+
const val = this.get(key);
|
|
78
|
+
if (val !== undefined) {
|
|
79
|
+
this.#registry.unregister(val);
|
|
80
|
+
}
|
|
81
|
+
return this.#map.delete(key);
|
|
82
|
+
}
|
|
83
|
+
get(key) {
|
|
84
|
+
return this.#map.get(key)?.deref();
|
|
85
|
+
}
|
|
86
|
+
has(key) {
|
|
87
|
+
return this.#map.has(key);
|
|
88
|
+
}
|
|
89
|
+
clear() {
|
|
90
|
+
this.values().filter(Boolean).forEach((p) => this.#registry.unregister(p));
|
|
91
|
+
this.#map.clear();
|
|
92
|
+
}
|
|
93
|
+
forEach(callbackfn, thisArg) {
|
|
94
|
+
for (const [key, value] of this) {
|
|
95
|
+
callbackfn.call(thisArg, value, key, this);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
get size() {
|
|
99
|
+
return this.#map.size;
|
|
100
|
+
}
|
|
101
|
+
entries() {
|
|
102
|
+
return this.#map.entries().map(([key, ref]) => [key, ref.deref()]);
|
|
103
|
+
}
|
|
104
|
+
keys() {
|
|
105
|
+
return this.#map.keys();
|
|
106
|
+
}
|
|
107
|
+
values() {
|
|
108
|
+
return this.#map.values().map((ref) => ref.deref());
|
|
109
|
+
}
|
|
110
|
+
[Symbol.iterator]() {
|
|
111
|
+
return this.entries();
|
|
112
|
+
}
|
|
113
|
+
[Symbol.toStringTag] = "KindaWeakMap";
|
|
114
|
+
}
|
|
115
|
+
export {
|
|
116
|
+
ImmutableLinkedList,
|
|
117
|
+
KindaWeakMap
|
|
118
|
+
};
|
package/package.json
CHANGED
|
@@ -1,16 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rhombus-toolkit/collections",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Collection data structures: ImmutableLinkedList (persistent, both ends known), KindaWeakMap (strong keys, weak values).",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/rhombus-toolkit/ts.git",
|
|
8
8
|
"directory": "libraries/collections"
|
|
9
9
|
},
|
|
10
10
|
"type": "module",
|
|
11
|
+
"sideEffects": false,
|
|
12
|
+
"main": "./dist/bundle/index.js",
|
|
13
|
+
"types": "./dist/bundle/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/bundle/index.d.ts",
|
|
17
|
+
"import": "./dist/bundle/index.js",
|
|
18
|
+
"default": "./dist/bundle/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"keywords": [],
|
|
11
25
|
"author": "Thomas Butler",
|
|
12
|
-
"license": "MIT",
|
|
13
26
|
"publishConfig": {
|
|
14
|
-
"access": "public"
|
|
27
|
+
"access": "public",
|
|
28
|
+
"provenance": true
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "bun ../../scripts/build-lib.ts",
|
|
32
|
+
"lint": "bun x tsc --noEmit -p tsconfig.ci.json",
|
|
33
|
+
"test": "bun test --pass-with-no-tests"
|
|
15
34
|
}
|
|
16
|
-
}
|
|
35
|
+
}
|
package/README.md
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
Placeholder reserving `@rhombus-toolkit/collections`. The real package follows.
|