package kot

  1. Overview
  2. Docs

Source file Deque.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
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
(******************************************************************************)
(*                                                                            *)
(*                                     Kot                                    *)
(*                                                                            *)
(*                         Juliette Ponsonnet, ENS Lyon                       *)
(*                         François Pottier, Inria Paris                      *)
(*                                                                            *)
(*       Copyright 2025--2025 Inria. All rights reserved. This file is        *)
(*       distributed under the terms of the GNU Library General Public        *)
(*       License, with an exception, as described in the file LICENSE.        *)
(*                                                                            *)
(******************************************************************************)

(* -------------------------------------------------------------------------- *)

(* As a building block, we need buffers (that is, deques) of capacity 8. *)

module B = struct

  include Buffer8

  (* [iter] is used only by [check], so its efficiency is not critical. *)
  let iter (type a) (f : a -> unit) (b : a buffer) : unit =
    fold_left (fun () x -> f x) () b

  (* [length_is_between] is also used only by [check]. *)
  let length_is_between b min max =
    min <= length b && length b <= max

end

type 'a buffer =
  'a B.buffer

(* -------------------------------------------------------------------------- *)

(* The data structure. *)

(* The reference is a stable reference: every update of this reference
   overwrites a previous 5-tuple with a new 5-tuple that represents the
   same sequence of elements. Thus, even though this data structure
   involves mutable state, it appears immutable to the user. *)

type 'a deque =
  'a nonempty_deque option

and 'a nonempty_deque =
  'a five_tuple ref

and 'a five_tuple = {
  prefix : 'a buffer;
  left   : 'a triple deque;
  middle : 'a buffer;
  right  : 'a triple deque;
  suffix : 'a buffer;
}

and 'a triple = {
  first  : 'a buffer;
  child  : 'a triple deque;
  last   : 'a buffer;
}

type 'a t =
  'a deque

(* -------------------------------------------------------------------------- *)

(* The data structure obeys the following invariant. *)

(* A 5-tuple must obey the following local constraint. *)

let check_five_tuple_local f =
  let { prefix; left; middle; right; suffix } = f in
  if B.is_empty middle then begin
    (* A 5-tuple whose middle buffer is empty is "suffix-only". *)
    assert (B.length_is_between prefix 0 0);
    assert (left = None);
    assert (right = None);
    assert (B.length_is_between suffix 1 8)
  end
  else begin
    assert (B.length_is_between prefix 3 6);
    assert (B.length middle = 2);
    assert (B.length_is_between suffix 3 6);
  end

(* Inside a triple, we say that the buffer [first] or [last] is ordinary
   if its size is 2 or 3. If it is not ordinary then it must be empty. *)

let is_ordinary b =
  B.length_is_between b 2 3

(* A triple must obey the following local constraint. *)

let check_triple_local t =
  let { first; child; last } = t in
  (* The buffer [first] is always ordinary. In the paper, this invariant
     is not imposed when a triple is constructed; instead, it is imposed
     in some places when a triple is inspected (e.g., in cases 1 and 2
     in the description of [pop]). *)
  assert (is_ordinary first);
  (* When [child] is empty, [last] is either ordinary or empty.
     When [child] is nonempty, [last] is ordinary. *)
  match child with
  | None ->
      assert (is_ordinary last || B.is_empty last)
  | Some _ ->
      assert (is_ordinary last)

(* [check_deque] and [check_triple] perform a recursive traversal and
   check that every local constraint holds. *)

let rec check_deque : type a. (a -> unit) -> a deque -> unit = fun check_elem d ->
  match d with
  | None ->
      ()
  | Some r ->
      let f = !r in
      let { prefix; left; middle; right; suffix } = f in
      (* Check each component of this 5-tuple. *)
      B.iter check_elem prefix;
      check_deque (check_triple check_elem) left;
      B.iter check_elem middle;
      check_deque (check_triple check_elem) right;
      B.iter check_elem suffix;
      (* Check the local constraint at this node. *)
      check_five_tuple_local f

