]> mj.ucw.cz Git - libucw.git/blobdiff - ucw/fb-grow.c
Merge remote-tracking branch 'origin/master'
[libucw.git] / ucw / fb-grow.c
index e1da0107f4bfadc07118b1620603476819d92037..25f521ec5dc424de32541843848031c41b6f2164 100644 (file)
  *     of the GNU Lesser General Public License.
  */
 
-#include "ucw/lib.h"
-#include "ucw/fastbuf.h"
+#include <ucw/lib.h>
+#include <ucw/fastbuf.h>
+#include <ucw/mempool.h>
 
 #include <stdio.h>
 #include <stdlib.h>
 
 struct fb_gbuf {
   struct fastbuf fb;
-  byte *last_written;
+  struct mempool *mp;
+  byte *end;
 };
-#define FB_GBUF(f) ((struct fb_gbuf *)(f)->is_fastbuf)
+#define FB_GBUF(f) ((struct fb_gbuf *)(f))
 
-static int
-fbgrow_refill(struct fastbuf *b)
+static int fbgrow_refill(struct fastbuf *b)
 {
-  if (b->bstop != FB_GBUF(b)->last_written)
-    {
-      /* There was an intervening flush */
-      b->bstop = FB_GBUF(b)->last_written;
-      b->pos = b->bstop - b->buffer;
-      return 1;
-    }
-  /* We are at the end */
-  return 0;
+  b->bstop = FB_GBUF(b)->end;
+  b->pos = b->bstop - b->buffer;
+  return b->bstop > b->bptr;
 }
 
-static void
-fbgrow_spout(struct fastbuf *b)
+static void fbgrow_spout(struct fastbuf *b)
 {
-  if (b->bptr >= b->bufend)
+  if (b->bptr == b->bufend)
     {
-      uns len = b->bufend - b->buffer;
-      b->buffer = xrealloc(b->buffer, 2*len);
-      b->bufend = b->buffer + 2*len;
-      b->bstop = b->buffer;
-      b->bptr = b->buffer + len;
+      uint len = b->bufend - b->buffer;
+      if (FB_GBUF(b)->mp)
+       {
+         byte *old = b->buffer;
+         b->buffer = mp_alloc(FB_GBUF(b)->mp, 2 * len);
+         memcpy(b->buffer, old, len);
+       }
+      else
+        b->buffer = xrealloc(b->buffer, 2 * len);
+      b->bufend = b->buffer + 2 * len;
+      FB_GBUF(b)->end = b->bptr = b->buffer + len;
     }
+  else if (FB_GBUF(b)->end < b->bptr)
+    FB_GBUF(b)->end = b->bptr;
+  b->bstop = b->buffer;
+  b->pos = 0;
 }
 
-static int
-fbgrow_seek(struct fastbuf *b, ucw_off_t pos, int whence)
+static int fbgrow_seek(struct fastbuf *b, ucw_off_t pos, int whence)
 {
-  ASSERT(FB_GBUF(b)->last_written);    /* Seeks allowed only in read mode */
-  ucw_off_t len = FB_GBUF(b)->last_written - b->buffer;
+  ucw_off_t len = FB_GBUF(b)->end - b->buffer;
   if (whence == SEEK_END)
     pos += len;
-  ASSERT(pos >= 0 && pos <= len);
+  if (pos < 0 || pos > len)
+    bthrow(b, "seek", "Seek out of range");
   b->bptr = b->buffer + pos;
-  b->bstop = FB_GBUF(b)->last_written;
-  b->pos = len;
+  b->bstop = b->buffer;
+  b->pos = 0;
   return 1;
 }
 
-static void
-fbgrow_close(struct fastbuf *b)
+static void fbgrow_close(struct fastbuf *b)
 {
   xfree(b->buffer);
   xfree(b);
 }
 
-struct fastbuf *
-fbgrow_create(unsigned basic_size)
+struct fastbuf *fbgrow_create_mp(struct mempool *mp, uint basic_size)
 {
-  struct fastbuf *b = xmalloc_zero(sizeof(struct fb_gbuf));
-  b->buffer = xmalloc(basic_size);
+  ASSERT(basic_size);
+  struct fastbuf *b;
+  if (mp)
+    {
+      b = mp_alloc_zero(mp, sizeof(struct fb_gbuf));
+      b->buffer = mp_alloc(mp, basic_size);
+      FB_GBUF(b)->mp = mp;
+    }
+  else
+    {
+      b = xmalloc_zero(sizeof(struct fb_gbuf));
+      b->buffer = xmalloc(basic_size);
+      b->close = fbgrow_close;
+    }
   b->bufend = b->buffer + basic_size;
   b->bptr = b->bstop = b->buffer;
   b->name = "<fbgbuf>";
   b->refill = fbgrow_refill;
   b->spout = fbgrow_spout;
   b->seek = fbgrow_seek;
-  b->close = fbgrow_close;
   b->can_overwrite_buffer = 1;
   return b;
 }
 
-void
-fbgrow_reset(struct fastbuf *b)
+struct fastbuf *fbgrow_create(uint basic_size)
 {
-  b->bptr = b->bstop = b->buffer;
+  return fbgrow_create_mp(NULL, basic_size);
+}
+
+void fbgrow_reset(struct fastbuf *b)
+{
+  FB_GBUF(b)->end = b->bptr = b->bstop = b->buffer;
   b->pos = 0;
-  FB_GBUF(b)->last_written = NULL;
 }
 
-void
-fbgrow_rewind(struct fastbuf *b)
+void fbgrow_rewind(struct fastbuf *b)
 {
-  if (!FB_GBUF(b)->last_written)
-    {
-      /* Last operation was a write, so remember the end position */
-      FB_GBUF(b)->last_written = b->bptr;
-    }
-  b->bptr = b->buffer;
-  b->bstop = FB_GBUF(b)->last_written;
-  b->pos = b->bstop - b->buffer;
+  brewind(b);
+}
+
+uint fbgrow_get_buf(struct fastbuf *b, byte **buf)
+{
+  byte *end = FB_GBUF(b)->end;
+  end = MAX(end, b->bptr);
+  if (buf)
+    *buf = b->buffer;
+  return end - b->buffer;
 }
 
 #ifdef TEST
@@ -109,10 +125,10 @@ fbgrow_rewind(struct fastbuf *b)
 int main(void)
 {
   struct fastbuf *f;
-  uns t;
+  uint t;
 
   f = fbgrow_create(3);
-  for (uns i=0; i<5; i++)
+  for (uint i=0; i<5; i++)
     {
       fbgrow_reset(f);
       bwrite(f, "12345", 5);