File: netbuffer.ml

package info (click to toggle)
netstring 0.10.1-3
  • links: PTS
  • area: main
  • in suites: woody
  • size: 1,000 kB
  • ctags: 895
  • sloc: ml: 8,389; xml: 416; makefile: 188; sh: 103
file content (142 lines) | stat: -rw-r--r-- 4,082 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
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
(* $Id: netbuffer.ml,v 1.3 2000/06/25 22:34:43 gerd Exp $
 * ----------------------------------------------------------------------
 *
 *)

type t = 
    { mutable buffer : string;
      mutable length : int;
    }

(* To help the garbage collector:
 * The 'buffer' has a minimum length of 31 bytes. This minimum can still
 * be stored in the minor heap.
 * The 'buffer' has a length which is always near a multiple of two. This
 * limits the number of different bucket sizes, and simplifies reallocation
 * of freed memory.
 *)

(* Optimal string length:
 * Every string takes: 1 word for the header, enough words for the 
 * contents + 1 Null byte (for C compatibility).
 * If the buffer grows, it is best to use a new string length such
 * that the number of words is exactly twice as large as for the previous
 * string.
 * n:              length of the previous string in bytes
 * w:              storage size of the previous string in words
 * n':             length of the new string in bytes
 * w' = 2*w:       storage size of the new string in words
 *
 * w = (n+1) / word_length + 1
 *            [it is assumed that (n+1) is always a multiple of word_length]
 *
 * n' = (2*w - 1) * word_length - 1
 *
 * n' = [2 * ( [n+1] / word_length + 1) - 1] * word_length - 1
 *    = ...
 *    = (2*n + 2) + word_length - 1
 *    = 2 * n + word_length + 1
 *
 * n'+1 is again a multiple of word_length:
 * n'+1 = 2*n + 2 + word_length
 *      = 2*(n+1) + word_length
 *      = a multiple of word_length because n+1 is a multiple of word_length
 *)

let word_length = Sys.word_size / 8       (* in bytes *)

let create n =
  { buffer = String.create (max n 31); length = 0; }

let contents b =
  String.sub b.buffer 0 b.length
    
let sub b ~pos:k ~len:n =
  if k+n > b.length then
    raise (Invalid_argument "Netbuffer.sub");
  String.sub b.buffer k n
    
let unsafe_buffer b =
  b.buffer

let length b =
  b.length

let add_string b s =
  let l = String.length s in
  if l + b.length > String.length b.buffer then begin
    let l' = l + b.length in
    let rec new_size s =
      if s >= l' then s else new_size(2*s + word_length + 1)
    in
    let buffer' = String.create (new_size (String.length b.buffer)) in
    String.blit b.buffer 0 buffer' 0 b.length;
    b.buffer <- buffer'
  end;
  String.blit s 0 b.buffer b.length l;
  b.length <- b.length + l
    
let add_sub_string b s ~pos:k ~len:l =
  if l + b.length > String.length b.buffer then begin
    let l' = l + b.length in
    let rec new_size s =
      if s >= l' then s else new_size(2*s + word_length + 1)
    in
    let buffer' = String.create (new_size (String.length b.buffer)) in
    String.blit b.buffer 0 buffer' 0 b.length;
    b.buffer <- buffer'
  end;
  String.blit s k b.buffer b.length l;
  b.length <- b.length + l
    
let delete b ~pos:k ~len:l =
  (* deletes l bytes at position k in b *)
  let n = String.length b.buffer in
  if k+l <> n & k <> n then
    String.blit b.buffer (k+l) b.buffer k (n-l-k);
  b.length <- b.length - l;
  ()

let try_shrinking b =
  (* If the buffer size decreases drastically, reallocate the buffer *)
  if b.length < (String.length b.buffer / 2) then begin
    let rec new_size s =
      if s >= b.length then s else new_size(2*s + word_length + 1)
    in
    let buffer' = String.create (new_size 31) in
    String.blit b.buffer 0 buffer' 0 b.length;
    b.buffer <- buffer'
  end 

let clear b =
  delete b 0 (b.length)
  
let index_from b k c =
  if k > b.length then
    raise (Invalid_argument "Netbuffer.index_from");
  let p = String.index_from b.buffer k c in
  if p >= b.length then raise Not_found;
  p

let print_buffer b =
  Format.printf
    "<NETBUFFER: %d/%d>"
    b.length
    (String.length b.buffer)
;;

(* ======================================================================
 * History:
 * 
 * $Log: netbuffer.ml,v $
 * Revision 1.3  2000/06/25 22:34:43  gerd
 * 	Added labels to arguments.
 *
 * Revision 1.2  2000/06/24 20:20:33  gerd
 * 	Added the toploop printer.
 *
 * Revision 1.1  2000/04/15 13:07:48  gerd
 * 	Initial revision.
 *
 * 
 *)