1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | "use strict";
|
7 |
|
8 | const isWeakKey = thing => typeof thing === "object" && thing !== null;
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 | class WeakTupleMap {
|
15 | constructor() {
|
16 |
|
17 | this.f = 0;
|
18 |
|
19 | this.v = undefined;
|
20 |
|
21 | this.m = undefined;
|
22 |
|
23 | this.w = undefined;
|
24 | }
|
25 |
|
26 | |
27 |
|
28 |
|
29 |
|
30 | set(...args) {
|
31 |
|
32 | let node = this;
|
33 | for (let i = 0; i < args.length - 1; i++) {
|
34 | node = node._get(args[i]);
|
35 | }
|
36 | node._setValue(args[args.length - 1]);
|
37 | }
|
38 |
|
39 | |
40 |
|
41 |
|
42 |
|
43 | has(...args) {
|
44 |
|
45 | let node = this;
|
46 | for (let i = 0; i < args.length; i++) {
|
47 | node = node._peek(args[i]);
|
48 | if (node === undefined) return false;
|
49 | }
|
50 | return node._hasValue();
|
51 | }
|
52 |
|
53 | |
54 |
|
55 |
|
56 |
|
57 | get(...args) {
|
58 |
|
59 | let node = this;
|
60 | for (let i = 0; i < args.length; i++) {
|
61 | node = node._peek(args[i]);
|
62 | if (node === undefined) return undefined;
|
63 | }
|
64 | return node._getValue();
|
65 | }
|
66 |
|
67 | |
68 |
|
69 |
|
70 |
|
71 | provide(...args) {
|
72 |
|
73 | let node = this;
|
74 | for (let i = 0; i < args.length - 1; i++) {
|
75 | node = node._get(args[i]);
|
76 | }
|
77 | if (node._hasValue()) return node._getValue();
|
78 | const fn = args[args.length - 1];
|
79 | const newValue = fn(...args.slice(0, -1));
|
80 | node._setValue(newValue);
|
81 | return newValue;
|
82 | }
|
83 |
|
84 | |
85 |
|
86 |
|
87 |
|
88 | delete(...args) {
|
89 |
|
90 | let node = this;
|
91 | for (let i = 0; i < args.length; i++) {
|
92 | node = node._peek(args[i]);
|
93 | if (node === undefined) return;
|
94 | }
|
95 | node._deleteValue();
|
96 | }
|
97 |
|
98 | |
99 |
|
100 |
|
101 | clear() {
|
102 | this.f = 0;
|
103 | this.v = undefined;
|
104 | this.w = undefined;
|
105 | this.m = undefined;
|
106 | }
|
107 |
|
108 | _getValue() {
|
109 | return this.v;
|
110 | }
|
111 |
|
112 | _hasValue() {
|
113 | return (this.f & 1) === 1;
|
114 | }
|
115 |
|
116 | _setValue(v) {
|
117 | this.f |= 1;
|
118 | this.v = v;
|
119 | }
|
120 |
|
121 | _deleteValue() {
|
122 | this.f &= 6;
|
123 | this.v = undefined;
|
124 | }
|
125 |
|
126 | _peek(thing) {
|
127 | if (isWeakKey(thing)) {
|
128 | if ((this.f & 4) !== 4) return undefined;
|
129 | return this.w.get(thing);
|
130 | } else {
|
131 | if ((this.f & 2) !== 2) return undefined;
|
132 | return this.m.get(thing);
|
133 | }
|
134 | }
|
135 |
|
136 | _get(thing) {
|
137 | if (isWeakKey(thing)) {
|
138 | if ((this.f & 4) !== 4) {
|
139 | const newMap = new WeakMap();
|
140 | this.f |= 4;
|
141 | const newNode = new WeakTupleMap();
|
142 | (this.w = newMap).set(thing, newNode);
|
143 | return newNode;
|
144 | }
|
145 | const entry = this.w.get(thing);
|
146 | if (entry !== undefined) {
|
147 | return entry;
|
148 | }
|
149 | const newNode = new WeakTupleMap();
|
150 | this.w.set(thing, newNode);
|
151 | return newNode;
|
152 | } else {
|
153 | if ((this.f & 2) !== 2) {
|
154 | const newMap = new Map();
|
155 | this.f |= 2;
|
156 | const newNode = new WeakTupleMap();
|
157 | (this.m = newMap).set(thing, newNode);
|
158 | return newNode;
|
159 | }
|
160 | const entry = this.m.get(thing);
|
161 | if (entry !== undefined) {
|
162 | return entry;
|
163 | }
|
164 | const newNode = new WeakTupleMap();
|
165 | this.m.set(thing, newNode);
|
166 | return newNode;
|
167 | }
|
168 | }
|
169 | }
|
170 |
|
171 | module.exports = WeakTupleMap;
|