@contember/utilities 2.0.0-alpha.16 → 2.0.0-alpha.17

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.
Files changed (49) hide show
  1. package/dist/development/index.cjs +6 -0
  2. package/dist/development/index.cjs.map +1 -1
  3. package/dist/development/index.js +6 -0
  4. package/dist/development/index.js.map +1 -1
  5. package/dist/development/src/structures/BijectiveIndexedMap.cjs +116 -0
  6. package/dist/development/src/structures/BijectiveIndexedMap.cjs.map +1 -0
  7. package/dist/development/src/structures/BijectiveIndexedMap.js +116 -0
  8. package/dist/development/src/structures/BijectiveIndexedMap.js.map +1 -0
  9. package/dist/development/src/structures/LRUCache.cjs +32 -0
  10. package/dist/development/src/structures/LRUCache.cjs.map +1 -0
  11. package/dist/development/src/structures/LRUCache.js +32 -0
  12. package/dist/development/src/structures/LRUCache.js.map +1 -0
  13. package/dist/development/src/structures/WeakIdCache.cjs +30 -0
  14. package/dist/development/src/structures/WeakIdCache.cjs.map +1 -0
  15. package/dist/development/src/structures/WeakIdCache.js +30 -0
  16. package/dist/development/src/structures/WeakIdCache.js.map +1 -0
  17. package/dist/production/index.cjs +6 -0
  18. package/dist/production/index.cjs.map +1 -1
  19. package/dist/production/index.js +6 -0
  20. package/dist/production/index.js.map +1 -1
  21. package/dist/production/src/structures/BijectiveIndexedMap.cjs +116 -0
  22. package/dist/production/src/structures/BijectiveIndexedMap.cjs.map +1 -0
  23. package/dist/production/src/structures/BijectiveIndexedMap.js +116 -0
  24. package/dist/production/src/structures/BijectiveIndexedMap.js.map +1 -0
  25. package/dist/production/src/structures/LRUCache.cjs +32 -0
  26. package/dist/production/src/structures/LRUCache.cjs.map +1 -0
  27. package/dist/production/src/structures/LRUCache.js +32 -0
  28. package/dist/production/src/structures/LRUCache.js.map +1 -0
  29. package/dist/production/src/structures/WeakIdCache.cjs +30 -0
  30. package/dist/production/src/structures/WeakIdCache.cjs.map +1 -0
  31. package/dist/production/src/structures/WeakIdCache.js +30 -0
  32. package/dist/production/src/structures/WeakIdCache.js.map +1 -0
  33. package/dist/types/index.d.ts +1 -0
  34. package/dist/types/index.d.ts.map +1 -1
  35. package/dist/types/structures/BijectiveIndexedMap.d.ts +24 -0
  36. package/dist/types/structures/BijectiveIndexedMap.d.ts.map +1 -0
  37. package/dist/types/structures/LRUCache.d.ts +9 -0
  38. package/dist/types/structures/LRUCache.d.ts.map +1 -0
  39. package/dist/types/structures/WeakIdCache.d.ts +9 -0
  40. package/dist/types/structures/WeakIdCache.d.ts.map +1 -0
  41. package/dist/types/structures/index.d.ts +4 -0
  42. package/dist/types/structures/index.d.ts.map +1 -0
  43. package/dist/types/tsconfig.tsbuildinfo +1 -1
  44. package/package.json +1 -1
  45. package/src/index.ts +1 -0
  46. package/src/structures/BijectiveIndexedMap.ts +137 -0
  47. package/src/structures/LRUCache.ts +29 -0
  48. package/src/structures/WeakIdCache.ts +25 -0
  49. package/src/structures/index.ts +3 -0
