Files
Luma-Parser/ui/javascript/gleam_stdlib/gleam/dict.mjs
T
2026-06-29 15:56:30 +02:00

453 lines
11 KiB
JavaScript

import {
toTransient as to_transient,
fromTransient as from_transient,
size,
fold,
make as new$,
destructiveTransientInsert as transient_insert,
has as has_key,
get,
insert,
map as map_values,
destructiveTransientUpdateWith as transient_update_with,
destructiveTransientDelete as transient_delete,
} from "../dict.mjs";
import { Ok, toList, Empty as $Empty, prepend as listPrepend } from "../gleam.mjs";
import * as $option from "../gleam/option.mjs";
export { fold, get, has_key, insert, map_values, new$, size };
/**
* Determines whether or not the dict is empty.
*
* ## Examples
*
* ```gleam
* assert new() |> is_empty
* ```
*
* ```gleam
* assert !{ new() |> insert("b", 1) |> is_empty }
* ```
*/
export function is_empty(dict) {
return size(dict) === 0;
}
/**
* Converts the dict to a list of 2-element tuples `#(key, value)`, one for
* each key-value pair in the dict.
*
* The tuples in the list have no specific order.
*
* ## Examples
*
* Calling `to_list` on an empty `dict` returns an empty list.
*
* ```gleam
* assert new() |> to_list == []
* ```
*
* The ordering of elements in the resulting list is an implementation detail
* that should not be relied upon.
*
* ```gleam
* assert new()
* |> insert("b", 1)
* |> insert("a", 0)
* |> insert("c", 2)
* |> to_list
* == [#("a", 0), #("b", 1), #("c", 2)]
* ```
*/
export function to_list(dict) {
return fold(
dict,
toList([]),
(acc, key, value) => { return listPrepend([key, value], acc); },
);
}
function from_list_loop(loop$transient, loop$list) {
while (true) {
let transient = loop$transient;
let list = loop$list;
if (list instanceof $Empty) {
return from_transient(transient);
} else {
let rest = list.tail;
let key = list.head[0];
let value = list.head[1];
loop$transient = transient_insert(key, value, transient);
loop$list = rest;
}
}
}
/**
* Converts a list of 2-element tuples `#(key, value)` to a dict.
*
* If two tuples have the same key the last one in the list will be the one
* that is present in the dict.
*/
export function from_list(list) {
return from_list_loop(to_transient(new$()), list);
}
/**
* Gets a list of all keys in a given dict.
*
* Dicts are not ordered so the keys are not returned in any specific order. Do
* not write code that relies on the order keys are returned by this function
* as it may change in later versions of Gleam or Erlang.
*
* ## Examples
*
* ```gleam
* assert from_list([#("a", 0), #("b", 1)]) |> keys == ["a", "b"]
* ```
*/
export function keys(dict) {
return fold(
dict,
toList([]),
(acc, key, _) => { return listPrepend(key, acc); },
);
}
/**
* Gets a list of all values in a given dict.
*
* Dicts are not ordered so the values are not returned in any specific order. Do
* not write code that relies on the order values are returned by this function
* as it may change in later versions of Gleam or Erlang.
*
* ## Examples
*
* ```gleam
* assert from_list([#("a", 0), #("b", 1)]) |> values == [0, 1]
* ```
*/
export function values(dict) {
return fold(
dict,
toList([]),
(acc, _, value) => { return listPrepend(value, acc); },
);
}
function do_filter(f, dict) {
let _pipe = to_transient(new$());
let _pipe$1 = fold(
dict,
_pipe,
(transient, key, value) => {
let $ = f(key, value);
if ($) {
return transient_insert(key, value, transient);
} else {
return transient;
}
},
);
return from_transient(_pipe$1);
}
/**
* Creates a new dict from a given dict, minus any entries that a given function
* returns `False` for.
*
* ## Examples
*
* ```gleam
* assert from_list([#("a", 0), #("b", 1)])
* |> filter(fn(key, value) { value != 0 })
* == from_list([#("b", 1)])
* ```
*
* ```gleam
* assert from_list([#("a", 0), #("b", 1)])
* |> filter(fn(key, value) { True })
* == from_list([#("a", 0), #("b", 1)])
* ```
*/
export function filter(dict, predicate) {
return do_filter(predicate, dict);
}
function do_take_loop(loop$dict, loop$desired_keys, loop$acc) {
while (true) {
let dict = loop$dict;
let desired_keys = loop$desired_keys;
let acc = loop$acc;
if (desired_keys instanceof $Empty) {
return from_transient(acc);
} else {
let key = desired_keys.head;
let rest = desired_keys.tail;
let $ = get(dict, key);
if ($ instanceof Ok) {
let value = $[0];
loop$dict = dict;
loop$desired_keys = rest;
loop$acc = transient_insert(key, value, acc);
} else {
loop$dict = dict;
loop$desired_keys = rest;
loop$acc = acc;
}
}
}
}
function do_take(desired_keys, dict) {
return do_take_loop(dict, desired_keys, to_transient(new$()));
}
/**
* Creates a new dict from a given dict, only including any entries for which the
* keys are in a given list.
*
* ## Examples
*
* ```gleam
* assert from_list([#("a", 0), #("b", 1)])
* |> take(["b"])
* == from_list([#("b", 1)])
* ```
*
* ```gleam
* assert from_list([#("a", 0), #("b", 1)])
* |> take(["a", "b", "c"])
* == from_list([#("a", 0), #("b", 1)])
* ```
*/
export function take(dict, desired_keys) {
return do_take(desired_keys, dict);
}
function do_combine(combine, left, right) {
let _block;
let $1 = size(left) >= size(right);
if ($1) {
_block = [left, right, combine];
} else {
_block = [right, left, (k, l, r) => { return combine(k, r, l); }];
}
let $ = _block;
let big = $[0];
let small = $[1];
let combine$1 = $[2];
let _pipe = to_transient(big);
let _pipe$1 = fold(
small,
_pipe,
(transient, key, value) => {
let update = (existing) => { return combine$1(key, existing, value); };
return transient_update_with(key, update, value, transient);
},
);
return from_transient(_pipe$1);
}
/**
* Creates a new dict from a pair of given dicts by combining their entries.
*
* If there are entries with the same keys in both dicts the given function is
* used to determine the new value to use in the resulting dict.
*
* ## Examples
*
* ```gleam
* let a = from_list([#("a", 0), #("b", 1)])
* let b = from_list([#("a", 2), #("c", 3)])
* assert combine(a, b, fn(one, other) { one + other })
* == from_list([#("a", 2), #("b", 1), #("c", 3)])
* ```
*/
export function combine(dict, other, fun) {
return do_combine((_, l, r) => { return fun(l, r); }, dict, other);
}
/**
* Creates a new dict from a pair of given dicts by combining their entries.
*
* If there are entries with the same keys in both dicts the entry from the
* second dict takes precedence.
*
* ## Examples
*
* ```gleam
* let a = from_list([#("a", 0), #("b", 1)])
* let b = from_list([#("b", 2), #("c", 3)])
* assert merge(a, b) == from_list([#("a", 0), #("b", 2), #("c", 3)])
* ```
*/
export function merge(dict, new_entries) {
return combine(dict, new_entries, (_, new_entry) => { return new_entry; });
}
/**
* Creates a new dict from a given dict with all the same entries except for the
* one with a given key, if it exists.
*
* ## Examples
*
* ```gleam
* assert from_list([#("a", 0), #("b", 1)]) |> delete("a")
* == from_list([#("b", 1)])
* ```
*
* ```gleam
* assert from_list([#("a", 0), #("b", 1)]) |> delete("c")
* == from_list([#("a", 0), #("b", 1)])
* ```
*/
export function delete$(dict, key) {
let _pipe = to_transient(dict);
let _pipe$1 = ((_capture) => { return transient_delete(key, _capture); })(
_pipe,
);
return from_transient(_pipe$1);
}
function drop_loop(loop$transient, loop$disallowed_keys) {
while (true) {
let transient = loop$transient;
let disallowed_keys = loop$disallowed_keys;
if (disallowed_keys instanceof $Empty) {
return from_transient(transient);
} else {
let key = disallowed_keys.head;
let rest = disallowed_keys.tail;
loop$transient = transient_delete(key, transient);
loop$disallowed_keys = rest;
}
}
}
function do_drop(disallowed_keys, dict) {
return drop_loop(to_transient(dict), disallowed_keys);
}
/**
* Creates a new dict from a given dict with all the same entries except any with
* keys found in a given list.
*
* ## Examples
*
* ```gleam
* assert from_list([#("a", 0), #("b", 1)]) |> drop(["a"])
* == from_list([#("b", 1)])
* ```
*
* ```gleam
* assert from_list([#("a", 0), #("b", 1)]) |> drop(["c"])
* == from_list([#("a", 0), #("b", 1)])
* ```
*
* ```gleam
* assert from_list([#("a", 0), #("b", 1)]) |> drop(["a", "b", "c"])
* == from_list([])
* ```
*/
export function drop(dict, disallowed_keys) {
return do_drop(disallowed_keys, dict);
}
/**
* Creates a new dict with one entry inserted or updated using a given function.
*
* If there was not an entry in the dict for the given key then the function
* gets `None` as its argument, otherwise it gets `Some(value)`.
*
* ## Examples
*
* ```gleam
* let dict = from_list([#("a", 0)])
* let increment = fn(x) {
* case x {
* Some(i) -> i + 1
* None -> 0
* }
* }
*
* assert upsert(dict, "a", increment) == from_list([#("a", 1)])
* ```
*
* ```gleam
* assert upsert(dict, "b", increment) == from_list([#("a", 0), #("b", 0)])
* ```
*/
export function upsert(dict, key, fun) {
let $ = get(dict, key);
if ($ instanceof Ok) {
let value = $[0];
return insert(dict, key, fun(new $option.Some(value)));
} else {
return insert(dict, key, fun(new $option.None()));
}
}
/**
* Calls a function for each key and value in a dict, discarding the return
* value.
*
* Useful for producing a side effect for every item of a dict.
*
* ```gleam
* import gleam/io
*
* let dict = from_list([#("a", "apple"), #("b", "banana"), #("c", "cherry")])
*
* assert
* each(dict, fn(k, v) {
* io.println(k <> " => " <> v)
* })
* == Nil
* // a => apple
* // b => banana
* // c => cherry
* ```
*
* The order of elements in the iteration is an implementation detail that
* should not be relied upon.
*/
export function each(dict, fun) {
return fold(
dict,
undefined,
(nil, k, v) => {
fun(k, v);
return nil;
},
);
}
function group_loop(loop$transient, loop$to_key, loop$list) {
while (true) {
let transient = loop$transient;
let to_key = loop$to_key;
let list = loop$list;
if (list instanceof $Empty) {
return from_transient(transient);
} else {
let value = list.head;
let rest = list.tail;
let key = to_key(value);
let update = (existing) => { return listPrepend(value, existing); };
let _pipe = transient;
let _pipe$1 = ((_capture) => {
return transient_update_with(key, update, toList([value]), _capture);
})(_pipe);
loop$transient = _pipe$1;
loop$to_key = to_key;
loop$list = rest;
}
}
}
export function group(key, list) {
return group_loop(to_transient(new$()), key, list);
}