Skip to content

Commit

Permalink
Implement same interface as Js.Dict
Browse files Browse the repository at this point in the history
  • Loading branch information
davesnx committed Aug 8, 2023
1 parent 849bb23 commit bf99d8d
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 39 deletions.
56 changes: 26 additions & 30 deletions packages/js/js.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2707,61 +2707,57 @@ module type Dictionary = sig
val fromList : (key * 'a) list -> 'a t
val keys : 'a t -> key array
val values : 'a t -> 'a array
val set : 'a t -> key -> 'a -> 'a t
val set : 'a t -> key -> 'a -> unit
val get : 'a t -> key -> 'a option
val unsafeGet : 'a t -> key -> 'a
val map : ('a -> 'b) -> 'a t -> 'b t
val unsafeDeleteKey : 'a t -> key -> 'a t
val unsafeDeleteKey : 'a t -> key -> unit
end

module Dict : Dictionary = struct
(** Provide utilities for JS dictionary object *)

type key = string
type 'a t = (key * 'a) list
type 'a t = (key, 'a) Hashtbl.t

exception NotFound
let empty () : 'a t = Hashtbl.create 10

let empty () : 'a t = []
let entries (dict : 'a t) : (string * 'a) array = dict |> Stdlib.Array.of_list
let entries (dict : 'a t) : (string * 'a) array =
Hashtbl.fold (fun k v acc -> (k, v) :: acc) dict [] |> Stdlib.Array.of_list

let get (dict : 'a t) (k : key) : 'a option =
let rec get' dict k =
match dict with
| [] -> None
| (k', x) :: rest -> if k = k' then Some x else get' rest k
in
get' dict k
try Some (Hashtbl.find dict k) with Not_found -> None

let map (f : 'a -> 'b) (dict : 'a t) =
Stdlib.List.map (fun (k, a) -> (k, f a)) dict
Hashtbl.fold
(fun k v acc ->
Hashtbl.add acc k (f v);
acc)
dict (empty ())

let set (dict : 'a t) (k : key) (x : 'a) : 'a t =
let update (dict : 'a t) (key : key) (value : 'a) =
Stdlib.List.map
(fun (k, v) -> if Stdlib.String.equal k key then (k, value) else (k, v))
dict
in
match get dict k with None -> (k, x) :: dict | Some v -> update dict k v
let set (dict : 'a t) (k : key) (x : 'a) : unit = Hashtbl.replace dict k x

let fromList (lst : (key * 'a) list) : 'a t =
Stdlib.List.fold_left (fun acc (k, v) -> set acc k v) [] lst
|> Stdlib.List.rev
let length = Stdlib.List.length lst in
let dict = Hashtbl.create length in
Stdlib.List.iter (fun (k, v) -> Hashtbl.add dict k v) lst;
dict

let fromArray (arr : (key * 'a) array) : 'a t =
Stdlib.Array.to_list arr |> fromList
let length = Stdlib.Array.length arr in
let dict = Hashtbl.create length in
Stdlib.Array.iter (fun (k, v) -> Hashtbl.add dict k v) arr;
dict

let keys (dict : 'a t) =
Stdlib.List.map (fun (k, _) -> k) dict |> Stdlib.Array.of_list
Hashtbl.fold (fun k _ acc -> k :: acc) dict [] |> Stdlib.Array.of_list

let values (dict : 'a t) =
Stdlib.List.map (fun (_, value) -> value) dict |> Stdlib.Array.of_list

let unsafeGet (dict : 'a t) (k : key) : 'a =
match get dict k with None -> raise NotFound | Some x -> x
Hashtbl.fold (fun _k value acc -> value :: acc) dict []
|> Stdlib.Array.of_list

let unsafeDeleteKey (dict : 'a t) (key : key) =
List.filter (fun (k, _) -> k <> key) dict
let unsafeGet (dict : 'a t) (k : key) : 'a = Hashtbl.find dict k
let unsafeDeleteKey (dict : 'a t) (key : key) = Hashtbl.remove dict key
end

module Global = struct
Expand Down
16 changes: 8 additions & 8 deletions packages/js/test.ml
Original file line number Diff line number Diff line change
Expand Up @@ -407,24 +407,24 @@ let dict_tests =
assert_int (Js.Dict.unsafeGet (obj ()) "foo") 43);
case "set" (fun _ ->
let o = Js.Dict.empty () in
let new_ = Js.Dict.set o "foo" 36 in
assert_option_int (Js.Dict.get new_ "foo") (Some 36));
Js.Dict.set o "foo" 36;
assert_option_int (Js.Dict.get o "foo") (Some 36));
case "keys" (fun _ ->
assert_string_array
(Js.Dict.keys (long_obj ()))
[| "david"; "foo"; "bar" |]);
[| "bar"; "david"; "foo" |]);
case "keys duplicated" (fun _ ->
assert_string_array
(Js.Dict.keys (obj_duplicated ()))
[| "foo"; "bar" |]);
[| "bar"; "bar"; "foo" |]);
case "entries" (fun _ ->
assert_int_dict_entries
(Js.Dict.entries (obj ()))
[| ("foo", 43); ("bar", 86) |]);
[| ("bar", 86); ("foo", 43) |]);
case "values" (fun _ ->
assert_int_array (Js.Dict.values (obj ())) [| 43; 86 |]);
assert_int_array (Js.Dict.values (obj ())) [| 86; 43 |]);
case "values duplicated" (fun _ ->
assert_int_array (Js.Dict.values (obj_duplicated ())) [| 43; 86 |]);
assert_int_array (Js.Dict.values (obj_duplicated ())) [| 86; 1; 43 |]);
case "fromList - []" (fun _ ->
assert_int_dict_entries (Js.Dict.entries (Js.Dict.fromList [])) [||]);
case "fromList" (fun _ ->
Expand All @@ -445,7 +445,7 @@ let dict_tests =
let salePrices = Js.Dict.map discount prices in
assert_int_dict_entries
(Js.Dict.entries salePrices)
[| ("pen", 10); ("book", 50); ("stapler", 70) |]);
[| ("book", 50); ("stapler", 70); ("pen", 10) |]);
] )

let () =
Expand Down
2 changes: 1 addition & 1 deletion server-reason-react.opam
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ depends: [
"melange"
"ppxlib" {>= "0.23.0"}
"reason" {>= "3.8.1"}
"pcre" {>= "7.5.0"}
"pcre" {<= "7.5.0"}
"promise" {>= "1.1.2"}
"lwt" {>= "5.6.0"}
"alcotest" {with-test}
Expand Down

0 comments on commit bf99d8d

Please sign in to comment.