import type { Eq } from "@principia/prelude/Eq"; import type { Ord } from "@principia/prelude/Ord"; import { toNumber } from "@principia/prelude/Ordering"; import { pipe } from "../Function"; import type { Option } from "../Option"; import * as O from "../Option"; interface Next { readonly done?: boolean; readonly value: A; } /** * Get a sorted array of the keys contained in a map * * @since 2.5.0 */ export const keys = (O: Ord) => (m: ReadonlyMap): ReadonlyArray => Array.from(m.keys()).sort((a, b) => toNumber(O.compare_(a, b))); export const lookupWithKey_ = (E: Eq) => (m: ReadonlyMap, k: K): Option => { const entries = m.entries(); let e: Next; while (!(e = entries.next()).done) { const [ka, a] = e.value; if (E.equals_(ka, k)) { return O.some([ka, a]); } } return O.none(); }; export const lookupWithKey = (E: Eq) => { const lookupWithKeyE_ = lookupWithKey_(E); return (k: K) => (m: ReadonlyMap) => lookupWithKeyE_(m, k); }; /** * Calculate the number of key/value pairs in a map */ export const size = (d: Map) => d.size; export const lookup_ = (E: Eq) => { const lookupWithKeyE_ = lookupWithKey_(E); return (m: ReadonlyMap, k: K) => pipe( lookupWithKeyE_(m, k), O.map(([_, a]) => a) ); }; export const lookup = (E: Eq) => { const lookupE_ = lookup_(E); return (k: K) => (m: ReadonlyMap) => lookupE_(m, k); }; export const insertAt_ = (E: Eq) => { const lookupWithKeyE_ = lookupWithKey_(E); return (m: ReadonlyMap, k: K, a: A) => { const found = lookupWithKeyE_(m, k); if (O.isNone(found)) { const r = new Map(m); r.set(k, a); return r; } else if (found.value[1] !== a) { const r = new Map(m); r.set(found.value[0], a); return r; } return m; }; }; export const insertAt = (E: Eq) => { const insertAtE_ = insertAt_(E); return (k: K, a: A) => (m: ReadonlyMap) => insertAtE_(m, k, a); }; export const copy = (me: ReadonlyMap) => { const m = new Map(); me.forEach((v, k) => { m.set(k, v); }); return m; }; export const insert_ = (me: ReadonlyMap, k: K, v: V): ReadonlyMap => { const m = copy(me); m.set(k, v); return m; }; export const insert = (k: K, v: V) => (me: ReadonlyMap) => insert_(me, k, v); export const remove = (k: K) => (me: ReadonlyMap): ReadonlyMap => { const m = copy(me); m.delete(k); return m; }; export const deleteAt_ = (E: Eq) => { const lookupWithKeyE_ = lookupWithKey_(E); return (m: ReadonlyMap, k: K) => { const found = lookupWithKeyE_(m, k); if (O.isSome(found)) { const r = new Map(m); r.delete(found.value[0]); return r; } return m; }; }; export const deleteAt = (E: Eq) => { const deleteAtE_ = deleteAt_(E); return (k: K) => (m: ReadonlyMap) => deleteAtE_(m, k); }; export const updateAt_ = (E: Eq) => { const lookupWithKeyE_ = lookupWithKey_(E); return (m: ReadonlyMap, k: K, a: A): Option> => { const found = lookupWithKeyE_(m, k); if (O.isNone(found)) { return O.none(); } const r = new Map(m); r.set(found.value[0], a); return O.some(r); }; }; export const updateAt = (E: Eq) => { const updateAtE_ = updateAt_(E); return (k: K, a: A) => (m: ReadonlyMap) => updateAtE_(m, k, a); }; export const modifyAt_ = (E: Eq) => { const lookupWithKeyE_ = lookupWithKey_(E); return (m: ReadonlyMap, k: K, f: (a: A) => A): Option> => { const found = lookupWithKeyE_(m, k); if (O.isNone(found)) { return O.none(); } const r = new Map(m); r.set(found.value[0], f(found.value[1])); return O.some(r); }; }; export const modifyAt = (E: Eq) => { const modifyAtE_ = modifyAt_(E); return (k: K, f: (a: A) => A) => (m: ReadonlyMap) => modifyAtE_(m, k, f); }; export const pop_ = (E: Eq) => { const lookupE_ = lookup_(E); const deleteAtE_ = deleteAt_(E); return (m: ReadonlyMap, k: K): Option]> => pipe( lookupE_(m, k), O.map((a) => [a, deleteAtE_(m, k)]) ); }; export const pop = (E: Eq) => { const popE_ = pop_(E); return (k: K) => (m: ReadonlyMap) => popE_(m, k); };