and check_triple : type a. (a -> unit) -> a triple -> unit = fun check_elem t ->
  let { first; child; last } = t in
  (* Check each component of this triple. *)
  B.iter check_elem first;
  check_deque (check_triple check_elem) child;
  B.iter check_elem last;
  (* Check the local constraint at this node. *)
  check_triple_local t

(* The main function [check] can be invoked from the outside. *)

let check d =
  check_deque (fun _x -> ()) d

(* [validate d] checks that the deque [d] is valid and returns [d].
   This check takes place only if runtime assertions are enabled. *)

let[@inline] validate d =
  assert (check d; true);
  d

(* -------------------------------------------------------------------------- *)

(* The empty deque is represented by [None], and only by [None]. *)

let empty =
  None

let is_empty =
  Option.is_none

(* A singleton deque is constructed as follows. *)

let singleton x =
  Some (ref {
    prefix = B.empty;
    left = empty;
    middle = B.empty;
    right = empty;
    suffix = B.push x B.empty
  })

(* -------------------------------------------------------------------------- *)

(* [assemble_] and [assemble] construct a deque whose content is the 5-tuple
   [{ prefix; left; middle; right; suffix }].

   [assemble_] does not allow [middle] and [suffix] to be both empty.
   It allocates a new 5-tuple and a new deque.

   [assemble] allows this situation. In this case, this 5-tuple must be
   entirely empty; then, the empty deque is returned. *)

let[@inline] assemble_ prefix left middle right suffix : _ deque =
  assert (not (B.is_empty middle && B.is_empty suffix));
  let f = { prefix; left; middle; right; suffix } in
  (* We cannot call [check_five_tuple_local f] here, because the
     5-tuple [f] might be invalid. The functions [naive_pop] and
     [naive_eject] can temporarily create invalid 5-tuples. *)
  Some (ref f)

let[@inline] assemble prefix left middle right suffix : _ deque =
  if B.is_empty middle && B.is_empty suffix then
    empty
  else
    assemble_ prefix left middle right suffix

(* [triple_] constructs the triple [{ first; child; last }].
   This triple must satisfy the invariant. *)

let[@inline] triple_ first child last : _ triple =
  let t = { first; child; last } in
  assert (check_triple_local t; true);
  t

(* [triple] constructs a triple that is equivalent to the triple
   [{ first; child; last }] and that satisfies the invariant. *)

let[@inline] triple first child last : _ triple =
  if B.is_empty first then
    let () = assert (is_empty child) in
    let first = last
    and last = B.empty in
    triple_ first child last
  else
    triple_ first child last

(* [buffer] converts a nonempty buffer into a triple. *)

let[@inline] buffer (type a) (b : a buffer) : a triple =
  assert (not (B.is_empty b));
  triple_ b empty B.empty

(* -------------------------------------------------------------------------- *)

(* Insertion at the front end. *)

