~williewillus/persistent

e830ba3696801d3665a2ab6aae9a0cab6fb81d64 — Vincent Lee 1 year, 9 months ago d09352e
Tweaks
2 files changed, 27 insertions(+), 16 deletions(-)

M lib/vector.ml
M lib/vector.mli
M lib/vector.ml => lib/vector.ml +9 -16
@@ 18,6 18,7 @@ let inner_mask = branch_factor - 1
let outer_mask = lnot inner_mask

type 'a node = {
    (* Note: This array is always [branch_factor]-sized. *)
    array : 'a node_item array;
  } [@@unboxed]
and 'a node_item =


@@ 43,8 44,13 @@ type 'a t = {
    (* The "tail" is an optimization to the vector that allows true-constant time
       access to the end of the vector, in recognition of the fact that vectors
       are often pushed and popped at the end.
       
       Typed as 'a node_item to match node type, but is logically 'a option array.
       i.e., this should never hold Inner, only Leaf or Empty *)
       i.e., this should never hold Inner, only Leaf or Empty
       
       Note: This array will grow and shrink as the vector is updated, unlike the array
       inside 'a node.
     *)
    tail : 'a node_item array;
  }



@@ 67,7 73,6 @@ let empty () : 'a t  =
   *)
  Obj.magic empty_value

(** Returns the length of the vector *)
let length (t : 'a t) : int = t.count

(** Returns the logical index represented by tail.(0) *)


@@ 96,7 101,6 @@ let array_for (t : 'a t) (i : int) : 'a node_item array option =
    in
    Some (descend t.root t.height)

(** Gets the element at index, or None if out of bounds *)
let nth_opt (t : 'a t) (index : int) : 'a option =
  let last_level_index = index land inner_mask in
  match array_for t index with


@@ 107,23 111,15 @@ let nth_opt (t : 'a t) (index : int) : 'a option =
      | Inner _ -> failwith "Invariant violation, not expecting Inner in last-level array")
  | _ -> None

(** Gets the element at index, or raises Invalid_argument if out of bounds *)
let nth (t : 'a t) (index : int) : 'a =
  match nth_opt t index with
  | Some value -> value
  | None -> invalid_arg "Index out of bounds"

(** Appends an element to the vector *)
let append (t : 'a t) (value : 'a) : 'a t =
  let old_count = length t in
  if old_count - (tail_offset t) < branch_factor then
    (* *)
    (* Create a new tail that is one longer.
       Note: Array.init is no faster than this,
       because it gets the zeroth element, fills the
       array with that, then sets all the subsequent elements.
       Do it manually here to avoid a closure allocation.
     *)
    (* Create a new tail that is one longer *)
    let old_tail_length = Array.length t.tail in
    let new_tail = Array.make (old_tail_length + 1) (Leaf value) in
    Array.blit t.tail 0 new_tail 0 old_tail_length;


@@ 174,8 170,6 @@ let append (t : 'a t) (value : 'a) : 'a t =
      tail = [|(Leaf value)|];
    }

(* Returns a new vector with index i associated to a. If i is equal to the current vector size, a is appended to the vector, expanding it.
   If i is less than zero or greater than the current vector size, Invalid_argument is raised. *)
let update (t : 'a t) (i : int) (value : 'a) : 'a t =
  let count = length t in
  if i < 0 || i > count then


@@ 228,8 222,7 @@ let pop (t : 'a t) : 'a t =
let of_seq (xs : 'a Seq.t) : 'a t =
  Seq.fold_left append (empty ()) xs

(** Dead-simple Sequence implementation.
    TODO: optimize by holding onto the leaf so we don't have to walk down every time *)
(* TODO: optimize by holding onto the leaf so we don't have to walk down every time *)
let to_seq (t : 'a t) : 'a Seq.t =
  Seq.init t.count (fun i -> nth t i)


M lib/vector.mli => lib/vector.mli +18 -0
@@ 15,14 15,32 @@ val nth : 'a t -> int -> 'a
(** Appends an element to the vector *)
val append : 'a t -> 'a -> 'a t

(** Returns a new vector with index i associated to a. If i is equal to the current vector size, a is appended to the vector, expanding it.
    If i is less than zero or greater than the current vector size, Invalid_argument is raised.
 *)
val update : 'a t -> int -> 'a -> 'a t

(** Returns a new vector with the last element removed.
    If the vector was empty, returns [None].
 *)
val pop_opt : 'a t -> 'a t option

(** Returns a new vector with the last element removed.
    If the vector was empty, raises [Invalid_argument]
 *)
val pop : 'a t -> 'a t

(** Builds a vector from the provided sequence,
    which is consumed once entirely.
 *)
val of_seq : 'a Seq.t -> 'a t

(** Converts this vector to a sequence.
    The returned sequence can be reused.
 *)
val to_seq : 'a t -> 'a Seq.t

(** Determines of two vectors are equal according to the
    provided element comparator.
 *)
val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool