From: Jan 'Moskyt' Matejka Date: Wed, 11 Jul 2012 13:01:37 +0000 (+0200) Subject: Fastbuf: fbmulti_flatten + doc X-Git-Tag: v5.99~126 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=94e34eacc4086c13f68580e153d727739c17cf9c;p=libucw.git Fastbuf: fbmulti_flatten + doc --- diff --git a/ucw/fastbuf.h b/ucw/fastbuf.h index aeda6da2..564593dd 100644 --- a/ucw/fastbuf.h +++ b/ucw/fastbuf.h @@ -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]] ***/ diff --git a/ucw/fb-multi.c b/ucw/fb-multi.c index 23a45611..5b6b12ba 100644 --- a/ucw/fb-multi.c +++ b/ucw/fb-multi.c @@ -14,6 +14,8 @@ #include +#define FB_MULTI_NAME "" + 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 = ""; + 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); diff --git a/ucw/fb-multi.t b/ucw/fb-multi.t index 4946f65f..5ac8bb4c 100644 --- a/ucw/fb-multi.t +++ b/ucw/fb-multi.t @@ -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