package apero-core

  1. Overview
  2. Docs

Source file abytes.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
open Identifiers

module Id = NumId.Make(Int64)

type byte = char
type bigstring = (char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t

type buffer = | Bytes of bytes | Bigstr of bigstring | Bufset of t list
and  t = { 
  id : Id.t;
  mutable buffer : buffer;
  mutable offset : int; 
  mutable capacity : int; 
  grow : int;
}

let compare a b = Id.compare a.id b.id 

let equal a b = Id.equal a.id b.id


let from_bigstring ?(grow=0) bs =
  { 
    id = Id.next_id ();
    buffer = Bigstr bs;
    offset = 0;
    capacity = Bigstringaf.length bs;
    grow;
  }

let from_bytes ?(grow=0) bs =
  { 
    id = Id.next_id ();
    buffer = Bytes bs;
    offset = 0;
    capacity = Bytes.length bs;
    grow;
  }

let create_bigstring ?(grow=0) len = from_bigstring ~grow (Bigstringaf.create len)

let create_bytes ?(grow=0) len = from_bytes ~grow (Bytes.create len)

let create ?(grow=0) len = 
  if len < 2048 
  then create_bytes ~grow len
  else create_bigstring ~grow len

let duplicate bs = 
  { 
    id = bs.id;
    buffer = bs.buffer;
    offset = bs.offset;
    capacity = bs.capacity;
    grow = bs.grow;
  }

let capacity bs = bs.capacity

let wrap ?(grow=0) bslist = 
  { 
    id = Id.next_id ();
    buffer = Bufset bslist;
    offset = 0;
    capacity = List.fold_left (fun accu bs -> accu + capacity bs) 0 bslist;
    grow;
  }

let slice from len bs = 
  if from >= 0 && len >= 0 && (from + len) <= bs.capacity  then
    { 
      id = Id.next_id ();
      buffer = bs.buffer;
      offset = bs.offset + from;
      capacity = len;
      grow = 0;
    }
  else raise @@ Atypes.Exception (`OutOfBounds (`Msg (
    Printf.sprintf "Abytes.slice")))

let expand n bs = 
  match bs.buffer with 
  | Bytes _ -> 
    let hd = duplicate bs in 
    bs.buffer <- Bufset [hd; create_bytes n];
    bs.capacity <- bs.capacity + n
  | Bigstr _ -> 
    let hd = duplicate bs in 
    bs.buffer <- Bufset [hd; create_bigstring n];
    bs.capacity <- bs.capacity + n
  | Bufset b -> 
    bs.buffer <- Bufset (List.append b [create n]);
    bs.capacity <- bs.capacity + n


let rec blit_from_bytes ~src ~src_idx ~dst ~dst_idx ~len = 
  if src_idx >= 0 && len >= 0 && src_idx + len <= Bytes.length src && dst_idx >= 0 
  then 
    if dst_idx + len <= capacity dst 
    then
      let dst_idx = (dst.offset + dst_idx) in
      match dst.buffer with 
      | Bytes b -> (Bytes.blit src src_idx b dst_idx len)
      | Bigstr b -> (Bigstringaf.blit_from_bytes src ~src_off:src_idx b ~dst_off:dst_idx ~len)
      | Bufset b -> 
        let rec blit_from_bytes_to_set ~src ~src_idx ~dst ~dst_idx ~len = 
          match dst with 
          | [] -> ()
          | hd :: tl -> 
            if capacity hd > dst_idx 
            then 
              let hd_writable = capacity hd - dst_idx in 
              if hd_writable >= len
              then blit_from_bytes ~src ~src_idx ~dst:hd ~dst_idx ~len
              else 
                begin 
                  blit_from_bytes ~src ~src_idx ~dst:hd ~dst_idx ~len:hd_writable ;                   
                  blit_from_bytes_to_set ~src ~src_idx:(src_idx + hd_writable) ~dst:tl ~dst_idx:0 ~len:(len - hd_writable)
                end
            else 
              blit_from_bytes_to_set ~src ~src_idx ~dst:tl ~dst_idx:(dst_idx - capacity hd) ~len
        in 
        blit_from_bytes_to_set ~src ~src_idx ~dst:b ~dst_idx ~len
    else
      match dst.grow with 
      | 0 -> raise @@ Atypes.Exception (`OutOfBounds (`Msg "Abytes.blit_from_bytes"))
      | n -> expand n dst; blit_from_bytes ~src ~src_idx ~dst ~dst_idx ~len
  else raise @@ Atypes.Exception (`OutOfBounds (`Msg "Abytes.blit_from_bytes"))
  
