aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew McMillan <matt@matthewmcmillan.me>2021-08-30 00:24:24 -0400
committerLouis Pilfold <louis@lpil.uk>2021-09-01 20:10:33 +0100
commit9f064a8497872b976c9ed089a21b47a3d92295ab (patch)
tree110373b761f41b00e05eb23173952b98248c65c1
parent0dc4a0aed4cbe8b9a2b3a575f112bbd30f0de39d (diff)
downloadgleam_stdlib-9f064a8497872b976c9ed089a21b47a3d92295ab.tar.gz
gleam_stdlib-9f064a8497872b976c9ed089a21b47a3d92295ab.zip
First attempt at map implementation
-rwxr-xr-x[-rw-r--r--]bin/run-tests.js0
-rwxr-xr-x[-rw-r--r--]bin/test.sh0
-rw-r--r--src/gleam/map.gleam707
-rw-r--r--src/gleam_stdlib.js64
-rw-r--r--test/gleam/map_test.gleam280
5 files changed, 622 insertions, 429 deletions
diff --git a/bin/run-tests.js b/bin/run-tests.js
index 3eaba7c..3eaba7c 100644..100755
--- a/bin/run-tests.js
+++ b/bin/run-tests.js
diff --git a/bin/test.sh b/bin/test.sh
index 777c50b..777c50b 100644..100755
--- a/bin/test.sh
+++ b/bin/test.sh
diff --git a/src/gleam/map.gleam b/src/gleam/map.gleam
index 7fd363f..ebb199a 100644
--- a/src/gleam/map.gleam
+++ b/src/gleam/map.gleam
@@ -1,329 +1,460 @@
+import gleam/result
+import gleam/option.{Option}
+import gleam/list
+
+/// A dictionary of keys and values.
+///
+/// Any type can be used for the keys and values of a map, but all the keys
+/// must be of the same type and all the values must be of the same type.
+///
+/// Each key can only be present in a map once.
+///
+/// Maps are not ordered in any way, and any unintentional ordering is not to
+/// be relied upon in your code as it may change in future versions of Erlang
+/// or Gleam.
+///
+/// See [the Erlang map module](https://erlang.org/doc/man/maps.html) for more
+/// information.
+///
+pub external type Map(key, value)
+
+/// Determines the number of key-value pairs in the map.
+/// This function runs in constant time and does not need to iterate the map.
+///
+/// ## Examples
+///
+/// > new() |> size()
+/// 0
+///
+/// > new() |> insert("key", "value") |> size()
+/// 1
+///
+///
+pub fn size(map: Map(k, v)) -> Int {
+ do_size(map)
+}
+
if erlang {
- import gleam/result
- import gleam/option.{Option}
- import gleam/list
-
- /// A dictionary of keys and values.
- ///
- /// Any type can be used for the keys and values of a map, but all the keys
- /// must be of the same type and all the values must be of the same type.
- ///
- /// Each key can only be present in a map once.
- ///
- /// Maps are not ordered in any way, and any unintentional ordering is not to
- /// be relied upon in your code as it may change in future versions of Erlang
- /// or Gleam.
- ///
- /// See [the Erlang map module](https://erlang.org/doc/man/maps.html) for more
- /// information.
- ///
- pub external type Map(key, value)
-
- /// Determines the number of key-value pairs in the map.
- /// This function runs in constant time and does not need to iterate the map.
- ///
- /// ## Examples
- ///
- /// > new() |> size()
- /// 0
- ///
- /// > new() |> insert("key", "value") |> size()
- /// 1
- ///
- ///
- pub external fn size(Map(k, v)) -> Int =
+ external fn do_size(Map(k, v)) -> Int =
"maps" "size"
+}
+
+if javascript {
+ external fn do_size(Map(k, v)) -> Int =
+ "../gleam_stdlib.js" "map_size"
+}
+
+/// Converts the map to a list of 2-element tuples `#(key, value)`, one for
+/// each key-value pair in the map.
+///
+/// The tuples in the list have no specific order.
+///
+/// ## Examples
+///
+/// > new() |> to_list()
+/// []
+///
+/// > new() |> insert("key", 0) |> to_list()
+/// [#("key", 0)]
+///
+pub fn to_list(map: Map(key, value)) -> List(#(key, value)) {
+ do_to_list(map)
+}
- /// Converts the map to a list of 2-element tuples `#(key, value)`, one for
- /// each key-value pair in the map.
- ///
- /// The tuples in the list have no specific order.
- ///
- /// ## Examples
- ///
- /// > new() |> to_list()
- /// []
- ///
- /// > new() |> insert("key", 0) |> to_list()
- /// [#("key", 0)]
- ///
- pub external fn to_list(Map(key, value)) -> List(#(key, value)) =
+if erlang {
+ external fn do_to_list(Map(key, value)) -> List(#(key, value)) =
"maps" "to_list"
+}
+
+if javascript {
+ external fn do_to_list(Map(key, value)) -> List(#(key, value)) =
+ "../gleam_stdlib.js" "map_to_list"
+}
+
+/// Converts a list of 2-element tuples `#(key, value)` to a map.
+///
+/// If two tuples have the same key the last one in the list will be the one
+/// that is present in the map.
+///
+pub fn from_list(list: List(#(key, value))) -> Map(key, value) {
+ do_from_list(list)
+}
- /// Converts a list of 2-element tuples `#(key, value)` to a map.
- ///
- /// If two tuples have the same key the last one in the list will be the one
- /// that is present in the map.
- ///
- pub external fn from_list(List(#(key, value))) -> Map(key, value) =
+if erlang {
+ external fn do_from_list(List(#(key, value))) -> Map(key, value) =
"maps" "from_list"
+}
+
+if javascript {
+ external fn do_from_list(List(#(key, value))) -> Map(key, value) =
+ "../gleam_stdlib.js" "map_to_list"
+}
+
+/// Determines whether or not a value present in the map for a given key.
+///
+/// ## Examples
+///
+/// > new() |> insert("a", 0) |> has_key("a")
+/// True
+///
+/// > new() |> insert("a", 0) |> has_key("b")
+/// False
+///
+pub fn has_key(map: Map(k, v), key: k) -> Bool {
+ do_has_key(key, map)
+}
- external fn is_key(key, Map(key, v)) -> Bool =
+if erlang {
+ external fn do_has_key(key, Map(key, v)) -> Bool =
"maps" "is_key"
+}
- /// Determines whether or not a value present in the map for a given key.
- ///
- /// ## Examples
- ///
- /// > new() |> insert("a", 0) |> has_key("a")
- /// True
- ///
- /// > new() |> insert("a", 0) |> has_key("b")
- /// False
- ///
- pub fn has_key(map: Map(k, v), key: k) -> Bool {
- is_key(key, map)
- }
+if javascript {
+ external fn do_has_key(k, Map(k, v)) -> Bool =
+ "../gleam_stdlib.js" "map_has_key"
+}
+
+/// Creates a fresh map that contains no values.
+///
+pub fn new() -> Map(key, value) {
+ do_new()
+}
- /// Creates a fresh map that contains no values.
- ///
- pub external fn new() -> Map(key, value) =
+if erlang {
+ external fn do_new() -> Map(key, value) =
"maps" "new"
+}
+
+if javascript {
+ external fn do_new() -> Map(key, value) =
+ "../gleam_stdlib.js" "new_map"
+}
+
+/// Fetches a value from a map for a given key.
+///
+/// The map may not have a value for the key, so the value is wrapped in a
+/// Result.
+///
+/// ## Examples
+///
+/// > new() |> insert("a", 0) |> get("a")
+/// Ok(0)
+///
+/// > new() |> insert("a", 0) |> get("b")
+/// Error(Nil)
+///
+pub fn get(from: Map(key, value), get: key) -> Result(value, Nil) {
+ do_get(from, get);
+}
- /// Fetches a value from a map for a given key.
- ///
- /// The map may not have a value for the key, so the value is wrapped in a
- /// Result.
- ///
- /// ## Examples
- ///
- /// > new() |> insert("a", 0) |> get("a")
- /// Ok(0)
- ///
- /// > new() |> insert("a", 0) |> get("b")
- /// Error(Nil)
- ///
- pub external fn get(from: Map(key, value), get: key) -> Result(value, Nil) =
+if erlang {
+ external fn do_get(Map(key, value), key) -> Result(value, Nil) =
"gleam_stdlib" "map_get"
+}
+
+if javascript {
+ external fn do_get(Map(key, value), key) -> Result(value, Nil) =
+ "../gleam_stdlib.js" "map_get"
+}
+
+/// Inserts a value into the map with the given key.
+///
+/// If the map already has a value for the given key then the value is
+/// replaced with the new value.
+///
+/// ## Examples
+///
+/// > new() |> insert("a", 0) |> to_list
+/// [#("a", 0)]
+///
+/// > new() |> insert("a", 0) |> insert("a", 5) |> to_list
+/// [#("a", 5)]
+///
+pub fn insert(into map: Map(k, v), for key: k, insert value: v) -> Map(k, v) {
+ do_insert(key, value, map)
+}
- external fn erl_insert(key, value, Map(key, value)) -> Map(key, value) =
+if erlang {
+ external fn do_insert(key, value, Map(key, value)) -> Map(key, value) =
"maps" "put"
+}
- /// Inserts a value into the map with the given key.
- ///
- /// If the map already has a value for the given key then the value is
- /// replaced with the new value.
- ///
- /// ## Examples
- ///
- /// > new() |> insert("a", 0) |> to_list
- /// [#("a", 0)]
- ///
- /// > new() |> insert("a", 0) |> insert("a", 5) |> to_list
- /// [#("a", 5)]
- ///
- pub fn insert(into map: Map(k, v), for key: k, insert value: v) -> Map(k, v) {
- erl_insert(key, value, map)
- }
+if javascript {
+ external fn do_insert(key, value, Map(key, value)) -> Map(key, value) =
+ "../gleam_stdlib.js" "map_insert"
+}
+
+/// Updates all values in a given map by calling a given function on each key
+/// and value.
+///
+/// ## Examples
+///
+/// > [#(3, 3), #(2, 4)]
+/// > |> from_list
+/// > |> map_values(fn(key, value) { key * value })
+/// [#(3, 9), #(2, 8)]
+///
+///
+pub fn map_values(in map: Map(k, v), with fun: fn(k, v) -> w) -> Map(k, w) {
+ do_map_values(fun, map)
+}
- external fn erl_map_values(fn(key, a) -> b, Map(key, value)) -> Map(key, b) =
+if erlang {
+ external fn do_map_values(fn(key, a) -> b, Map(key, value)) -> Map(key, b) =
"maps" "map"
+}
- /// Updates all values in a given map by calling a given function on each key
- /// and value.
- ///
- /// ## Examples
- ///
- /// > [#(3, 3), #(2, 4)]
- /// > |> from_list
- /// > |> map_values(fn(key, value) { key * value })
- /// [#(3, 9), #(2, 8)]
- ///
- ///
- pub fn map_values(in map: Map(k, v), with fun: fn(k, v) -> w) -> Map(k, w) {
- erl_map_values(fun, map)
- }
+if javascript {
+ external fn do_map_values(fn(key, a) -> b, Map(key, value)) -> Map(key, b) =
+ "../gleam_stdlib.js" "map_map_values"
+}
+
+/// Gets a list of all keys in a given map.
+///
+/// Maps 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
+///
+/// > keys([#("a", 0), #("b", 1)])
+/// ["a", "b"]
+///
+pub fn keys(map: Map(keys, v)) -> List(keys) {
+ do_keys(map)
+}
- /// Gets a list of all keys in a given map.
- ///
- /// Maps 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
- ///
- /// > keys([#("a", 0), #("b", 1)])
- /// ["a", "b"]
- ///
- pub external fn keys(Map(keys, v)) -> List(keys) =
+if erlang {
+ external fn do_keys(Map(keys, v)) -> List(keys) =
"maps" "keys"
+}
+
+if javascript {
+ external fn do_keys(Map(keys, v)) -> List(keys) =
+ "../gleam_stdlib.js" "map_keys"
+}
+
+/// Gets a list of all values in a given map.
+///
+/// Maps 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
+///
+/// > keys(from_list([#("a", 0), #("b", 1)]))
+/// [0, 1]
+///
+pub fn values(map: Map(k, values)) -> List(values) {
+ do_values(map)
+}
- /// Gets a list of all values in a given map.
- ///
- /// Maps 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
- ///
- /// > keys(from_list([#("a", 0), #("b", 1)]))
- /// [0, 1]
- ///
- pub external fn values(Map(k, values)) -> List(values) =
+if erlang {
+ external fn do_values(Map(k, values)) -> List(values) =
"maps" "values"
+}
+
+if javascript {
+ external fn do_values(Map(k, values)) -> List(values) =
+ "../gleam_stdlib.js" "map_values"
+}
+
+/// Creates a new map from a given map, minus any entries that a given function
+/// returns False for.
+///
+/// ## Examples
+///
+/// > from_list([#("a", 0), #("b", 1)])
+/// > |> filter(fn(key, value) { value != 0 })
+/// from_list([#("b", 1)])
+///
+/// > from_list([#("a", 0), #("b", 1)])
+/// > |> filter(fn(key, value) { True })
+/// from_list([#("a", 0), #("b", 1)])
+///
+pub fn filter(in map: Map(k, v), for property: fn(k, v) -> Bool) -> Map(k, v) {
+ do_filter(property, map)
+}
- external fn erl_filter(
+if erlang {
+ external fn do_filter(
fn(key, value) -> Bool,
Map(key, value),
) -> Map(key, value) =
"maps" "filter"
+}
- /// Creates a new map from a given map, minus any entries that a given function
- /// returns False for.
- ///
- /// ## Examples
- ///
- /// > from_list([#("a", 0), #("b", 1)])
- /// > |> filter(fn(key, value) { value != 0 })
- /// from_list([#("b", 1)])
- ///
- /// > from_list([#("a", 0), #("b", 1)])
- /// > |> filter(fn(key, value) { True })
- /// from_list([#("a", 0), #("b", 1)])
- ///
- pub fn filter(in map: Map(k, v), for property: fn(k, v) -> Bool) -> Map(k, v) {
- erl_filter(property, map)
- }
+if javascript {
+ external fn do_filter(
+ fn(key, value) -> Bool,
+ Map(key, value),
+ ) -> Map(key, value) =
+ "../gleam_stdlib.js" "map_filter"
+}
- external fn erl_take(List(k), Map(k, v)) -> Map(k, v) =
- "maps" "with"
-
- /// Creates a new map from a given map, only including any entries for which the
- /// keys are in a given list.
- ///
- /// ## Examples
- ///
- /// > from_list([#("a", 0), #("b", 1)])
- /// > |> take(["b"])
- /// from_list([#("b", 1)])
- ///
- /// > from_list([#("a", 0), #("b", 1)])
- /// > |> take(["a", "b", "c"])
- /// from_list([#("a", 0), #("b", 1)])
- ///
- pub fn take(from map: Map(k, v), keeping desired_keys: List(k)) -> Map(k, v) {
- erl_take(desired_keys, map)
- }
+/// Creates a new map from a given map, only including any entries for which the
+/// keys are in a given list.
+///
+/// ## Examples
+///
+/// > from_list([#("a", 0), #("b", 1)])
+/// > |> take(["b"])
+/// from_list([#("b", 1)])
+///
+/// > from_list([#("a", 0), #("b", 1)])
+/// > |> take(["a", "b", "c"])
+/// from_list([#("a", 0), #("b", 1)])
+///
+pub fn take(from map: Map(k, v), keeping desired_keys: List(k)) -> Map(k, v) {
+ do_take(desired_keys, map)
+}
- /// Creates a new map from a pair of given maps by combining their entries.
- ///
- /// If there are entries with the same keys in both maps the entry from the
- /// second map takes precedence.
- ///
- /// ## Examples
- ///
- /// > let a = from_list([#("a", 0), #("b", 1)])
- /// > let b = from_list([#("b", 2), #("c", 3)])
- /// > merge(a, b)
- /// from_list([#("a", 0), #("b", 2), #("c", 3)])
- ///
- pub external fn merge(into: Map(k, v), merge: Map(k, v)) -> Map(k, v) =
+if erlang {
+ external fn do_take(List(k), Map(k, v)) -> Map(k, v) =
+ "maps" "with"
+}
+
+if javascript {
+ external fn do_take(List(k), Map(k, v)) -> Map(k, v) =
+ "../gleam_stdlib.js" "map_take"
+}
+
+/// Creates a new map from a pair of given maps by combining their entries.
+///
+/// If there are entries with the same keys in both maps the entry from the
+/// second map takes precedence.
+///
+/// ## Examples
+///
+/// > let a = from_list([#("a", 0), #("b", 1)])
+/// > let b = from_list([#("b", 2), #("c", 3)])
+/// > merge(a, b)
+/// from_list([#("a", 0), #("b", 2), #("c", 3)])
+///
+pub fn merge(into: Map(k, v), merge: Map(k, v)) -> Map(k, v) {
+ do_merge(into, merge)
+}
+
+if erlang {
+ external fn do_merge(into: Map(k, v), merge: Map(k, v)) -> Map(k, v) =
"maps" "merge"
+}
- external fn erl_delete(k, Map(k, v)) -> Map(k, v) =
+if javascript {
+ external fn do_merge(into: Map(k, v), merge: Map(k, v)) -> Map(k, v) =
+ "../gleam_stdlib.js" "map_merge"
+}
+
+/// Creates a new map from a given map with all the same entries except for the
+/// one with a given key, if it exists.
+///
+/// ## Examples
+///
+/// > delete([#("a", 0), #("b", 1)], "a")
+/// from_list([#("b", 1)])
+///
+/// > delete([#("a", 0), #("b", 1)], "c")
+/// from_list([#("a", 0), #("b", 1)])
+///
+pub fn delete(from map: Map(k, v), delete key: k) -> Map(k, v) {
+ do_delete(key, map)
+}
+
+if erlang {
+ external fn do_delete(k, Map(k, v)) -> Map(k, v) =
"maps" "remove"
+}
- /// Creates a new map from a given map with all the same entries except for the
- /// one with a given key, if it exists.
- ///
- /// ## Examples
- ///
- /// > delete([#("a", 0), #("b", 1)], "a")
- /// from_list([#("b", 1)])
- ///
- /// > delete([#("a", 0), #("b", 1)], "c")
- /// from_list([#("a", 0), #("b", 1)])
- ///
- pub fn delete(from map: Map(k, v), delete key: k) -> Map(k, v) {
- erl_delete(key, map)
- }
+if javascript {
+ external fn do_delete(k, Map(k, v)) -> Map(k, v) =
+ "../gleam_stdlib.js" "map_remove"
+}
- /// Creates a new map from a given map with all the same entries except any with
- /// keys found in a given list.
- ///
- /// ## Examples
- ///
- /// > drop([#("a", 0), #("b", 1)], ["a"])
- /// from_list([#("b", 2)])
- ///
- /// > delete([#("a", 0), #("b", 1)], ["c"])
- /// from_list([#("a", 0), #("b", 1)])
- ///
- /// > drop([#("a", 0), #("b", 1)], ["a", "b", "c"])
- /// from_list([])
- ///
- pub fn drop(from map: Map(k, v), drop disallowed_keys: List(k)) -> Map(k, v) {
- list.fold(disallowed_keys, map, fn(key, acc) { delete(acc, key) })
- }
+/// Creates a new map from a given map with all the same entries except any with
+/// keys found in a given list.
+///
+/// ## Examples
+///
+/// > drop([#("a", 0), #("b", 1)], ["a"])
+/// from_list([#("b", 2)])
+///
+/// > delete([#("a", 0), #("b", 1)], ["c"])
+/// from_list([#("a", 0), #("b", 1)])
+///
+/// > drop([#("a", 0), #("b", 1)], ["a", "b", "c"])
+/// from_list([])
+///
+pub fn drop(from map: Map(k, v), drop disallowed_keys: List(k)) -> Map(k, v) {
+ list.fold(disallowed_keys, map, fn(key, acc) { delete(acc, key) })
+}
- /// Creates a new map with one entry updated using a given function.
- ///
- /// If there was not an entry in the map for the given key then the function
- /// gets `Error(Nil)` as its argument, otherwise it gets `Ok(value)`.
- ///
- /// ## Example
- ///
- /// > let increment = fn(x) {
- /// > case x {
- /// > Ok(i) -> i + 1
- /// > Error(Nil) -> 0
- /// > }
- /// > }
- /// > let map = from_list([#("a", 0)])
- /// >
- /// > update(map, "a" increment)
- /// from_list([#("a", 1)])
- ///
- /// > update(map, "b" increment)
- /// from_list([#("a", 0), #("b", 0)])
- ///
- pub fn update(
- in map: Map(k, v),
- update key: k,
- with fun: fn(Option(v)) -> v,
- ) -> Map(k, v) {
- map
- |> get(key)
- |> option.from_result
- |> fun
- |> insert(map, key, _)
- }
+/// Creates a new map with one entry updated using a given function.
+///
+/// If there was not an entry in the map for the given key then the function
+/// gets `Error(Nil)` as its argument, otherwise it gets `Ok(value)`.
+///
+/// ## Example
+///
+/// > let increment = fn(x) {
+/// > case x {
+/// > Ok(i) -> i + 1
+/// > Error(Nil) -> 0
+/// > }
+/// > }
+/// > let map = from_list([#("a", 0)])
+/// >
+/// > update(map, "a" increment)
+/// from_list([#("a", 1)])
+///
+/// > update(map, "b" increment)
+/// from_list([#("a", 0), #("b", 0)])
+///
+pub fn update(
+ in map: Map(k, v),
+ update key: k,
+ with fun: fn(Option(v)) -> v,
+) -> Map(k, v) {
+ map
+ |> get(key)
+ |> option.from_result
+ |> fun
+ |> insert(map, key, _)
+}
- fn do_fold(
- list: List(#(k, v)),
- initial: acc,
- fun: fn(k, v, acc) -> acc,
- ) -> acc {
- case list {
- [] -> initial
- [#(k, v), ..tail] -> do_fold(tail, fun(k, v, initial), fun)
- }
+fn do_fold(
+ list: List(#(k, v)),
+ initial: acc,
+ fun: fn(k, v, acc) -> acc,
+) -> acc {
+ case list {
+ [] -> initial
+ [#(k, v), ..tail] -> do_fold(tail, fun(k, v, initial), fun)
}
+}
- /// Combines all entries into a single value by calling a given function on each
- /// one.
- ///
- /// Maps are not ordered so the values are not returned in any specific order. Do
- /// not write code that relies on the order entries are used by this function
- /// as it may change in later versions of Gleam or Erlang.
- ///
- /// # Examples
- ///
- /// > let map = from_list([#("a", 1), #("b", 3), #("c", 9)])
- /// > fold(map, 0, fn(key, value, accumulator) { accumulator + value })
- /// 13
- ///
- /// > import gleam/string.{append}
- /// > fold(map, "", fn(key, value, accumulator) { append(accumulator, value) })
- /// "abc"
- ///
- pub fn fold(
- over map: Map(k, v),
- from initial: acc,
- with fun: fn(k, v, acc) -> acc,
- ) -> acc {
- map
- |> to_list
- |> do_fold(initial, fun)
- }
+/// Combines all entries into a single value by calling a given function on each
+/// one.
+///
+/// Maps are not ordered so the values are not returned in any specific order. Do
+/// not write code that relies on the order entries are used by this function
+/// as it may change in later versions of Gleam or Erlang.
+///
+/// # Examples
+///
+/// > let map = from_list([#("a", 1), #("b", 3), #("c", 9)])
+/// > fold(map, 0, fn(key, value, accumulator) { accumulator + value })
+/// 13
+///
+/// > import gleam/string.{append}
+/// > fold(map, "", fn(key, value, accumulator) { append(accumulator, value) })
+/// "abc"
+///
+pub fn fold(
+ over map: Map(k, v),
+ from initial: acc,
+ with fun: fn(k, v, acc) -> acc,
+) -> acc {
+ map
+ |> to_list
+ |> do_fold(initial, fun)
}
diff --git a/src/gleam_stdlib.js b/src/gleam_stdlib.js
index 652b7b5..0cb2417 100644
--- a/src/gleam_stdlib.js
+++ b/src/gleam_stdlib.js
@@ -258,3 +258,67 @@ export function regex_scan(regex, string) {
});
return List.fromArray(matches);
}
+
+export function new_map() {
+ return new Map();
+}
+
+export function map_size(map) {
+ return map.size;
+}
+
+export function map_to_list(map) {
+ const result = [];
+ map.forEach(([a, b]) => result.push([JSON.parse(a), b]))
+}
+
+export function map_from_list(list) {
+ return new Map(list.map(([a, b]) => [JSON.stringify(a), b]));
+}
+
+export function map_has_key(k, map) {
+ return map.contains(JSON.stringify(k));
+}
+
+export function map_remove(k, map) {
+ new Map(map).remove(JSON.stringify(k));
+}
+
+export function map_filter(f, map) {
+ const result = new Map();
+ map.entries.forEach(([a, b]) => {
+ if (f(JSON.parse(a))) {
+ result.set(a, b);
+ }
+ })
+}
+
+export function map_get(from, get) {
+ from.get(JSON.stringify(get));
+}
+
+export function map_insert(key, value, map) {
+ return new Map(map).set(JSON.stringify(key), value);
+}
+
+export function map_keys(map) {
+ return [...map.keys()].map(key => JSON.parse(key));
+}
+
+export function map_values(map) {
+ return [...map.values()];
+}
+
+export function map_map_values(fn, map) {
+ const result = new Map();
+ map.forEach(([a, b]) => result.set(JSON.stringify(fn(JSON.parse(a))), b));
+}
+
+export function map_merge(into, merge) {
+ return new Map(...into, ...merge);
+}
+
+export function map_take(keys, map) {
+ const result = new Map();
+ keys.forEach(key => result.set(JSON.stringify(key), map.get(JSON.stringify(key))));
+} \ No newline at end of file
diff --git a/test/gleam/map_test.gleam b/test/gleam/map_test.gleam
index d09a00a..6790166 100644
--- a/test/gleam/map_test.gleam
+++ b/test/gleam/map_test.gleam
@@ -1,172 +1,170 @@
-if erlang {
- import gleam/string
- import gleam/should
- import gleam/map
- import gleam/option.{None, Some}
-
- pub fn from_list_test() {
- [#(4, 0), #(1, 0)]
- |> map.from_list
- |> map.size
- |> should.equal(2)
-
- [#(1, 0), #(1, 1)]
- |> map.from_list
- |> should.equal(map.from_list([#(1, 1)]))
- }
+import gleam/string
+import gleam/should
+import gleam/map
+import gleam/option.{None, Some}
+
+pub fn from_list_test() {
+ [#(4, 0), #(1, 0)]
+ |> map.from_list
+ |> map.size
+ |> should.equal(2)
+
+ [#(1, 0), #(1, 1)]
+ |> map.from_list
+ |> should.equal(map.from_list([#(1, 1)]))
+}
- pub fn has_key_test() {
- []
- |> map.from_list
- |> map.has_key(1)
- |> should.be_false
-
- [#(1, 0)]
- |> map.from_list
- |> map.has_key(1)
- |> should.be_true
-
- [#(4, 0), #(1, 0)]
- |> map.from_list
- |> map.has_key(1)
- |> should.be_true
-
- [#(4, 0), #(1, 0)]
- |> map.from_list
- |> map.has_key(0)
- |> should.be_false
- }
+pub fn has_key_test() {
+ []
+ |> map.from_list
+ |> map.has_key(1)
+ |> should.be_false
+
+ [#(1, 0)]
+ |> map.from_list
+ |> map.has_key(1)
+ |> should.be_true
+
+ [#(4, 0), #(1, 0)]
+ |> map.from_list
+ |> map.has_key(1)
+ |> should.be_true
+
+ [#(4, 0), #(1, 0)]
+ |> map.from_list
+ |> map.has_key(0)
+ |> should.be_false
+}
- pub fn new_test() {
- map.new()
- |> map.size
- |> should.equal(0)
+pub fn new_test() {
+ map.new()
+ |> map.size
+ |> should.equal(0)
- map.new()
- |> map.to_list
- |> should.equal([])
- }
+ map.new()
+ |> map.to_list
+ |> should.equal([])
+}
- pub fn get_test() {
- let proplist = [#(4, 0), #(1, 1)]
- let m = map.from_list(proplist)
+pub fn get_test() {
+ let proplist = [#(4, 0), #(1, 1)]
+ let m = map.from_list(proplist)
- m
- |> map.get(4)
- |> should.equal(Ok(0))
+ m
+ |> map.get(4)
+ |> should.equal(Ok(0))
- m
- |> map.get(1)
- |> should.equal(Ok(1))
+ m
+ |> map.get(1)
+ |> should.equal(Ok(1))
- m
- |> map.get(2)
- |> should.equal(Error(Nil))
- }
+ m
+ |> map.get(2)
+ |> should.equal(Error(Nil))
+}
- pub fn insert_test() {
- map.new()
- |> map.insert("a", 0)
- |> map.insert("b", 1)
- |> map.insert("c", 2)
- |> should.equal(map.from_list([#("a", 0), #("b", 1), #("c", 2)]))
- }
+pub fn insert_test() {
+ map.new()
+ |> map.insert("a", 0)
+ |> map.insert("b", 1)
+ |> map.insert("c", 2)
+ |> should.equal(map.from_list([#("a", 0), #("b", 1), #("c", 2)]))
+}
- pub fn map_values_test() {
- [#(1, 0), #(2, 1), #(3, 2)]
- |> map.from_list
- |> map.map_values(fn(k, v) { k + v })
- |> should.equal(map.from_list([#(1, 1), #(2, 3), #(3, 5)]))
- }
+pub fn map_values_test() {
+ [#(1, 0), #(2, 1), #(3, 2)]
+ |> map.from_list
+ |> map.map_values(fn(k, v) { k + v })
+ |> should.equal(map.from_list([#(1, 1), #(2, 3), #(3, 5)]))
+}
- pub fn keys_test() {
- [#("a", 0), #("b", 1), #("c", 2)]
- |> map.from_list
- |> map.keys
- |> should.equal(["a", "b", "c"])
- }
+pub fn keys_test() {
+ [#("a", 0), #("b", 1), #("c", 2)]
+ |> map.from_list
+ |> map.keys
+ |> should.equal(["a", "b", "c"])
+}
- pub fn values_test() {
- [#("a", 0), #("b", 1), #("c", 2)]
- |> map.from_list
- |> map.values
- |> should.equal([0, 1, 2])
- }
+pub fn values_test() {
+ [#("a", 0), #("b", 1), #("c", 2)]
+ |> map.from_list
+ |> map.values
+ |> should.equal([0, 1, 2])
+}
- pub fn take_test() {
- [#("a", 0), #("b", 1), #("c", 2)]
- |> map.from_list
- |> map.take(["a", "b", "d"])
- |> should.equal(map.from_list([#("a", 0), #("b", 1)]))
- }
+pub fn take_test() {
+ [#("a", 0), #("b", 1), #("c", 2)]
+ |> map.from_list
+ |> map.take(["a", "b", "d"])
+ |> should.equal(map.from_list([#("a", 0), #("b", 1)]))
+}
- pub fn drop_test() {
- [#("a", 0), #("b", 1), #("c", 2)]
- |> map.from_list
- |> map.drop(["a", "b", "d"])
- |> should.equal(map.from_list([#("c", 2)]))
- }
+pub fn drop_test() {
+ [#("a", 0), #("b", 1), #("c", 2)]
+ |> map.from_list
+ |> map.drop(["a", "b", "d"])
+ |> should.equal(map.from_list([#("c", 2)]))
+}
- pub fn merge_test() {
- let a = map.from_list([#("a", 2), #("c", 4), #("d", 3)])
+pub fn merge_test() {
+ let a = map.from_list([#("a", 2), #("c", 4), #("d", 3)])
- let b = map.from_list([#("a", 0), #("b", 1), #("c", 2)])
+ let b = map.from_list([#("a", 0), #("b", 1), #("c", 2)])
- map.merge(a, b)
- |> should.equal(map.from_list([#("a", 0), #("b", 1), #("c", 2), #("d", 3)]))
+ map.merge(a, b)
+ |> should.equal(map.from_list([#("a", 0), #("b", 1), #("c", 2), #("d", 3)]))
- map.merge(b, a)
- |> should.equal(map.from_list([#("a", 2), #("b", 1), #("c", 4), #("d", 3)]))
- }
+ map.merge(b, a)
+ |> should.equal(map.from_list([#("a", 2), #("b", 1), #("c", 4), #("d", 3)]))
+}
- pub fn delete_test() {
- [#("a", 0), #("b", 1), #("c", 2)]
- |> map.from_list
- |> map.delete("a")
- |> map.delete("d")
- |> should.equal(map.from_list([#("b", 1), #("c", 2)]))
- }
+pub fn delete_test() {
+ [#("a", 0), #("b", 1), #("c", 2)]
+ |> map.from_list
+ |> map.delete("a")
+ |> map.delete("d")
+ |> should.equal(map.from_list([#("b", 1), #("c", 2)]))
+}
- pub fn update_test() {
- let dict = map.from_list([#("a", 0), #("b", 1), #("c", 2)])
+pub fn update_test() {
+ let dict = map.from_list([#("a", 0), #("b", 1), #("c", 2)])
- let inc_or_zero = fn(x) {
- case x {
- Some(i) -> i + 1
- None -> 0
- }
+ let inc_or_zero = fn(x) {
+ case x {
+ Some(i) -> i + 1
+ None -> 0
}
+ }
- dict
- |> map.update("a", inc_or_zero)
- |> should.equal(map.from_list([#("a", 1), #("b", 1), #("c", 2)]))
+ dict
+ |> map.update("a", inc_or_zero)
+ |> should.equal(map.from_list([#("a", 1), #("b", 1), #("c", 2)]))
- dict
- |> map.update("b", inc_or_zero)
- |> should.equal(map.from_list([#("a", 0), #("b", 2), #("c", 2)]))
+ dict
+ |> map.update("b", inc_or_zero)
+ |> should.equal(map.from_list([#("a", 0), #("b", 2), #("c", 2)]))
- dict
- |> map.update("z", inc_or_zero)
- |> should.equal(map.from_list([#("a", 0), #("b", 1), #("c", 2), #("z", 0)]))
- }
+ dict
+ |> map.update("z", inc_or_zero)
+ |> should.equal(map.from_list([#("a", 0), #("b", 1), #("c", 2), #("z", 0)]))
+}
- pub fn fold_test() {
- let dict = map.from_list([#("a", 0), #("b", 1), #("c", 2), #("d", 3)])
+pub fn fold_test() {
+ let dict = map.from_list([#("a", 0), #("b", 1), #("c", 2), #("d", 3)])
- let add = fn(_, v, acc) { v + acc }
+ let add = fn(_, v, acc) { v + acc }
- dict
- |> map.fold(0, add)
- |> should.equal(6)
+ dict
+ |> map.fold(0, add)
+ |> should.equal(6)
- let concat = fn(k, _, acc) { string.append(acc, k) }
+ let concat = fn(k, _, acc) { string.append(acc, k) }
- dict
- |> map.fold("", concat)
- |> should.equal("abcd")
+ dict
+ |> map.fold("", concat)
+ |> should.equal("abcd")
- map.from_list([])
- |> map.fold(0, add)
- |> should.equal(0)
- }
+ map.from_list([])
+ |> map.fold(0, add)
+ |> should.equal(0)
}