Skip to content

Commit 3de188b

Browse files
authored
Merge pull request #16 from codex-semantics-library/dlesbre/equal-compare
Add equal/compare functions
2 parents 5198893 + f28c422 commit 3de188b

File tree

2 files changed

+96
-4
lines changed

2 files changed

+96
-4
lines changed

src/functors.ml

+46-4
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ module MakeCustomHeterogeneousMap
5353
| Leaf{key;value} -> KeyValue(key,value)
5454
| Branch{tree1;_} -> unsigned_max_binding tree1
5555

56-
5756
(* Merge trees whose prefix disagree. *)
5857
let join pa treea pb treeb =
5958
(* Printf.printf "join %d %d\n" pa pb; *)
@@ -64,9 +63,6 @@ module MakeCustomHeterogeneousMap
6463
else
6564
branch ~prefix:p ~branching_bit:m ~tree0:treeb ~tree1:treea
6665

67-
68-
69-
7066
let singleton = leaf
7167

7268
let rec cardinal m =
@@ -400,6 +396,47 @@ module MakeCustomHeterogeneousMap
400396
(* Any other case: there are elements in ta that are unmatched in tb. *)
401397
else false
402398

399+
type 'map polycompare =
400+
{ f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> int; } [@@unboxed]
401+
402+
let compare_aux : type a b m. m polycompare -> a key -> (a,m) value -> b key -> (b,m) value -> int -> int =
403+
fun f ka va kb vb default ->
404+
let cmp = Int.compare (Key.to_int ka) (Key.to_int kb) in
405+
if cmp <> 0 then cmp else
406+
match Key.polyeq ka kb with
407+
| Eq -> let cmp = f.f ka va vb in
408+
if cmp <> 0 then cmp else default
409+
| Diff -> default (* Should not happen since same Key.to_int values should imply equality *)
410+
411+
let rec reflexive_compare f ta tb = match (NODE.view ta),(NODE.view tb) with
412+
| _ when ta == tb -> 0
413+
| Empty, _ -> 1
414+
| _, Empty -> -1
415+
| Branch _, Leaf {key;value} ->
416+
let KeyValue(k,v) = unsigned_min_binding ta in
417+
compare_aux f k v key value 1
418+
| Leaf {key;value}, Branch _ ->
419+
let KeyValue(k,v) = unsigned_min_binding tb in
420+
compare_aux f key value k v (-1)
421+
| Leaf {key;value}, Leaf{key=keyb;value=valueb} ->
422+
compare_aux f key value keyb valueb 0
423+
| Branch{prefix=pa;branching_bit=ma;tree0=ta0;tree1=ta1},
424+
Branch{prefix=pb;branching_bit=mb;tree0=tb0;tree1=tb1} ->
425+
if ma == mb && pa == pb
426+
(* Same prefix: divide the search. *)
427+
then
428+
let cmp = reflexive_compare f ta0 tb0 in
429+
if cmp <> 0 then cmp else
430+
reflexive_compare f ta1 tb1
431+
else if branches_before pb mb pa ma (* ta has to be included in tb0 or tb1. *)
432+
then if (mb :> int) land (pa :> int) == 0
433+
then let cmp = reflexive_compare f ta tb0 in if cmp <> 0 then cmp else -1
434+
else -1 (* ta included in tb1, so there are elements of tb that appear before any elements of ta *)
435+
else if branches_before pa ma pb mb (* tb has to be included in ta0 or ta1. *)
436+
then if (mb :> int) land (pa :> int) == 0
437+
then let cmp = reflexive_compare f ta0 tb in if cmp <> 0 then cmp else 1
438+
else 1 (* tb included in ta1, so there are elements of ta that appear before any elements of tb *)
439+
else Int.compare (pa :> int) (pb :> int)
403440

404441
let rec disjoint ta tb =
405442
if ta == tb then is_empty ta
@@ -1098,6 +1135,8 @@ module MakeCustomHeterogeneousSet
10981135
let of_seq s = add_seq s empty
10991136
let of_list l = of_seq (List.to_seq l)
11001137
let to_list s = List.of_seq (to_seq s)
1138+
1139+
let compare s1 s2 = BaseMap.reflexive_compare {f=fun _ () () -> 0} s1 s2
11011140
end
11021141

11031142
module MakeHeterogeneousMap(Key:HETEROGENEOUS_KEY)(Value:HETEROGENEOUS_VALUE) =
@@ -1225,6 +1264,9 @@ module MakeCustomMap
12251264
let of_seq s = add_seq s empty
12261265
let of_list l = of_seq (List.to_seq l)
12271266
let to_list s = List.of_seq (to_seq s)
1267+
1268+
let reflexive_equal f m1 m2 = reflexive_same_domain_for_all2 (fun _ -> f) m1 m2
1269+
let reflexive_compare f m1 m2 = reflexive_compare {f=fun _ (Snd v1) (Snd v2) -> f v1 v2} m1 m2
12281270
end
12291271

