2025-06-30 18:58:24 +02:00
|
|
|
/*
|
|
|
|
SPDX-FileCopyrightText: © 2025 Hornwitser <code@hornwitser.no>
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
*/
|
2025-03-12 14:44:06 +01:00
|
|
|
/** Returns a tuple consisting of a running index starting from 0, and the item of the iterable */
|
|
|
|
export function* enumerate<T>(iterable: Iterable<T>) {
|
|
|
|
let index = 0;
|
|
|
|
for (const item of iterable) {
|
|
|
|
yield [index++, item] as [number, T];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-06-11 21:05:17 +02:00
|
|
|
/** Filters an iterable based on the passed predicate function */
|
2025-06-14 19:22:53 +02:00
|
|
|
export function filter<T, S extends T>(it: Iterable<T>, predicate: (value: T) => value is S): Generator<S, void, unknown>;
|
|
|
|
export function filter<T>(it: Iterable<T>, predicate: (value: T) => unknown): Generator<T, void, unknown>;
|
|
|
|
export function* filter(it: Iterable<unknown>, predicate: (value: unknown) => unknown): Generator<unknown, void, unknown> {
|
2025-06-11 21:05:17 +02:00
|
|
|
for (const value of it) {
|
|
|
|
if (predicate(value)) {
|
|
|
|
yield value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-15 13:46:13 +01:00
|
|
|
/** Converts a name to an id */
|
|
|
|
export function toId(name: string) {
|
|
|
|
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
|
|
}
|
|
|
|
|
2025-03-12 14:44:06 +01:00
|
|
|
/** Returns adjacent pairs from iterable */
|
|
|
|
export function* pairs<T>(iterable: Iterable<T>) {
|
|
|
|
let first;
|
|
|
|
let second;
|
|
|
|
for (const [index, item] of enumerate(iterable)) {
|
|
|
|
[first, second] = [second, item];
|
|
|
|
if (index >= 1) {
|
|
|
|
yield [first, second] as [T, T];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-06-12 21:45:34 +02:00
|
|
|
/**
|
|
|
|
Returns true if the two arrays passed as input compare equal to each other.
|
|
|
|
@param a Input array
|
|
|
|
@param b Input array
|
|
|
|
@param equals Function to compare individual elements in the array.
|
|
|
|
@returns True if the arrays compare equal
|
|
|
|
*/
|
|
|
|
export function arrayEquals<T>(
|
|
|
|
a: T[],
|
|
|
|
b: T[],
|
|
|
|
equals: (a: T, b: T) => unknown = (a, b) => a === b,
|
|
|
|
) {
|
|
|
|
if (a.length !== b.length) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
for (let i = 0; i < a.length; i++) {
|
|
|
|
if (!equals(a[i], b[i])) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2025-03-12 14:44:06 +01:00
|
|
|
/**
|
|
|
|
Returns true if all sets are equal
|
|
|
|
@param sets set to compare
|
|
|
|
@returns true if all sets are the same size and have the same elements
|
|
|
|
*/
|
|
|
|
export function setEquals<T>(...sets: Set<T>[]) {
|
|
|
|
if (sets.length < 2) {
|
|
|
|
throw TypeError("At least two sets must be passed to setEquals");
|
|
|
|
}
|
|
|
|
const ref = sets[0];
|
|
|
|
const rest = sets.slice(1);
|
|
|
|
if (rest.some(set => set.size !== ref.size)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
for (const set of rest) {
|
|
|
|
for (const el of set) {
|
|
|
|
if (!ref.has(el)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2025-06-14 19:12:31 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
Returns true if the two maps passed as input compare equal to each other.
|
|
|
|
@param a Input map
|
|
|
|
@param b Input map
|
|
|
|
@param equals Function to compare individual values in the map.
|
|
|
|
@returns True if the maps compare equal
|
|
|
|
*/
|
|
|
|
export function mapEquals<K, V>(
|
|
|
|
a: Map<K, V>,
|
|
|
|
b: Map<K, V>,
|
|
|
|
equals: (a: V, b: V) => unknown = (a, b) => a === b,
|
|
|
|
) {
|
|
|
|
if (a.size !== b.size) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
for (const [key, value] of a) {
|
|
|
|
if (!b.has(key) || value !== b.get(key)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|