package spotlib

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file dllist.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
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
(* doubly linked list *)

module type S = sig

  type 'a t
    (** The type of the dllist *)

  type 'a node
    (** The type of the dllist node *)

  val create : unit -> 'a t
    (** Create an empty dllist *)

  val length : 'a t -> int
    (** O(1). The length of the dllist *)

  val is_empty : 'a t -> bool
    
  val list : 'a node -> 'a t option
    (** [list node] returns [Some t] if [node] is an element of [t].
        If [node] is removed, it returns [None]. *)

  val is_removed : 'a node -> bool

  val value : 'a node -> 'a
    (** Get the value from the node *)    

  val add : 'a t -> 'a -> 'a node
    (** O(1). [add t v] adds [v] to dllist [t] and returns the newly created
        node for [v]. The node is used to remove the value from [t] in constant
        time.
    *)

  val remove : 'a node -> (unit, [> `Already_removed]) result
    (** O(1). [remove node] removes [node] from the dllist it belongs to.
        Successful removal returns [`Ok]. If the node is already removed,
        [remove node] returns [`Already_removed]. *)

  val hd : 'a t -> 'a node option
    (** [hd t] returns the first node of the dllist [t]. *)

  val tl : 'a t -> 'a node option option
    (** [tl t] returns the second node of the dllist [t]. 

        None : t is null
        Some None : t is a singleton
        Some (Some n) : n is the second
    *)

  val hd_tl : 'a t -> ('a node * 'a node option) option

  val iter : ('a node -> unit) -> 'a t -> unit
    (** Iteration over the nodes of a dllist from the top to the bottom *)

  val fold_left : ('a -> 'b node -> 'a) -> 'a -> 'b t -> 'a
    (** Folding the nodes of a dllist from the top to the bottom *)

  val fold_right : ('b node -> 'a -> 'a) -> 'b t -> 'a -> 'a
    (** Folding the nodes of a dllist from the bottom to top *)

  val scan_left : ('a -> 'b node -> [< `Continue of 'a | `Stop of 'a ]) ->
    'a -> 'b t -> 'a
    (** [fold] with stop *)

  val scan_left_nodes : ('a -> 'b node -> [< `Continue of 'a | `Stop of 'a ]) ->
    'a -> 'b node -> 'a
    (** [scan] but starts with a node *)

  (** list <=> dllist conversion functions *)    
  val to_nodes : 'a t -> 'a node list
  val to_list : 'a t -> 'a list
  val of_list : 'a list -> 'a t

  val invariant : 'a t -> unit
    (** Invariant checks *)

end

module Z : S = struct
  type 'a node = {
    mutable prev : 'a node option;
    mutable next : 'a node option;
    mutable parent : 'a t option;
    value : 'a;
  }
  
  and 'a t = {
    mutable top : 'a node option;
    mutable bottom : 'a node option;
    mutable length : int;
  }
  
  let create () = 
    { top = None;
      bottom = None;
      length = 0 }
  ;;
  
  let length t = t.length
  let is_empty t = t.length = 0
  
  let list node = node.parent
  let is_removed node = node.parent = None
  let value node = node.value
  
  let add t v =
    let node = { prev = t.bottom;
                 next = None;
                 parent = Some t;
                 value = v }
    in
    begin match t.bottom with
    | None -> t.top <- Some node
    | Some bottom -> bottom.next <- Some node
    end;
    t.bottom <- Some node;
    t.length <- t.length + 1;
    node
  ;;
  
  let remove node =
    match node.parent with
    | None -> Error `Already_removed
    | Some t ->
        let top =
          match node.prev with
          | None -> node.next
          | Some prev -> 
  	    prev.next <- node.next;
  	    t.top 
        in
        let bottom = 
          match node.next with
          | None -> node.prev
          | Some next -> 
  	    next.prev <- node.prev;
  	    t.bottom
        in
        node.parent <- None;
        node.prev <- None;
        node.next <- None;
        t.length <- t.length - 1; 
        t.top <- top;
        t.bottom <- bottom;
        Ok ()
  ;;
  
  let hd t = 
    match t.top with
    | Some node -> Some node
    | None -> None
  ;;
  
  let tl t = 
    match t.top with
    | Some node -> Some node.next
    | None -> None
  ;;

  let hd_tl t = match t.top with
    | None -> None
    | Some node -> Some (node, node.next)

  let iter f t =
    let rec iter = function
      | None -> ()
      | Some node -> f node; iter node.next
    in
    iter t.top
  ;;
  
  let fold_left f init t =
    let rec fold acc = function
      | None -> acc
      | Some node -> fold (f acc node) node.next
    in
    fold init t.top
  ;;
  
  let gen_scan f init nopt =
    let rec scan acc = function
      | None -> acc
      | Some node -> 
          match f acc node with
          | `Stop acc' -> acc'
          | `Continue acc' -> scan acc' node.next
    in
    scan init nopt
  ;;
  
  let scan_left_nodes f init n = gen_scan f init (Some n)
    
  let scan_left f init t = gen_scan f init t.top
  
  let fold_right f t init =
    let rec fold v acc = match v with
      | None -> acc
      | Some node -> fold node.prev (f node acc) 
    in
    fold t.bottom init
  ;;
  
  let to_nodes t = fold_right (fun x acc -> x :: acc) t []
  let to_list t = fold_right (fun x acc -> x.value :: acc) t []
  
  let of_list l =
    let t = create () in
    List.iter (fun x -> ignore (add t x)) l; 
    t
  ;;
  
  (* invariants *)
      
  let invariant_node node =
    match node.parent with
    | None -> 
        assert (node.prev = None);
        assert (node.next = None);
    | Some t ->
        let self_prev =
          match node.prev with
          | None -> t.top
          | Some prev -> prev.next
        in
        let self_next =
          match node.next with
          | None -> t.bottom
          | Some next -> next.prev
        in
        let check_self = function
          | None -> assert false
          | Some self -> assert (self == node)
        in
        check_self self_prev;
        check_self self_next
  ;;
  
  let invariant t =
    let counted_length =
      fold_left (fun acc node ->
        begin match node.parent with
        | None -> assert false
        | Some parent -> assert (t == parent)
        end;
        invariant_node node;
        acc + 1) 0 t 
    in
    if t.length <> counted_length then begin
      Printf.eprintf "length=%d counted=%d\n"
        t.length counted_length;
      assert false
    end
  ;;  
end

module Test(Z:S) = struct (* check the types first *)

  open Z

  (* very simple test *)
  let () =
    let t = create () in
    let node = add t 1 in
    begin match hd t with
    | None -> assert false
    | Some node -> assert (value node = 1)
    end;
    assert (to_list t = [1]);
    assert (remove node = Ok ());
    assert (is_empty t);
    prerr_endline "very simple: passed";
  ;;

  (* to_list . of_list = ident *)
  let () =
    let ints = 
      let rec ints acc = function
        | 0 -> acc
        | n -> ints (n::acc) (n-1) 
      in
      ints [] 10000
    in
    let t = of_list ints in
    invariant t;
    assert (to_list (of_list ints) = ints);
    prerr_endline "to_list . of_list = id: passed"
  ;;

  (* misc api test *)
  let () = 
    let t = create () in
    assert (is_empty t);

    let ints = [1;2;3;4;5;6;7;8;9;10] in 
    let t = of_list ints in

    let s = ref [] in
    iter (fun node -> s := value node :: !s) t;
    assert (List.rev ints = !s);

    assert (55 = fold_left (fun acc node -> acc + value node) 0 t);
    assert (ints = fold_right (fun node acc -> value node :: acc) t []);
    prerr_endline "misc api test: passed";
  ;;
  
  (* random add/removal test *)
  let () =
    let t = create () in
    (* get a random element of a list, one path *)
    let random_in_list = function
      | [] -> None
      | x::xs ->
          let rec random_in_list len cand = function
            | [] -> cand
            | x::xs ->
                (* cand survives : len/(len+1) *)
                (* x overrides : 1/(len+1) *)
                let cand = 
                  if Random.int (len+1) = 0 then x
                  else cand
                in
                random_in_list (len+1) cand xs
          in
          Some (random_in_list 1 x xs)
    in
  
    let rec loop added rev_current = function
      | 10000 -> rev_current
      | n ->
          invariant t;
          if Random.int 3 = 0 then begin
            let rev_current =
              match random_in_list added with
              | None -> rev_current
              | Some node ->
                  let removed = is_removed node in
                  match removed, remove node with
                  | true, Error `Already_removed -> rev_current
                  | false, Ok _ ->
                      List.filter (fun x -> x != node) rev_current 
                  | _ -> assert false
            in
            loop added rev_current n
          end else 
            let node = add t n in
            loop (node :: added) (node :: rev_current) (n+1)
    in
    let rev_current = loop [] [] 0 in 
    invariant t;
    assert (to_list t = List.rev_map value rev_current);
    (* remove all the elements remaining *)
    let rec f rev_current =
      match random_in_list rev_current with
      | None -> assert (is_empty t)
      | Some node ->
          assert (remove node = Ok ());
          invariant t;
          f (List.filter (fun x -> x != node) rev_current)
    in
    f rev_current;
    prerr_endline "big random add/remove test: passed";
  ;;

end    

[%%TEST
  let () = 
    let module TZ = Test(Z) in
    true
]

include Z
OCaml

Innovation. Community. Security.