Path: blob/main/extensions/copilot/src/extension/prompts/node/test/fixtures/map.ts
13406 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { URI } from 'vs/base/common/uri';67export function getOrSet<K, V>(map: Map<K, V>, key: K, value: V): V {8let result = map.get(key);9if (result === undefined) {10result = value;11map.set(key, result);12}1314return result;15}1617export function mapToString<K, V>(map: Map<K, V>): string {18const entries: string[] = [];19map.forEach((value, key) => {20entries.push(`${key} => ${value}`);21});2223return `Map(${map.size}) {${entries.join(', ')}}`;24}2526export function setToString<K>(set: Set<K>): string {27const entries: K[] = [];28set.forEach(value => {29entries.push(value);30});3132return `Set(${set.size}) {${entries.join(', ')}}`;33}3435interface ResourceMapKeyFn {36(resource: URI): string;37}3839class ResourceMapEntry<T> {40constructor(readonly uri: URI, readonly value: T) { }41}4243export class ResourceMap<T> implements Map<URI, T> {4445private static readonly defaultToKey = (resource: URI) => resource.toString();4647readonly [Symbol.toStringTag] = 'ResourceMap';4849private readonly map: Map<string, ResourceMapEntry<T>>;50private readonly toKey: ResourceMapKeyFn;5152/**53*54* @param toKey Custom uri identity function, e.g use an existing `IExtUri#getComparison`-util55*/56constructor(toKey?: ResourceMapKeyFn);5758/**59*60* @param other Another resource which this maps is created from61* @param toKey Custom uri identity function, e.g use an existing `IExtUri#getComparison`-util62*/63constructor(other?: ResourceMap<T>, toKey?: ResourceMapKeyFn);6465constructor(mapOrKeyFn?: ResourceMap<T> | ResourceMapKeyFn, toKey?: ResourceMapKeyFn) {66if (mapOrKeyFn instanceof ResourceMap) {67this.map = new Map(mapOrKeyFn.map);68this.toKey = toKey ?? ResourceMap.defaultToKey;69} else {70this.map = new Map();71this.toKey = mapOrKeyFn ?? ResourceMap.defaultToKey;72}73}7475set(resource: URI, value: T): this {76this.map.set(this.toKey(resource), new ResourceMapEntry(resource, value));77return this;78}7980get(resource: URI): T | undefined {81return this.map.get(this.toKey(resource))?.value;82}8384has(resource: URI): boolean {85return this.map.has(this.toKey(resource));86}8788get size(): number {89return this.map.size;90}9192clear(): void {93this.map.clear();94}9596delete(resource: URI): boolean {97return this.map.delete(this.toKey(resource));98}99100forEach(clb: (value: T, key: URI, map: Map<URI, T>) => void, thisArg?: any): void {101if (typeof thisArg !== 'undefined') {102clb = clb.bind(thisArg);103}104for (const [_, entry] of this.map) {105clb(entry.value, entry.uri, <any>this);106}107}108109*values(): IterableIterator<T> {110for (const entry of this.map.values()) {111yield entry.value;112}113}114115*keys(): IterableIterator<URI> {116for (const entry of this.map.values()) {117yield entry.uri;118}119}120121*entries(): IterableIterator<[URI, T]> {122for (const entry of this.map.values()) {123yield [entry.uri, entry.value];124}125}126127*[Symbol.iterator](): IterableIterator<[URI, T]> {128for (const [, entry] of this.map) {129yield [entry.uri, entry.value];130}131}132}133134export class ResourceSet implements Set<URI> {135136readonly [Symbol.toStringTag]: string = 'ResourceSet';137138private readonly _map: ResourceMap<URI>;139140constructor(toKey?: ResourceMapKeyFn);141constructor(entries: readonly URI[], toKey?: ResourceMapKeyFn);142constructor(entriesOrKey?: readonly URI[] | ResourceMapKeyFn, toKey?: ResourceMapKeyFn) {143if (!entriesOrKey || typeof entriesOrKey === 'function') {144this._map = new ResourceMap(entriesOrKey);145} else {146this._map = new ResourceMap(toKey);147entriesOrKey.forEach(this.add, this);148}149}150151152get size(): number {153return this._map.size;154}155156add(value: URI): this {157this._map.set(value, value);158return this;159}160161clear(): void {162this._map.clear();163}164165delete(value: URI): boolean {166return this._map.delete(value);167}168169forEach(callbackfn: (value: URI, value2: URI, set: Set<URI>) => void, thisArg?: any): void {170this._map.forEach((_value, key) => callbackfn.call(thisArg, key, key, this));171}172173has(value: URI): boolean {174return this._map.has(value);175}176177entries(): IterableIterator<[URI, URI]> {178return this._map.entries();179}180181keys(): IterableIterator<URI> {182return this._map.keys();183}184185values(): IterableIterator<URI> {186return this._map.keys();187}188189[Symbol.iterator](): IterableIterator<URI> {190return this.keys();191}192}193194195interface Item<K, V> {196previous: Item<K, V> | undefined;197next: Item<K, V> | undefined;198key: K;199value: V;200}201202export const enum Touch {203None = 0,204AsOld = 1,205AsNew = 2206}207208export class LinkedMap<K, V> implements Map<K, V> {209210readonly [Symbol.toStringTag] = 'LinkedMap';211212private _map: Map<K, Item<K, V>>;213private _head: Item<K, V> | undefined;214private _tail: Item<K, V> | undefined;215private _size: number;216217private _state: number;218219constructor() {220this._map = new Map<K, Item<K, V>>();221this._head = undefined;222this._tail = undefined;223this._size = 0;224this._state = 0;225}226227clear(): void {228this._map.clear();229this._head = undefined;230this._tail = undefined;231this._size = 0;232this._state++;233}234235isEmpty(): boolean {236return !this._head && !this._tail;237}238239get size(): number {240return this._size;241}242243get first(): V | undefined {244return this._head?.value;245}246247get last(): V | undefined {248return this._tail?.value;249}250251has(key: K): boolean {252return this._map.has(key);253}254255get(key: K, touch: Touch = Touch.None): V | undefined {256const item = this._map.get(key);257if (!item) {258return undefined;259}260if (touch !== Touch.None) {261this.touch(item, touch);262}263return item.value;264}265266set(key: K, value: V, touch: Touch = Touch.None): this {267let item = this._map.get(key);268if (item) {269item.value = value;270if (touch !== Touch.None) {271this.touch(item, touch);272}273} else {274item = { key, value, next: undefined, previous: undefined };275switch (touch) {276case Touch.None:277this.addItemLast(item);278break;279case Touch.AsOld:280this.addItemFirst(item);281break;282case Touch.AsNew:283this.addItemLast(item);284break;285default:286this.addItemLast(item);287break;288}289this._map.set(key, item);290this._size++;291}292return this;293}294295delete(key: K): boolean {296return !!this.remove(key);297}298299remove(key: K): V | undefined {300const item = this._map.get(key);301if (!item) {302return undefined;303}304this._map.delete(key);305this.removeItem(item);306this._size--;307return item.value;308}309310shift(): V | undefined {311if (!this._head && !this._tail) {312return undefined;313}314if (!this._head || !this._tail) {315throw new Error('Invalid list');316}317const item = this._head;318this._map.delete(item.key);319this.removeItem(item);320this._size--;321return item.value;322}323324forEach(callbackfn: (value: V, key: K, map: LinkedMap<K, V>) => void, thisArg?: any): void {325const state = this._state;326let current = this._head;327while (current) {328if (thisArg) {329callbackfn.bind(thisArg)(current.value, current.key, this);330} else {331callbackfn(current.value, current.key, this);332}333if (this._state !== state) {334throw new Error(`LinkedMap got modified during iteration.`);335}336current = current.next;337}338}339340keys(): IterableIterator<K> {341const map = this;342const state = this._state;343let current = this._head;344const iterator: IterableIterator<K> = {345[Symbol.iterator]() {346return iterator;347},348next(): IteratorResult<K> {349if (map._state !== state) {350throw new Error(`LinkedMap got modified during iteration.`);351}352if (current) {353const result = { value: current.key, done: false };354current = current.next;355return result;356} else {357return { value: undefined, done: true };358}359}360};361return iterator;362}363364values(): IterableIterator<V> {365const map = this;366const state = this._state;367let current = this._head;368const iterator: IterableIterator<V> = {369[Symbol.iterator]() {370return iterator;371},372next(): IteratorResult<V> {373if (map._state !== state) {374throw new Error(`LinkedMap got modified during iteration.`);375}376if (current) {377const result = { value: current.value, done: false };378current = current.next;379return result;380} else {381return { value: undefined, done: true };382}383}384};385return iterator;386}387388entries(): IterableIterator<[K, V]> {389const map = this;390const state = this._state;391let current = this._head;392const iterator: IterableIterator<[K, V]> = {393[Symbol.iterator]() {394return iterator;395},396next(): IteratorResult<[K, V]> {397if (map._state !== state) {398throw new Error(`LinkedMap got modified during iteration.`);399}400if (current) {401const result: IteratorResult<[K, V]> = { value: [current.key, current.value], done: false };402current = current.next;403return result;404} else {405return { value: undefined, done: true };406}407}408};409return iterator;410}411412[Symbol.iterator](): IterableIterator<[K, V]> {413return this.entries();414}415416protected trimOld(newSize: number) {417if (newSize >= this.size) {418return;419}420if (newSize === 0) {421this.clear();422return;423}424let current = this._head;425let currentSize = this.size;426while (current && currentSize > newSize) {427this._map.delete(current.key);428current = current.next;429currentSize--;430}431this._head = current;432this._size = currentSize;433if (current) {434current.previous = undefined;435}436this._state++;437}438439private addItemFirst(item: Item<K, V>): void {440// First time Insert441if (!this._head && !this._tail) {442this._tail = item;443} else if (!this._head) {444throw new Error('Invalid list');445} else {446item.next = this._head;447this._head.previous = item;448}449this._head = item;450this._state++;451}452453private addItemLast(item: Item<K, V>): void {454// First time Insert455if (!this._head && !this._tail) {456this._head = item;457} else if (!this._tail) {458throw new Error('Invalid list');459} else {460item.previous = this._tail;461this._tail.next = item;462}463this._tail = item;464this._state++;465}466467private removeItem(item: Item<K, V>): void {468if (item === this._head && item === this._tail) {469this._head = undefined;470this._tail = undefined;471}472else if (item === this._head) {473// This can only happen if size === 1 which is handled474// by the case above.475if (!item.next) {476throw new Error('Invalid list');477}478item.next.previous = undefined;479this._head = item.next;480}481else if (item === this._tail) {482// This can only happen if size === 1 which is handled483// by the case above.484if (!item.previous) {485throw new Error('Invalid list');486}487item.previous.next = undefined;488this._tail = item.previous;489}490else {491const next = item.next;492const previous = item.previous;493if (!next || !previous) {494throw new Error('Invalid list');495}496next.previous = previous;497previous.next = next;498}499item.next = undefined;500item.previous = undefined;501this._state++;502}503504private touch(item: Item<K, V>, touch: Touch): void {505if (!this._head || !this._tail) {506throw new Error('Invalid list');507}508if ((touch !== Touch.AsOld && touch !== Touch.AsNew)) {509return;510}511512if (touch === Touch.AsOld) {513if (item === this._head) {514return;515}516517const next = item.next;518const previous = item.previous;519520// Unlink the item521if (item === this._tail) {522// previous must be defined since item was not head but is tail523// So there are more than on item in the map524previous!.next = undefined;525this._tail = previous;526}527else {528// Both next and previous are not undefined since item was neither head nor tail.529next!.previous = previous;530previous!.next = next;531}532533// Insert the node at head534item.previous = undefined;535item.next = this._head;536this._head.previous = item;537this._head = item;538this._state++;539} else if (touch === Touch.AsNew) {540if (item === this._tail) {541return;542}543544const next = item.next;545const previous = item.previous;546547// Unlink the item.548if (item === this._head) {549// next must be defined since item was not tail but is head550// So there are more than on item in the map551next!.previous = undefined;552this._head = next;553} else {554// Both next and previous are not undefined since item was neither head nor tail.555next!.previous = previous;556previous!.next = next;557}558item.next = undefined;559item.previous = this._tail;560this._tail.next = item;561this._tail = item;562this._state++;563}564}565566toJSON(): [K, V][] {567const data: [K, V][] = [];568569this.forEach((value, key) => {570data.push([key, value]);571});572573return data;574}575576fromJSON(data: [K, V][]): void {577this.clear();578579for (const [key, value] of data) {580this.set(key, value);581}582}583}584585export class LRUCache<K, V> extends LinkedMap<K, V> {586587private _limit: number;588private _ratio: number;589590constructor(limit: number, ratio: number = 1) {591super();592this._limit = limit;593this._ratio = Math.min(Math.max(0, ratio), 1);594}595596get limit(): number {597return this._limit;598}599600set limit(limit: number) {601this._limit = limit;602this.checkTrim();603}604605get ratio(): number {606return this._ratio;607}608609set ratio(ratio: number) {610this._ratio = Math.min(Math.max(0, ratio), 1);611this.checkTrim();612}613614override get(key: K, touch: Touch = Touch.AsNew): V | undefined {615return super.get(key, touch);616}617618peek(key: K): V | undefined {619return super.get(key, Touch.None);620}621622override set(key: K, value: V): this {623super.set(key, value, Touch.AsNew);624this.checkTrim();625return this;626}627628private checkTrim() {629if (this.size > this._limit) {630this.trimOld(Math.round(this._limit * this._ratio));631}632}633}634635export class CounterSet<T> {636637private map = new Map<T, number>();638639add(value: T): CounterSet<T> {640this.map.set(value, (this.map.get(value) || 0) + 1);641return this;642}643644delete(value: T): boolean {645let counter = this.map.get(value) || 0;646647if (counter === 0) {648return false;649}650651counter--;652653if (counter === 0) {654this.map.delete(value);655} else {656this.map.set(value, counter);657}658659return true;660}661662has(value: T): boolean {663return this.map.has(value);664}665}666667/**668* A map that allows access both by keys and values.669* **NOTE**: values need to be unique.670*/671export class BidirectionalMap<K, V> {672673private readonly _m1 = new Map<K, V>();674private readonly _m2 = new Map<V, K>();675676constructor(entries?: readonly (readonly [K, V])[]) {677if (entries) {678for (const [key, value] of entries) {679this.set(key, value);680}681}682}683684clear(): void {685this._m1.clear();686this._m2.clear();687}688689set(key: K, value: V): void {690this._m1.set(key, value);691this._m2.set(value, key);692}693694get(key: K): V | undefined {695return this._m1.get(key);696}697698getKey(value: V): K | undefined {699return this._m2.get(value);700}701702delete(key: K): boolean {703const value = this._m1.get(key);704if (value === undefined) {705return false;706}707this._m1.delete(key);708this._m2.delete(value);709return true;710}711712forEach(callbackfn: (value: V, key: K, map: BidirectionalMap<K, V>) => void, thisArg?: any): void {713this._m1.forEach((value, key) => {714callbackfn.call(thisArg, value, key, this);715});716}717718keys(): IterableIterator<K> {719return this._m1.keys();720}721722values(): IterableIterator<V> {723return this._m1.values();724}725}726727728