@@ -0,0 +1,137 @@
1
+ // Bijective as in we need to supply the inverse and also guarantee that the values are unique.
2
+ // Provided this invariant, this should behave more or less like a regular map except it has a somewhat special
3
+ // iteration order. Unlike a regular map, which just honors insertion order, this also provides a special method
4
+ // changeKey. With this, we can change the key under which a value (that is already on the map) is accessible.
5
+ // With an ordinary map, that operation would require us to delete the original [K1, V] pair and insert
6
+ // a new one [K2, V]. That would however change the order of iteration. This main purpose of this data structure is
7
+ // the ability to avoid that and enable the value V to preserve its original place.
8
+ export class BijectiveIndexedMap<K, V> implements Map<K, V> {
9
+ private readonly valueStore: Map<number, V>
10
+ private readonly index: Map<K, number>
11
+ private indexSeed: number
12
+
13
+ private readonly inverse: (value: V) => K
14
+
15
+ public readonly [Symbol.toStringTag] = 'BijectiveIndexedMap'
16
+
17
+ public constructor(originalMap: BijectiveIndexedMap<K, V>)
18
+ public constructor(inverse: (value: V) => K)
19
+ public constructor(inverseOrMap: BijectiveIndexedMap<K, V> | ((value: V) => K)) {
20
+ if (inverseOrMap instanceof BijectiveIndexedMap) {
21
+ this.valueStore = new Map(inverseOrMap.valueStore)
22
+ this.index = new Map(inverseOrMap.index)
23
+ this.indexSeed = inverseOrMap.indexSeed
24
+ this.inverse = inverseOrMap.inverse
25
+ } else {
26
+ this.valueStore = new Map()
27
+ this.index = new Map()
28
+ this.indexSeed = 0
29
+ this.inverse = inverseOrMap
30
+ }
31
+ }
32
+
33
+ private getNewIndex() {
34
+ return this.indexSeed++
35
+ }
36
+
37
+ public get size(): number {
38
+ return this.valueStore.size
39
+ }
40
+
41
+ public clear(): void {
42
+ this.valueStore.clear()
43
+ this.index.clear()
44
+ }
45
+ public delete(key: K): boolean {
46
+ const index = this.index.get(key)
47
+
48
+ if (index === undefined) {
49
+ return false
50
+ }
51
+ this.valueStore.delete(index)
52
+ this.index.delete(key)
53
+ return true
54
+ }
55
+ public forEach(callback: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void {
56
+ for (const [key, value] of this.entries()) {
57
+ callback.call(thisArg, value, key, this)
58
+ }
59
+ }
60
+
61
+ public get(key: K): V | undefined {
62
+ const index = this.index.get(key)
63
+
64
+ if (index === undefined) {
65
+ return undefined
66
+ }
67
+ return this.valueStore.get(index)
68
+ }
69
+ public has(key: K): boolean {
70
+ return this.index.has(key)
71
+ }
72
+ public set(key: K, value: V): this {
73
+ const existingIndex = this.index.get(key)
74
+
75
+ if (existingIndex === undefined) {
76
+ const newIndex = this.getNewIndex()
77
+ this.index.set(key, newIndex)
78
+ this.valueStore.set(newIndex, value)
79
+ } else {
80
+ this.valueStore.set(existingIndex, value)
81
+ }
82
+ return this
83
+ }
84
+
85
+ // This doesn't use the inverse in order to avoid confusion.
86
+ // See the description above.
87
+ public changeKey(oldKey: K, newKey: K): this {
88
+ const index = this.index.get(oldKey)
89
+ if (index === undefined) {
90
+ throw new Error()
91
+ }
92
+ this.index.delete(oldKey)
93
+ this.index.set(newKey, index)
94
+ return this
95
+ }
96
+
97
+ public changeKeyOrder(newOrder: Iterable<K>) {
98
+ for (const key of newOrder) {
99
+ const keyIndex = this.index.get(key)
100
+ if (keyIndex === undefined) {
101
+ throw new Error()
102
+ }
103
+ const value = this.valueStore.get(keyIndex)!
104
+
105
+ // This effectively removes value from wherever it was and puts it at the end.
106
+ // Provided newOrder.size is the same as valueStore, by the end of this loop
107
+ // the values will be in the correct order.
108
+ this.valueStore.delete(keyIndex)
109
+ this.valueStore.set(keyIndex, value)
110
+ }
111
+ }
112
+
113
+ public *[Symbol.iterator](): IterableIterator<[K, V]> {
114
+ yield* this.entries()
115
+ }
116
+
117
+ public *entries(): IterableIterator<[K, V]> {
118
+ for (const value of this.values()) {
119
+ yield [this.inverse(value), value]
120
+ }
121
+ }
122
+
123
+ public *keys(): IterableIterator<K> {
124
+ for (const value of this.values()) {
125
+ yield this.inverse(value)
126
+ }
127
+ }
128
+
129
+ public *values(): IterableIterator<V> {
130
+ for (const value of this.valueStore.values()) {
131
+ if (value === undefined) {
132
+ continue
133
+ }
134
+ yield value
135
+ }
136
+ }
137
+ }
@@ -0,0 +1,29 @@
1
+ // This is heavily inspired by https://stackoverflow.com/a/46432113
2
+ export class LRUCache<Key, Value> {
3
+ private readonly cache = new Map<Key, Value>()
4
+
5
+ public constructor(private readonly maxSize: number) {}
6
+
7
+ public get(key: Key): Value | undefined {
8
+ const value = this.cache.get(key)
9
+
10
+ if (value !== undefined) {
11
+ this.cache.delete(key)
12
+ this.cache.set(key, value)
13
+ }
14
+ return value
15
+ }
16
+
17
+ public set(key: Key, value: Value) {
18
+ if (this.cache.has(key)) {
19
+ this.cache.delete(key) // Refresh this key
20
+ } else if (this.cache.size === this.maxSize) {
21
+ this.cache.delete(this.getOldestKey()) // Evict the oldest value
22
+ }
23
+ this.cache.set(key, value)
24
+ }
25
+
26
+ private getOldestKey(): Key {
27
+ return this.cache.keys().next().value
28
+ }
29
+ }
@@ -0,0 +1,25 @@
1
+ export class WeakIdCache<K extends object> {
2
+ private readonly cache = new WeakMap<K, string>()
3
+ private seed = 0
4
+ private readonly rootId = this.seedToId(this.seed++)
5
+
6
+ public getId(key: K): string {
7
+ let existing = this.cache.get(key)
8
+
9
+ if (existing === undefined) {
10
+ this.cache.set(key, (existing = this.seedToId(this.seed++)))
11
+ }
12
+ return existing
13
+ }
14
+
15
+ public getOptionalKeyId(key: K | undefined): string {
16
+ if (key === undefined) {
17
+ return this.rootId
18
+ }
19
+ return this.getId(key)
20
+ }
21
+
22
+ private seedToId(seed: number): string {
23
+ return seed.toFixed(0)
24
+ }
25
+ }
@@ -0,0 +1,3 @@
1
+ export * from './BijectiveIndexedMap'
2
+ export * from './LRUCache'
3
+ export * from './WeakIdCache'