1 { Copyright (C) 2005 Bas Steendijk and Peter Green
\r 
   2   For conditions of distribution and use, see copyright notice in zlib_license.txt
\r 
   3   which is included in the package
\r 
   4   ----------------------------------------------------------------------------- }
\r 
  12 {-$define bfifo_assert}
\r 
  15   {$ifdef bfifo_assert}
\r 
  21   bfifo_minallocsize:integer=4096;
\r 
  24   tfifo=class(tobject)
\r 
  27     lastallocsize:integer; //last seen before we freed the buffer
\r 
  28     lastalloccount:integer;
\r 
  31     function getallocsizeforsize(i:integer):integer;
\r 
  35     procedure add(data:pointer;len:integer);
\r 
  36     function get(var resultptr:pointer;len:integer):integer;
\r 
  37     procedure del(len:integer);
\r 
  38     destructor destroy; override;
\r 
  43 function tfifo.getallocsizeforsize(i:integer):integer;
\r 
  47   //get smallest power of two >= i and >= minallocsize
\r 
  49   if (i <= bfifo_minallocsize) then begin
\r 
  50     result := bfifo_minallocsize;
\r 
  55   for a := 1 to 31 do result := result or (i shr a);
\r 
  60 procedure tfifo.add;
\r 
  65   if len <= 0 then exit;
\r 
  67   {$ifdef bfifo_assert}
\r 
  68   if (size < 0) then raise exception.create('tfifo.add: size<0: '+inttostr(size));
\r 
  69   if (allocsize < 0) then raise exception.create('tfifo.add: allocsize<0: '+inttostr(allocsize));
\r 
  70   if assigned(p) and (size = 0) then raise exception.create('tfifo.add: p assigned and size=0');
\r 
  71   if assigned(p) and (allocsize = 0) then raise exception.create('tfifo.add: p assigned and allocsize=0');
\r 
  74   if not assigned(p) then begin
\r 
  75     {$ifdef bfifo_assert}
\r 
  76     if (size > 0) then raise exception.create('tfifo.add: p not assigned and size>0: '+inttostr(size));
\r 
  77     if (allocsize > 0) then raise exception.create('tfifo.add: p not assigned and allocsize>0: '+inttostr(allocsize));
\r 
  80     //no buffer is allocated, allocate big enough one now
\r 
  81     allocsize := getallocsizeforsize(len);
\r 
  83     //reuse the biggest size seen to avoid unnecessary growing of the buffer all the time, but sometimes shrink it
\r 
  84     //so an unnecessary big buffer isn't around forever
\r 
  85     inc(lastalloccount);
\r 
  86     if (lastalloccount and 7 = 0) then lastallocsize := getallocsizeforsize(lastallocsize div 2);
\r 
  88     if allocsize < lastallocsize then allocsize := lastallocsize;
\r 
  90     getmem(p,allocsize);
\r 
  93   end else if (head + len > allocsize) then begin
\r 
  94     //buffer is not big enough to add new data to the end
\r 
  96     if (size + len <= allocsize) then begin
\r 
  97       //it will fit if we move the data in the buffer to the start first
\r 
  98       if (size > 0) then move(pointer(taddrint(p) + tail)^,p^,size);
\r 
  99       //if (size > 0) then move(p[tail],p[0],size);
\r 
 103       allocsize := getallocsizeforsize(size + len);
\r 
 105       getmem(p2,allocsize);
\r 
 106       move(pointer(taddrint(p) + tail)^,p2^,size);
\r 
 114   {$ifdef bfifo_assert}
\r 
 115   if (head + len > allocsize) or (head < 0) then raise exception.create('tfifo.add: allocsize - head < len: '+inttostr(allocsize)+' '+inttostr(head)+' '+inttostr(len));
\r 
 116   if (not assigned(p)) then raise exception.create('tfifo.add: p '+inttostr(size));
\r 
 121   move(data^,pointer(taddrint(p) + head)^,len);
\r 
 125 function tfifo.get;
\r 
 127   if len > size then len := size;
\r 
 128   if len <= 0 then begin
\r 
 134   //return a pointer into the buffer without copying
\r 
 137   resultptr := pointer(taddrint(p) + tail);
\r 
 140 procedure tfifo.del;
\r 
 142   if len <= 0 then exit;
\r 
 144   {$ifdef bfifo_assert}
\r 
 145   if (size < 0) then raise exception.create('tfifo.del: size negative: '+inttostr(size));
\r 
 146   if (head - tail <> size) then raise exception.create('tfifo.del: size head tail: '+inttostr(size)+' '+inttostr(head)+' '+inttostr(tail));
\r 
 147   if (head > allocsize) then raise exception.create('tfifo.del: head allocsize: '+inttostr(head)+' '+inttostr(allocsize));
\r 
 150   if (len > size) then len := size;
\r 
 155   if (size <= 0) then begin
\r 
 156     if (allocsize > lastallocsize) then lastallocsize := allocsize;
\r 
 160     if assigned(p) then freemem(p);
\r 
 165 destructor tfifo.destroy;
\r 
 169   {$ifdef bfifo_assert}
\r 
 170   if assigned(p) then raise exception.create('tfifo.destroy: did not free '+inttostr(size)+' '+inttostr(allocsize));
\r