Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/prompts/node/test/fixtures/map.ts
13406 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { URI } from 'vs/base/common/uri';
7
8
export function getOrSet<K, V>(map: Map<K, V>, key: K, value: V): V {
9
let result = map.get(key);
10
if (result === undefined) {
11
result = value;
12
map.set(key, result);
13
}
14
15
return result;
16
}
17
18
export function mapToString<K, V>(map: Map<K, V>): string {
19
const entries: string[] = [];
20
map.forEach((value, key) => {
21
entries.push(`${key} => ${value}`);
22
});
23
24
return `Map(${map.size}) {${entries.join(', ')}}`;
25
}
26
27
export function setToString<K>(set: Set<K>): string {
28
const entries: K[] = [];
29
set.forEach(value => {
30
entries.push(value);
31
});
32
33
return `Set(${set.size}) {${entries.join(', ')}}`;
34
}
35
36
interface ResourceMapKeyFn {
37
(resource: URI): string;
38
}
39
40
class ResourceMapEntry<T> {
41
constructor(readonly uri: URI, readonly value: T) { }
42
}
43
44
export class ResourceMap<T> implements Map<URI, T> {
45
46
private static readonly defaultToKey = (resource: URI) => resource.toString();
47
48
readonly [Symbol.toStringTag] = 'ResourceMap';
49
50
private readonly map: Map<string, ResourceMapEntry<T>>;
51
private readonly toKey: ResourceMapKeyFn;
52
53
/**
54
*
55
* @param toKey Custom uri identity function, e.g use an existing `IExtUri#getComparison`-util
56
*/
57
constructor(toKey?: ResourceMapKeyFn);
58
59
/**
60
*
61
* @param other Another resource which this maps is created from
62
* @param toKey Custom uri identity function, e.g use an existing `IExtUri#getComparison`-util
63
*/
64
constructor(other?: ResourceMap<T>, toKey?: ResourceMapKeyFn);
65
66
constructor(mapOrKeyFn?: ResourceMap<T> | ResourceMapKeyFn, toKey?: ResourceMapKeyFn) {
67
if (mapOrKeyFn instanceof ResourceMap) {
68
this.map = new Map(mapOrKeyFn.map);
69
this.toKey = toKey ?? ResourceMap.defaultToKey;
70
} else {
71
this.map = new Map();
72
this.toKey = mapOrKeyFn ?? ResourceMap.defaultToKey;
73
}
74
}
75
76
set(resource: URI, value: T): this {
77
this.map.set(this.toKey(resource), new ResourceMapEntry(resource, value));
78
return this;
79
}
80
81
get(resource: URI): T | undefined {
82
return this.map.get(this.toKey(resource))?.value;
83
}
84
85
has(resource: URI): boolean {
86
return this.map.has(this.toKey(resource));
87
}
88
89
get size(): number {
90
return this.map.size;
91
}
92
93
clear(): void {
94
this.map.clear();
95
}
96
97
delete(resource: URI): boolean {
98
return this.map.delete(this.toKey(resource));
99
}
100
101
forEach(clb: (value: T, key: URI, map: Map<URI, T>) => void, thisArg?: any): void {
102
if (typeof thisArg !== 'undefined') {
103
clb = clb.bind(thisArg);
104
}
105
for (const [_, entry] of this.map) {
106
clb(entry.value, entry.uri, <any>this);
107
}
108
}
109
110
*values(): IterableIterator<T> {
111
for (const entry of this.map.values()) {
112
yield entry.value;
113
}
114
}
115
116
*keys(): IterableIterator<URI> {
117
for (const entry of this.map.values()) {
118
yield entry.uri;
119
}
120
}
121
122
*entries(): IterableIterator<[URI, T]> {
123
for (const entry of this.map.values()) {
124
yield [entry.uri, entry.value];
125
}
126
}
127
128
*[Symbol.iterator](): IterableIterator<[URI, T]> {
129
for (const [, entry] of this.map) {
130
yield [entry.uri, entry.value];
131
}
132
}
133
}
134
135
export class ResourceSet implements Set<URI> {
136
137
readonly [Symbol.toStringTag]: string = 'ResourceSet';
138
139
private readonly _map: ResourceMap<URI>;
140
141
constructor(toKey?: ResourceMapKeyFn);
142
constructor(entries: readonly URI[], toKey?: ResourceMapKeyFn);
143
constructor(entriesOrKey?: readonly URI[] | ResourceMapKeyFn, toKey?: ResourceMapKeyFn) {
144
if (!entriesOrKey || typeof entriesOrKey === 'function') {
145
this._map = new ResourceMap(entriesOrKey);
146
} else {
147
this._map = new ResourceMap(toKey);
148
entriesOrKey.forEach(this.add, this);
149
}
150
}
151
152
153
get size(): number {
154
return this._map.size;
155
}
156
157
add(value: URI): this {
158
this._map.set(value, value);
159
return this;
160
}
161
162
clear(): void {
163
this._map.clear();
164
}
165
166
delete(value: URI): boolean {
167
return this._map.delete(value);
168
}
169
170
forEach(callbackfn: (value: URI, value2: URI, set: Set<URI>) => void, thisArg?: any): void {
171
this._map.forEach((_value, key) => callbackfn.call(thisArg, key, key, this));
172
}
173
174
has(value: URI): boolean {
175
return this._map.has(value);
176
}
177
178
entries(): IterableIterator<[URI, URI]> {
179
return this._map.entries();
180
}
181
182
keys(): IterableIterator<URI> {
183
return this._map.keys();
184
}
185
186
values(): IterableIterator<URI> {
187
return this._map.keys();
188
}
189
190
[Symbol.iterator](): IterableIterator<URI> {
191
return this.keys();
192
}
193
}
194
195
196
interface Item<K, V> {
197
previous: Item<K, V> | undefined;
198
next: Item<K, V> | undefined;
199
key: K;
200
value: V;
201
}
202
203
export const enum Touch {
204
None = 0,
205
AsOld = 1,
206
AsNew = 2
207
}
208
209
export class LinkedMap<K, V> implements Map<K, V> {
210
211
readonly [Symbol.toStringTag] = 'LinkedMap';
212
213
private _map: Map<K, Item<K, V>>;
214
private _head: Item<K, V> | undefined;
215
private _tail: Item<K, V> | undefined;
216
private _size: number;
217
218
private _state: number;
219
220
constructor() {
221
this._map = new Map<K, Item<K, V>>();
222
this._head = undefined;
223
this._tail = undefined;
224
this._size = 0;
225
this._state = 0;
226
}
227
228
clear(): void {
229
this._map.clear();
230
this._head = undefined;
231
this._tail = undefined;
232
this._size = 0;
233
this._state++;
234
}
235
236
isEmpty(): boolean {
237
return !this._head && !this._tail;
238
}
239
240
get size(): number {
241
return this._size;
242
}
243
244
get first(): V | undefined {
245
return this._head?.value;
246
}
247
248
get last(): V | undefined {
249
return this._tail?.value;
250
}
251
252
has(key: K): boolean {
253
return this._map.has(key);
254
}
255
256
get(key: K, touch: Touch = Touch.None): V | undefined {
257
const item = this._map.get(key);
258
if (!item) {
259
return undefined;
260
}
261
if (touch !== Touch.None) {
262
this.touch(item, touch);
263
}
264
return item.value;
265
}
266
267
set(key: K, value: V, touch: Touch = Touch.None): this {
268
let item = this._map.get(key);
269
if (item) {
270
item.value = value;
271
if (touch !== Touch.None) {
272
this.touch(item, touch);
273
}
274
} else {
275
item = { key, value, next: undefined, previous: undefined };
276
switch (touch) {
277
case Touch.None:
278
this.addItemLast(item);
279
break;
280
case Touch.AsOld:
281
this.addItemFirst(item);
282
break;
283
case Touch.AsNew:
284
this.addItemLast(item);
285
break;
286
default:
287
this.addItemLast(item);
288
break;
289
}
290
this._map.set(key, item);
291
this._size++;
292
}
293
return this;
294
}
295
296
delete(key: K): boolean {
297
return !!this.remove(key);
298
}
299
300
remove(key: K): V | undefined {
301
const item = this._map.get(key);
302
if (!item) {
303
return undefined;
304
}
305
this._map.delete(key);
306
this.removeItem(item);
307
this._size--;
308
return item.value;
309
}
310
311
shift(): V | undefined {
312
if (!this._head && !this._tail) {
313
return undefined;
314
}
315
if (!this._head || !this._tail) {
316
throw new Error('Invalid list');
317
}
318
const item = this._head;
319
this._map.delete(item.key);
320
this.removeItem(item);
321
this._size--;
322
return item.value;
323
}
324
325
forEach(callbackfn: (value: V, key: K, map: LinkedMap<K, V>) => void, thisArg?: any): void {
326
const state = this._state;
327
let current = this._head;
328
while (current) {
329
if (thisArg) {
330
callbackfn.bind(thisArg)(current.value, current.key, this);
331
} else {
332
callbackfn(current.value, current.key, this);
333
}
334
if (this._state !== state) {
335
throw new Error(`LinkedMap got modified during iteration.`);
336
}
337
current = current.next;
338
}
339
}
340
341
keys(): IterableIterator<K> {
342
const map = this;
343
const state = this._state;
344
let current = this._head;
345
const iterator: IterableIterator<K> = {
346
[Symbol.iterator]() {
347
return iterator;
348
},
349
next(): IteratorResult<K> {
350
if (map._state !== state) {
351
throw new Error(`LinkedMap got modified during iteration.`);
352
}
353
if (current) {
354
const result = { value: current.key, done: false };
355
current = current.next;
356
return result;
357
} else {
358
return { value: undefined, done: true };
359
}
360
}
361
};
362
return iterator;
363
}
364
365
values(): IterableIterator<V> {
366
const map = this;
367
const state = this._state;
368
let current = this._head;
369
const iterator: IterableIterator<V> = {
370
[Symbol.iterator]() {
371
return iterator;
372
},
373
next(): IteratorResult<V> {
374
if (map._state !== state) {
375
throw new Error(`LinkedMap got modified during iteration.`);
376
}
377
if (current) {
378
const result = { value: current.value, done: false };
379
current = current.next;
380
return result;
381
} else {
382
return { value: undefined, done: true };
383
}
384
}
385
};
386
return iterator;
387
}
388
389
entries(): IterableIterator<[K, V]> {
390
const map = this;
391
const state = this._state;
392
let current = this._head;
393
const iterator: IterableIterator<[K, V]> = {
394
[Symbol.iterator]() {
395
return iterator;
396
},
397
next(): IteratorResult<[K, V]> {
398
if (map._state !== state) {
399
throw new Error(`LinkedMap got modified during iteration.`);
400
}
401
if (current) {
402
const result: IteratorResult<[K, V]> = { value: [current.key, current.value], done: false };
403
current = current.next;
404
return result;
405
} else {
406
return { value: undefined, done: true };
407
}
408
}
409
};
410
return iterator;
411
}
412
413
[Symbol.iterator](): IterableIterator<[K, V]> {
414
return this.entries();
415
}
416
417
protected trimOld(newSize: number) {
418
if (newSize >= this.size) {
419
return;
420
}
421
if (newSize === 0) {
422
this.clear();
423
return;
424
}
425
let current = this._head;
426
let currentSize = this.size;
427
while (current && currentSize > newSize) {
428
this._map.delete(current.key);
429
current = current.next;
430
currentSize--;
431
}
432
this._head = current;
433
this._size = currentSize;
434
if (current) {
435
current.previous = undefined;
436
}
437
this._state++;
438
}
439
440
private addItemFirst(item: Item<K, V>): void {
441
// First time Insert
442
if (!this._head && !this._tail) {
443
this._tail = item;
444
} else if (!this._head) {
445
throw new Error('Invalid list');
446
} else {
447
item.next = this._head;
448
this._head.previous = item;
449
}
450
this._head = item;
451
this._state++;
452
}
453
454
private addItemLast(item: Item<K, V>): void {
455
// First time Insert
456
if (!this._head && !this._tail) {
457
this._head = item;
458
} else if (!this._tail) {
459
throw new Error('Invalid list');
460
} else {
461
item.previous = this._tail;
462
this._tail.next = item;
463
}
464
this._tail = item;
465
this._state++;
466
}
467
468
private removeItem(item: Item<K, V>): void {
469
if (item === this._head && item === this._tail) {
470
this._head = undefined;
471
this._tail = undefined;
472
}
473
else if (item === this._head) {
474
// This can only happen if size === 1 which is handled
475
// by the case above.
476
if (!item.next) {
477
throw new Error('Invalid list');
478
}
479
item.next.previous = undefined;
480
this._head = item.next;
481
}
482
else if (item === this._tail) {
483
// This can only happen if size === 1 which is handled
484
// by the case above.
485
if (!item.previous) {
486
throw new Error('Invalid list');
487
}
488
item.previous.next = undefined;
489
this._tail = item.previous;
490
}
491
else {
492
const next = item.next;
493
const previous = item.previous;
494
if (!next || !previous) {
495
throw new Error('Invalid list');
496
}
497
next.previous = previous;
498
previous.next = next;
499
}
500
item.next = undefined;
501
item.previous = undefined;
502
this._state++;
503
}
504
505
private touch(item: Item<K, V>, touch: Touch): void {
506
if (!this._head || !this._tail) {
507
throw new Error('Invalid list');
508
}
509
if ((touch !== Touch.AsOld && touch !== Touch.AsNew)) {
510
return;
511
}
512
513
if (touch === Touch.AsOld) {
514
if (item === this._head) {
515
return;
516
}
517
518
const next = item.next;
519
const previous = item.previous;
520
521
// Unlink the item
522
if (item === this._tail) {
523
// previous must be defined since item was not head but is tail
524
// So there are more than on item in the map
525
previous!.next = undefined;
526
this._tail = previous;
527
}
528
else {
529
// Both next and previous are not undefined since item was neither head nor tail.
530
next!.previous = previous;
531
previous!.next = next;
532
}
533
534
// Insert the node at head
535
item.previous = undefined;
536
item.next = this._head;
537
this._head.previous = item;
538
this._head = item;
539
this._state++;
540
} else if (touch === Touch.AsNew) {
541
if (item === this._tail) {
542
return;
543
}
544
545
const next = item.next;
546
const previous = item.previous;
547
548
// Unlink the item.
549
if (item === this._head) {
550
// next must be defined since item was not tail but is head
551
// So there are more than on item in the map
552
next!.previous = undefined;
553
this._head = next;
554
} else {
555
// Both next and previous are not undefined since item was neither head nor tail.
556
next!.previous = previous;
557
previous!.next = next;
558
}
559
item.next = undefined;
560
item.previous = this._tail;
561
this._tail.next = item;
562
this._tail = item;
563
this._state++;
564
}
565
}
566
567
toJSON(): [K, V][] {
568
const data: [K, V][] = [];
569
570
this.forEach((value, key) => {
571
data.push([key, value]);
572
});
573
574
return data;
575
}
576
577
fromJSON(data: [K, V][]): void {
578
this.clear();
579
580
for (const [key, value] of data) {
581
this.set(key, value);
582
}
583
}
584
}
585
586
export class LRUCache<K, V> extends LinkedMap<K, V> {
587
588
private _limit: number;
589
private _ratio: number;
590
591
constructor(limit: number, ratio: number = 1) {
592
super();
593
this._limit = limit;
594
this._ratio = Math.min(Math.max(0, ratio), 1);
595
}
596
597
get limit(): number {
598
return this._limit;
599
}
600
601
set limit(limit: number) {
602
this._limit = limit;
603
this.checkTrim();
604
}
605
606
get ratio(): number {
607
return this._ratio;
608
}
609
610
set ratio(ratio: number) {
611
this._ratio = Math.min(Math.max(0, ratio), 1);
612
this.checkTrim();
613
}
614
615
override get(key: K, touch: Touch = Touch.AsNew): V | undefined {
616
return super.get(key, touch);
617
}
618
619
peek(key: K): V | undefined {
620
return super.get(key, Touch.None);
621
}
622
623
override set(key: K, value: V): this {
624
super.set(key, value, Touch.AsNew);
625
this.checkTrim();
626
return this;
627
}
628
629
private checkTrim() {
630
if (this.size > this._limit) {
631
this.trimOld(Math.round(this._limit * this._ratio));
632
}
633
}
634
}
635
636
export class CounterSet<T> {
637
638
private map = new Map<T, number>();
639
640
add(value: T): CounterSet<T> {
641
this.map.set(value, (this.map.get(value) || 0) + 1);
642
return this;
643
}
644
645
delete(value: T): boolean {
646
let counter = this.map.get(value) || 0;
647
648
if (counter === 0) {
649
return false;
650
}
651
652
counter--;
653
654
if (counter === 0) {
655
this.map.delete(value);
656
} else {
657
this.map.set(value, counter);
658
}
659
660
return true;
661
}
662
663
has(value: T): boolean {
664
return this.map.has(value);
665
}
666
}
667
668
/**
669
* A map that allows access both by keys and values.
670
* **NOTE**: values need to be unique.
671
*/
672
export class BidirectionalMap<K, V> {
673
674
private readonly _m1 = new Map<K, V>();
675
private readonly _m2 = new Map<V, K>();
676
677
constructor(entries?: readonly (readonly [K, V])[]) {
678
if (entries) {
679
for (const [key, value] of entries) {
680
this.set(key, value);
681
}
682
}
683
}
684
685
clear(): void {
686
this._m1.clear();
687
this._m2.clear();
688
}
689
690
set(key: K, value: V): void {
691
this._m1.set(key, value);
692
this._m2.set(value, key);
693
}
694
695
get(key: K): V | undefined {
696
return this._m1.get(key);
697
}
698
699
getKey(value: V): K | undefined {
700
return this._m2.get(value);
701
}
702
703
delete(key: K): boolean {
704
const value = this._m1.get(key);
705
if (value === undefined) {
706
return false;
707
}
708
this._m1.delete(key);
709
this._m2.delete(value);
710
return true;
711
}
712
713
forEach(callbackfn: (value: V, key: K, map: BidirectionalMap<K, V>) => void, thisArg?: any): void {
714
this._m1.forEach((value, key) => {
715
callbackfn.call(thisArg, value, key, this);
716
});
717
}
718
719
keys(): IterableIterator<K> {
720
return this._m1.keys();
721
}
722
723
values(): IterableIterator<V> {
724
return this._m1.values();
725
}
726
}
727
728