let rec blit_to_bytes ~src ~src_idx ~dst ~dst_idx ~len = 
  if src_idx >= 0 && len >= 0 && src_idx + len <= capacity src 
  then
    let src_idx = (src.offset + src_idx) in
    match src.buffer with 
    | Bytes b -> (Bytes.blit b src_idx dst dst_idx len)
    | Bigstr b -> (Bigstringaf.blit_to_bytes b ~src_off:src_idx dst ~dst_off:dst_idx ~len)
    | Bufset b -> 
      let rec blit_set_to_bytes ~src ~src_idx ~dst ~dst_idx ~len = 
        match src with 
        | [] ->  ()
        | hd :: tl -> 
          if capacity hd > src_idx 
          then 
            let hd_readable = capacity hd - src_idx in
            if hd_readable >= len
            then blit_to_bytes ~src:hd ~src_idx ~dst ~dst_idx ~len
            else 
              begin 
                blit_to_bytes ~src:hd ~src_idx ~dst ~dst_idx ~len:hd_readable ;
                blit_set_to_bytes ~src:tl ~src_idx:0 ~dst ~dst_idx:(dst_idx + hd_readable) ~len:(len - hd_readable)
              end               
          else 
            blit_set_to_bytes ~src:tl ~src_idx:(src_idx - capacity hd) ~dst ~dst_idx ~len
      in 
      blit_set_to_bytes ~src:b ~src_idx ~dst ~dst_idx ~len
  else 
    raise @@ Atypes.Exception (`OutOfBounds (`Msg "Abytes.blit_to_bytes")) 

let rec blit_from_bigstring ~src ~src_idx ~dst ~dst_idx ~len = 
  if src_idx >= 0 && len >= 0 && src_idx + len <= Bigstringaf.length src && dst_idx >= 0 
  then 
    if dst_idx + len <= capacity dst 
    then
      let dst_idx = (dst.offset + dst_idx) in
      match dst.buffer with 
      | Bytes b -> (Bigstringaf.blit_to_bytes src ~src_off:src_idx b ~dst_off:dst_idx ~len)
      | Bigstr b -> (Bigstringaf.blit src ~src_off:src_idx b ~dst_off:dst_idx ~len)
      | Bufset b -> 
        let rec blit_from_bigstring_to_set ~src ~src_idx ~dst ~dst_idx ~len = 
          match dst with 
          | [] -> ()
          | hd :: tl -> 
            if capacity hd > dst_idx 
            then 
              let hd_writable = capacity hd - dst_idx in 
              if hd_writable >= len
              then blit_from_bigstring ~src ~src_idx ~dst:hd ~dst_idx ~len
              else 
                begin 
                  blit_from_bigstring ~src ~src_idx ~dst:hd ~dst_idx ~len:hd_writable ;
                  blit_from_bigstring_to_set ~src ~src_idx:(src_idx + hd_writable) ~dst:tl ~dst_idx:0 ~len:(len - hd_writable)
                end
            else 
              blit_from_bigstring_to_set ~src ~src_idx ~dst:tl ~dst_idx:(dst_idx - capacity hd) ~len
        in 
        blit_from_bigstring_to_set ~src ~src_idx ~dst:b ~dst_idx ~len
    else
      match dst.grow with 
      | 0 -> raise @@ Atypes.Exception (`OutOfBounds (`Msg "Abytes.blit_from_bigstring"))
      | n -> expand n dst; blit_from_bigstring ~src ~src_idx ~dst ~dst_idx ~len
  else 
    raise @@ Atypes.Exception (`OutOfBounds (`Msg "Abytes.blit_from_bigstring"))
  
