loudo-ds-lmap 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- package/LICENSE.txt +28 -0
- package/README.md +1 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +153 -0
- package/package.json +38 -0
package/LICENSE.txt
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
BSD 3-Clause License
|
2
|
+
|
3
|
+
Copyright (c) 2024, p-jack
|
4
|
+
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
7
|
+
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
9
|
+
list of conditions and the following disclaimer.
|
10
|
+
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
13
|
+
and/or other materials provided with the distribution.
|
14
|
+
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
16
|
+
contributors may be used to endorse or promote products derived from
|
17
|
+
this software without specific prior written permission.
|
18
|
+
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# loudo-ds-lmap
|
package/dist/index.d.ts
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
import { Entry, MapChange, MapRemove } from "loudo-ds-map-interfaces";
|
2
|
+
interface Bucket<K, V> {
|
3
|
+
key: K;
|
4
|
+
value: V;
|
5
|
+
hashCode: number;
|
6
|
+
next: B<K, V>;
|
7
|
+
prev: B<K, V>;
|
8
|
+
chain: B<K, V>;
|
9
|
+
}
|
10
|
+
type B<K, V> = Bucket<K, V> | null;
|
11
|
+
export interface HashConfig<K extends {}, V extends {}> {
|
12
|
+
readonly load?: number;
|
13
|
+
hashCode(key: K): number;
|
14
|
+
keyEq?(key1: K, key2: K): boolean;
|
15
|
+
valueEq?(value1: V, value2: V): boolean;
|
16
|
+
}
|
17
|
+
export declare class LMap<K extends {}, V extends {}> {
|
18
|
+
#private;
|
19
|
+
readonly config: HashConfig<K, V>;
|
20
|
+
private buckets;
|
21
|
+
firstB: B<K, V>;
|
22
|
+
lastB: B<K, V>;
|
23
|
+
constructor(config: HashConfig<K, V>);
|
24
|
+
get size(): number;
|
25
|
+
get first(): Entry<K, V> | undefined;
|
26
|
+
get last(): Entry<K, V> | undefined;
|
27
|
+
get only(): Entry<K, V>;
|
28
|
+
get keyEq(): (k1: K, k2: K) => boolean;
|
29
|
+
get valueEq(): (v1: V, v2: V) => boolean;
|
30
|
+
get load(): number;
|
31
|
+
hasKey(key: K): boolean;
|
32
|
+
get(key: K): V | undefined;
|
33
|
+
[Symbol.iterator](): IterableIterator<Entry<K, V>>;
|
34
|
+
private grow;
|
35
|
+
private bucket;
|
36
|
+
put(key: K, value: V): V | undefined;
|
37
|
+
remove(key: K): V | undefined;
|
38
|
+
clear(): void;
|
39
|
+
}
|
40
|
+
export interface LMap<K extends {}, V extends {}> extends MapChange<K, V>, MapRemove<K, V> {
|
41
|
+
}
|
42
|
+
export {};
|
package/dist/index.js
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
2
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
3
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
4
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
5
|
+
};
|
6
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
7
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
10
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
11
|
+
};
|
12
|
+
var _LMap_size;
|
13
|
+
import { mixin, toTin, OnlyError } from "loudo-ds-core";
|
14
|
+
import { MapChange, MapRemove } from "loudo-ds-map-interfaces";
|
15
|
+
export class LMap {
|
16
|
+
constructor(config) {
|
17
|
+
this.buckets = [];
|
18
|
+
this.firstB = null;
|
19
|
+
this.lastB = null;
|
20
|
+
_LMap_size.set(this, 0);
|
21
|
+
this.config = config;
|
22
|
+
for (let i = 0; i < 4; i++) {
|
23
|
+
this.buckets.push(null);
|
24
|
+
}
|
25
|
+
}
|
26
|
+
get size() { return __classPrivateFieldGet(this, _LMap_size, "f"); }
|
27
|
+
get first() { var _a; return (_a = this.firstB) !== null && _a !== void 0 ? _a : undefined; }
|
28
|
+
get last() { var _a; return (_a = this.lastB) !== null && _a !== void 0 ? _a : undefined; }
|
29
|
+
get only() {
|
30
|
+
if (__classPrivateFieldGet(this, _LMap_size, "f") !== 1)
|
31
|
+
throw new OnlyError();
|
32
|
+
return this.firstB;
|
33
|
+
}
|
34
|
+
get keyEq() { var _a; return (_a = this.config.keyEq) !== null && _a !== void 0 ? _a : Object.is; }
|
35
|
+
get valueEq() { var _a; return (_a = this.config.valueEq) !== null && _a !== void 0 ? _a : Object.is; }
|
36
|
+
get load() { var _a; return (_a = this.config.load) !== null && _a !== void 0 ? _a : 0.75; }
|
37
|
+
hasKey(key) {
|
38
|
+
return this.bucket(key) !== null;
|
39
|
+
}
|
40
|
+
get(key) {
|
41
|
+
var _a;
|
42
|
+
return (_a = this.bucket(key)) === null || _a === void 0 ? void 0 : _a.value;
|
43
|
+
}
|
44
|
+
*[(_LMap_size = new WeakMap(), Symbol.iterator)]() {
|
45
|
+
for (let bucket = this.firstB; bucket !== null; bucket = bucket.next) {
|
46
|
+
yield bucket;
|
47
|
+
}
|
48
|
+
}
|
49
|
+
grow() {
|
50
|
+
const buckets = [];
|
51
|
+
for (let i = 0; i < this.buckets.length; i++)
|
52
|
+
buckets.push(null);
|
53
|
+
this.buckets = buckets;
|
54
|
+
for (let bucket = this.firstB; bucket != null; bucket = bucket.next) {
|
55
|
+
const i = Math.abs(bucket.hashCode) % buckets.length;
|
56
|
+
const chain = buckets[i];
|
57
|
+
buckets[i] = bucket;
|
58
|
+
bucket.chain = chain;
|
59
|
+
}
|
60
|
+
}
|
61
|
+
bucket(key) {
|
62
|
+
const hash = this.config.hashCode(key);
|
63
|
+
let bucket = this.buckets[Math.abs(hash) % this.buckets.length];
|
64
|
+
while (bucket !== null) {
|
65
|
+
if (bucket.hashCode === hash && this.keyEq(key, bucket.key))
|
66
|
+
return bucket;
|
67
|
+
bucket = bucket.chain;
|
68
|
+
}
|
69
|
+
return null;
|
70
|
+
}
|
71
|
+
put(key, value) {
|
72
|
+
var _a;
|
73
|
+
if (__classPrivateFieldGet(this, _LMap_size, "f") / this.buckets.length >= this.load)
|
74
|
+
this.grow();
|
75
|
+
const hashCode = this.config.hashCode(key);
|
76
|
+
const bucket = {
|
77
|
+
key, value, hashCode, prev: null, next: null, chain: null,
|
78
|
+
};
|
79
|
+
const i = Math.abs(hashCode) % this.buckets.length;
|
80
|
+
let b = this.buckets[i];
|
81
|
+
while (b !== null) {
|
82
|
+
if (b.hashCode === hashCode && this.keyEq(key, b.key)) {
|
83
|
+
const r = b.value;
|
84
|
+
b.value = value;
|
85
|
+
const elements = toTin([bucket]);
|
86
|
+
this.fire({
|
87
|
+
cleared: false,
|
88
|
+
added: { elements: toTin([bucket]), at: undefined, count: 1 },
|
89
|
+
removed: { elements: toTin([{ key: key, value: r }]), at: undefined, count: 1 }
|
90
|
+
});
|
91
|
+
return r;
|
92
|
+
}
|
93
|
+
b = b.chain;
|
94
|
+
}
|
95
|
+
bucket.chain = this.buckets[i];
|
96
|
+
this.buckets[i] = bucket;
|
97
|
+
if (this.firstB === null) {
|
98
|
+
this.firstB = bucket;
|
99
|
+
this.lastB = bucket;
|
100
|
+
}
|
101
|
+
else {
|
102
|
+
this.lastB.next = bucket;
|
103
|
+
bucket.prev = this.lastB;
|
104
|
+
this.lastB = bucket;
|
105
|
+
}
|
106
|
+
__classPrivateFieldSet(this, _LMap_size, (_a = __classPrivateFieldGet(this, _LMap_size, "f"), _a++, _a), "f");
|
107
|
+
this.fire({ cleared: false, added: { elements: toTin([bucket]), at: undefined, count: 1 } });
|
108
|
+
return undefined;
|
109
|
+
}
|
110
|
+
remove(key) {
|
111
|
+
var _a;
|
112
|
+
const hash = this.config.hashCode(key);
|
113
|
+
let prev = null;
|
114
|
+
const i = Math.abs(hash) % this.buckets.length;
|
115
|
+
let bucket = this.buckets[i];
|
116
|
+
while (bucket !== null) {
|
117
|
+
if (bucket.hashCode === hash && this.keyEq(key, bucket.key))
|
118
|
+
break;
|
119
|
+
prev = bucket;
|
120
|
+
bucket = bucket.chain;
|
121
|
+
}
|
122
|
+
if (bucket === null)
|
123
|
+
return undefined;
|
124
|
+
__classPrivateFieldSet(this, _LMap_size, (_a = __classPrivateFieldGet(this, _LMap_size, "f"), _a--, _a), "f");
|
125
|
+
if (prev === null)
|
126
|
+
this.buckets[i] = bucket.chain;
|
127
|
+
else
|
128
|
+
prev.chain = bucket.chain;
|
129
|
+
if (this.firstB === bucket)
|
130
|
+
this.firstB = bucket.next;
|
131
|
+
if (this.lastB === bucket)
|
132
|
+
this.lastB = bucket.prev;
|
133
|
+
if (bucket.next !== null) {
|
134
|
+
bucket.next.prev = bucket.prev;
|
135
|
+
}
|
136
|
+
if (bucket.prev !== null) {
|
137
|
+
bucket.prev.next = bucket.next;
|
138
|
+
}
|
139
|
+
const elements = toTin([bucket]);
|
140
|
+
this.fire({ cleared: false, removed: { elements, at: undefined, count: 1 } });
|
141
|
+
return bucket.value;
|
142
|
+
}
|
143
|
+
clear() {
|
144
|
+
if (this.size === 0)
|
145
|
+
return;
|
146
|
+
this.firstB = null;
|
147
|
+
this.lastB = null;
|
148
|
+
__classPrivateFieldSet(this, _LMap_size, 0, "f");
|
149
|
+
this.fire({ cleared: true });
|
150
|
+
}
|
151
|
+
}
|
152
|
+
mixin(LMap, [MapChange, MapRemove]);
|
153
|
+
//# sourceMappingURL=index.js.map
|
package/package.json
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
{
|
2
|
+
"name": "loudo-ds-lmap",
|
3
|
+
"type": "module",
|
4
|
+
"version": "0.0.1",
|
5
|
+
"description": "Flexible loud map.",
|
6
|
+
"main": "dist/index.js",
|
7
|
+
"types": "dist/index.d.ts",
|
8
|
+
"files": [
|
9
|
+
"README.md",
|
10
|
+
"dist/index.js",
|
11
|
+
"dist/index.d.ts"
|
12
|
+
],
|
13
|
+
"scripts": {
|
14
|
+
"build": "tsc",
|
15
|
+
"prepare": "tsc",
|
16
|
+
"test": "vitest --coverage"
|
17
|
+
},
|
18
|
+
"repository": {
|
19
|
+
"type": "git",
|
20
|
+
"url": "git+https://github.com/p-jack/loudo-ds.git"
|
21
|
+
},
|
22
|
+
"author": "Paul Jack",
|
23
|
+
"license": "BSD-3-Clause",
|
24
|
+
"bugs": {
|
25
|
+
"url": "https://github.com/p-jack/loudo-ds/issues"
|
26
|
+
},
|
27
|
+
"homepage": "https://github.com/p-jack/loudo-ds#readme",
|
28
|
+
"devDependencies": {
|
29
|
+
"@types/web": "^0.0.138",
|
30
|
+
"@vitest/coverage-v8": "^2.1.4",
|
31
|
+
"jsdom": "^25.0.1",
|
32
|
+
"typescript": "^5.6.3",
|
33
|
+
"vitest": "^2.1.4"
|
34
|
+
},
|
35
|
+
"dependencies": {
|
36
|
+
"loudo-ds-map-interfaces": "^0.0.4"
|
37
|
+
}
|
38
|
+
}
|