2022-08-28 21:12:25 +02:00
|
|
|
|
2022-08-29 16:17:55 +02:00
|
|
|
export function assert(test: boolean): asserts test {
|
|
|
|
if (!test) {
|
|
|
|
throw new Error(`Assertion failed. See the stack trace for more information.`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-31 13:29:56 +02:00
|
|
|
export function countDigits(x: number, base: number = 10) {
|
|
|
|
return x === 0 ? 1 : Math.ceil(Math.log(x+1) / Math.log(base))
|
|
|
|
}
|
|
|
|
|
2022-09-06 15:13:07 +02:00
|
|
|
export function isEmpty<T>(iter: Iterable<T> | Iterator<T>): boolean {
|
|
|
|
if ((iter as any)[Symbol.iterator] !== undefined) {
|
|
|
|
iter = (iter as any)[Symbol.iterator]();
|
|
|
|
}
|
|
|
|
return !!(iter as Iterator<T>).next().done;
|
|
|
|
}
|
|
|
|
|
2022-08-29 16:17:55 +02:00
|
|
|
export type JSONValue = null | boolean | number | string | JSONArray | JSONObject
|
|
|
|
export type JSONArray = Array<JSONValue>;
|
|
|
|
export type JSONObject = { [key: string]: JSONValue };
|
2022-08-28 21:12:25 +02:00
|
|
|
|
|
|
|
export class MultiDict<K, V> {
|
|
|
|
|
|
|
|
private mapping = new Map<K, V[]>();
|
|
|
|
|
|
|
|
public constructor(iterable?: Iterable<[K, V]>) {
|
|
|
|
if (iterable) {
|
|
|
|
for (const [key, value] of iterable) {
|
|
|
|
this.add(key, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public get(key: K): Iterable<V> {
|
|
|
|
return this.mapping.get(key) ?? [];
|
|
|
|
}
|
|
|
|
|
|
|
|
public add(key: K, value: V): void {
|
|
|
|
const values = this.mapping.get(key);
|
|
|
|
if (values) {
|
|
|
|
values.push(value);
|
|
|
|
} else {
|
|
|
|
this.mapping.set(key, [ value ])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public *[Symbol.iterator](): Iterator<[K, V]> {
|
|
|
|
for (const [key, values] of this.mapping) {
|
|
|
|
for (const value of values) {
|
|
|
|
yield [key, value];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface Stream<T> {
|
|
|
|
get(): T;
|
|
|
|
peek(offset?: number): T;
|
|
|
|
}
|
|
|
|
|
|
|
|
export abstract class BufferedStream<T> {
|
|
|
|
|
|
|
|
private buffer: Array<T> = [];
|
|
|
|
|
|
|
|
public abstract read(): T;
|
|
|
|
|
|
|
|
public get(): T {
|
|
|
|
if (this.buffer.length > 0) {
|
|
|
|
return this.buffer.shift()!;
|
|
|
|
}
|
|
|
|
return this.read();
|
|
|
|
}
|
|
|
|
|
|
|
|
public peek(offset = 1): T {
|
|
|
|
while (this.buffer.length < offset) {
|
|
|
|
this.buffer.push(this.read());
|
|
|
|
}
|
|
|
|
return this.buffer[offset-1];
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|