12301272

src/signatures.ml

+50
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,21 @@ module type BASE_MAP = sig
424424
val is_submap : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
425425
]} *)
426426

427+
type 'map polycompare =
428+
{ f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> int; } [@@unboxed]
429+
val reflexive_compare : 'a polycompare -> 'a t -> 'a t -> int
430+
(** [reflexive_compare f m1 m2] is an order relation on maps.
431+
[m1] and [m2] are equal (return [0]) if they have the same domain and for all bindings
432+
[(k,v)] in [m1], [(k,v')] in [m2], we have [f v v' = 0].
433+
434+
[m1] is considered striclty smaller than [m2] (return a negative integer)
435+
when the first difference (lowest key in the {{!unsigned_lt}unsigned order} of {!KEY.to_int})
436+
is either a shared binding [(k,v)] in [m1], [(k,v')] in [m2] with [f v v' < 0],
437+
or a binding that only occurs in [m2].
438+
439+
Assumes that [f v v = 0].
440+
@since 0.11.0 *)
441+
427442
val disjoint : 'a t -> 'a t -> bool
428443
(** [disjoint m1 m2] is [true] iff [m1] and [m2] have disjoint domains *)
429444

@@ -717,6 +732,14 @@ module type HETEROGENEOUS_SET = sig
717732
val equal : t -> t -> bool
718733
(** [equal a b] is [true] if [a] and [b] contain the same elements. *)
719734

735+
val compare : t -> t -> int
736+
(** [compare s1 s2] is an order on setss.
737+
[s1] and [s2] are equal if they contain the same bindings (compare by {!KEY.to_int}).
738+
[s1] is strictly smaller than [s2] if the first difference (in the order of {!KEY.to_int})
739+
is an element that appears in [s2] but not in [s1].
740+
741+
@since 0.11.0 *)
742+
720743
val subset : t -> t -> bool
721744
(** [subset a b] is [true] if all elements of [a] are also in [b]. *)
722745

@@ -895,6 +918,14 @@ module type SET = sig
895918
val equal : t -> t -> bool
896919
(** [equal a b] is [true] if [a] and [b] contain the same elements. *)
897920

921+
val compare : t -> t -> int
922+
(** [compare s1 s2] is an order on setss.
923+
[s1] and [s2] are equal if they contain the same bindings (compare by {!KEY.to_int}).
924+
[s1] is strictly smaller than [s2] if the first difference (in the order of {!KEY.to_int})
925+
is an element that appears in [s2] but not in [s1].
926+
927+
@since 0.11.0 *)
928+
898929
val subset : t -> t -> bool
899930
(** [subset a b] is [true] if all elements of [a] are also in [b]. *)
900931

@@ -1160,6 +1191,25 @@ module type MAP_WITH_VALUE = sig
11601191
Delta is the number of different keys between [map1] and
11611192
[map2]. *)
11621193

1194+
val reflexive_equal: ('a value -> 'a value -> bool) -> 'a t -> 'a t -> bool
1195+
(** [reflexive_equal f m1 m2] is true if both maps are equal, using [f] to compare values.
1196+
[f] is assumed to be reflexive (i.e. [f v v = true]).
1197+
1198+
@since 0.11.0 *)
1199+
1200+
val reflexive_compare: ('a value -> 'a value -> int) -> 'a t -> 'a t -> int
1201+
(** [reflexive_compare f m1 m2] is an order on both maps.
1202+
[m1] and [m2] are equal (return [0]) if they have the same domain and for all bindings
1203+
[(k,v)] in [m1], [(k,v')] in [m2], we have [f v v' = 0].
1204+
1205+
[m1] is considered striclty smaller than [m2] (return a negative integer)
1206+
when the first difference (lowest key in the {{!unsigned_lt}unsigned order} of {!KEY.to_int})
1207+
is either a shared binding [(k,v)] in [m1], [(k,v')] in [m2] with [f v v' < 0],
1208+
or a binding that only occurs in [m2].
1209+
1210+
Assumes that [f v v = 0].
1211+
@since 0.11.0 *)
1212+
11631213
val disjoint : 'a t -> 'a t -> bool
11641214
(** [disjoint a b] is [true] if and only if [a] and [b] have disjoint domains. *)
11651215

0 commit comments

Comments
 (0)