let rec blit_to_bigstring ~src ~src_idx ~dst ~dst_idx ~len = 
  if src_idx >= 0 && len >= 0 && src_idx + len <= capacity src 
  then
    let src_idx = (src.offset + src_idx) in
    match src.buffer with 
    | Bytes b -> (Bigstringaf.blit_from_bytes b ~src_off:src_idx dst ~dst_off:dst_idx ~len)
    | Bigstr b -> (Bigstringaf.blit b ~src_off:src_idx dst ~dst_off:dst_idx ~len)
    | Bufset b -> 
      let rec blit_set_to_bigstring ~src ~src_idx ~dst ~dst_idx ~len = 
        match src with 
        | [] -> ()
        | hd :: tl -> 
          if capacity hd > src_idx 
          then 
            let hd_readable = capacity hd - src_idx in
            if hd_readable >= len
            then blit_to_bigstring ~src:hd ~src_idx ~dst ~dst_idx ~len:len
            else
              begin 
                blit_to_bigstring ~src:hd ~src_idx ~dst ~dst_idx ~len:hd_readable ;
                blit_set_to_bigstring ~src:tl ~src_idx:0 ~dst ~dst_idx:(dst_idx + hd_readable) ~len:(len - hd_readable)
              end
          else 
            blit_set_to_bigstring ~src:tl ~src_idx:(src_idx - capacity hd) ~dst ~dst_idx ~len
      in 
      blit_set_to_bigstring ~src:b ~src_idx ~dst ~dst_idx ~len
  else 
    raise @@ Atypes.Exception (`OutOfBounds (`Msg "Abytes.blit_to_bigstring")) 

let rec blit ~src ~src_idx ~dst ~dst_idx ~len = 
  if src_idx >= 0 && len >= 0 && src_idx + len <= capacity src && dst_idx >= 0 
  then 
    let src_idx = (src.offset + src_idx) in
    if dst_idx + len <= capacity dst 
    then
      match src.buffer with 
      | Bytes b -> blit_from_bytes ~src:b ~src_idx ~dst ~dst_idx ~len
      | Bigstr b -> blit_from_bigstring ~src:b ~src_idx ~dst ~dst_idx ~len
      | Bufset b -> 
        let rec blit_fromto_set ~src ~src_idx ~dst ~dst_idx ~len = 
          match src with 
          | [] -> ()
          | hd :: tl -> 
            if capacity hd > src_idx 
            then 
              let hd_readable = capacity hd - src_idx in
              if hd_readable >= len
              then blit ~src:hd ~src_idx ~dst ~dst_idx ~len:len
              else 
                begin 
                  blit ~src:hd ~src_idx ~dst ~dst_idx ~len:hd_readable ;                
                  blit_fromto_set ~src:tl ~src_idx:0 ~dst ~dst_idx:(dst_idx + hd_readable) ~len:(len - hd_readable)
                end
            else 
              blit_fromto_set ~src:tl ~src_idx:(src_idx - capacity hd) ~dst ~dst_idx ~len
        in
        blit_fromto_set ~src:b ~src_idx ~dst ~dst_idx ~len
    else
      match dst.grow with 
      | 0 -> raise @@ Atypes.Exception (`OutOfBounds (`Msg "Abytes.blit"))
      | n -> expand n dst; blit ~src ~src_idx ~dst ~dst_idx ~len
  else raise @@ Atypes.Exception (`OutOfBounds (`Msg "Abytes.blit"))


let rec get_byte ~at bs =
  if at >= 0 && at + 1 <= capacity bs then
    begin
      let at = bs.offset + at in
      (match bs.buffer with 
      | Bytes b -> (Bytes.get b at)
      | Bigstr b -> (Bigstringaf.get b at)
      | Bufset b -> 
        let rec get_byte_from_set at set = 
          match set with 
          | [] -> raise @@ Atypes.Exception (`OutOfBounds (`Msg "Abytes.get_byte"))
          | hd :: tl -> 
            if capacity hd > at 
            then get_byte ~at hd
            else get_byte_from_set (at - capacity hd) tl in 
        get_byte_from_set at b)
    end
  else 
    raise @@ Atypes.Exception (`OutOfBounds (`Msg "Abytes.get_byte"))

