package lwd

  1. Overview
  2. Docs

Source file lwd_table.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
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
type 'a binding =
  | Bound of { value : 'a ; mutable valid : bool }
  | Unbound

type 'a tree =
  | Leaf
  | Node of {
      mutable version : int;
      mutable left    : 'a tree;
      mutable binding : 'a binding;
      mutable right   : 'a tree;
      mutable parent  : 'a tree;
      mutable size    : int;
    }
  | Root of {
      mutable version : int;
      mutable child : 'a tree;
      mutable generation : unit ref;
      mutable on_invalidate : Obj.t Lwd.prim list;
    }

type 'a t = 'a tree
type 'a row = 'a tree

let not_origin = ref () (* not {!origin} *)
let origin = ref () (* not {!not_origin} *)

let make () =
  Root { child = Leaf; generation = origin; version = 0; on_invalidate = [] }

let set_parent ~parent = function
  | Root _ -> assert false
  | Node n -> n.parent <- parent
  | Leaf -> ()

let reparent ~parent ~oldchild ~newchild =
  match parent with
  | Root r ->
    assert (r.child == oldchild);
    r.child <- newchild
  | Node n when n.left == oldchild ->
    n.left <- newchild
  | Node n when n.right == oldchild ->
    n.right <- newchild
  | Leaf | Node _ -> assert false

let make_node set ~left ~right ~parent =
  let binding = match set with
    | None -> Unbound
    | Some value -> Bound { value ; valid = true }
  in
  let node = Node { left; right; parent; version = 0; size = 0; binding } in
  set_parent left  ~parent:node;
  set_parent right ~parent:node;
  node

let rec raw_invalidate = function
  | Node { size = 0; _ } -> ()
  | Node t ->
    t.size <- 0;
    raw_invalidate t.parent
  | Root r ->
    List.iter Lwd.invalidate r.on_invalidate
  | Leaf -> assert false

let prepend ?set = function
  | Root r as parent ->
    raw_invalidate parent;
    let node = make_node set ~left:Leaf ~right:r.child ~parent in
    r.child <- node;
    node
  | Leaf | Node _ -> assert false

let prepend' x set = ignore (prepend x ~set)

let append ?set = function
  | Root r as parent ->
    raw_invalidate parent;
    let node = make_node set ~left:r.child ~right:Leaf ~parent in
    r.child <- node;
    node
  | Leaf | Node _ -> assert false

let append' x set = ignore (append x ~set)

let before ?set = function
  | Node { parent = Leaf ; _ } | Leaf -> Leaf
  | Node n as parent ->
    raw_invalidate parent;
    let node = make_node set ~left:n.left ~right:Leaf ~parent in
    n.left <- node;
    node
  | Root _ -> assert false

let after ?set = function
  | Node { parent = Leaf ; _ } | Leaf -> Leaf
  | Node n as parent ->
    raw_invalidate parent;
    let node = make_node set ~left:Leaf ~right:n.right ~parent in
    n.right <- node;
    node
  | Root _ -> assert false

let get = function
  | Node { binding = Bound { value ; _ } ; _ } -> Some value
  | Leaf | Root _ | Node { binding = Unbound ; _ } -> None

let invalidate_binding = function
  | Unbound -> ()
  | Bound b -> b.valid <- false

let set_binding x = function
  | Root _ -> assert false
  | Leaf | Node { parent = Leaf; _ } -> ()
  | Node n as t ->
    raw_invalidate t;
    invalidate_binding n.binding;
    n.binding <- x

let set t value = set_binding (Bound { value; valid = true }) t
let unset t = set_binding Unbound t

let is_bound = function
  | Leaf | Node { parent = Leaf; _ } -> false
  | Root _ | Node _ -> true

let rec join left = function
  | Root _ | Leaf -> assert false
  | Node ({ left = Leaf; _ } as n) as self ->
    n.left <- left;
    set_parent left ~parent:self;
    self
  | Node node ->
    join left node.left

let remove = function
  | Root _ | Leaf | Node {parent = Leaf; _} -> ()
  | Node ({left; right; parent; _} as n) as t ->
    invalidate_binding n.binding;
    n.left <- Leaf;
    n.right <- Leaf;
    n.parent <- Leaf;
    n.binding <- Unbound;
    n.version <- max_int;
    let join, invalid = match left, right with
      | Leaf, other | other, Leaf -> (other, parent)
      | _ -> (right, join left right)
    in
    reparent ~parent ~oldchild:t ~newchild:join;
    set_parent join ~parent;
    raw_invalidate invalid

let rec clear = function
  | Leaf -> ()
  | Node ({left; right; _} as n) ->
    invalidate_binding n.binding;
    n.left <- Leaf;
    n.right <- Leaf;
    n.parent <- Leaf;
    n.binding <- Unbound;
    n.version <- max_int;
    clear left;
    clear right
  | Root r as root ->
    let child = r.child in
    r.child <- Leaf;
    clear child;
    raw_invalidate root

(* Tree balancing *)

let size = function
  | Node node ->
    assert (node.size <> 0);
    node.size
  | Leaf -> 0
  | Root _ -> assert false

(** [smaller_ell smin smax] iff
    - [smin] is less than [smax]
    - [smin] and [smax] differs by less than two magnitude orders, i.e
      msbs(smin) >= msbs(smax) - 1
      where msbs is the index of the most significant bit set *)
let smaller_ell smin smax = (smin < smax) && ((smin land smax) lsl 1 < smax)

(** [disbalanced smin smax] check if two sub-trees of size [smin] and [smax],
    are disbalanczed. That is, msbs(smin) < msbs(smax) - 1 *)
let disbalanced smin smax = smaller_ell smin (smax lsr 1)

let reparent ~parent ~oldchild ~newchild =
  match parent with
  | Root r ->
    assert (r.child == oldchild);
    r.child <- newchild;
  | Node n when n.left == oldchild ->
    n.left <- newchild
  | Node n when n.right == oldchild ->
    n.right <- newchild
  | Leaf | Node _ -> assert false

let rec rot_left version = function
  | Node ({ right = (Node rn) as r; _} as sn) as s ->
    let parent = sn.parent in
    let rl = match rn.left with
      | Root _ -> assert false
      | Leaf -> Leaf
      | (Node rln) as rl ->
        rln.parent <- s;
        rl
    in
    rn.left <- s;
    sn.right <- rl;
    sn.parent <- r;
    rn.parent <- parent;
    reparent ~parent ~oldchild:s ~newchild:r;
    ignore (balance version s);
    balance version r
  | _ -> assert false

and rot_right version = function
  | Node ({ left = (Node ln) as l; _} as sn) as s ->
    let parent = sn.parent in
    let lr = match ln.right with
      | Root _ -> assert false
      | Leaf -> Leaf
      | (Node lrn) as lr ->
        lrn.parent <- s;
        lr
    in
    ln.right <- s;
    sn.left <- lr;
    sn.parent <- l;
    ln.parent <- parent;
    reparent ~parent ~oldchild:s ~newchild:l;
    ignore (balance version s);
    balance version l
  | _ -> assert false

and inc_left version = function
  | Root _ | Leaf -> assert false
  | Node {right; _} as self ->
    begin match right with
      | Node rn when smaller_ell (size rn.right) (size rn.left) ->
        ignore (rot_right version right)
      | _ -> ()
    end;
    rot_left version self

and inc_right version = function
  | Root _ | Leaf -> assert false
  | Node {left; _} as self ->
    begin match left with
      | Node ln when smaller_ell (size ln.left) (size ln.right) ->
        ignore (rot_left version left)
      | _ -> ()
    end;
    rot_right version self

and balance version = function
  | Root _ | Leaf -> assert false
  | Node node as self ->
    let sl = size node.left and sr = size node.right in
    if sl < sr then (
      if disbalanced sl sr
      then inc_left version self
      else (node.version <- version; node.size <- 1 + sl + sr; self)
    ) else (
      if disbalanced sr sl
      then inc_right version self
      else (node.version <- version; node.size <- 1 + sl + sr; self)
    )

let rec _compute_sub_size1 version = function
  | Root _ -> ()
  | Leaf -> ()
  | Node node as self ->
    if node.size = 0 then begin
      _compute_sub_size1 version node.left;
      _compute_sub_size1 version node.right;
      ignore (balance version self)
    end

let compute_sub_size = _compute_sub_size1

let rec reset_version version = function
  | Leaf -> ()
  | Node n ->
    n.version <- version;
    reset_version version n.left;
    reset_version version n.right
  | Root _ -> assert false

let rebalance = function
  | Root r ->
    begin match r.child with
      | Node { size = 0; _ } ->
        let version = succ r.version in
        let version =
          if version = max_int then (
            r.generation <- ref ();
            reset_version 0 r.child;
            0
          )
          else version
        in
        r.version <- version;
        compute_sub_size version r.child;
        version
      | Node _ | Leaf -> r.version
      | Root _ -> assert false
    end
  | _ -> assert false

let plus (zero, plus) x y =
  if x == zero then y
  else if y == zero then x
  else plus x y

type ('a, 'b) reduction_tree =
  | Red_leaf
  | Red_node of {
      cell: 'a row;
      binding: 'a binding;
      reduction: 'b;
      aggregate: 'b;
      left : ('a, 'b) reduction_tree;
      right : ('a, 'b) reduction_tree;
    }

type ('a, 'b) reduction = {
  mutable version: int;
  source: 'a tree;
  mutable result : ('a, 'b) reduction_tree;
  mutable generation: unit ref;
  mapper: 'a row -> 'a -> 'b;
  monoid: 'b Lwd_utils.monoid;
}


let extract_bindings tree =
  let rec aux acc = function
    | Red_leaf -> acc
    | Red_node rnode ->
      let acc = aux acc rnode.right in
      let acc = match rnode.binding with
        | Unbound -> acc
        | Bound { valid = false; _ } -> acc
        | _ -> (rnode.binding, rnode.reduction) :: acc
      in
      aux acc rnode.left
  in
  aux [] tree

let full_rebuild red tree =
  let bindings = ref (extract_bindings red.result) in
  let rec aux = function
    | Node node as cell ->
      let left = aux node.left in
      let reduction =
        match node.binding, !bindings with
        | Unbound, _ -> fst red.monoid
        | binding, ((binding', reduction) :: bindings')
          when binding == binding' ->
          bindings := bindings';
          reduction
        | Bound b, _ -> assert b.valid; red.mapper cell b.value
      in
      let right = aux node.right in
      let aggregate = match left with
        | Red_leaf -> reduction
        | Red_node r -> plus red.monoid r.aggregate reduction
      in
      let aggregate = match right with
        | Red_leaf -> aggregate
        | Red_node r -> plus red.monoid aggregate r.aggregate
      in
      Red_node {
        cell;
        binding = node.binding;
        reduction;
        aggregate;
        left;
        right;
      }
    | Leaf -> Red_leaf
    | Root _ -> assert false
  in
  let result = aux tree in
  assert (!bindings = []);
  result

let extract_fringe version tree =
  let rec aux acc = function
    | Red_leaf -> acc
    | Red_node rnode as tree ->
      match rnode.cell with
      | Node node when node.version <= version -> tree :: acc
      | _ ->
        let acc = aux acc rnode.right in
        let acc = match rnode.binding with
          | Unbound -> acc
          | Bound { valid = false; _ } -> acc
          | _ -> tree :: acc
        in
        aux acc rnode.left
  in
  aux [] tree

let incremental_rebuild red version tree =
  let fringe = ref (extract_fringe version red.result) in
  let rec aux = function
    | Node node as cell when node.version <= version ->
      begin match !fringe with
        | (Red_node rnode as reduction) :: fringe' ->
          assert (rnode.cell == cell);
          fringe := fringe';
          reduction
        | _ -> assert false
      end
    | Node node as cell ->
      let left = aux node.left in
      let reduction =
        match node.binding, !fringe with
        | Unbound, _ -> fst red.monoid
        | binding, (Red_node rnode :: fringe')
          when binding == rnode.binding ->
          fringe := fringe';
          rnode.reduction
        | Bound b, _ ->
          assert b.valid; red.mapper cell b.value
      in
      let right = aux node.right in
      let aggregate = match left with
        | Red_leaf -> reduction
        | Red_node r -> plus red.monoid r.aggregate reduction
      in
      let aggregate = match right with
        | Red_leaf -> aggregate
        | Red_node r -> plus red.monoid aggregate r.aggregate
      in
      Red_node {
        cell;
        binding = node.binding;
        reduction;
        aggregate;
        left;
        right;
      }
    | Root _ | Leaf -> Red_leaf
  in
  let result = aux tree in
  assert (!fringe = []);
  result

let eval red =
  match red.source with
  | Leaf | Node _ -> assert false
  | Root root ->
    let version = rebalance red.source in
    if true then (
      if red.generation != root.generation then (
        red.generation <- root.generation;
        red.result <- full_rebuild red root.child;
      ) else (
        red.result <- incremental_rebuild red red.version root.child
      );
    ) else (
      red.result <- full_rebuild red root.child;
    );
    red.version <- version;
    match red.result with
    | Red_leaf -> fst red.monoid
    | Red_node r -> r.aggregate

let opaque : 'a Lwd.prim -> Obj.t Lwd.prim = Obj.magic

let map_reduce mapper monoid source =
  let reduction = {
    source; mapper; monoid;
    result = Red_leaf;
    generation = not_origin;
    version = 0;
  } in
  let prim = Lwd.prim
      ~acquire:(fun self ->
          match reduction.source with
          | Leaf | Node _ -> assert false
          | Root root ->
            root.on_invalidate <- opaque self :: root.on_invalidate;
            reduction
        )
      ~release:(fun self reduction ->
          match reduction.source with
          | Leaf | Node _ -> assert false
          | Root root ->
            root.on_invalidate <-
              List.filter ((!=) (opaque self)) root.on_invalidate
        )
  in
  Lwd.map ~f:eval (Lwd.get_prim prim)

let reduce monoid source = map_reduce (fun _ x -> x) monoid source

let rec iter f = function
  | Leaf -> ()
  | Node t ->
    iter f t.left;
    begin match t.binding with
      | Bound x -> f x.value
      | Unbound -> ()
    end;
    iter f t.right
  | Root t ->
    iter f t.child

let rec left_most : 'a row -> 'a row option = function
  | Root _ -> assert false
  | Leaf -> None
  | Node n as self ->
    match left_most n.left with
    | Some _ as x -> x
    | None -> Some self

let rec right_most : 'a row -> 'a row option = function
  | Root _ -> assert false
  | Leaf -> None
  | Node n as self ->
    match right_most n.right with
    | Some _ as x -> x
    | None -> Some self

let first : 'a t -> 'a row option = function
  | Leaf | Node _ -> assert false
  | Root root -> left_most root.child

let last : 'a t -> 'a row option = function
  | Leaf | Node _ -> assert false
  | Root root -> right_most root.child

let next : 'a row -> 'a row option = function
  | Root _ -> assert false
  | Leaf -> None
  | Node n as self ->
    match left_most n.right with
    | Some _ as x -> x
    | None ->
      let rec walk_root self = function
        | Leaf -> assert false
        | Root _ -> None
        | Node n' as parent ->
          if n'.left == self then Some parent else (
            assert (n'.right == self);
            walk_root parent n'.parent
          )
      in
      walk_root self n.parent

let prev : 'a row -> 'a row option = function
  | Root _ -> assert false
  | Leaf -> None
  | Node n as self ->
    match right_most n.left with
    | Some _ as x -> x
    | None ->
      let rec walk_root self = function
        | Leaf -> assert false
        | Root _ -> None
        | Node n' as parent ->
          if n'.right == self then Some parent else (
            assert (n'.left == self);
            walk_root parent n'.parent
          )
      in
      walk_root self n.parent