let rec push : type a. a -> a deque -> a deque = fun x c ->
  match c with
  | None ->
      singleton x
  | Some r ->
      let f = !r in
      let { prefix; left; middle; right; suffix } = f in
      if B.is_empty middle then
        if B.has_length_8 suffix then
          let prefix, middle, suffix = B.split8 suffix in
          r := { f with prefix; middle; suffix };
          assemble_ (B.push x prefix) left middle right suffix
        else
          assemble_ B.empty empty B.empty empty (B.push x suffix)
      else
        if B.has_length_6 prefix then
          let prefix, prefix' = B.split642 prefix in
          let left = push (buffer prefix') left in
          r := { f with prefix; left };
          assemble_ (B.push x prefix) left middle right suffix
        else
          assemble_ (B.push x prefix) left middle right suffix

(* Insertion at the rear end. *)

let rec inject : type a. a deque -> a -> a deque = fun c x ->
  match c with
  | None ->
      singleton x
  | Some r ->
      let f = !r in
      let { prefix; left; middle; right; suffix } = f in
      if B.is_empty middle then
        if B.has_length_8 suffix then
          let prefix, middle, suffix = B.split8 suffix in
          r := { f with prefix; middle; suffix };
          assemble_ prefix left middle right (B.inject suffix x)
        else
          assemble_ B.empty empty B.empty empty (B.inject suffix x)
      else
        if B.has_length_6 suffix then
          let suffix', suffix = B.split624 suffix in
          let right = inject right (buffer suffix') in
          r := { f with right; suffix };
          assemble_ prefix left middle right (B.inject suffix x)
        else
          assemble_ prefix left middle right (B.inject suffix x)

(* -------------------------------------------------------------------------- *)

(* Concatenation. *)

let concat d1 d2 =
  match d1, d2 with
  | None, _ ->
      d2
  | _, None ->
      d1
  | Some r1, Some r2 ->
      let { prefix = prefix1; left = left1; middle = middle1;
                            right = right1; suffix = suffix1 } = !r1
      and { prefix = prefix2; left = left2; middle = middle2;
                            right = right2; suffix = suffix2 } = !r2 in
      match B.is_empty middle1, B.is_empty middle2 with
      | false, false ->
          (* Extract the last element of [d1] and the first element of [d2].
             Form a middle buffer with them. *)
          let suffix1, x1 = B.eject suffix1
          and x2, prefix2 = B.pop prefix2 in
          let middle = B.doubleton x1 x2 in
          (* The length of [suffix1] is between 2 and 5. Split it into two
             chunks of length 2 or 3 -- except the second chunk may have
             length 0. *)
          let suffix1a, suffix1b = B.split23l suffix1 in
          (* Inject [middle1], [right1], and [suffix1a], as a triple,
             into [left1]. *)
          let left1 = inject left1 (triple_ middle1 right1 suffix1a) in
          (* Unless it is empty, inject [suffix1b], as a triple,
             into [left1]. *)
          let left1 =
            if B.is_empty suffix1b then left1
            else inject left1 (triple_ suffix1b empty B.empty)
          in
          (* The length of [prefix2] is between 2 and 5. Split it into two
             chunks of length 2 or 3 -- except the first chunk may have
             length 0. *)
          let prefix2a, prefix2b = B.split23r prefix2 in
          (* Push [prefix2b], [left2], and [middle2], as a triple,
             into [right2]. *)
          let right2 = push (triple_ prefix2b left2 middle2) right2 in
          (* Unless it is empty, push [prefix2a], as a triple,
             into [right2]. *)
          let right2 =
            if B.is_empty prefix2a then right2
            else push (triple_ prefix2a empty B.empty) right2
          in
          (* Done. *)
          assemble_ prefix1 left1 middle right2 suffix2
      | _, true ->
          (* [d2] is suffix-only. *)
          B.fold_left inject d1 suffix2
      | true, _ ->
          (* [d1] is suffix-only. *)
          B.fold_right push suffix1 d2

(* -------------------------------------------------------------------------- *)

(* Extraction at the front end (pop). *)

(* [naive_pop_safe f] is a sufficient condition for [naive_pop f]
   to produce a valid deque. (See below.) *)

let[@inline] naive_pop_safe (type a) (f : a five_tuple) : bool =
  let { prefix; middle; _ } = f in
  B.is_empty middle || B.length prefix > 3

(* [naive_pop] expects a 5-tuple [f], extracts its first element [x],
   and returns the remaining elements as a deque [d]. *)

(* There are two distinct scenarios under which [naive_pop] is used.

   In the first scenario, the precondition [naive_pop_safe f] holds.
   Then, [naive_pop f] returns a valid deque.

   In the second scenario, [naive_pop_safe f] does not necessarily
   hold. [naive_pop f] returns a pair [(x, d)] where the deque [d] is
   not necessarily valid. (The root 5-tuple, and only this 5-tuple,
   can violate the local constraint; its prefix buffer can have 2
   elements only.) Then, for every [x'], the operation [push x' d]
   produces a valid deque again. *)

let naive_pop (type a) (f : a five_tuple) : a * a deque =
  let { prefix; left; middle; right; suffix } = f in
  if B.is_empty middle then
    let x, suffix = B.pop suffix in
    x, assemble prefix left middle right suffix
  else
    let x, prefix = B.pop prefix in
    x, assemble_ prefix left middle right suffix

(* [inspect_first f] returns the first element of the 5-tuple [f]. *)

let inspect_first (type a) (f : a five_tuple) : a =
  let { prefix; left; middle; right; suffix } = f in
  if B.is_empty middle then
    (* This 5-tuple is suffix-only. *)
    let () = assert (B.is_empty prefix && left = None && right = None) in
    B.first suffix
  else
    (* This 5-tuple is not suffix-only. Its prefix must be nonempty. *)
    B.first prefix

(* The functions [prepare_pop_case_X] should be studied after reading
   [prepare_pop]. The motivation for [prepare_pop] is apparent in the
   main function, [pop_nonempty]. *)

(* [prepare_pop_case_1 f t left] requires the 5-tuple [f] to have
   a prefix buffer of length 3. Furthermore, it expects the left deque
   of [f] to have been already decomposed into one triple [t] followed
   with a deque [left]. It returns a 5-tuple that is equivalent to [f]
   and that is an acceptable argument for [naive_pop]. *)

(* The pair [t, left] may have been produced either by [naive_pop] or
   by [pop_nonempty]. In the former case, the deque [left] is invalid,
   and must be repaired by a [push] operation. In the code below, the
   [push] operations that (potentially) repair the data structure are
   followed with a call to [validate]. *)

let[@inline] prepare_pop_case_1 (type a)
  (f : a five_tuple) (t : a triple) (left : a triple deque)
: a five_tuple =
  let { prefix; _ } = f in
  assert (B.length prefix = 3);
  let { first; child; last } = t in
  (* The buffer [first] has length 3 or 2.
     This gives rise to two subcases. *)
  assert (is_ordinary first);

  if B.has_length_3 first then
    (* Move one element from [first], towards the left, into [prefix]. *)
    let prefix, first = B.move_left_1_33 prefix first in
    let t = triple_ first child last in
    let left = validate (push t left) in
    { f with prefix; left }

  else
    (* Move all elements from [first], towards the left, into [prefix]. *)
    let prefix = B.concat32 prefix first in
    (* If [child] and [last] are both empty, then we are done. *)
    if is_empty child && B.is_empty last then
      (* Here, because [child] is empty and [first] does not have length 3,
         the deque [left] cannot have been produced by [naive_pop]. Thus,
         no repairing [push] is needed. *)
      let left = validate left in
      { f with prefix; left }
    (* Otherwise, *)
    else
      (* When [child] is nonempty, [last] is nonempty. *)
      (* Therefore, here, [last] must be nonempty. *)
      let t = buffer last in
      let left = validate (push t left) in
      let left = concat child left in
      { f with prefix; left }

(* [prepare_pop_case_2 f t right] is analogous. *)

let[@inline] prepare_pop_case_2 (type a)
  (f : a five_tuple) (t : a triple) (right : a triple deque)
: a five_tuple =
  let { prefix; left; middle; _ } = f in
  assert (B.length prefix = 3);
  assert (is_empty left);
  assert (B.length middle = 2);
  let { first; child; last } = t in
  assert (is_ordinary first);

  if B.has_length_3 first then
    (* Move one element from [first], towards the left, into [middle],
       and one element from [middle], towards the left, into [prefix]. *)
    let prefix, middle, first = B.double_move_left_323 prefix middle first in
    let t = triple_ first child last in
    let right = validate (push t right) in
    { f with prefix; middle; right }

  else
    (* Move all of [middle], towards the left, into [prefix]. *)
    let prefix = B.concat32 prefix middle in
    (* Move [first] towards the left into [middle]. *)
    let middle = first in
    (* The rest is analogous to a similar subcase in [prepare_pop_case_1]. *)
    if is_empty child && B.is_empty last then
      let right = validate right in
      { f with prefix; middle; right }
    else
      let t = buffer last in
      let right = validate (push t right) in
      let right = concat child right in
      { f with prefix; middle; right }

(* [pop_nonempty r] pops an element out of a nonempty deque [r]. *)

let rec pop_nonempty : type a. a nonempty_deque -> a * a deque = fun r ->
  let f = !r in
  (* If [naive_pop] is safe now, then just do it. Otherwise, update
     the data structure so that [naive_pop] is safe, and do it. *)
  if naive_pop_safe f then
    naive_pop f
  else
    let f = prepare_pop f in
    r := f;
    assert (naive_pop_safe f);
    naive_pop f

(* [pop_triple] is used in cases 1 and 2 of [prepare_pop]. It extracts the
   first element out of a nonempty deque (of triples). This element is
   extracted using either [naive_pop] or [pop_nonempty]. *)

and pop_triple : type a. a triple nonempty_deque -> a triple * a triple deque = fun r ->
  let f = !r in
  (* Inspect the first triple in [f]. *)
  let t = inspect_first f in
  (* If this triple satisfies a certain mysterious condition, then extract it
     using [naive_pop]; otherwise extract it using [pop_nonempty]. This use of
     [naive_pop] is not "safe"; it produces a deque whose invariant does not
     necessarily hold. This deque must be repaired by a [push] operation,
     which replaces the triple [t] with a new triple. *)
  (* The reader might wonder why we do not just call [pop_nonempty] always, as
     it is unconditionally safe and functionally equivalent to [naive_pop].
     The answer is, [pop_nonempty] is more expensive than [naive_pop].
     Achieving the desired asymptotic complexity requires care here. *)
  let { first; last; _ } = t in
  if not (B.is_empty last) || B.has_length_3 first then
    naive_pop f
  else
    pop_nonempty r

(* [prepare_pop f] expects a 5-tuple [f] such that [naive_pop_safe f]
   does not hold and returns an equivalent 5-tuple [f'] such that
   [naive_pop_safe f'] holds. *)

and prepare_pop : type a. a five_tuple -> a five_tuple = fun f ->
  assert (not (naive_pop_safe f));
  let { prefix; left; middle; right; suffix } = f in
  assert (B.length prefix = 3);
  assert (B.length middle = 2);
  match left, right with

  | Some left, _ ->
      (* Case 1: [left] is a nonempty deque. *)
      (* Extract one triple [t] out of [left],
         then jump to the function that handles case 1. *)
      let t, left = pop_triple left in
      prepare_pop_case_1 f t left

  | _, Some right ->
      (* Case 2: [left] is empty; [right] is nonempty. *)
      let t, right = pop_triple right in
      prepare_pop_case_2 f t right

  | None, None ->
      (* Case 3: [left] and [right] are empty. *)
      if B.has_length_3 suffix then
        let suffix = B.concat323 prefix middle suffix
        and middle = B.empty
        and prefix = B.empty in
        { f with middle; prefix; suffix }
      else
        (* Move one element from [suffix], towards the left, into [middle],
            and one element from [middle], towards the left, into [prefix]. *)
        let prefix, middle, suffix = B.double_move_left_32x prefix middle suffix in
        { f with prefix; middle; suffix }

(* [pop d] pops an element out of a deque [d]. *)

let pop d =
  match d with
  | None ->
      assert false
  | Some r ->
      pop_nonempty r

let pop_opt d =
  match d with
  | None ->
      None
  | Some r ->
      Some (pop_nonempty r)

(* -------------------------------------------------------------------------- *)

(* Extraction at the rear end (eject). *)

(* This code is largely symmetric with [pop]. One source of asymmetry lies in
   the invariant that we impose on triples: when [child] is empty, the buffer
   [last] is allowed to be empty, but the buffer [first] is not. In [pop],
   this convention is convenient. In [eject], it is inconvenient; we want the
   reverse convention. Thus, we introduce the function [antinormalize], which
   imposes the reverse convention, and we use the smart constructor [triple]
   to go back to the regular convention. *)

let[@inline] antinormalize (type a) (t : a triple) : a triple =
  let { first; child; last } = t in
  if B.is_empty last then
    let () = assert (is_empty child) in
    let first, last = B.empty, first in
    { first; child; last }
  else
    t

(* [naive_eject_safe f] is a sufficient condition for [naive_eject f]
   to produce a valid deque. *)

let[@inline] naive_eject_safe (type a) (f : a five_tuple) : bool =
  let { middle; suffix; _ } = f in
  B.is_empty middle || B.length suffix > 3

(* [naive_eject] expects a 5-tuple [f], extracts its last element [x],
   and returns the preceding elements as a deque [d]. *)

(* Like [naive_pop], [naive_eject] can construct a deque whose root
   5-tuple is invalid. *)

(* Because a suffix buffer is never empty, [naive_eject] is slightly
   simpler than [naive_pop]. *)

let naive_eject (type a) (f : a five_tuple) : a deque * a =
  let { prefix; left; middle; right; suffix } = f in
  let suffix, x = B.eject suffix in
  assemble prefix left middle right suffix, x

(* [inspect_last f] returns the last element of the 5-tuple [f]. *)

let[@inline] inspect_last (type a) (f : a five_tuple) : a =
  B.last f.suffix

(* [eject_nonempty r] ejects an element out of a nonempty deque [r]. *)

let rec eject_nonempty : type a. a nonempty_deque -> a deque * a = fun r ->
  let f = !r in
  if naive_eject_safe f then
    naive_eject f
  else
    let f = prepare_eject f in
    r := f;
    assert (naive_eject_safe f);
    naive_eject f

(* [eject_triple] is used in cases 1 and 2 of [prepare_eject]. It extracts
   the last element out of a nonempty deque (of triples). This element is
   extracted using either [naive_eject] or [eject_nonempty]. *)

(* [eject_triple] returns an antinormalized triple. *)

and eject_triple : type a. a triple nonempty_deque -> a triple deque * a triple = fun r ->
  let f = !r in
  let t = inspect_last f in
  (* We do not antinormalize the triple [t]. This saves an allocation.
     We take this into account in the following test, where the third
     disjunct identifies the case where the buffers [first] and [last]
     have length 0 and 3. (In this disjunct, [child] must be empty.) *)
  let d, t =
    let { first; last; _ } = t in
    if not (B.is_empty last) || B.has_length_3 first
    then
      naive_eject f
    else
      eject_nonempty r
  in
  (* We return an antinormalized triple. *)
  d, antinormalize t

(* [prepare_eject f] expects a 5-tuple [f] such that [naive_eject_safe f]
   does not hold and returns an equivalent 5-tuple [f'] such that
   [naive_eject_safe f'] holds. *)

(* We do not isolate the functions [prepare_eject_case_1]
   and [prepare_eject_case_2], although we could. *)

and prepare_eject : type a. a five_tuple -> a five_tuple = fun f ->
  assert (not (naive_eject_safe f));
  let { prefix; left; middle; right; suffix } = f in
  assert (B.length middle = 2);
  assert (B.length suffix = 3);
  match left, right with

  | _, Some right ->
      (* Case 1: [right] is nonempty. *)
      let right, t = eject_triple right in
      let { first; child; last } = t in
      assert (is_ordinary last);
      if B.has_length_3 last then
        (* Move one element from [last], towards the right, into [suffix]. *)
        let last, suffix = B.move_right_1_33 last suffix in
        let t = triple first child last in
        let right = validate (inject right t) in
        { f with right; suffix }
      else
        (* Move all elements from [last], towards the right, into [suffix]. *)
        let suffix = B.concat23 last suffix in
        if is_empty child && B.is_empty first then
          let right = validate right in
          { f with right; suffix }
        else
          let t = buffer first in
          let right = validate (inject right t) in
          let right = concat right child in
          { f with right; suffix }

  | Some left, None ->
      (* Case 2: [left] is nonempty; [right] is empty. *)
      let left, t = eject_triple left in
      let { first; child; last } = t in
      assert (is_ordinary last);
      if B.has_length_3 last then
        (* Move one element from [last], towards the right, into [middle],
           and one element from [middle], towards the right, into [suffix]. *)
        let last, middle, suffix = B.double_move_right_323 last middle suffix in
        let t = triple first child last in
        let left = validate (inject left t) in
        { f with left; middle; suffix }
      else
        (* Move all of [middle], towards the right, into [suffix]. *)
        let suffix = B.concat23 middle suffix in
        (* Move [last] towards the right into [middle]. *)
        let middle = last in
        if is_empty child && B.is_empty first then
          let left = validate left in
          { f with left; middle; suffix }
        else
          let t = buffer first in
          let left = validate (inject left t) in
          let left = concat left child in
          { f with left; middle; suffix }

  | None, None ->
      (* Case 3: [left] and [right] are empty. *)
      if B.has_length_3 prefix then
        let suffix = B.concat323 prefix middle suffix
        and middle = B.empty
        and prefix = B.empty in
        { f with prefix; middle; suffix }
      else
        (* Move one element from [prefix], towards the right, into [middle],
            and one element from [middle], towards the right, into [suffix]. *)
        let prefix, middle, suffix = B.double_move_right_x23 prefix middle suffix in
        { f with prefix; middle; suffix }

(* [eject d] ejects an element out of a deque [d]. *)

let eject d =
  match d with
  | None ->
      assert false
  | Some r ->
      eject_nonempty r

let eject_opt d =
  match d with
  | None ->
      None
  | Some r ->
      Some (eject_nonempty r)

(* -------------------------------------------------------------------------- *)

(* Map. *)

(* [map] does not preserve sharing: if a reference is reachable via several
   paths in the original deque then [map] creates several distinct copies of
   this reference. In the time complexity analysis, this may at first sight
   appear problematic, as each copy of the reference needs its own copy of
   the reference's potential (time credits). Fortunately, this can be
   achieved by having [map] require [K.n] time credits for a sufficiently
   large constant [K]. This argument relies on the fact that the number of
   references in a deque is at most [n] -- in other words, the number of
   5-tuples in a deque is at most the number of elements. This is true
   because there are no empty 5-tuples. *)

let rec map : type a b. (a -> b) -> a deque -> b deque = fun f d ->
  match d with
  | None ->
      None
  | Some r ->
      let { prefix; left; middle; right; suffix } = !r in
      let prefix = B.map f prefix in
      let left = map (map_triple f) left in
      let middle = B.map f middle in
      let right = map (map_triple f) right in
      let suffix = B.map f suffix in
      Some (ref { prefix; left; middle; right; suffix })

and map_triple : type a b. (a -> b) -> a triple -> b triple = fun f t ->
  let { first; child; last } = t in
  let first = B.map f first in
  let child = map (map_triple f) child in
  let last = B.map f last in
  { first; child; last }

(* -------------------------------------------------------------------------- *)

(* Iteration. *)

let rec fold_left : type a s. (s -> a -> s) -> s -> a deque -> s =
  fun f s d ->
  match d with
  | None ->
      s
  | Some r ->
      let { prefix; left; middle; right; suffix } = !r in
      let s = B.fold_left f s prefix in
      let s = fold_left (fold_left_triple f) s left in
      let s = B.fold_left f s middle in
      let s = fold_left (fold_left_triple f) s right in
      let s = B.fold_left f s suffix in
      s

and fold_left_triple : type a s. (s -> a -> s) -> s -> a triple -> s =
  fun f s t ->
  let { first; child; last } = t in
  let s = B.fold_left f s first in
  let s = fold_left (fold_left_triple f) s child in
  let s = B.fold_left f s last in
  s

let rec fold_right : type a s. (a -> s -> s) -> a deque -> s -> s =
  fun f d s ->
  match d with
  | None ->
      s
  | Some r ->
      let { prefix; left; middle; right; suffix } = !r in
      let s = B.fold_right f suffix s in
      let s = fold_right (fold_right_triple f) right s in
      let s = B.fold_right f middle s in
      let s = fold_right (fold_right_triple f) left s in
      let s = B.fold_right f prefix s in
      s

and fold_right_triple : type a s. (a -> s -> s) -> a triple -> s -> s =
  fun f t s ->
  let { first; child; last } = t in
  let s = B.fold_right f last s in
  let s = fold_right (fold_right_triple f) child s in
  let s = B.fold_right f first s in
  s

(* -------------------------------------------------------------------------- *)

(* Length. *)

let[@inline] length d =
  fold_left (fun s _x -> s + 1) 0 d