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 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
@@ -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
+ }