]> mj.ucw.cz Git - libucw.git/commitdiff
Fastbuf: fbmulti_flatten + doc
authorJan 'Moskyt' Matejka <mq@ucw.cz>
Wed, 11 Jul 2012 13:01:37 +0000 (15:01 +0200)
committerJan 'Moskyt' Matejka <mq@ucw.cz>
Thu, 19 Jul 2012 13:25:28 +0000 (15:25 +0200)
ucw/fastbuf.h
ucw/fb-multi.c
ucw/fb-multi.t

index aeda6da2e63e451a34d0fa83d9873825f338601a..564593dd16094e9ef32a4506b254042ea955f014 100644 (file)
@@ -488,15 +488,32 @@ static inline void fbatomic_commit(struct fastbuf *b)
  *
  * This backend is seekable iff all of the supplied fastbufs are seekable.
  *
- * Please note that no cleanup of underlying fastbufs is provided.
- *
  * Also, please be aware of direct operations on the underlying buffers. The
- * fbmulti backend doesn't expect it.
+ * fbmulti backend doesn't expect you doing something directly on them.
+ *
+ * You may init a fbmulti by @fbmulti_create(bufsize, fb1, fb2, ..., NULL).
+ * This call returns a fastbuf that concatenates all the given fastbufs.
+ * The last parameter of @fbmulti_create must be NULL.
+ *
+ * By default, if @bclose() is called on fbmulti, all the underlying buffers
+ * get closed recursively.
+ *
+ * You may init a fbmulti by @fbmulti_create(bufsize) with no underlying buffers
+ * and then append the underlying buffers one by one. If allow_close is set to 0,
+ * the fastbuf doesn't get closed at @bclose() and you have to do the cleanup on
+ * yourself.
+ *
+ * If used in some formatter, you'll probably have a large and deep structure
+ * of nested fastbufs. Just before reading from the fbmulti, you may call
+ * @fbmulti_flatten() to flatten the structure. After @fbmulti_flatten(), the
+ * fbmulti is seeked to the beginning, flushed and ready to read the whole buffer.
  *
- * The last parameter must be NULL.
+ * For performance reasons, use @fbmulti_flatten() only once, just before reading.
  ***/
 
 struct fastbuf* fbmulti_create(uns bufsize, ...) SENTINEL_CHECK;
+void fbmulti_append(struct fastbuf *f, struct fastbuf *fa, int allow_close);
+void fbmulti_flatten(struct fastbuf *f);
 
 /*** === Configuring stream parameters [[bconfig]] ***/
 
index 23a45611d5e049e6dc5c6a4a19514ec4735478b9..5b6b12ba3ce651269c91bd873dcce9d799f3ffd7 100644 (file)
@@ -14,6 +14,8 @@
 
 #include <stdio.h>
 
+#define FB_MULTI_NAME "<multi>"
+
 struct fb_multi {
   struct fastbuf fb;
   struct mempool* mp;
@@ -26,6 +28,7 @@ struct fb_multi {
 struct subbuf {
   cnode n;
   ucw_off_t begin, end;
+  int allow_close;
   struct fastbuf* fb;
 };
 #define SUBBUF(f) ((struct subbuf *)(f))
@@ -153,7 +156,8 @@ fbmulti_update_capability(struct fastbuf *f) {
 static void
 fbmulti_close(struct fastbuf *f) {
   CLIST_FOR_EACH(struct subbuf *, n, *(FB_MULTI(f)->subbufs))
-    bclose(n->fb);
+    if (n->allow_close)
+      bclose(n->fb);
 
   mp_delete(FB_MULTI(f)->mp);
 }
@@ -173,9 +177,7 @@ fbmulti_create(uns bufsize, ...)
   va_list args;
   va_start(args, bufsize);
   while (fb_in = va_arg(args, struct fastbuf *)) {
-    struct subbuf *sb = mp_alloc(mp, sizeof(struct subbuf));
-    sb->fb = fb_in;
-    clist_add_tail(subbufs, &(sb->n));
+    fbmulti_append(fb_out, fb_in, 1);
   }
   va_end(args);
 
@@ -184,7 +186,7 @@ fbmulti_create(uns bufsize, ...)
   fb_out->buffer = mp_alloc(mp, bufsize);
   fb_out->bptr = fb_out->bstop = fb_out->buffer;
   fb_out->bufend = fb_out->buffer + bufsize;
-  fb_out->name = "<multi>";
+  fb_out->name = FB_MULTI_NAME;
 
   fbmulti_update_capability(fb_out);
   fb_out->close = fbmulti_close;
@@ -192,6 +194,46 @@ fbmulti_create(uns bufsize, ...)
   return fb_out;
 }
 
+void
+fbmulti_append(struct fastbuf *f, struct fastbuf *fb, int allow_close) {
+  struct subbuf *sb = mp_alloc(FB_MULTI(f)->mp, sizeof(struct subbuf));
+  sb->fb = fb;
+  sb->allow_close = allow_close;
+  clist_add_tail(FB_MULTI(f)->subbufs, &(sb->n));
+}
+
+static void fbmulti_flatten_internal(struct fastbuf *f, clist* c, int allow_close) {
+  CLIST_FOR_EACH(struct subbuf *, n, *c) {
+    if (strcmp(n->fb->name, FB_MULTI_NAME))
+      fbmulti_append(f, n->fb, n->allow_close && allow_close);
+    else {
+      fbmulti_flatten_internal(f, FB_MULTI(n->fb)->subbufs, allow_close && n->allow_close);
+      if (allow_close && n->allow_close) {
+       FB_MULTI(n->fb)->subbufs = mp_alloc(FB_MULTI(n->fb)->mp, sizeof(clist));
+       clist_init(FB_MULTI(n->fb)->subbufs);
+       bclose(n->fb);
+      }
+    }
+  }
+}
+
+void
+fbmulti_flatten(struct fastbuf *f) {
+  if (strcmp(f->name, FB_MULTI_NAME)) {
+    DBG("fbmulti: given fastbuf isn't fbmulti");
+    return;
+  }
+  
+  clist* c = FB_MULTI(f)->subbufs;
+  FB_MULTI(f)->subbufs = mp_alloc(FB_MULTI(f)->mp, sizeof(clist));
+  clist_init(FB_MULTI(f)->subbufs);
+
+  fbmulti_flatten_internal(f, c, 1);
+  FB_MULTI(f)->cur = clist_head(FB_MULTI(f)->subbufs);
+  f->bptr = f->bstop = f->buffer;
+  f->pos = 0;
+}
+
 #ifdef TEST
 
 int main(int argc, char ** argv)
@@ -256,6 +298,7 @@ int main(int argc, char ** argv)
          bclose(f);
          break;
        }
+      case 'f':
       case 'n':
        {
          char *data[] = { "Nested", "Data", "As", "In", "Real", "Usage", };
@@ -290,6 +333,9 @@ int main(int argc, char ** argv)
              &nl,
              NULL);
 
+         if (*argv[1] == 'f')
+           fbmulti_flatten(f);
+
          char buffer[20];
          while (bgets(f, buffer, 20))
            puts(buffer);
index 4946f65f03aa2e674777cc49c0f17332cccf22cc..5ac8bb4cd81347302b9b8f66d14b694621fdaf70 100644 (file)
@@ -21,3 +21,9 @@ Run:  ../obj/ucw/fb-multi-t n
 Out:   Nested Data
        As In
        Real Usage
+
+Name:  Read Nested Flatten
+Run:   ../obj/ucw/fb-multi-t f
+Out:   Nested Data
+       As In
+       Real Usage