Source file CCByte_buffer.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
type 'a iter = ('a -> unit) -> unit

type t = {
  mutable bs: bytes;
  mutable len: int;
}

let create ?(cap = 0) () : t =
  let bs =
    if cap = 0 then
      Bytes.unsafe_of_string ""
    else
      Bytes.create cap
  in
  { len = 0; bs }

let[@inline] capacity self : int = Bytes.length self.bs
let[@inline] bytes self = self.bs
let[@inline] length self = self.len
let[@inline] is_empty self = self.len = 0
let[@inline] clear self = self.len <- 0

let grow_cap_ self =
  min Sys.max_string_length
    (let n = capacity self in
     n + (n lsl 1) + 5)

let grow_to_ self newcap =
  if newcap = capacity self then invalid_arg "byte_buf: cannot grow further";
  let newbytes = Bytes.create newcap in
  Bytes.blit self.bs 0 newbytes 0 self.len;
  self.bs <- newbytes

let[@inline never] grow_ self =
  let newcap = grow_cap_ self in
  grow_to_ self newcap

let[@inline never] ensure_cap_grow_ self n =
  (* new capacity, make sure it's at least [grow_cap_] so
     that repeated calls to [ensure_cap] have the amortized complexity *)
  let newcap = max n (grow_cap_ self) in
  grow_to_ self newcap

let[@inline] ensure_cap self n =
  if n > capacity self then ensure_cap_grow_ self n

let[@inline] ensure_free self n =
  if n > capacity self - self.len then ensure_cap_grow_ self (self.len + n)

let[@inline] shrink_to self n = if self.len > n then self.len <- n

let append_buf (self : t) buf : unit =
  let n = Buffer.length buf in
  ensure_cap self (length self + n);
  Buffer.blit buf 0 self.bs self.len n;
  self.len <- self.len + n

let append_subbytes self b off len =
  ensure_cap self (length self + len);
  Bytes.blit b off self.bs self.len len;
  self.len <- self.len + len

let[@inline] append_bytes self b = append_subbytes self b 0 (Bytes.length b)
let[@inline] append_string self s = append_bytes self (Bytes.unsafe_of_string s)

let[@inline] append_substring self s off len =
  append_subbytes self (Bytes.unsafe_of_string s) off len

let[@inline] add_char_unsafe_ self c =
  Bytes.unsafe_set self.bs self.len c;
  self.len <- self.len + 1

let[@inline] add_char self c =
  if self.len = capacity self then grow_ self;
  add_char_unsafe_ self c

let[@inline] unsafe_get self i = Bytes.unsafe_get self.bs i
let[@inline] unsafe_set self i c = Bytes.unsafe_set self.bs i c

let[@inline] get self i =
  if i < 0 || i >= self.len then invalid_arg "Byte_buf.get";
  unsafe_get self i

let[@inline] set self i c =
  if i < 0 || i >= self.len then invalid_arg "Byte_buf.set";
  unsafe_set self i c

let[@inline] contents self = Bytes.sub_string self.bs 0 self.len
let[@inline] contents_bytes self = Bytes.sub self.bs 0 self.len
let[@inline] append_iter self i = i (add_char self)
let[@inline] append_seq self seq = Seq.iter (add_char self) seq
let[@inline] to_slice self = CCByte_slice.create ~len:self.len self.bs

let fold_left f acc self =
  let { bs; len } = self in

  (* capture current content *)
  let acc = ref acc in
  for i = 0 to len do
    acc := f !acc (Bytes.unsafe_get bs i)
  done;
  !acc

let[@inline] iter f self =
  (* capture current content *)
  let { bs; len } = self in
  for i = 0 to len do
    f (Bytes.unsafe_get bs i)
  done

let[@inline] iteri f self =
  let { bs; len } = self in
  for i = 0 to len do
    f i (Bytes.unsafe_get bs i)
  done

let of_seq seq =
  let self = create ~cap:32 () in
  append_seq self seq;
  self

let of_iter iter =
  let self = create ~cap:32 () in
  append_iter self iter;
  self

let to_iter self yield = iter yield self

let to_seq self =
  let { bs; len } = self in
  let rec s i () =
    if i = len then
      Seq.Nil
    else
      Seq.Cons (Bytes.unsafe_get bs i, s (i + 1))
  in
  s 0

(* TODO: unicode operators.*)