shrub/pkg/npm/api/lib/BigIntArrayOrderedMap.ts

153 lines
3.4 KiB
TypeScript

import produce, { immerable, castDraft, setAutoFreeze, enablePatches } from 'immer';
import bigInt, { BigInteger } from 'big-integer';
setAutoFreeze(false);
enablePatches();
export function stringToArr(str: string) {
return str.split('/').slice(1).map((ind) => {
return bigInt(ind);
});
}
export function arrToString(arr: BigInteger[]) {
let string = '';
arr.forEach((key) => {
string = string + `/${key.toString()}`;
});
return string;
}
function sorted(a: BigInteger[], b: BigInteger[], reversed = false) {
const getSort = sortBigIntArr(a, b);
if (reversed) {
return getSort * -1;
} else {
return getSort;
}
}
export function sortBigIntArr(a: BigInteger[], b: BigInteger[]) {
const aLen = a.length;
const bLen = b.length;
const aCop = a.slice(0);
const bCop = b.slice(0);
aCop.reverse();
bCop.reverse();
let i = 0;
while (i < aLen && i < bLen) {
if (aCop[i].lt(bCop[i])) {
return 1;
} else if (aCop[i].gt(bCop[i])) {
return -1;
} else {
i++;
}
}
return bLen - aLen;
}
export class BigIntArrayOrderedMap<V> implements Iterable<[BigInteger[], V]> {
root: Record<string, V> = {}
cachedIter: [BigInteger[], V][] | null = null;
[immerable] = true;
reversed = false;
constructor(items: [BigInteger[], V][] = [], reversed = false) {
items.forEach(([key, val]) => {
this.set(key, val);
});
this.reversed = reversed;
}
get size() {
return Object.keys(this.root).length;
}
get(key: BigInteger[]) {
return this.root[arrToString(key)] ?? null;
}
gas(items: [BigInteger[], V][]) {
return produce(this, (draft) => {
items.forEach(([key, value]) => {
draft.root[arrToString(key)] = castDraft(value);
});
draft.generateCachedIter();
},
(patches) => {
// console.log(`gassed with ${JSON.stringify(patches, null, 2)}`);
});
}
set(key: BigInteger[], value: V) {
return produce(this, (draft) => {
draft.root[arrToString(key)] = castDraft(value);
draft.cachedIter = null;
});
}
clear() {
return produce(this, (draft) => {
draft.cachedIter = [];
draft.root = {};
});
}
has(key: BigInteger[]) {
return arrToString(key) in this.root;
}
delete(key: BigInteger[]) {
const result = produce(this, (draft) => {
delete draft.root[arrToString(key)];
draft.cachedIter = null;
});
return result;
}
[Symbol.iterator](): IterableIterator<[BigInteger[], V]> {
let idx = 0;
const result = this.generateCachedIter();
return {
[Symbol.iterator]: this[Symbol.iterator],
next: (): IteratorResult<[BigInteger[], V]> => {
if (idx < result.length) {
return { value: result[idx++], done: false };
}
return { done: true, value: null };
}
};
}
peekLargest() {
const sorted = Array.from(this);
return sorted[0] as [BigInteger[], V] | null;
}
peekSmallest() {
const sorted = Array.from(this);
return sorted[sorted.length - 1] as [BigInteger[], V] | null;
}
keys() {
return Array.from(this).map(([k,v]) => k);
}
generateCachedIter() {
if(this.cachedIter) {
return [...this.cachedIter];
}
const result = Object.keys(this.root).map((key) => {
return [stringToArr(key), this.root[key]] as [BigInteger[], V];
}).sort(([a], [b]) => sorted(a, b, this.reversed));
this.cachedIter = result;
return [...result];
}
}