(* $Id$ * ---------------------------------------------------------------------- * *) 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 "" b.length (String.length b.buffer) ;; (* ====================================================================== * History: * * $Log$ * Revision 1.1 2000/11/17 09:57:27 lpadovan * Initial revision * * 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. * * *)