Skip to content

Instantly share code, notes, and snippets.

@EduardoRFS
Last active June 12, 2021 13:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save EduardoRFS/cbf4072acddaaddd11cdcf892330deec to your computer and use it in GitHub Desktop.
Save EduardoRFS/cbf4072acddaaddd11cdcf892330deec to your computer and use it in GitHub Desktop.
/* this miss all the casts in PHP, it's more of a low level implementation
on how you could commit such crime while still being relatively fast */
// TODO: use vectors instead of Array
module Array: {
module Key: {
type t =
| Int(int)
| String(string);
let compare: (t, t) => int;
};
type t('a);
let make: array((Key.t, 'a)) => t('a);
let get: (t('a), Key.t) => option('a);
let set: (t('a), Key.t, 'a) => unit;
} = {
module Key = {
type t =
| Int(int)
| String(string);
let compare = (a, b) =>
switch (a, b) {
| (Int(_), String(_)) => (-1)
| (String(_), Int(_)) => 1
| (Int(a), Int(b)) => Int.compare(a, b)
| (String(a), String(b)) => String.compare(a, b)
};
};
type storage('a) =
| Hashtbl(Hashtbl.t(Key.t, 'a))
| Array(array(option('a)))
| Empty;
type t('a) = {mutable storage: storage('a)};
type property_of_initial =
| Only_int(int)
| String
| No_initial;
let rec property_of_initial = (index, acc, length, arr) =>
if (index < length) {
switch (Array.unsafe_get(arr, index)) {
| (Key.String(_), _) => String
| (Key.Int(n), _) =>
property_of_initial(index + 1, max(acc, n), length, arr)
};
} else {
Only_int(acc);
};
let property_of_initial = arr => {
let length = Array.length(arr);
if (length == 0) {
No_initial;
} else {
property_of_initial(0, 0, length, arr);
};
};
let make = initial => {
let storage =
switch (property_of_initial(initial)) {
| No_initial => Empty
| String =>
let hashtbl = Hashtbl.create(Array.length(initial));
Array.iter(
((key, value)) => Hashtbl.add(hashtbl, key, value),
initial,
);
Hashtbl(hashtbl);
| Only_int(max_int) =>
let array = Array.make(max_int, None);
Array.iter(
((key, value)) =>
switch (key) {
| Key.Int(key) => Array.unsafe_set(array, key, Some(value))
| _ => assert(false)
},
initial,
);
Array(array);
};
{storage: storage};
};
let get = (t, key) =>
switch (t.storage, key) {
| (Hashtbl(hashtbl), key) => Hashtbl.find_opt(hashtbl, key)
| (Array(array), Key.Int(n)) =>
n < Array.length(array) ? Array.unsafe_get(array, n) : None
| (Array(_), String(_)) => None
| (Empty, _) => None
};
let rec set = (t, key, value) =>
switch (t.storage, key) {
| (Hashtbl(hashtbl), key) => Hashtbl.add(hashtbl, key, value)
| (Array(array), Key.Int(n)) =>
let array =
if (n < Array.length(array)) {
array;
} else {
let new_array = Array.make(n, None);
t.storage = Array(new_array);
Array.iteri(Array.unsafe_set(array), array);
new_array;
};
Array.unsafe_set(array, n, Some(value));
| (Empty, Int(n)) =>
let array = Array.make(n, None);
t.storage = Array(array);
Array.unsafe_set(array, n, Some(value));
| (Array(array), String(_)) =>
let hashtbl = Hashtbl.create(Array.length(array));
t.storage = Hashtbl(hashtbl);
set(t, key, value);
| (Empty, String(_)) =>
let hashtbl = Hashtbl.create(1);
t.storage = Hashtbl(hashtbl);
set(t, key, value);
};
};
let array = Array.make;
let arr = array([|(String("a"), "b")|]);
let arr = array([||]);
arr[String("a")] = "b";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment