package base
Source file stack.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221open! Import include Stack_intf let raise_s = Error.raise_s (* This implementation is similar to [Deque] in that it uses an array of ['a] and a mutable [int] to indicate what in the array is used. We choose to implement [Stack] directly rather than on top of [Deque] for performance reasons. E.g. a simple microbenchmark shows that push/pop is about 20% faster. *) type 'a t = { mutable length : int ; mutable elts : 'a Option_array.t } [@@deriving_inline sexp_of] let sexp_of_t : 'a. ('a -> Sexplib0.Sexp.t) -> 'a t -> Sexplib0.Sexp.t = fun _of_a__001_ { length = length__003_; elts = elts__005_ } -> let bnds__002_ = ([] : _ Stdlib.List.t) in let bnds__002_ = let arg__006_ = Option_array.sexp_of_t _of_a__001_ elts__005_ in (Sexplib0.Sexp.List [ Sexplib0.Sexp.Atom "elts"; arg__006_ ] :: bnds__002_ : _ Stdlib.List.t) in let bnds__002_ = let arg__004_ = sexp_of_int length__003_ in (Sexplib0.Sexp.List [ Sexplib0.Sexp.Atom "length"; arg__004_ ] :: bnds__002_ : _ Stdlib.List.t) in Sexplib0.Sexp.List bnds__002_ ;; [@@@end] let sexp_of_t_internal = sexp_of_t let sexp_of_t = `Rebound_later let _ = sexp_of_t let capacity t = Option_array.length t.elts let invariant invariant_a ({ length; elts } as t) : unit = try assert (0 <= length && length <= Option_array.length elts); for i = 0 to length - 1 do invariant_a (Option_array.get_some_exn elts i) done; (* We maintain the invariant that unused elements are unset to avoid a space leak. *) for i = length to Option_array.length elts - 1 do assert (not (Option_array.is_some elts i)) done with | exn -> raise_s (Sexp.message "Stack.invariant failed" [ "exn", exn |> Exn.sexp_of_t; "stack", t |> sexp_of_t_internal sexp_of_opaque ]) ;; let create (type a) () : a t = { length = 0; elts = Option_array.empty } let length t = t.length let is_empty t = length t = 0 (* The order in which elements are visited has been chosen so as to be backwards compatible with [Stdlib.Stack] *) let fold t ~init ~f = let r = ref init in for i = t.length - 1 downto 0 do r := f !r (Option_array.get_some_exn t.elts i) done; !r ;; let iter t ~f = for i = t.length - 1 downto 0 do f (Option_array.get_some_exn t.elts i) done ;; module C = Container.Make (struct type nonrec 'a t = 'a t let fold = fold let iter = `Custom iter let length = `Custom length end) let mem = C.mem let exists = C.exists let for_all = C.for_all let count = C.count let sum = C.sum let find = C.find let find_map = C.find_map let to_list = C.to_list let to_array = C.to_array let min_elt = C.min_elt let max_elt = C.max_elt let fold_result = C.fold_result let fold_until = C.fold_until let of_list (type a) (l : a list) = if List.is_empty l then create () else ( let length = List.length l in let elts = Option_array.create ~len:(2 * length) in let r = ref l in for i = length - 1 downto 0 do match !r with | [] -> assert false | a :: l -> Option_array.set_some elts i a; r := l done; { length; elts }) ;; let sexp_of_t sexp_of_a t = List.sexp_of_t sexp_of_a (to_list t) let t_of_sexp a_of_sexp sexp = of_list (List.t_of_sexp a_of_sexp sexp) let t_sexp_grammar (type a) (grammar : a Sexplib0.Sexp_grammar.t) : a t Sexplib0.Sexp_grammar.t = Sexplib0.Sexp_grammar.coerce (List.t_sexp_grammar grammar) ;; let resize t size = let arr = Option_array.create ~len:size in Option_array.blit ~src:t.elts ~dst:arr ~src_pos:0 ~dst_pos:0 ~len:t.length; t.elts <- arr ;; let set_capacity t new_capacity = let new_capacity = max new_capacity (length t) in if new_capacity <> capacity t then resize t new_capacity ;; let push t a = if t.length = Option_array.length t.elts then resize t (2 * (t.length + 1)); Option_array.set_some t.elts t.length a; t.length <- t.length + 1 ;; let pop_nonempty t = let i = t.length - 1 in let result = Option_array.get_some_exn t.elts i in Option_array.set_none t.elts i; t.length <- i; result ;; let pop_error = Error.of_string "Stack.pop of empty stack" let pop t = if is_empty t then None else Some (pop_nonempty t) let pop_exn t = if is_empty t then Error.raise pop_error else pop_nonempty t let top_nonempty t = Option_array.get_some_exn t.elts (t.length - 1) let top_error = Error.of_string "Stack.top of empty stack" let top t = if is_empty t then None else Some (top_nonempty t) let top_exn t = if is_empty t then Error.raise top_error else top_nonempty t let copy { length; elts } = { length; elts = Option_array.copy elts } let clear t = if t.length > 0 then ( for i = 0 to t.length - 1 do Option_array.set_none t.elts i done; t.length <- 0) ;; let until_empty t f = let rec loop () = if t.length > 0 then ( f (pop_nonempty t); loop ()) in loop () [@nontail] ;; let filter_map t ~f = let t_result = create () in for i = 0 to t.length - 1 do match f (Option_array.get_some_exn t.elts i) with | None -> () | Some x -> push t_result x done; t_result ;; let filter t ~f = let t_result = create () in for i = 0 to t.length - 1 do let x = Option_array.get_some_exn t.elts i in if f x then push t_result x done; t_result ;; let filter_inplace t ~f = let write_index = ref 0 in Exn.protect ~f:(fun () -> for read_index = 0 to t.length - 1 do let x = Option_array.unsafe_get_some_assuming_some t.elts read_index in if f x then ( if !write_index < read_index then Option_array.unsafe_set_some t.elts !write_index x; incr write_index) done) ~finally:(fun () -> for i = !write_index to t.length - 1 do Option_array.unsafe_set_none t.elts i done; t.length <- !write_index) [@nontail] ;; let singleton x = let t = create () in push t x; t ;;