let get_bytes ~at len bs = 
  let dst = Bytes.create len in
  blit_to_bytes ~src:bs ~src_idx:at ~dst ~dst_idx:0 ~len ;
  dst 

let get_bigstring ~at len bs = 
  let dst = Bigstringaf.create len in
  blit_to_bigstring ~src:bs ~src_idx:at ~dst ~dst_idx:0 ~len ; dst 

let get_abytes ~at len bs = 
  let dst = create len in
  blit ~src:bs ~src_idx:at ~dst ~dst_idx:0 ~len ; dst 


let rec set_byte c ~at bs = 
  if at >= 0 then 
    begin
      if at + 1 <= capacity bs then
        begin
          match bs.buffer with 
          | Bytes b -> Bytes.set b (bs.offset + at) c
          | Bigstr b -> Bigstringaf.set b (bs.offset + at) c
          | Bufset b -> 
            let rec set_byte_to_set at set = 
              match set with 
              | [] -> raise @@ Atypes.Exception (`OutOfBounds (`Msg "Abytes.set_byte"))
              | hd :: tl -> 
                if capacity hd > at 
                then set_byte c ~at hd
                else set_byte_to_set (at - capacity hd) tl in 
            set_byte_to_set at b
        end
      else
        match bs.grow with 
        | 0 -> raise @@ Atypes.Exception (`OutOfBounds (`Msg "Abytes.set_byte"))
        | n -> expand n bs; set_byte ~at c bs
    end
  else raise @@ Atypes.Exception (`OutOfBounds (`Msg "Abytes.set_byte"))

let set_bytes src ~at bs = 
  blit_from_bytes ~src ~src_idx:0 ~dst:bs ~dst_idx:at ~len:(Bytes.length src)

let set_bigstring src ~at bs = 
  blit_from_bigstring ~src ~src_idx:0 ~dst:bs ~dst_idx:at ~len:(Bigstringaf.length src)

let set_abytes src ~at bs = 
  blit ~src ~src_idx:0 ~dst:bs ~dst_idx:at ~len:(capacity src) 

let rec to_io_vecs ~idx ~len ~append_bytes ~append_bigarray io_vecs bs = 
  if capacity bs >= idx + len 
  then 
    let idx = bs.offset + idx in
    match bs.buffer with 
    | Bytes b -> append_bytes io_vecs b idx len 
    | Bigstr b -> append_bigarray io_vecs b idx len 
    | Bufset b -> 
      let rec set_to_io_vecs ~idx ~len ~append_bytes ~append_bigarray io_vecs b = match b with 
      | [] -> ()
      | hd :: tl -> 
        if capacity hd >= idx
        then 
          let fst_len = min (len) (capacity hd - idx) in
          to_io_vecs ~idx ~len:fst_len  ~append_bytes ~append_bigarray io_vecs hd; 
          set_to_io_vecs ~idx:0 ~len:(len - fst_len) ~append_bytes ~append_bigarray io_vecs tl; 
        else 
          set_to_io_vecs ~idx:(idx - capacity hd) ~len ~append_bytes ~append_bigarray io_vecs tl in 
      set_to_io_vecs  ~idx ~len ~append_bytes ~append_bigarray io_vecs b
  else 
    match bs.grow with 
    | 0 -> raise @@ Atypes.Exception (`OutOfBounds (`Msg "Abytes.to_io_vecs"))
    | n -> expand n bs; to_io_vecs ~idx ~len ~append_bytes ~append_bigarray io_vecs bs
    


let hexdump ?separator:(sep="") bs =
  let rec hexdump bs idx =
    if idx < bs.capacity then 
    (Printf.sprintf "%02x%s" (get_byte ~at:idx bs |> int_of_char ) sep ) ^ (hexdump bs (idx+1))
    else "" in 
  hexdump bs 0
    
let to_string bs =
  "(capacity: " ^ (string_of_int bs.capacity) ^ " content: " ^ (hexdump bs ~separator:":") ^ ")"