diff --git a/jscomp/others/bs_Set.ml b/jscomp/others/bs_Set.ml index 649154eb067..9b56a9b6056 100644 --- a/jscomp/others/bs_Set.ml +++ b/jscomp/others/bs_Set.ml @@ -69,13 +69,15 @@ let addArray (type elt) (type id) (m : (elt,id) t) e = let dict, data = B.(dict m, data m) in let module M = (val dict) in let newData = I.addArray0 ~cmp:M.cmp data e in - B.bag ~dict ~data:newData + if newData == data then m + else B.bag ~dict ~data:newData let removeArray (type elt) (type id) (m : (elt,id) t) e = let dict, data = B.(dict m, data m) in let module M = (val dict) in let newData = I.removeArray0 ~cmp:M.cmp data e in - B.bag ~dict ~data:newData + if newData == data then m + else B.bag ~dict ~data:newData let singleton dict e = B.bag ~dict diff --git a/jscomp/others/bs_internalAVLset.ml b/jscomp/others/bs_internalAVLset.ml index 37cdeeb3cb7..6184266b94d 100644 --- a/jscomp/others/bs_internalAVLset.ml +++ b/jscomp/others/bs_internalAVLset.ml @@ -7,11 +7,12 @@ type 'elt node = { } [@@bs.deriving abstract] +module A = Bs_Array external toOpt : 'a Js.null -> 'a option = "#null_to_opt" external return : 'a -> 'a Js.null = "%identity" external empty : 'a Js.null = "#null" - +external unsafeCoerce : 'a Js.null -> 'a = "%identity" type ('elt, 'id) t0 = 'elt node Js.null (* Sets are represented by balanced binary trees (the heights of the children differ by at most 2 *) @@ -52,77 +53,54 @@ let heightGe l r = Assumes l and r balanced and | height l - height r | <= 3. Inline expansion of create for better speed in the most frequent case where no rebalancing is required. *) -(* FIXME: bal should return [node] instead of [_ t0] *) +(* TODO: inline all [create] operation, save duplicated [h] calcuation *) let bal l v r = let hl = match toOpt l with None -> 0 | Some n -> h n in let hr = match toOpt r with None -> 0 | Some n -> h n in if hl > hr + 2 then begin - match toOpt l with - | None -> assert false - | Some n (* Node(ll, lv, lr, _) *) -> - let ll,lv,lr = left n, key n, right n in - if heightGe ll lr then - create ll lv (create lr v r) - else begin - match toOpt lr with - None -> assert false - | Some n (* (lrl, lrv, lrr, _) *) -> - let lrl, lrv, lrr = left n, key n, right n in - create (create ll lv lrl) lrv (create lrr v r) - end + let n = unsafeCoerce l in (* [l] could not be empty *) + let ll,lv,lr = left n, key n, right n in + if heightGe ll lr then + create ll lv (create lr v r) + else begin + let n = unsafeCoerce lr in (* [lr] could not be empty*) + let lrl, lrv, lrr = left n, key n, right n in + create (create ll lv lrl) lrv (create lrr v r) + end end else if hr > hl + 2 then begin - match toOpt r with - None -> assert false - | Some n (* (rl, rv, rr, _) *) -> - let rl,rv,rr = left n, key n, right n in - if heightGe rr rl then - create (create l v rl) rv rr - else begin - match toOpt rl with - None -> assert false - | Some n (* (rll, rlv, rlr, _)*) -> - let rll, rlv, rlr = left n, key n, right n in - create (create l v rll) rlv (create rlr rv rr) - end + let n = unsafeCoerce r in (* [r] could not be empty *) + let rl,rv,rr = left n, key n, right n in + if heightGe rr rl then + create (create l v rl) rv rr + else begin + let n = unsafeCoerce rl in (* [rl] could not be empty *) + let rll, rlv, rlr = left n, key n, right n in + create (create l v rll) rlv (create rlr rv rr) + end end else return @@ node ~left:l ~key:v ~right:r ~h:(if hl >= hr then hl + 1 else hr + 1) let singleton0 x = return @@ node ~left:empty ~key:x ~right:empty ~h:1 -(* Beware: those two functions assume that the added v is *strictly* - smaller (or bigger) than all the present elements in the tree; it - does not test for equality with the current min (or max) element. - Indeed, they are only used during the "join" operation which +(* [addMinElement v n] and [addMaxElement v n] + assume that the added v is *strictly* + smaller (or bigger) than all the present elements in the tree. + They are only used during the "join" operation which respects this precondition. *) -let rec add_min_element v n = +let rec addMinElement v n = match toOpt n with | None -> singleton0 v - | Some n (* (l, x, r, h)*) -> - bal (add_min_element v (left n)) (key n) (right n) + | Some n -> + bal (addMinElement v (left n)) (key n) (right n) -let rec add_max_element v n = +let rec addMaxElement v n = match toOpt n with | None -> singleton0 v - | Some n (* (l, x, r, h)*) -> - bal (left n) (key n) (add_max_element v (right n)) - -(* Same as create and bal, but no assumptions are made on the - relative heights of l and r. *) - -let rec join ln v rn = - match (toOpt ln, toOpt rn) with - (None, _) -> add_min_element v rn (* could be inlined *) - | (_, None) -> add_max_element v ln (* could be inlined *) - | Some l, Some r -> - let lh = h l in - let rh = h r in - if lh > rh + 2 then bal (left l) (key l) (join (right l) v rn) else - if rh > lh + 2 then bal (join ln v (left r)) (key r) (right r) else - create ln v rn + | Some n -> + bal (left n) (key n) (addMaxElement v (right n)) -(* Smallest and greatest element of a set *) let rec min0Aux n = match toOpt (left n) with | None -> key n @@ -143,7 +121,7 @@ let rec max0Aux n = | None -> key n | Some n -> max0Aux n -let maxOpt0 n = +let maxOpt0 n = match toOpt n with | None -> None | Some n -> Some (max0Aux n) @@ -152,34 +130,41 @@ let maxNull0 n = match toOpt n with | None -> Js.null | Some n -> return (max0Aux n) -(* Remove the smallest element of the given set *) -let rec removeMinAux n = +let rec removeMinAuxWithRef n v = let rn, ln = right n, left n in match toOpt ln with - | None -> rn - | Some ln -> bal (removeMinAux ln) (key n) rn + | None -> v:= key n ; rn + | Some ln -> bal (removeMinAuxWithRef ln v) (key n) rn + -(* Merge two trees l and r into one. - All elements of l must precede the elements of r. - Assume | height l - height r | <= 2. *) - -let merge t1 t2 = - match (toOpt t1, toOpt t2) with - (None, _) -> t2 - | (_, None) -> t1 - | (_, Some t2n) -> bal t1 (min0Aux t2n) (removeMinAux t2n) +(* [join ln v rn] return a balanced tree simliar to [create ln v rn] + bal, but no assumptions are made on the + relative heights of [ln] and [rn]. *) -(* Merge two trees l and r into one. - All elements of l must precede the elements of r. +let rec join ln v rn = + match (toOpt ln, toOpt rn) with + (None, _) -> addMinElement v rn + | (_, None) -> addMaxElement v ln + | Some l, Some r -> + let lh = h l in + let rh = h r in + if lh > rh + 2 then bal (left l) (key l) (join (right l) v rn) else + if rh > lh + 2 then bal (join ln v (left r)) (key r) (right r) else + create ln v rn + +(* [concat l r] No assumption on the heights of l and r. *) let concat t1 t2 = match (toOpt t1, toOpt t2) with (None, _) -> t2 | (_, None) -> t1 - | (_, Some t2n) -> join t1 (min0Aux t2n) (removeMinAux t2n) + | (_, Some t2n) -> + let v = ref (key t2n ) in + let t2r = removeMinAuxWithRef t2n v in + join t1 !v t2r (* Implementation of the set operations *) @@ -187,11 +172,11 @@ let empty0 = empty let isEmpty0 n = match toOpt n with Some _ -> false | None -> true -let rec cons_enum s e = +let rec toEnum s e = match toOpt s with None -> e - | Some n (* Node(l, v, r, _) *) - -> cons_enum (left n) (More( key n, right n, e)) + | Some n + -> toEnum (left n) (More( key n, right n, e)) let rec iter0 n f = @@ -200,6 +185,7 @@ let rec iter0 n f = | Some n -> iter0 (left n) f; f (key n) [@bs]; iter0 (right n) f + let rec fold0 s accu f = match toOpt s with | None -> accu @@ -268,17 +254,17 @@ let rec length0 n = | Some n -> cardinalAux n -let rec elements_aux accu n = +let rec toListAux accu n = match toOpt n with | None -> accu | Some n -> let l,k,r = left n, key n, right n in - elements_aux - (k :: elements_aux accu r) + toListAux + (k :: toListAux accu r) l let toList0 s = - elements_aux [] s + toListAux [] s let rec checkInvariant (v : _ t0) = match toOpt v with @@ -288,7 +274,7 @@ let rec checkInvariant (v : _ t0) = let diff = height l - height r in diff <=2 && diff >= -2 && checkInvariant l && checkInvariant r -module A = Bs_Array + let rec fillArray n i arr = let l,v,r = left n, key n, right n in @@ -304,8 +290,7 @@ let rec fillArray n i arr = | Some r -> fillArray r rnext arr -(* TODO: binary search tree to array efficiency -*) + let toArray0 n = match toOpt n with | None -> [||] @@ -317,7 +302,7 @@ let toArray0 n = -external unsafeCoerce : 'a Js.null -> 'a = "%identity" + (* L rotation, return root node @@ -387,14 +372,6 @@ let balMutate nt = nt end -(* let rec removeMinAuxMutate n = - let rn, ln = right n, left n in - match toOpt ln with - | None -> rn - | Some ln -> - leftSet n (removeMinAuxMutate ln); - return (balMutate n) *) - let rec removeMinAuxMutateWithRoot nt n = @@ -434,6 +411,6 @@ let rec ofSortedArrayAux arr off len = create left mid right - + let ofSortedArrayUnsafe0 arr = ofSortedArrayAux arr 0 (A.length arr) \ No newline at end of file diff --git a/jscomp/others/bs_internalSet.ml b/jscomp/others/bs_internalSet.ml index 1eb9e7b3781..2c7c6243827 100644 --- a/jscomp/others/bs_internalSet.ml +++ b/jscomp/others/bs_internalSet.ml @@ -58,7 +58,7 @@ let rec splitAux ~cmp (n : _ N.node) x : _ * bool * _ = let split0 ~cmp (t : _ t0) x : _ t0 * bool * _ t0 = match N.toOpt t with None -> - N.(empty, false, empty) + N.empty, false, N.empty | Some n -> splitAux ~cmp n x @@ -76,7 +76,15 @@ let rec remove0 ~cmp (t : _ t0) x : _ t0 = | Some n -> let l,v,r = N.(left n , key n, right n) in let c = (Bs_Cmp.getCmp cmp) x v [@bs] in - if c = 0 then N.merge l r else + if c = 0 then + match N.toOpt l, N.toOpt r with + | (None, _) -> r + | (_, None) -> l + | (_, Some rn) -> + let v = ref (N.key rn) in + let r = N.removeMinAuxWithRef rn v in + N.bal l !v r + else if c < 0 then let ll = remove0 ~cmp l x in if ll == l then t @@ -150,7 +158,7 @@ let rec diff0 ~cmp s1 s2 = -let rec compare_aux ~cmp e1 e2 = +let rec compareAux ~cmp e1 e2 = match (e1, e2) with (End, End) -> 0 | (End, _) -> -1 @@ -159,21 +167,19 @@ let rec compare_aux ~cmp e1 e2 = let c = (Bs_Cmp.getCmp cmp) v1 v2 [@bs] in if c <> 0 then c - else compare_aux ~cmp (N.cons_enum r1 e1) (N.cons_enum r2 e2) + else compareAux ~cmp (N.toEnum r1 e1) (N.toEnum r2 e2) let cmp0 ~cmp s1 s2 = - compare_aux ~cmp (N.cons_enum s1 End) (N.cons_enum s2 End) + compareAux ~cmp (N.toEnum s1 End) (N.toEnum s2 End) let eq0 ~cmp s1 s2 = cmp0 ~cmp s1 s2 = 0 let rec subset0 ~cmp (s1 : _ t0) (s2 : _ t0) = match N.(toOpt s1, toOpt s2) with - None, _ -> - true - | _, None -> - false - | Some t1 , Some t2 (* Node (l1, v1, r1, _), (Node (l2, v2, r2, _) as t2) *) -> + | None, _ -> true + | _, None -> false + | Some t1 , Some t2 -> let l1,v1,r1 = N.(left t1, key t1, right t1) in let l2,v2,r2 = N.(left t2, key t2, right t2) in let c = (Bs_Cmp.getCmp cmp) v1 v2 [@bs] in diff --git a/jscomp/others/bs_internalSetInt.ml b/jscomp/others/bs_internalSetInt.ml index 7fa8cd3d9e0..83590ab0ec5 100644 --- a/jscomp/others/bs_internalSetInt.ml +++ b/jscomp/others/bs_internalSetInt.ml @@ -78,7 +78,15 @@ let rec remove (t : t) (x : elt) : t = | None -> t | Some n -> let l,v,r = N.(left n, key n, right n) in - if x = v then N.merge l r else + if x = v then + match N.toOpt l, N.toOpt r with + | None, _ -> r + | _, None -> l + | _, Some rn -> + let v = ref (N.key rn) in + let r = N.removeMinAuxWithRef rn v in + N.bal l !v r + else if x < v then let ll = remove l x in if ll == l then t @@ -140,22 +148,22 @@ let rec compare_aux e1 e2 = | (More(v1, r1, e1), More(v2, r2, e2)) -> if (v1 : elt) <> v2 then if v1 < v2 then -1 else 1 - else compare_aux (N.cons_enum r1 e1) (N.cons_enum r2 e2) + else compare_aux (N.toEnum r1 e1) (N.toEnum r2 e2) let cmp s1 s2 = - compare_aux (N.cons_enum s1 End) (N.cons_enum s2 End) + compare_aux (N.toEnum s1 End) (N.toEnum s2 End) -let rec eq_aux e1 e2 = +let rec eqAux (e1 : enumeration) e2 = match (e1, e2) with (End, End) -> true | (End, More _) -> false | (More _, End) -> false | (More(v1, r1, e1), More(v2, r2, e2)) -> - (v1 : elt) = v2 && - eq_aux (N.cons_enum r1 e1) (N.cons_enum r2 e2) + v1 = v2 && + eqAux (N.toEnum r1 e1) (N.toEnum r2 e2) let eq s1 s2 = - eq_aux (N.cons_enum s1 End) (N.cons_enum s2 End) + eqAux (N.toEnum s1 End) (N.toEnum s2 End) (* This algorithm applies to BST, it does not need to be balanced tree *) let rec subset (s1 : t) (s2 : t) = diff --git a/jscomp/others/bs_internalSetString.ml b/jscomp/others/bs_internalSetString.ml index 9531f9a6336..fdbeb84bc6a 100644 --- a/jscomp/others/bs_internalSetString.ml +++ b/jscomp/others/bs_internalSetString.ml @@ -78,7 +78,15 @@ let rec remove (t : t) (x : elt) : t = | None -> t | Some n -> let l,v,r = N.(left n, key n, right n) in - if x = v then N.merge l r else + if x = v then + match N.toOpt l, N.toOpt r with + | None, _ -> r + | _, None -> l + | _, Some rn -> + let v = ref (N.key rn) in + let r = N.removeMinAuxWithRef rn v in + N.bal l !v r + else if x < v then let ll = remove l x in if ll == l then t @@ -140,22 +148,22 @@ let rec compare_aux e1 e2 = | (More(v1, r1, e1), More(v2, r2, e2)) -> if (v1 : elt) <> v2 then if v1 < v2 then -1 else 1 - else compare_aux (N.cons_enum r1 e1) (N.cons_enum r2 e2) + else compare_aux (N.toEnum r1 e1) (N.toEnum r2 e2) let cmp s1 s2 = - compare_aux (N.cons_enum s1 End) (N.cons_enum s2 End) + compare_aux (N.toEnum s1 End) (N.toEnum s2 End) -let rec eq_aux e1 e2 = +let rec eqAux (e1 : enumeration) e2 = match (e1, e2) with (End, End) -> true | (End, More _) -> false | (More _, End) -> false | (More(v1, r1, e1), More(v2, r2, e2)) -> - (v1 : elt) = v2 && - eq_aux (N.cons_enum r1 e1) (N.cons_enum r2 e2) + v1 = v2 && + eqAux (N.toEnum r1 e1) (N.toEnum r2 e2) let eq s1 s2 = - eq_aux (N.cons_enum s1 End) (N.cons_enum s2 End) + eqAux (N.toEnum s1 End) (N.toEnum s2 End) (* This algorithm applies to BST, it does not need to be balanced tree *) let rec subset (s1 : t) (s2 : t) = diff --git a/jscomp/others/internal_set.cppo.ml b/jscomp/others/internal_set.cppo.ml index 65591c2f8ad..bae26354a35 100644 --- a/jscomp/others/internal_set.cppo.ml +++ b/jscomp/others/internal_set.cppo.ml @@ -82,7 +82,15 @@ let rec remove (t : t) (x : elt) : t = | None -> t | Some n -> let l,v,r = N.(left n, key n, right n) in - if x = v then N.merge l r else + if x = v then + match N.toOpt l, N.toOpt r with + | None, _ -> r + | _, None -> l + | _, Some rn -> + let v = ref (N.key rn) in + let r = N.removeMinAuxWithRef rn v in + N.bal l !v r + else if x < v then let ll = remove l x in if ll == l then t @@ -144,22 +152,22 @@ let rec compare_aux e1 e2 = | (More(v1, r1, e1), More(v2, r2, e2)) -> if (v1 : elt) <> v2 then if v1 < v2 then -1 else 1 - else compare_aux (N.cons_enum r1 e1) (N.cons_enum r2 e2) + else compare_aux (N.toEnum r1 e1) (N.toEnum r2 e2) let cmp s1 s2 = - compare_aux (N.cons_enum s1 End) (N.cons_enum s2 End) + compare_aux (N.toEnum s1 End) (N.toEnum s2 End) -let rec eq_aux e1 e2 = +let rec eqAux (e1 : enumeration) e2 = match (e1, e2) with (End, End) -> true | (End, More _) -> false | (More _, End) -> false | (More(v1, r1, e1), More(v2, r2, e2)) -> - (v1 : elt) = v2 && - eq_aux (N.cons_enum r1 e1) (N.cons_enum r2 e2) + v1 = v2 && + eqAux (N.toEnum r1 e1) (N.toEnum r2 e2) let eq s1 s2 = - eq_aux (N.cons_enum s1 End) (N.cons_enum s2 End) + eqAux (N.toEnum s1 End) (N.toEnum s2 End) (* This algorithm applies to BST, it does not need to be balanced tree *) let rec subset (s1 : t) (s2 : t) = diff --git a/jscomp/test/.depend b/jscomp/test/.depend index 0564e3e2f85..56dcd43fd78 100644 --- a/jscomp/test/.depend +++ b/jscomp/test/.depend @@ -105,6 +105,8 @@ bs_mutable_set_test.cmj : mt.cmj ../runtime/js.cmj ../others/bs.cmj \ bs_node_string_buffer_test.cmj : ../others/node.cmj ../runtime/js.cmj bs_poly_mutable_set_test.cmj : mt.cmj ../runtime/js.cmj ../others/bs.cmj \ array_data_util.cmj +bs_poly_set_test.cmj : mt.cmj ../runtime/js.cmj ../others/bs.cmj \ + array_data_util.cmj bs_qualified.cmj : ../runtime/js.cmj bs_queue_test.cmj : ../runtime/js.cmj ../others/bs.cmj bs_rbset_int_bench.cmj : rbset.cmj diff --git a/jscomp/test/Makefile b/jscomp/test/Makefile index a8e31815697..e3d28dbf468 100644 --- a/jscomp/test/Makefile +++ b/jscomp/test/Makefile @@ -232,6 +232,7 @@ OTHERS := test_literals a test_ari test_export2 test_internalOO test_obj_simple_ bs_sort_test\ equal_box_test\ bs_poly_mutable_set_test\ + bs_poly_set_test\ # bs_uncurry_test # needs Lam to get rid of Uncurry arity first # simple_derive_test diff --git a/jscomp/test/bs_poly_set_test.js b/jscomp/test/bs_poly_set_test.js new file mode 100644 index 00000000000..3cc607fa395 --- /dev/null +++ b/jscomp/test/bs_poly_set_test.js @@ -0,0 +1,176 @@ +'use strict'; + +var Mt = require("./mt.js"); +var Bs_Set = require("../../lib/js/bs_Set.js"); +var Caml_obj = require("../../lib/js/caml_obj.js"); +var Caml_primitive = require("../../lib/js/caml_primitive.js"); +var Array_data_util = require("./array_data_util.js"); +var Bs_internalAVLset = require("../../lib/js/bs_internalAVLset.js"); + +var suites = [/* [] */0]; + +var test_id = [0]; + +function eq(loc, x, y) { + return Mt.eq_suites(test_id, suites, loc, x, y); +} + +function b(loc, x) { + return Mt.bool_suites(test_id, suites, loc, x); +} + +var IntCmp = /* module */[/* cmp */Caml_primitive.caml_int_compare]; + +var u0 = Bs_Set.ofArray(IntCmp, Array_data_util.range(0, 30)); + +var u1 = Bs_Set.remove(u0, 0); + +var u2 = Bs_Set.remove(u1, 0); + +var u3 = Bs_Set.remove(u2, 30); + +var u4 = Bs_Set.remove(u3, 20); + +var r = Array_data_util.randomRange(0, 30); + +var u5 = Bs_Set.add(u4, 3); + +var u6 = Bs_Set.removeArray(u5, r); + +var u7 = Bs_Set.addArray(u6, /* int array */[ + 0, + 1, + 2, + 0 + ]); + +var u8 = Bs_Set.removeArray(u7, /* int array */[ + 0, + 1, + 2, + 3 + ]); + +var u9 = Bs_Set.addArray(u8, Array_data_util.randomRange(0, 20000)); + +var u10 = Bs_Set.addArray(u9, Array_data_util.randomRange(0, 200)); + +var u11 = Bs_Set.removeArray(u10, Array_data_util.randomRange(0, 200)); + +var u12 = Bs_Set.removeArray(u11, Array_data_util.randomRange(0, 1000)); + +var u13 = Bs_Set.removeArray(u12, Array_data_util.randomRange(0, 1000)); + +var u14 = Bs_Set.removeArray(u13, Array_data_util.randomRange(1000, 10000)); + +var u15 = Bs_Set.removeArray(u14, Array_data_util.randomRange(10000, 19999)); + +var u16 = Bs_Set.removeArray(u15, Array_data_util.randomRange(20000, 21000)); + +b("File \"bs_poly_set_test.ml\", line 33, characters 4-11", +(u0 !== u1)); + +b("File \"bs_poly_set_test.ml\", line 34, characters 4-11", +(u2 === u1)); + +eq("File \"bs_poly_set_test.ml\", line 35, characters 5-12", Bs_internalAVLset.length0(u4.data), 28); + +b("File \"bs_poly_set_test.ml\", line 36, characters 4-11", +(29 === Bs_internalAVLset.maxNull0(u4.data))); + +b("File \"bs_poly_set_test.ml\", line 37, characters 4-11", +(1 === Bs_internalAVLset.minNull0(u4.data))); + +b("File \"bs_poly_set_test.ml\", line 38, characters 4-11", +(u4 === u5)); + +b("File \"bs_poly_set_test.ml\", line 39, characters 4-11", Bs_internalAVLset.isEmpty0(u6.data)); + +eq("File \"bs_poly_set_test.ml\", line 40, characters 6-13", Bs_internalAVLset.length0(u7.data), 3); + +b("File \"bs_poly_set_test.ml\", line 41, characters 4-11", 1 - Bs_internalAVLset.isEmpty0(u7.data)); + +b("File \"bs_poly_set_test.ml\", line 42, characters 4-11", Bs_internalAVLset.isEmpty0(u8.data)); + +b("File \"bs_poly_set_test.ml\", line 43, characters 4-11", +(u9 === u10)); + +b("File \"bs_poly_set_test.ml\", line 44, characters 4-11", Bs_Set.mem(u10, 20)); + +b("File \"bs_poly_set_test.ml\", line 45, characters 4-11", Bs_Set.mem(u10, 21)); + +eq("File \"bs_poly_set_test.ml\", line 46, characters 5-12", Bs_internalAVLset.length0(u10.data), 20001); + +eq("File \"bs_poly_set_test.ml\", line 47, characters 5-12", Bs_internalAVLset.length0(u11.data), 19800); + +eq("File \"bs_poly_set_test.ml\", line 48, characters 5-12", Bs_internalAVLset.length0(u12.data), 19000); + +b("File \"bs_poly_set_test.ml\", line 49, characters 4-11", +(u12 === u13)); + +eq("File \"bs_poly_set_test.ml\", line 50, characters 5-12", Bs_internalAVLset.length0(u14.data), 10000); + +eq("File \"bs_poly_set_test.ml\", line 51, characters 5-12", Bs_internalAVLset.length0(u15.data), 1); + +b("File \"bs_poly_set_test.ml\", line 52, characters 4-11", Bs_Set.mem(u15, 20000)); + +b("File \"bs_poly_set_test.ml\", line 53, characters 4-11", 1 - Bs_Set.mem(u15, 2000)); + +b("File \"bs_poly_set_test.ml\", line 54, characters 4-11", Bs_internalAVLset.isEmpty0(u16.data)); + +var u17 = Bs_Set.ofArray(IntCmp, Array_data_util.randomRange(0, 100)); + +var u18 = Bs_Set.ofArray(IntCmp, Array_data_util.randomRange(59, 200)); + +var u19 = Bs_Set.union(u17, u18); + +var u20 = Bs_Set.ofArray(IntCmp, Array_data_util.randomRange(0, 200)); + +b("File \"bs_poly_set_test.ml\", line 59, characters 4-11", Bs_Set.eq(u19, u20)); + +var u21 = Bs_Set.inter(u17, u18); + +eq("File \"bs_poly_set_test.ml\", line 61, characters 5-12", Bs_internalAVLset.toArray0(u21.data), Array_data_util.range(59, 100)); + +var u22 = Bs_Set.diff(u17, u18); + +eq("File \"bs_poly_set_test.ml\", line 63, characters 5-12", Bs_internalAVLset.toArray0(u22.data), Array_data_util.range(0, 58)); + +var u23 = Bs_Set.diff(u18, u17); + +var u24 = Bs_Set.union(u18, u17); + +b("File \"bs_poly_set_test.ml\", line 66, characters 4-11", Bs_Set.eq(u24, u19)); + +eq("File \"bs_poly_set_test.ml\", line 67, characters 5-12", Bs_internalAVLset.toArray0(u23.data), Array_data_util.range(101, 200)); + +b("File \"bs_poly_set_test.ml\", line 68, characters 4-11", Bs_Set.subset(u23, u18)); + +b("File \"bs_poly_set_test.ml\", line 69, characters 4-11", 1 - Bs_Set.subset(u18, u23)); + +b("File \"bs_poly_set_test.ml\", line 70, characters 4-11", Bs_Set.subset(u22, u17)); + +b("File \"bs_poly_set_test.ml\", line 71, characters 4-11", Bs_Set.subset(u21, u17) && Bs_Set.subset(u21, u18)); + +b("File \"bs_poly_set_test.ml\", line 72, characters 4-11", +(47 === Bs_Set.findNull(u22, 47))); + +b("File \"bs_poly_set_test.ml\", line 73, characters 4-11", Caml_obj.caml_equal(/* Some */[47], Bs_Set.findOpt(u22, 47))); + +b("File \"bs_poly_set_test.ml\", line 74, characters 4-11", +(Bs_Set.findNull(u22, 59) === null)); + +b("File \"bs_poly_set_test.ml\", line 75, characters 4-11", +(/* None */0 === Bs_Set.findOpt(u22, 59))); + +var u25 = Bs_Set.add(u22, 59); + +eq("File \"bs_poly_set_test.ml\", line 77, characters 5-12", Bs_internalAVLset.length0(u25.data), 60); + +Mt.from_pair_suites("bs_poly_set_test.ml", suites[0]); + +var N = 0; + +var I = 0; + +var A = 0; + +exports.suites = suites; +exports.test_id = test_id; +exports.eq = eq; +exports.b = b; +exports.N = N; +exports.I = I; +exports.A = A; +exports.IntCmp = IntCmp; +/* u0 Not a pure module */ diff --git a/jscomp/test/bs_poly_set_test.ml b/jscomp/test/bs_poly_set_test.ml new file mode 100644 index 00000000000..37cb767f64c --- /dev/null +++ b/jscomp/test/bs_poly_set_test.ml @@ -0,0 +1,79 @@ +let suites : Mt.pair_suites ref = ref [] +let test_id = ref 0 +let eq loc x y = Mt.eq_suites ~test_id ~suites loc x y +let b loc x = Mt.bool_suites ~test_id ~suites loc x + +module N = Bs.Set +module I = Array_data_util +module A = Bs.Array +module IntCmp = + (val Bs.Cmp.make (fun[@bs] (x:int) y -> compare x y)) + + +let () = + let u0 = N.ofArray (module IntCmp) (I.range 0 30) in + let u1 = N.remove u0 0 in + let u2 = N.remove u1 0 in + let u3 = N.remove u2 30 in + let u4 = N.remove u3 20 in + let r = I.randomRange 0 30 in + + let u5 = N.add u4 3 in + let u6 = N.removeArray u5 r in + let u7 = N.addArray u6 [|0;1;2;0|] in + let u8 = N.removeArray u7 [|0;1;2;3|] in + let u9 = N.addArray u8 (I.randomRange 0 20000) in + let u10 = N.addArray u9 (I.randomRange 0 200) in + let u11 = N.removeArray u10 (I.randomRange 0 200) in + let u12 = N.removeArray u11 (I.randomRange 0 1000) in + let u13 = N.removeArray u12 (I.randomRange 0 1000) in + let u14 = N.removeArray u13 (I.randomRange 1000 10000) in + let u15 = N.removeArray u14 (I.randomRange 10000 (20000 - 1)) in + let u16 = N.removeArray u15 (I.randomRange 20000 21000) in + b __LOC__ (u0 != u1); + b __LOC__ (u2 == u1); + eq __LOC__ (N.length u4) 28; + b __LOC__ (Js.eqNull 29 (N.maxNull u4)); + b __LOC__ (Js.eqNull 1 (N.minNull u4)); + b __LOC__ (u4 == u5); + b __LOC__ (N.isEmpty u6); + eq __LOC__ (N.length u7) 3 ; + b __LOC__ (not (N.isEmpty u7)); + b __LOC__ (N.isEmpty u8); + b __LOC__ (u9 == u10); + b __LOC__ (N.mem u10 20); + b __LOC__ (N.mem u10 21); + eq __LOC__ (N.length u10) 20001; + eq __LOC__ (N.length u11) 19800; + eq __LOC__ (N.length u12) 19000; + b __LOC__ (u12 == u13); + eq __LOC__ (N.length u14) 10000; + eq __LOC__ (N.length u15) 1 ; + b __LOC__ (N.mem u15 20000); + b __LOC__ (not @@ N.mem u15 2000); + b __LOC__ (N.isEmpty u16); + let u17 = N.ofArray (module IntCmp) (I.randomRange 0 100) in + let u18 = N.ofArray (module IntCmp) (I.randomRange 59 200) in + let u19 = N.union u17 u18 in + let u20 = N.ofArray (module IntCmp) (I.randomRange 0 200) in + b __LOC__ (N.eq u19 u20); + let u21 = N.inter u17 u18 in + eq __LOC__ (N.toArray u21) (I.range 59 100); + let u22 = N.diff u17 u18 in + eq __LOC__ (N.toArray u22) (I.range 0 58); + let u23 = N.diff u18 u17 in + let u24 = N.union u18 u17 in + b __LOC__ (N.eq u24 u19); + eq __LOC__ (N.toArray u23) (I.range 101 200); + b __LOC__ (N.subset u23 u18); + b __LOC__ (not (N.subset u18 u23)); + b __LOC__ (N.subset u22 u17); + b __LOC__ (N.subset u21 u17 && N.subset u21 u18); + b __LOC__ (Js.eqNull 47 (N.findNull u22 47)); + b __LOC__ ( Some 47 = (N.findOpt u22 47)); + b __LOC__ (Js.Null.test (N.findNull u22 59)); + b __LOC__ (None = (N.findOpt u22 59)); + let u25 = N.add u22 59 in + eq __LOC__ (N.length u25) 60 + +;; Mt.from_pair_suites __FILE__ !suites \ No newline at end of file diff --git a/lib/js/bs_Set.js b/lib/js/bs_Set.js index 59c8013ba41..78dd3d2992e 100644 --- a/lib/js/bs_Set.js +++ b/lib/js/bs_Set.js @@ -45,20 +45,28 @@ function addArray(m, e) { var dict = m.dict; var data = m.data; var newData = Bs_internalSet.addArray0(dict[/* cmp */0], data, e); - return { - dict: dict, - data: newData - }; + if (newData === data) { + return m; + } else { + return { + dict: dict, + data: newData + }; + } } function removeArray(m, e) { var dict = m.dict; var data = m.data; var newData = Bs_internalSet.removeArray0(data, e, dict[/* cmp */0]); - return { - dict: dict, - data: newData - }; + if (newData === data) { + return m; + } else { + return { + dict: dict, + data: newData + }; + } } function singleton(dict, e) { diff --git a/lib/js/bs_internalAVLset.js b/lib/js/bs_internalAVLset.js index 08fa71ce1fb..1daaf157f9c 100644 --- a/lib/js/bs_internalAVLset.js +++ b/lib/js/bs_internalAVLset.js @@ -51,40 +51,28 @@ function bal(l, v, r) { var hl = l !== null ? l.h : 0; var hr = r !== null ? r.h : 0; if (hl > (hr + 2 | 0)) { - if (l !== null) { - var ll = l.left; - var lv = l.key; - var lr = l.right; - if (heightGe(ll, lr)) { - return create(ll, lv, create(lr, v, r)); - } else if (lr !== null) { - var lrl = lr.left; - var lrv = lr.key; - var lrr = lr.right; - return create(create(ll, lv, lrl), lrv, create(lrr, v, r)); - } else { - return /* assert false */0; - } + var ll = l.left; + var lv = l.key; + var lr = l.right; + if (heightGe(ll, lr)) { + return create(ll, lv, create(lr, v, r)); } else { - return /* assert false */0; + var lrl = lr.left; + var lrv = lr.key; + var lrr = lr.right; + return create(create(ll, lv, lrl), lrv, create(lrr, v, r)); } } else if (hr > (hl + 2 | 0)) { - if (r !== null) { - var rl = r.left; - var rv = r.key; - var rr = r.right; - if (heightGe(rr, rl)) { - return create(create(l, v, rl), rv, rr); - } else if (rl !== null) { - var rll = rl.left; - var rlv = rl.key; - var rlr = rl.right; - return create(create(l, v, rll), rlv, create(rlr, rv, rr)); - } else { - return /* assert false */0; - } + var rl = r.left; + var rv = r.key; + var rr = r.right; + if (heightGe(rr, rl)) { + return create(create(l, v, rl), rv, rr); } else { - return /* assert false */0; + var rll = rl.left; + var rlv = rl.key; + var rlr = rl.right; + return create(create(l, v, rll), rlv, create(rlr, rv, rr)); } } else { return { @@ -105,42 +93,22 @@ function singleton0(x) { }; } -function add_min_element(v, n) { +function addMinElement(v, n) { if (n !== null) { - return bal(add_min_element(v, n.left), n.key, n.right); + return bal(addMinElement(v, n.left), n.key, n.right); } else { return singleton0(v); } } -function add_max_element(v, n) { +function addMaxElement(v, n) { if (n !== null) { - return bal(n.left, n.key, add_max_element(v, n.right)); + return bal(n.left, n.key, addMaxElement(v, n.right)); } else { return singleton0(v); } } -function join(ln, v, rn) { - if (ln !== null) { - if (rn !== null) { - var lh = ln.h; - var rh = rn.h; - if (lh > (rh + 2 | 0)) { - return bal(ln.left, ln.key, join(ln.right, v, rn)); - } else if (rh > (lh + 2 | 0)) { - return bal(join(ln, v, rn.left), rn.key, rn.right); - } else { - return create(ln, v, rn); - } - } else { - return add_max_element(v, ln); - } - } else { - return add_min_element(v, rn); - } -} - function min0Aux(_n) { while(true) { var n = _n; @@ -201,32 +169,43 @@ function maxNull0(n) { } } -function removeMinAux(n) { +function removeMinAuxWithRef(n, v) { var rn = n.right; var ln = n.left; if (ln !== null) { - return bal(removeMinAux(ln), n.key, rn); + return bal(removeMinAuxWithRef(ln, v), n.key, rn); } else { + v[0] = n.key; return rn; } } -function merge(t1, t2) { - if (t1 !== null) { - if (t2 !== null) { - return bal(t1, min0Aux(t2), removeMinAux(t2)); +function join(ln, v, rn) { + if (ln !== null) { + if (rn !== null) { + var lh = ln.h; + var rh = rn.h; + if (lh > (rh + 2 | 0)) { + return bal(ln.left, ln.key, join(ln.right, v, rn)); + } else if (rh > (lh + 2 | 0)) { + return bal(join(ln, v, rn.left), rn.key, rn.right); + } else { + return create(ln, v, rn); + } } else { - return t1; + return addMaxElement(v, ln); } } else { - return t2; + return addMinElement(v, rn); } } function concat(t1, t2) { if (t1 !== null) { if (t2 !== null) { - return join(t1, min0Aux(t2), removeMinAux(t2)); + var v = [t2.key]; + var t2r = removeMinAuxWithRef(t2, v); + return join(t1, v[0], t2r); } else { return t1; } @@ -245,7 +224,7 @@ function isEmpty0(n) { } } -function cons_enum(_s, _e) { +function toEnum(_s, _e) { while(true) { var e = _e; var s = _s; @@ -398,7 +377,7 @@ function length0(n) { } } -function elements_aux(_accu, _n) { +function toListAux(_accu, _n) { while(true) { var n = _n; var accu = _accu; @@ -409,7 +388,7 @@ function elements_aux(_accu, _n) { _n = l; _accu = /* :: */[ k, - elements_aux(accu, r) + toListAux(accu, r) ]; continue ; @@ -420,7 +399,7 @@ function elements_aux(_accu, _n) { } function toList0(s) { - return elements_aux(/* [] */0, s); + return toListAux(/* [] */0, s); } function checkInvariant(_v) { @@ -622,27 +601,27 @@ function ofSortedArrayUnsafe0(arr) { var A = 0; +exports.A = A; exports.height = height; exports.copy = copy; exports.create = create; exports.heightGe = heightGe; exports.bal = bal; exports.singleton0 = singleton0; -exports.add_min_element = add_min_element; -exports.add_max_element = add_max_element; -exports.join = join; +exports.addMinElement = addMinElement; +exports.addMaxElement = addMaxElement; exports.min0Aux = min0Aux; exports.minOpt0 = minOpt0; exports.minNull0 = minNull0; exports.max0Aux = max0Aux; exports.maxOpt0 = maxOpt0; exports.maxNull0 = maxNull0; -exports.removeMinAux = removeMinAux; -exports.merge = merge; +exports.removeMinAuxWithRef = removeMinAuxWithRef; +exports.join = join; exports.concat = concat; exports.empty0 = empty0; exports.isEmpty0 = isEmpty0; -exports.cons_enum = cons_enum; +exports.toEnum = toEnum; exports.iter0 = iter0; exports.fold0 = fold0; exports.forAll0 = forAll0; @@ -651,10 +630,9 @@ exports.filter0 = filter0; exports.partition0 = partition0; exports.cardinalAux = cardinalAux; exports.length0 = length0; -exports.elements_aux = elements_aux; +exports.toListAux = toListAux; exports.toList0 = toList0; exports.checkInvariant = checkInvariant; -exports.A = A; exports.fillArray = fillArray; exports.toArray0 = toArray0; exports.rotateWithLeftChild = rotateWithLeftChild; diff --git a/lib/js/bs_internalSet.js b/lib/js/bs_internalSet.js index 6c81eec31e6..8ea2347e788 100644 --- a/lib/js/bs_internalSet.js +++ b/lib/js/bs_internalSet.js @@ -134,8 +134,16 @@ function remove0(cmp, t, x) { return Bs_internalAVLset.bal(l, v, rr); } } + } else if (l !== null) { + if (r !== null) { + var v$1 = [r.key]; + var r$1 = Bs_internalAVLset.removeMinAuxWithRef(r, v$1); + return Bs_internalAVLset.bal(l, v$1[0], r$1); + } else { + return l; + } } else { - return Bs_internalAVLset.merge(l, r); + return r; } } else { return t; @@ -236,7 +244,7 @@ function diff0(cmp, s1, s2) { } } -function compare_aux(cmp, _e1, _e2) { +function compareAux(cmp, _e1, _e2) { while(true) { var e2 = _e2; var e1 = _e1; @@ -246,8 +254,8 @@ function compare_aux(cmp, _e1, _e2) { if (c !== 0) { return c; } else { - _e2 = Bs_internalAVLset.cons_enum(e2[1], e2[2]); - _e1 = Bs_internalAVLset.cons_enum(e1[1], e1[2]); + _e2 = Bs_internalAVLset.toEnum(e2[1], e2[2]); + _e1 = Bs_internalAVLset.toEnum(e1[1], e1[2]); continue ; } @@ -263,7 +271,7 @@ function compare_aux(cmp, _e1, _e2) { } function cmp0(cmp, s1, s2) { - return compare_aux(cmp, Bs_internalAVLset.cons_enum(s1, /* End */0), Bs_internalAVLset.cons_enum(s2, /* End */0)); + return compareAux(cmp, Bs_internalAVLset.toEnum(s1, /* End */0), Bs_internalAVLset.toEnum(s2, /* End */0)); } function eq0(cmp, s1, s2) { @@ -589,7 +597,7 @@ exports.removeArray0 = removeArray0; exports.union0 = union0; exports.inter0 = inter0; exports.diff0 = diff0; -exports.compare_aux = compare_aux; +exports.compareAux = compareAux; exports.cmp0 = cmp0; exports.eq0 = eq0; exports.subset0 = subset0; diff --git a/lib/js/bs_internalSetInt.js b/lib/js/bs_internalSetInt.js index 78e18c0ca50..d8daca0ec2d 100644 --- a/lib/js/bs_internalSetInt.js +++ b/lib/js/bs_internalSetInt.js @@ -113,7 +113,17 @@ function remove(t, x) { var v = t.key; var r = t.right; if (x === v) { - return Bs_internalAVLset.merge(l, r); + if (l !== null) { + if (r !== null) { + var v$1 = [r.key]; + var r$1 = Bs_internalAVLset.removeMinAuxWithRef(r, v$1); + return Bs_internalAVLset.bal(l, v$1[0], r$1); + } else { + return l; + } + } else { + return r; + } } else if (x < v) { var ll = remove(l, x); if (ll === l) { @@ -223,8 +233,8 @@ function compare_aux(_e1, _e2) { return 1; } } else { - _e2 = Bs_internalAVLset.cons_enum(e2[1], e2[2]); - _e1 = Bs_internalAVLset.cons_enum(e1[1], e1[2]); + _e2 = Bs_internalAVLset.toEnum(e2[1], e2[2]); + _e1 = Bs_internalAVLset.toEnum(e1[1], e1[2]); continue ; } @@ -240,18 +250,18 @@ function compare_aux(_e1, _e2) { } function cmp(s1, s2) { - return compare_aux(Bs_internalAVLset.cons_enum(s1, /* End */0), Bs_internalAVLset.cons_enum(s2, /* End */0)); + return compare_aux(Bs_internalAVLset.toEnum(s1, /* End */0), Bs_internalAVLset.toEnum(s2, /* End */0)); } -function eq_aux(_e1, _e2) { +function eqAux(_e1, _e2) { while(true) { var e2 = _e2; var e1 = _e1; if (e1) { if (e2) { if (e1[0] === e2[0]) { - _e2 = Bs_internalAVLset.cons_enum(e2[1], e2[2]); - _e1 = Bs_internalAVLset.cons_enum(e1[1], e1[2]); + _e2 = Bs_internalAVLset.toEnum(e2[1], e2[2]); + _e1 = Bs_internalAVLset.toEnum(e1[1], e1[2]); continue ; } else { @@ -269,7 +279,7 @@ function eq_aux(_e1, _e2) { } function eq(s1, s2) { - return eq_aux(Bs_internalAVLset.cons_enum(s1, /* End */0), Bs_internalAVLset.cons_enum(s2, /* End */0)); + return eqAux(Bs_internalAVLset.toEnum(s1, /* End */0), Bs_internalAVLset.toEnum(s2, /* End */0)); } function subset(_s1, _s2) { @@ -508,7 +518,7 @@ exports.inter = inter; exports.diff = diff; exports.compare_aux = compare_aux; exports.cmp = cmp; -exports.eq_aux = eq_aux; +exports.eqAux = eqAux; exports.eq = eq; exports.subset = subset; exports.findOpt = findOpt; diff --git a/lib/js/bs_internalSetString.js b/lib/js/bs_internalSetString.js index 78e18c0ca50..d8daca0ec2d 100644 --- a/lib/js/bs_internalSetString.js +++ b/lib/js/bs_internalSetString.js @@ -113,7 +113,17 @@ function remove(t, x) { var v = t.key; var r = t.right; if (x === v) { - return Bs_internalAVLset.merge(l, r); + if (l !== null) { + if (r !== null) { + var v$1 = [r.key]; + var r$1 = Bs_internalAVLset.removeMinAuxWithRef(r, v$1); + return Bs_internalAVLset.bal(l, v$1[0], r$1); + } else { + return l; + } + } else { + return r; + } } else if (x < v) { var ll = remove(l, x); if (ll === l) { @@ -223,8 +233,8 @@ function compare_aux(_e1, _e2) { return 1; } } else { - _e2 = Bs_internalAVLset.cons_enum(e2[1], e2[2]); - _e1 = Bs_internalAVLset.cons_enum(e1[1], e1[2]); + _e2 = Bs_internalAVLset.toEnum(e2[1], e2[2]); + _e1 = Bs_internalAVLset.toEnum(e1[1], e1[2]); continue ; } @@ -240,18 +250,18 @@ function compare_aux(_e1, _e2) { } function cmp(s1, s2) { - return compare_aux(Bs_internalAVLset.cons_enum(s1, /* End */0), Bs_internalAVLset.cons_enum(s2, /* End */0)); + return compare_aux(Bs_internalAVLset.toEnum(s1, /* End */0), Bs_internalAVLset.toEnum(s2, /* End */0)); } -function eq_aux(_e1, _e2) { +function eqAux(_e1, _e2) { while(true) { var e2 = _e2; var e1 = _e1; if (e1) { if (e2) { if (e1[0] === e2[0]) { - _e2 = Bs_internalAVLset.cons_enum(e2[1], e2[2]); - _e1 = Bs_internalAVLset.cons_enum(e1[1], e1[2]); + _e2 = Bs_internalAVLset.toEnum(e2[1], e2[2]); + _e1 = Bs_internalAVLset.toEnum(e1[1], e1[2]); continue ; } else { @@ -269,7 +279,7 @@ function eq_aux(_e1, _e2) { } function eq(s1, s2) { - return eq_aux(Bs_internalAVLset.cons_enum(s1, /* End */0), Bs_internalAVLset.cons_enum(s2, /* End */0)); + return eqAux(Bs_internalAVLset.toEnum(s1, /* End */0), Bs_internalAVLset.toEnum(s2, /* End */0)); } function subset(_s1, _s2) { @@ -508,7 +518,7 @@ exports.inter = inter; exports.diff = diff; exports.compare_aux = compare_aux; exports.cmp = cmp; -exports.eq_aux = eq_aux; +exports.eqAux = eqAux; exports.eq = eq; exports.subset = subset; exports.findOpt = findOpt;