diff --git a/src/reactiveData.ml b/src/reactiveData.ml index 06e81e0..dc4db93 100644 --- a/src/reactiveData.ml +++ b/src/reactiveData.ml @@ -206,7 +206,60 @@ module DataList = struct end; Array.to_list a - let merge p l = List.fold_left (fun l x -> merge_p x l) l p + (* accumulates into acc i unmodified elements from l *) + let rec linear_merge_fwd i l ~acc = + assert (i >= 0); + if i > 0 then + match l with + | h :: l -> + let acc = h :: acc in + linear_merge_fwd (i - 1) l ~acc + | [] -> + invalid_arg "invalid index" + else + l, acc + + let rec linear_merge i0 p l ~acc = + let l, acc = + match p with + | (I (i, _) | R i | U (i, _)) :: _ when i > i0 -> + linear_merge_fwd (i - i0) l ~acc + | _ -> + l, acc + in + match p, l with + | I (i, x) :: p, _ -> + linear_merge i p (x :: l) ~acc + | R i :: p, _ :: l -> + linear_merge i p l ~acc + | R _ :: _, [] -> + invalid_arg "merge: invalid index" + | U (i, x) :: p, _ :: l -> + linear_merge i p (x :: l) ~acc + | U (_, _) :: _, [] -> + invalid_arg "merge: invalid index" + | [], l -> + List.rev_append acc l + | X (_, _) :: _, _ -> + failwith "linear_merge: X not supported" + + let rec linear_mergeable p ~n = + assert (n >= 0); + match p with + | (I (i, _) | R i | U (i, _)) :: p when i >= n -> + (* negative i's ruled out (among others) *) + linear_mergeable p ~n:i + | _ :: _ -> + false + | [] -> + true + + let merge p l = + if linear_mergeable p ~n:0 then + linear_merge 0 p l ~acc:[] + else + List.fold_left (fun l x -> merge_p x l) l p + end module RList = struct