@@ 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)
@@ 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