Skip to content

Commit f0ceddc

Browse files
authored
Merge pull request #2657 from cristianoc/polymorphic_compare_objects
Extend polymorphic compare to support objects.
2 parents bce6c06 + 16eb986 commit f0ceddc

File tree

4 files changed

+625
-41
lines changed

4 files changed

+625
-41
lines changed

jscomp/runtime/caml_obj.ml

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,18 @@ let caml_update_dummy x y =
131131

132132
type 'a selector = 'a -> 'a -> 'a
133133

134+
module O = struct
135+
external isArray : 'a -> bool = "Array.isArray" [@@bs.val]
136+
type key = string
137+
let for_in : (Obj.t -> (key -> unit) -> unit) [@bs] = [%bs.raw
138+
{|function (o, foo) {
139+
for (var x in o) { foo(x) }
140+
}
141+
|}]
142+
external hasOwnProperty : key -> bool [@bs.meth] = "" [@@bs.val]
143+
let hasOwnProperty (o: Obj.t) (key: key) : bool = (Obj.magic o)##hasOwnProperty(key)
144+
external get_value : Obj.t -> key -> Obj.t = "%array_unsafe_get"
145+
end
134146

135147
let unsafe_js_compare x y =
136148
if x == y then 0 else
@@ -199,7 +211,9 @@ let rec caml_compare (a : Obj.t) (b : Obj.t) : int =
199211
let len_a = Bs_obj.length a in
200212
let len_b = Bs_obj.length b in
201213
if len_a = len_b then
202-
aux_same_length a b 0 len_a
214+
if O.isArray(a)
215+
then aux_same_length a b 0 len_a
216+
else aux_obj_compare a b
203217
else if len_a < len_b then
204218
aux_length_a_short a b 0 len_a
205219
else
@@ -223,6 +237,27 @@ and aux_length_b_short (a : Obj.t) (b : Obj.t) i short_length =
223237
let res = caml_compare (Obj.field a i) (Obj.field b i) in
224238
if res <> 0 then res
225239
else aux_length_b_short a b (i+1) short_length
240+
and aux_obj_compare (a: Obj.t) (b: Obj.t) =
241+
let min_key_lhs = ref None in
242+
let min_key_rhs = ref None in
243+
let do_key (a, b, min_key) key =
244+
if not (O.hasOwnProperty b key) ||
245+
caml_compare (O.get_value a key) (O.get_value b key) > 0
246+
then
247+
match !min_key with
248+
| None -> min_key := Some key
249+
| Some mk ->
250+
if key < mk then min_key := Some key in
251+
let do_key_a = do_key (a, b, min_key_rhs) in
252+
let do_key_b = do_key (b, a, min_key_lhs) in
253+
O.for_in a do_key_a [@bs];
254+
O.for_in b do_key_b [@bs];
255+
let res = match !min_key_lhs, !min_key_rhs with
256+
| None, None -> 0
257+
| (Some _), None -> -1
258+
| None, (Some _) -> 1
259+
| (Some x), (Some y) -> compare x y in
260+
res
226261

227262
type eq = Obj.t -> Obj.t -> bool
228263

@@ -268,15 +303,28 @@ let rec caml_equal (a : Obj.t) (b : Obj.t) : bool =
268303
let len_a = Bs_obj.length a in
269304
let len_b = Bs_obj.length b in
270305
if len_a = len_b then
271-
aux_equal_length a b 0 len_a
306+
if O.isArray(a)
307+
then aux_equal_length a b 0 len_a
308+
else aux_obj_equal a b
272309
else false
273310
and aux_equal_length (a : Obj.t) (b : Obj.t) i same_length =
274311
if i = same_length then
275312
true
276313
else
277314
caml_equal (Obj.field a i) (Obj.field b i)
278315
&& aux_equal_length a b (i + 1) same_length
279-
316+
and aux_obj_equal (a: Obj.t) (b: Obj.t) =
317+
let result = ref true in
318+
let do_key_a key =
319+
if not (O.hasOwnProperty b key)
320+
then result := false in
321+
let do_key_b key =
322+
if not (O.hasOwnProperty a key) ||
323+
not (caml_equal (O.get_value b key) (O.get_value a key))
324+
then result := false in
325+
O.for_in a do_key_a [@bs];
326+
if !result then O.for_in b do_key_b [@bs];
327+
!result
280328

281329
let caml_equal_null (x : Obj.t) (y : Obj.t Js.null) =
282330
match Js.nullToOption y with

0 commit comments

Comments
 (0)