File: bigbuffer.ml

package info (click to toggle)
xen-api-libs 0.5.2-3
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 1,940 kB
  • sloc: ml: 13,925; sh: 2,930; ansic: 1,699; makefile: 1,240; python: 83
file content (111 lines) | stat: -rw-r--r-- 3,343 bytes parent folder | download
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
(*
 * Copyright (C) 2006-2009 Citrix Systems Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; version 2.1 only. with the special
 * exception on linking described in file LICENSE.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *)

type t = {
	mutable cells: string option array;
	mutable index: int64;
}

let cell_size = 4096
let default_array_len = 16

let make () = { cells = Array.make default_array_len None; index = 0L }

let length bigbuf = bigbuf.index

let get bigbuf n =
	let array_offset = Int64.to_int (Int64.div n (Int64.of_int cell_size)) in
	let cell_offset = Int64.to_int (Int64.rem n (Int64.of_int cell_size)) in
	match bigbuf.cells.(array_offset) with
	| None -> "".[0]
	| Some buf -> buf.[cell_offset]

let rec append_substring bigbuf s offset len =
	let array_offset = Int64.to_int (Int64.div bigbuf.index (Int64.of_int cell_size)) in
	let cell_offset = Int64.to_int (Int64.rem bigbuf.index (Int64.of_int cell_size)) in

	if Array.length bigbuf.cells <= array_offset then (
		(* we need to reallocate the array *)
		bigbuf.cells <- Array.append bigbuf.cells (Array.make default_array_len None)
	);

	let buf = match bigbuf.cells.(array_offset) with
	| None ->
		let newbuf = String.create cell_size in
		bigbuf.cells.(array_offset) <- Some newbuf;
		newbuf
	| Some buf ->
		buf
		in
	if len + cell_offset <= cell_size then (
		String.blit s offset buf cell_offset len;
		bigbuf.index <- Int64.add bigbuf.index (Int64.of_int len);
	) else (
		let rlen = cell_size - cell_offset in
		String.blit s offset buf cell_offset rlen;
		bigbuf.index <- Int64.add bigbuf.index (Int64.of_int rlen);
		append_substring bigbuf s (offset + rlen) (len - rlen)
	);
	()

let append_string b s = append_substring b s 0 (String.length s)

let to_fct bigbuf f =
	let array_offset = Int64.to_int (Int64.div bigbuf.index (Int64.of_int cell_size)) in
	let cell_offset = Int64.to_int (Int64.rem bigbuf.index (Int64.of_int cell_size)) in

	(* copy all complete cells *)
	for i = 0 to array_offset - 1
	do
		match bigbuf.cells.(i) with
		| None      -> (* should never happen *) ()
		| Some cell -> f cell
	done;

	if(cell_offset > 0) then
	  (* copy last cell *)
	  begin match bigbuf.cells.(array_offset) with
	    | None      -> (* Should never happen (any more) *) ()
	    | Some cell -> f (String.sub cell 0 cell_offset)
	  end


let to_string bigbuf =
	if bigbuf.index > (Int64.of_int Sys.max_string_length) then
		failwith "cannot allocate string big enough";

	let dest = String.create (Int64.to_int bigbuf.index) in
	let destoff = ref 0 in
	to_fct bigbuf (fun s ->
		let len = String.length s in
		String.blit s 0 dest !destoff len;
		destoff := !destoff + len
	);
	dest


let test max =
  let rec inner n =
    if n>max then () else begin
      let bb = make () in
      let s = String.create n in
      append_substring bb s 0 n;
      assert ((to_string bb)=s);
      inner (n+1)
    end
  in 
  inner 0

let to_stream bigbuf outchan =
	to_fct bigbuf (fun s -> output_string outchan s)