@opensumi/ide-utils 2.21.13 → 2.22.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/lib/arrays.d.ts +3 -3
- package/lib/arrays.d.ts.map +1 -1
- package/lib/arrays.js.map +1 -1
- package/lib/async.d.ts +3 -3
- package/lib/async.d.ts.map +1 -1
- package/lib/buffer.js +4 -4
- package/lib/buffer.js.map +1 -1
- package/lib/character-classifier.js +3 -3
- package/lib/character-classifier.js.map +1 -1
- package/lib/decorators.d.ts +1 -1
- package/lib/decorators.d.ts.map +1 -1
- package/lib/encoding.d.ts +7 -1
- package/lib/encoding.d.ts.map +1 -1
- package/lib/encoding.js +15 -2
- package/lib/encoding.js.map +1 -1
- package/lib/errors.d.ts +2 -2
- package/lib/errors.d.ts.map +1 -1
- package/lib/event.d.ts +2 -2
- package/lib/event.d.ts.map +1 -1
- package/lib/filters.d.ts +3 -3
- package/lib/filters.d.ts.map +1 -1
- package/lib/filters.js +25 -25
- package/lib/filters.js.map +1 -1
- package/lib/glob.d.ts +2 -2
- package/lib/glob.d.ts.map +1 -1
- package/lib/glob.js +1 -1
- package/lib/glob.js.map +1 -1
- package/lib/hash.js +10 -10
- package/lib/hash.js.map +1 -1
- package/lib/iterator.d.ts +1 -1
- package/lib/iterator.d.ts.map +1 -1
- package/lib/linked-text.d.ts +1 -1
- package/lib/linked-text.d.ts.map +1 -1
- package/lib/linked-text.js.map +1 -1
- package/lib/map.js +17 -17
- package/lib/map.js.map +1 -1
- package/lib/objects.d.ts +1 -0
- package/lib/objects.d.ts.map +1 -1
- package/lib/objects.js +38 -1
- package/lib/objects.js.map +1 -1
- package/lib/os.d.ts +1 -8
- package/lib/os.d.ts.map +1 -1
- package/lib/os.js +4 -8
- package/lib/os.js.map +1 -1
- package/lib/path.d.ts +1 -1
- package/lib/path.d.ts.map +1 -1
- package/lib/path.js +29 -29
- package/lib/path.js.map +1 -1
- package/lib/platform.js +8 -8
- package/lib/platform.js.map +1 -1
- package/lib/process.d.ts.map +1 -1
- package/lib/process.js +28 -13
- package/lib/process.js.map +1 -1
- package/lib/progress.js +3 -3
- package/lib/progress.js.map +1 -1
- package/lib/strings.js +9 -9
- package/lib/strings.js.map +1 -1
- package/lib/types.d.ts +5 -1
- package/lib/types.d.ts.map +1 -1
- package/lib/types.js +8 -1
- package/lib/types.js.map +1 -1
- package/lib/uint.js +4 -4
- package/lib/uint.js.map +1 -1
- package/lib/uri.js +8 -8
- package/lib/uri.js.map +1 -1
- package/lib/uuid.d.ts +1 -1
- package/lib/uuid.d.ts.map +1 -1
- package/lib/uuid.js +3 -2
- package/lib/uuid.js.map +1 -1
- package/package.json +8 -6
- package/src/ansi.ts +10 -0
- package/src/argv.ts +57 -0
- package/src/arrays.ts +328 -0
- package/src/async.ts +580 -0
- package/src/buffer.ts +290 -0
- package/src/cache.ts +37 -0
- package/src/cancellation.ts +136 -0
- package/src/charCode.ts +425 -0
- package/src/character-classifier.ts +82 -0
- package/src/const/encoding.ts +242 -0
- package/src/const/index.ts +1 -0
- package/src/date.ts +36 -0
- package/src/decorators.ts +166 -0
- package/src/disposable.ts +377 -0
- package/src/encoding.ts +278 -0
- package/src/errors.ts +192 -0
- package/src/event.ts +1024 -0
- package/src/file-uri.ts +41 -0
- package/src/filters.ts +887 -0
- package/src/functional.ts +43 -0
- package/src/glob.ts +752 -0
- package/src/hash.ts +336 -0
- package/src/iconLabels.ts +149 -0
- package/src/index.ts +40 -0
- package/src/iterator.ts +36 -0
- package/src/lifecycle.ts +48 -0
- package/src/linked-list.ts +144 -0
- package/src/linked-text.ts +55 -0
- package/src/lru-map.ts +133 -0
- package/src/map.ts +934 -0
- package/src/marshalling.ts +62 -0
- package/src/objects.ts +145 -0
- package/src/os.ts +76 -0
- package/src/path.ts +1885 -0
- package/src/platform.ts +194 -0
- package/src/process.ts +43 -0
- package/src/progress.ts +83 -0
- package/src/promises.ts +23 -0
- package/src/sequence.ts +28 -0
- package/src/strings.ts +1002 -0
- package/src/types.ts +214 -0
- package/src/uint.ts +59 -0
- package/src/uri.ts +298 -0
- package/src/uuid.ts +6 -0
package/src/map.ts
ADDED
|
@@ -0,0 +1,934 @@
|
|
|
1
|
+
import { URI as Uri } from 'vscode-uri';
|
|
2
|
+
|
|
3
|
+
import { CharCode } from './charCode';
|
|
4
|
+
import { Iterator, IteratorResult, FIN } from './iterator';
|
|
5
|
+
|
|
6
|
+
export function values<V = any>(set: Set<V>): V[];
|
|
7
|
+
export function values<K = any, V = any>(map: Map<K, V>): V[];
|
|
8
|
+
export function values<V>(forEachable: { forEach(callback: (value: V, ...more: any[]) => any): void }): V[] {
|
|
9
|
+
const result: V[] = [];
|
|
10
|
+
forEachable.forEach((value) => result.push(value));
|
|
11
|
+
return result;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function keys<K, V>(map: Map<K, V>): K[] {
|
|
15
|
+
const result: K[] = [];
|
|
16
|
+
map.forEach((value, key) => result.push(key));
|
|
17
|
+
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function getOrSet<K, V>(map: Map<K, V>, key: K, value: V): V {
|
|
22
|
+
let result = map.get(key);
|
|
23
|
+
if (result === undefined) {
|
|
24
|
+
result = value;
|
|
25
|
+
map.set(key, result);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function mapToString<K, V>(map: Map<K, V>): string {
|
|
32
|
+
const entries: string[] = [];
|
|
33
|
+
map.forEach((value, key) => {
|
|
34
|
+
entries.push(`${key} => ${value}`);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return `Map(${map.size}) {${entries.join(', ')}}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function setToString<K>(set: Set<K>): string {
|
|
41
|
+
const entries: K[] = [];
|
|
42
|
+
set.forEach((value) => {
|
|
43
|
+
entries.push(value);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
return `Set(${set.size}) {${entries.join(', ')}}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function mapToSerializable<T = string>(map: Map<string, T>): [string, T][] {
|
|
50
|
+
const serializable: [string, T][] = [];
|
|
51
|
+
|
|
52
|
+
map.forEach((value, key) => {
|
|
53
|
+
serializable.push([key, value]);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return serializable;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function serializableToMap<T = string>(serializable: [string, T][]): Map<string, T> {
|
|
60
|
+
const items = new Map<string, T>();
|
|
61
|
+
|
|
62
|
+
for (const [key, value] of serializable) {
|
|
63
|
+
items.set(key, value);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return items;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface IKeyIterator {
|
|
70
|
+
reset(key: string): this;
|
|
71
|
+
next(): this;
|
|
72
|
+
|
|
73
|
+
hasNext(): boolean;
|
|
74
|
+
cmp(a: string): number;
|
|
75
|
+
value(): string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export class StringIterator implements IKeyIterator {
|
|
79
|
+
private _value = '';
|
|
80
|
+
private _pos = 0;
|
|
81
|
+
|
|
82
|
+
reset(key: string): this {
|
|
83
|
+
this._value = key;
|
|
84
|
+
this._pos = 0;
|
|
85
|
+
return this;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
next(): this {
|
|
89
|
+
this._pos += 1;
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
hasNext(): boolean {
|
|
94
|
+
return this._pos < this._value.length - 1;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
cmp(a: string): number {
|
|
98
|
+
const aCode = a.charCodeAt(0);
|
|
99
|
+
const thisCode = this._value.charCodeAt(this._pos);
|
|
100
|
+
return aCode - thisCode;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
value(): string {
|
|
104
|
+
return this._value[this._pos];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export class PathIterator implements IKeyIterator {
|
|
109
|
+
private _value: string;
|
|
110
|
+
private _from: number;
|
|
111
|
+
private _to: number;
|
|
112
|
+
|
|
113
|
+
reset(key: string): this {
|
|
114
|
+
this._value = key.replace(/\\$|\/$/, '');
|
|
115
|
+
this._from = 0;
|
|
116
|
+
this._to = 0;
|
|
117
|
+
return this.next();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
hasNext(): boolean {
|
|
121
|
+
return this._to < this._value.length;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
next(): this {
|
|
125
|
+
// this._data = key.split(/[\\/]/).filter(s => !!s);
|
|
126
|
+
this._from = this._to;
|
|
127
|
+
let justSeps = true;
|
|
128
|
+
for (; this._to < this._value.length; this._to++) {
|
|
129
|
+
const ch = this._value.charCodeAt(this._to);
|
|
130
|
+
if (ch === CharCode.Slash || ch === CharCode.Backslash) {
|
|
131
|
+
if (justSeps) {
|
|
132
|
+
this._from++;
|
|
133
|
+
} else {
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
} else {
|
|
137
|
+
justSeps = false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return this;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
cmp(a: string): number {
|
|
144
|
+
let aPos = 0;
|
|
145
|
+
const aLen = a.length;
|
|
146
|
+
let thisPos = this._from;
|
|
147
|
+
|
|
148
|
+
while (aPos < aLen && thisPos < this._to) {
|
|
149
|
+
const cmp = a.charCodeAt(aPos) - this._value.charCodeAt(thisPos);
|
|
150
|
+
if (cmp !== 0) {
|
|
151
|
+
return cmp;
|
|
152
|
+
}
|
|
153
|
+
aPos += 1;
|
|
154
|
+
thisPos += 1;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (aLen === this._to - this._from) {
|
|
158
|
+
return 0;
|
|
159
|
+
} else if (aPos < aLen) {
|
|
160
|
+
return -1;
|
|
161
|
+
} else {
|
|
162
|
+
return 1;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
value(): string {
|
|
167
|
+
return this._value.substring(this._from, this._to);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
class TernarySearchTreeNode<E> {
|
|
172
|
+
segment: string;
|
|
173
|
+
value: E | undefined;
|
|
174
|
+
key: string;
|
|
175
|
+
left: TernarySearchTreeNode<E> | undefined;
|
|
176
|
+
mid: TernarySearchTreeNode<E> | undefined;
|
|
177
|
+
right: TernarySearchTreeNode<E> | undefined;
|
|
178
|
+
|
|
179
|
+
isEmpty(): boolean {
|
|
180
|
+
return !this.left && !this.mid && !this.right && !this.value;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export class TernarySearchTree<E> {
|
|
185
|
+
static forPaths<E>(): TernarySearchTree<E> {
|
|
186
|
+
return new TernarySearchTree<E>(new PathIterator());
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
static forStrings<E>(): TernarySearchTree<E> {
|
|
190
|
+
return new TernarySearchTree<E>(new StringIterator());
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
private _iter: IKeyIterator;
|
|
194
|
+
private _root: TernarySearchTreeNode<E> | undefined;
|
|
195
|
+
|
|
196
|
+
constructor(segments: IKeyIterator) {
|
|
197
|
+
this._iter = segments;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
clear(): void {
|
|
201
|
+
this._root = undefined;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
set(key: string, element: E): E | undefined {
|
|
205
|
+
const iter = this._iter.reset(key);
|
|
206
|
+
let node: TernarySearchTreeNode<E>;
|
|
207
|
+
|
|
208
|
+
if (!this._root) {
|
|
209
|
+
this._root = new TernarySearchTreeNode<E>();
|
|
210
|
+
this._root.segment = iter.value();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
node = this._root;
|
|
214
|
+
while (true) {
|
|
215
|
+
const val = iter.cmp(node.segment);
|
|
216
|
+
if (val > 0) {
|
|
217
|
+
// left
|
|
218
|
+
if (!node.left) {
|
|
219
|
+
node.left = new TernarySearchTreeNode<E>();
|
|
220
|
+
node.left.segment = iter.value();
|
|
221
|
+
}
|
|
222
|
+
node = node.left;
|
|
223
|
+
} else if (val < 0) {
|
|
224
|
+
// right
|
|
225
|
+
if (!node.right) {
|
|
226
|
+
node.right = new TernarySearchTreeNode<E>();
|
|
227
|
+
node.right.segment = iter.value();
|
|
228
|
+
}
|
|
229
|
+
node = node.right;
|
|
230
|
+
} else if (iter.hasNext()) {
|
|
231
|
+
// mid
|
|
232
|
+
iter.next();
|
|
233
|
+
if (!node.mid) {
|
|
234
|
+
node.mid = new TernarySearchTreeNode<E>();
|
|
235
|
+
node.mid.segment = iter.value();
|
|
236
|
+
}
|
|
237
|
+
node = node.mid;
|
|
238
|
+
} else {
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
const oldElement = node.value;
|
|
243
|
+
node.value = element;
|
|
244
|
+
node.key = key;
|
|
245
|
+
return oldElement;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
get(key: string): E | undefined {
|
|
249
|
+
const iter = this._iter.reset(key);
|
|
250
|
+
let node = this._root;
|
|
251
|
+
while (node) {
|
|
252
|
+
const val = iter.cmp(node.segment);
|
|
253
|
+
if (val > 0) {
|
|
254
|
+
// left
|
|
255
|
+
node = node.left;
|
|
256
|
+
} else if (val < 0) {
|
|
257
|
+
// right
|
|
258
|
+
node = node.right;
|
|
259
|
+
} else if (iter.hasNext()) {
|
|
260
|
+
// mid
|
|
261
|
+
iter.next();
|
|
262
|
+
node = node.mid;
|
|
263
|
+
} else {
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return node ? node.value : undefined;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
delete(key: string): void {
|
|
271
|
+
const iter = this._iter.reset(key);
|
|
272
|
+
const stack: [-1 | 0 | 1, TernarySearchTreeNode<E>][] = [];
|
|
273
|
+
let node = this._root;
|
|
274
|
+
|
|
275
|
+
// find and unset node
|
|
276
|
+
while (node) {
|
|
277
|
+
const val = iter.cmp(node.segment);
|
|
278
|
+
if (val > 0) {
|
|
279
|
+
// left
|
|
280
|
+
stack.push([1, node]);
|
|
281
|
+
node = node.left;
|
|
282
|
+
} else if (val < 0) {
|
|
283
|
+
// right
|
|
284
|
+
stack.push([-1, node]);
|
|
285
|
+
node = node.right;
|
|
286
|
+
} else if (iter.hasNext()) {
|
|
287
|
+
// mid
|
|
288
|
+
iter.next();
|
|
289
|
+
stack.push([0, node]);
|
|
290
|
+
node = node.mid;
|
|
291
|
+
} else {
|
|
292
|
+
// remove element
|
|
293
|
+
node.value = undefined;
|
|
294
|
+
|
|
295
|
+
// clean up empty nodes
|
|
296
|
+
while (stack.length > 0 && node.isEmpty()) {
|
|
297
|
+
const [dir, parent] = stack.pop()!;
|
|
298
|
+
switch (dir) {
|
|
299
|
+
case 1:
|
|
300
|
+
parent.left = undefined;
|
|
301
|
+
break;
|
|
302
|
+
case 0:
|
|
303
|
+
parent.mid = undefined;
|
|
304
|
+
break;
|
|
305
|
+
case -1:
|
|
306
|
+
parent.right = undefined;
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
node = parent;
|
|
310
|
+
}
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
findSubstr(key: string): E | undefined {
|
|
317
|
+
const iter = this._iter.reset(key);
|
|
318
|
+
let node = this._root;
|
|
319
|
+
let candidate: E | undefined;
|
|
320
|
+
while (node) {
|
|
321
|
+
const val = iter.cmp(node.segment);
|
|
322
|
+
if (val > 0) {
|
|
323
|
+
// left
|
|
324
|
+
node = node.left;
|
|
325
|
+
} else if (val < 0) {
|
|
326
|
+
// right
|
|
327
|
+
node = node.right;
|
|
328
|
+
} else if (iter.hasNext()) {
|
|
329
|
+
// mid
|
|
330
|
+
iter.next();
|
|
331
|
+
candidate = node.value || candidate;
|
|
332
|
+
node = node.mid;
|
|
333
|
+
} else {
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return (node && node.value) || candidate;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
findSuperstr(key: string): Iterator<E> | undefined {
|
|
341
|
+
const iter = this._iter.reset(key);
|
|
342
|
+
let node = this._root;
|
|
343
|
+
while (node) {
|
|
344
|
+
const val = iter.cmp(node.segment);
|
|
345
|
+
if (val > 0) {
|
|
346
|
+
// left
|
|
347
|
+
node = node.left;
|
|
348
|
+
} else if (val < 0) {
|
|
349
|
+
// right
|
|
350
|
+
node = node.right;
|
|
351
|
+
} else if (iter.hasNext()) {
|
|
352
|
+
// mid
|
|
353
|
+
iter.next();
|
|
354
|
+
node = node.mid;
|
|
355
|
+
} else {
|
|
356
|
+
// collect
|
|
357
|
+
if (!node.mid) {
|
|
358
|
+
return undefined;
|
|
359
|
+
} else {
|
|
360
|
+
return this._nodeIterator(node.mid);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return undefined;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
private _nodeIterator(node: TernarySearchTreeNode<E>): Iterator<E> {
|
|
368
|
+
let res: { done: false; value: E };
|
|
369
|
+
let idx: number;
|
|
370
|
+
let data: E[];
|
|
371
|
+
const next = (): IteratorResult<E> => {
|
|
372
|
+
if (!data) {
|
|
373
|
+
// lazy till first invocation
|
|
374
|
+
data = [];
|
|
375
|
+
idx = 0;
|
|
376
|
+
this._forEach(node, (value) => data.push(value));
|
|
377
|
+
}
|
|
378
|
+
if (idx >= data.length) {
|
|
379
|
+
return FIN;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (!res) {
|
|
383
|
+
res = { done: false, value: data[idx++] };
|
|
384
|
+
} else {
|
|
385
|
+
res.value = data[idx++];
|
|
386
|
+
}
|
|
387
|
+
return res;
|
|
388
|
+
};
|
|
389
|
+
return { next };
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
forEach(callback: (value: E, index: string) => any) {
|
|
393
|
+
this._forEach(this._root, callback);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
private _forEach(node: TernarySearchTreeNode<E> | undefined, callback: (value: E, index: string) => any) {
|
|
397
|
+
if (node) {
|
|
398
|
+
// left
|
|
399
|
+
this._forEach(node.left, callback);
|
|
400
|
+
|
|
401
|
+
// node
|
|
402
|
+
if (node.value) {
|
|
403
|
+
// callback(node.value, this._iter.join(parts));
|
|
404
|
+
callback(node.value, node.key);
|
|
405
|
+
}
|
|
406
|
+
// mid
|
|
407
|
+
this._forEach(node.mid, callback);
|
|
408
|
+
|
|
409
|
+
// right
|
|
410
|
+
this._forEach(node.right, callback);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
export class ResourceMap<T> {
|
|
416
|
+
protected readonly map: Map<string, T>;
|
|
417
|
+
protected readonly ignoreCase?: boolean;
|
|
418
|
+
|
|
419
|
+
constructor() {
|
|
420
|
+
this.map = new Map<string, T>();
|
|
421
|
+
this.ignoreCase = false; // in the future this should be an uri-comparator
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
set(resource: Uri, value: T): void {
|
|
425
|
+
this.map.set(this.toKey(resource), value);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
get(resource: Uri): T | undefined {
|
|
429
|
+
return this.map.get(this.toKey(resource));
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
has(resource: Uri): boolean {
|
|
433
|
+
return this.map.has(this.toKey(resource));
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
get size(): number {
|
|
437
|
+
return this.map.size;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
clear(): void {
|
|
441
|
+
this.map.clear();
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
delete(resource: Uri): boolean {
|
|
445
|
+
return this.map.delete(this.toKey(resource));
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
forEach(clb: (value: T) => void): void {
|
|
449
|
+
this.map.forEach(clb);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
values(): T[] {
|
|
453
|
+
return values(this.map);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
private toKey(resource: Uri): string {
|
|
457
|
+
let key = resource.toString();
|
|
458
|
+
if (this.ignoreCase) {
|
|
459
|
+
key = key.toLowerCase();
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
return key;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
keys(): Uri[] {
|
|
466
|
+
return keys(this.map).map((k) => Uri.parse(k));
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
clone(): ResourceMap<T> {
|
|
470
|
+
const resourceMap = new ResourceMap<T>();
|
|
471
|
+
|
|
472
|
+
this.map.forEach((value, key) => resourceMap.map.set(key, value));
|
|
473
|
+
|
|
474
|
+
return resourceMap;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// We should fold BoundedMap and LinkedMap. See https://github.com/Microsoft/vscode/issues/28496
|
|
479
|
+
|
|
480
|
+
interface Item<K, V> {
|
|
481
|
+
previous: Item<K, V> | undefined;
|
|
482
|
+
next: Item<K, V> | undefined;
|
|
483
|
+
key: K;
|
|
484
|
+
value: V;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
export const enum Touch {
|
|
488
|
+
None = 0,
|
|
489
|
+
AsOld = 1,
|
|
490
|
+
AsNew = 2,
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
export class LinkedMap<K, V> {
|
|
494
|
+
private _map: Map<K, Item<K, V>>;
|
|
495
|
+
private _head: Item<K, V> | undefined;
|
|
496
|
+
private _tail: Item<K, V> | undefined;
|
|
497
|
+
private _size: number;
|
|
498
|
+
|
|
499
|
+
constructor() {
|
|
500
|
+
this._map = new Map<K, Item<K, V>>();
|
|
501
|
+
this._head = undefined;
|
|
502
|
+
this._tail = undefined;
|
|
503
|
+
this._size = 0;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
clear(): void {
|
|
507
|
+
this._map.clear();
|
|
508
|
+
this._head = undefined;
|
|
509
|
+
this._tail = undefined;
|
|
510
|
+
this._size = 0;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
isEmpty(): boolean {
|
|
514
|
+
return !this._head && !this._tail;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
get size(): number {
|
|
518
|
+
return this._size;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
has(key: K): boolean {
|
|
522
|
+
return this._map.has(key);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
get(key: K, touch: Touch = Touch.None): V | undefined {
|
|
526
|
+
const item = this._map.get(key);
|
|
527
|
+
if (!item) {
|
|
528
|
+
return undefined;
|
|
529
|
+
}
|
|
530
|
+
if (touch !== Touch.None) {
|
|
531
|
+
this.touch(item, touch);
|
|
532
|
+
}
|
|
533
|
+
return item.value;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
set(key: K, value: V, touch: Touch = Touch.None): void {
|
|
537
|
+
let item = this._map.get(key);
|
|
538
|
+
if (item) {
|
|
539
|
+
item.value = value;
|
|
540
|
+
if (touch !== Touch.None) {
|
|
541
|
+
this.touch(item, touch);
|
|
542
|
+
}
|
|
543
|
+
} else {
|
|
544
|
+
item = { key, value, next: undefined, previous: undefined };
|
|
545
|
+
switch (touch) {
|
|
546
|
+
case Touch.None:
|
|
547
|
+
this.addItemLast(item);
|
|
548
|
+
break;
|
|
549
|
+
case Touch.AsOld:
|
|
550
|
+
this.addItemFirst(item);
|
|
551
|
+
break;
|
|
552
|
+
case Touch.AsNew:
|
|
553
|
+
this.addItemLast(item);
|
|
554
|
+
break;
|
|
555
|
+
default:
|
|
556
|
+
this.addItemLast(item);
|
|
557
|
+
break;
|
|
558
|
+
}
|
|
559
|
+
this._map.set(key, item);
|
|
560
|
+
this._size++;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
delete(key: K): boolean {
|
|
565
|
+
return !!this.remove(key);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
remove(key: K): V | undefined {
|
|
569
|
+
const item = this._map.get(key);
|
|
570
|
+
if (!item) {
|
|
571
|
+
return undefined;
|
|
572
|
+
}
|
|
573
|
+
this._map.delete(key);
|
|
574
|
+
this.removeItem(item);
|
|
575
|
+
this._size--;
|
|
576
|
+
return item.value;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
shift(): V | undefined {
|
|
580
|
+
if (!this._head && !this._tail) {
|
|
581
|
+
return undefined;
|
|
582
|
+
}
|
|
583
|
+
if (!this._head || !this._tail) {
|
|
584
|
+
throw new Error('Invalid list');
|
|
585
|
+
}
|
|
586
|
+
const item = this._head;
|
|
587
|
+
this._map.delete(item.key);
|
|
588
|
+
this.removeItem(item);
|
|
589
|
+
this._size--;
|
|
590
|
+
return item.value;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
forEach(callbackfn: (value: V, key: K, map: LinkedMap<K, V>) => void, thisArg?: any): void {
|
|
594
|
+
let current = this._head;
|
|
595
|
+
while (current) {
|
|
596
|
+
if (thisArg) {
|
|
597
|
+
callbackfn.bind(thisArg)(current.value, current.key, this);
|
|
598
|
+
} else {
|
|
599
|
+
callbackfn(current.value, current.key, this);
|
|
600
|
+
}
|
|
601
|
+
current = current.next;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
values(): V[] {
|
|
606
|
+
const result: V[] = [];
|
|
607
|
+
let current = this._head;
|
|
608
|
+
while (current) {
|
|
609
|
+
result.push(current.value);
|
|
610
|
+
current = current.next;
|
|
611
|
+
}
|
|
612
|
+
return result;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
keys(): K[] {
|
|
616
|
+
const result: K[] = [];
|
|
617
|
+
let current = this._head;
|
|
618
|
+
while (current) {
|
|
619
|
+
result.push(current.key);
|
|
620
|
+
current = current.next;
|
|
621
|
+
}
|
|
622
|
+
return result;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/* VS Code / Monaco editor runs on es5 which has no Symbol.iterator
|
|
626
|
+
keys(): IterableIterator<K> {
|
|
627
|
+
const current = this._head;
|
|
628
|
+
const iterator: IterableIterator<K> = {
|
|
629
|
+
[Symbol.iterator]() {
|
|
630
|
+
return iterator;
|
|
631
|
+
},
|
|
632
|
+
next():IteratorResult<K> {
|
|
633
|
+
if (current) {
|
|
634
|
+
const result = { value: current.key, done: false };
|
|
635
|
+
current = current.next;
|
|
636
|
+
return result;
|
|
637
|
+
} else {
|
|
638
|
+
return { value: undefined, done: true };
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
return iterator;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
values(): IterableIterator<V> {
|
|
646
|
+
const current = this._head;
|
|
647
|
+
const iterator: IterableIterator<V> = {
|
|
648
|
+
[Symbol.iterator]() {
|
|
649
|
+
return iterator;
|
|
650
|
+
},
|
|
651
|
+
next():IteratorResult<V> {
|
|
652
|
+
if (current) {
|
|
653
|
+
const result = { value: current.value, done: false };
|
|
654
|
+
current = current.next;
|
|
655
|
+
return result;
|
|
656
|
+
} else {
|
|
657
|
+
return { value: undefined, done: true };
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
return iterator;
|
|
662
|
+
}
|
|
663
|
+
*/
|
|
664
|
+
|
|
665
|
+
protected trimOld(newSize: number) {
|
|
666
|
+
if (newSize >= this.size) {
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
if (newSize === 0) {
|
|
670
|
+
this.clear();
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
let current = this._head;
|
|
674
|
+
let currentSize = this.size;
|
|
675
|
+
while (current && currentSize > newSize) {
|
|
676
|
+
this._map.delete(current.key);
|
|
677
|
+
current = current.next;
|
|
678
|
+
currentSize--;
|
|
679
|
+
}
|
|
680
|
+
this._head = current;
|
|
681
|
+
this._size = currentSize;
|
|
682
|
+
if (current) {
|
|
683
|
+
current.previous = undefined;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
private addItemFirst(item: Item<K, V>): void {
|
|
688
|
+
// First time Insert
|
|
689
|
+
if (!this._head && !this._tail) {
|
|
690
|
+
this._tail = item;
|
|
691
|
+
} else if (!this._head) {
|
|
692
|
+
throw new Error('Invalid list');
|
|
693
|
+
} else {
|
|
694
|
+
item.next = this._head;
|
|
695
|
+
this._head.previous = item;
|
|
696
|
+
}
|
|
697
|
+
this._head = item;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
private addItemLast(item: Item<K, V>): void {
|
|
701
|
+
// First time Insert
|
|
702
|
+
if (!this._head && !this._tail) {
|
|
703
|
+
this._head = item;
|
|
704
|
+
} else if (!this._tail) {
|
|
705
|
+
throw new Error('Invalid list');
|
|
706
|
+
} else {
|
|
707
|
+
item.previous = this._tail;
|
|
708
|
+
this._tail.next = item;
|
|
709
|
+
}
|
|
710
|
+
this._tail = item;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
private removeItem(item: Item<K, V>): void {
|
|
714
|
+
if (item === this._head && item === this._tail) {
|
|
715
|
+
this._head = undefined;
|
|
716
|
+
this._tail = undefined;
|
|
717
|
+
} else if (item === this._head) {
|
|
718
|
+
// This can only happend if size === 1 which is handle
|
|
719
|
+
// by the case above.
|
|
720
|
+
if (!item.next) {
|
|
721
|
+
throw new Error('Invalid list');
|
|
722
|
+
}
|
|
723
|
+
item.next.previous = undefined;
|
|
724
|
+
this._head = item.next;
|
|
725
|
+
} else if (item === this._tail) {
|
|
726
|
+
// This can only happend if size === 1 which is handle
|
|
727
|
+
// by the case above.
|
|
728
|
+
if (!item.previous) {
|
|
729
|
+
throw new Error('Invalid list');
|
|
730
|
+
}
|
|
731
|
+
item.previous.next = undefined;
|
|
732
|
+
this._tail = item.previous;
|
|
733
|
+
} else {
|
|
734
|
+
const next = item.next;
|
|
735
|
+
const previous = item.previous;
|
|
736
|
+
if (!next || !previous) {
|
|
737
|
+
throw new Error('Invalid list');
|
|
738
|
+
}
|
|
739
|
+
next.previous = previous;
|
|
740
|
+
previous.next = next;
|
|
741
|
+
}
|
|
742
|
+
item.next = undefined;
|
|
743
|
+
item.previous = undefined;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
private touch(item: Item<K, V>, touch: Touch): void {
|
|
747
|
+
if (!this._head || !this._tail) {
|
|
748
|
+
throw new Error('Invalid list');
|
|
749
|
+
}
|
|
750
|
+
if (touch !== Touch.AsOld && touch !== Touch.AsNew) {
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
if (touch === Touch.AsOld) {
|
|
755
|
+
if (item === this._head) {
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
const next = item.next;
|
|
760
|
+
const previous = item.previous;
|
|
761
|
+
|
|
762
|
+
// Unlink the item
|
|
763
|
+
if (item === this._tail) {
|
|
764
|
+
// previous must be defined since item was not head but is tail
|
|
765
|
+
// So there are more than on item in the map
|
|
766
|
+
previous!.next = undefined;
|
|
767
|
+
this._tail = previous;
|
|
768
|
+
} else {
|
|
769
|
+
// Both next and previous are not undefined since item was neither head nor tail.
|
|
770
|
+
next!.previous = previous;
|
|
771
|
+
previous!.next = next;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// Insert the node at head
|
|
775
|
+
item.previous = undefined;
|
|
776
|
+
item.next = this._head;
|
|
777
|
+
this._head.previous = item;
|
|
778
|
+
this._head = item;
|
|
779
|
+
} else if (touch === Touch.AsNew) {
|
|
780
|
+
if (item === this._tail) {
|
|
781
|
+
return;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
const next = item.next;
|
|
785
|
+
const previous = item.previous;
|
|
786
|
+
|
|
787
|
+
// Unlink the item.
|
|
788
|
+
if (item === this._head) {
|
|
789
|
+
// next must be defined since item was not tail but is head
|
|
790
|
+
// So there are more than on item in the map
|
|
791
|
+
next!.previous = undefined;
|
|
792
|
+
this._head = next;
|
|
793
|
+
} else {
|
|
794
|
+
// Both next and previous are not undefined since item was neither head nor tail.
|
|
795
|
+
next!.previous = previous;
|
|
796
|
+
previous!.next = next;
|
|
797
|
+
}
|
|
798
|
+
item.next = undefined;
|
|
799
|
+
item.previous = this._tail;
|
|
800
|
+
this._tail.next = item;
|
|
801
|
+
this._tail = item;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
toJSON(): [K, V][] {
|
|
806
|
+
const data: [K, V][] = [];
|
|
807
|
+
|
|
808
|
+
this.forEach((value, key) => {
|
|
809
|
+
data.push([key, value]);
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
return data;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
fromJSON(data: [K, V][]): void {
|
|
816
|
+
this.clear();
|
|
817
|
+
|
|
818
|
+
for (const [key, value] of data) {
|
|
819
|
+
this.set(key, value);
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
export class LRUCache<K, V> extends LinkedMap<K, V> {
|
|
825
|
+
private _limit: number;
|
|
826
|
+
private _ratio: number;
|
|
827
|
+
|
|
828
|
+
constructor(limit: number, ratio = 1) {
|
|
829
|
+
super();
|
|
830
|
+
this._limit = limit;
|
|
831
|
+
this._ratio = Math.min(Math.max(0, ratio), 1);
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
get limit(): number {
|
|
835
|
+
return this._limit;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
set limit(limit: number) {
|
|
839
|
+
this._limit = limit;
|
|
840
|
+
this.checkTrim();
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
get ratio(): number {
|
|
844
|
+
return this._ratio;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
set ratio(ratio: number) {
|
|
848
|
+
this._ratio = Math.min(Math.max(0, ratio), 1);
|
|
849
|
+
this.checkTrim();
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
get(key: K): V | undefined {
|
|
853
|
+
return super.get(key, Touch.AsNew);
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
peek(key: K): V | undefined {
|
|
857
|
+
return super.get(key, Touch.None);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
set(key: K, value: V): void {
|
|
861
|
+
super.set(key, value, Touch.AsNew);
|
|
862
|
+
this.checkTrim();
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
private checkTrim() {
|
|
866
|
+
if (this.size > this._limit) {
|
|
867
|
+
this.trimOld(Math.round(this._limit * this._ratio));
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
export class SetMap<K, V> {
|
|
873
|
+
private map = new Map<K, Set<V>>();
|
|
874
|
+
|
|
875
|
+
add(key: K, value: V): void {
|
|
876
|
+
let values = this.map.get(key);
|
|
877
|
+
|
|
878
|
+
if (!values) {
|
|
879
|
+
values = new Set<V>();
|
|
880
|
+
this.map.set(key, values);
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
values.add(value);
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
delete(key: K, value: V): void {
|
|
887
|
+
const values = this.map.get(key);
|
|
888
|
+
|
|
889
|
+
if (!values) {
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
values.delete(value);
|
|
894
|
+
|
|
895
|
+
if (values.size === 0) {
|
|
896
|
+
this.map.delete(key);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
forEach(key: K, fn: (value: V) => void): void {
|
|
901
|
+
const values = this.map.get(key);
|
|
902
|
+
|
|
903
|
+
if (!values) {
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
values.forEach(fn);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
export class CaseInsensitiveMap<K, V> extends Map<K, V> {
|
|
912
|
+
set(key: K, value: V): this {
|
|
913
|
+
if (typeof key === 'string') {
|
|
914
|
+
key = key.toLowerCase() as any as K;
|
|
915
|
+
}
|
|
916
|
+
return super.set(key, value);
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
get(key: K): V | undefined {
|
|
920
|
+
if (typeof key === 'string') {
|
|
921
|
+
key = key.toLowerCase() as any as K;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
return super.get(key);
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
has(key: K): boolean {
|
|
928
|
+
if (typeof key === 'string') {
|
|
929
|
+
key = key.toLowerCase() as any as K;
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
return super.has(key);
|
|
933
|
+
}
|
|
934
|
+
}
|