2 * UCW Library -- Fast Buffered I/O on itself
4 * (c) 2012 Jan Moskyto Matejka <mq@ucw.cz>
6 * This software may be freely distributed and used according to the terms
7 * of the GNU Lesser General Public License.
11 #include <ucw/clists.h>
12 #include <ucw/fastbuf.h>
13 #include <ucw/mempool.h>
17 #define FB_MULTI_NAME "<multi>"
26 #define FB_MULTI(f) ((struct fb_multi *)(f))
36 fbmulti_subbuf_get_end(struct subbuf *s)
39 bseek(s->fb, 0, SEEK_END);
40 s->end = s->begin + btell(s->fb);
45 fbmulti_subbuf_next(struct fastbuf *f)
47 struct subbuf* next = clist_next(FB_MULTI(f)->subbufs, &FB_MULTI(f)->cur->n);
53 next->begin = FB_MULTI(f)->cur->end;
56 FB_MULTI(f)->cur = next;
61 fbmulti_refill(struct fastbuf *f)
63 if (f->bufend == f->bstop)
64 f->bptr = f->bstop = f->buffer;
65 uns len = bread(FB_MULTI(f)->cur->fb, f->bstop, (f->bufend - f->bstop));
71 // Current buf returned EOF
72 // Update the information on end of this buffer
73 fbmulti_subbuf_get_end(FB_MULTI(f)->cur);
75 // Take the next one if exists
76 if (fbmulti_subbuf_next(f))
77 return fbmulti_refill(f);
83 fbmulti_get_len(struct fastbuf *f)
88 CLIST_FOR_EACH(struct subbuf *, n, *(FB_MULTI(f)->subbufs))
90 n->begin = FB_MULTI(f)->len;
91 fbmulti_subbuf_get_end(n);
92 FB_MULTI(f)->len = n->end;
97 fbmulti_seek(struct fastbuf *f, ucw_off_t pos, int whence)
103 FB_MULTI(f)->cur = clist_head(FB_MULTI(f)->subbufs);
104 FB_MULTI(f)->cur->begin = 0;
106 return fbmulti_seek(f, pos, SEEK_SET);
110 fbmulti_subbuf_get_end(FB_MULTI(f)->cur);
111 if (pos < FB_MULTI(f)->cur->end)
114 if (!fbmulti_subbuf_next(f)) {
115 if (pos == FB_MULTI(f)->cur->end)
118 bthrow(f, "seek", "Seek out of range");
123 bsetpos(FB_MULTI(f)->cur->fb, (pos - FB_MULTI(f)->cur->begin));
125 f->bptr = f->bstop = f->buffer;
131 return fbmulti_seek(f, FB_MULTI(f)->len+pos, SEEK_SET);
140 fbmulti_update_capability(struct fastbuf *f) {
141 // FB Multi is only a proxy to other fastbufs ... if any of them lacks
142 // support of any feature, FB Multi also provides no support of that feature
143 f->refill = fbmulti_refill;
144 f->seek = fbmulti_seek;
146 CLIST_FOR_EACH(struct subbuf *, n, *(FB_MULTI(f)->subbufs)) {
147 ASSERT(n->fb->refill)
155 fbmulti_close(struct fastbuf *f) {
156 CLIST_FOR_EACH(struct subbuf *, n, *(FB_MULTI(f)->subbufs))
160 mp_delete(FB_MULTI(f)->mp);
164 fbmulti_create(uns bufsize, ...)
166 struct mempool *mp = mp_new(bufsize);
167 struct fastbuf *fb_out = mp_alloc(mp, sizeof(struct fb_multi));
168 FB_MULTI(fb_out)->mp = mp;
170 struct fastbuf *fb_in;
171 clist* subbufs = mp_alloc(mp, sizeof(clist));
173 FB_MULTI(fb_out)->subbufs = subbufs;
176 va_start(args, bufsize);
177 while (fb_in = va_arg(args, struct fastbuf *)) {
178 fbmulti_append(fb_out, fb_in, 1);
182 FB_MULTI(fb_out)->cur = clist_head(subbufs);
184 fb_out->buffer = mp_alloc(mp, bufsize);
185 fb_out->bptr = fb_out->bstop = fb_out->buffer;
186 fb_out->bufend = fb_out->buffer + bufsize;
187 fb_out->name = FB_MULTI_NAME;
189 fbmulti_update_capability(fb_out);
190 fb_out->close = fbmulti_close;
196 fbmulti_append(struct fastbuf *f, struct fastbuf *fb, int allow_close) {
197 struct subbuf *sb = mp_alloc(FB_MULTI(f)->mp, sizeof(struct subbuf));
199 sb->allow_close = allow_close;
200 clist_add_tail(FB_MULTI(f)->subbufs, &(sb->n));
203 static void fbmulti_flatten_internal(struct fastbuf *f, clist* c, int allow_close) {
204 CLIST_FOR_EACH(struct subbuf *, n, *c) {
205 if (strcmp(n->fb->name, FB_MULTI_NAME))
206 fbmulti_append(f, n->fb, n->allow_close && allow_close);
208 fbmulti_flatten_internal(f, FB_MULTI(n->fb)->subbufs, allow_close && n->allow_close);
209 if (allow_close && n->allow_close) {
210 FB_MULTI(n->fb)->subbufs = mp_alloc(FB_MULTI(n->fb)->mp, sizeof(clist));
211 clist_init(FB_MULTI(n->fb)->subbufs);
219 fbmulti_flatten(struct fastbuf *f) {
220 if (strcmp(f->name, FB_MULTI_NAME)) {
221 DBG("fbmulti: given fastbuf isn't fbmulti");
225 clist* c = FB_MULTI(f)->subbufs;
226 FB_MULTI(f)->subbufs = mp_alloc(FB_MULTI(f)->mp, sizeof(clist));
227 clist_init(FB_MULTI(f)->subbufs);
229 fbmulti_flatten_internal(f, c, 1);
230 FB_MULTI(f)->cur = clist_head(FB_MULTI(f)->subbufs);
231 f->bptr = f->bstop = f->buffer;
237 int main(int argc, char ** argv)
241 fprintf(stderr, "You must specify a test (r, w, o)\n");
248 char *data[] = { "One\nLine", "Two\nLines", "Th\nreeLi\nnes\n" };
249 struct fastbuf fb[ARRAY_SIZE(data)];
250 for (uns i=0;i<ARRAY_SIZE(data);i++)
251 fbbuf_init_read(&fb[i], data[i], strlen(data[i]), 0);
253 struct fastbuf* f = fbmulti_create(4, &fb[0], &fb[1], &fb[2], NULL);
256 while (bgets(f, buffer, 9))
264 char *data[] = { "Mnl", "ige" };
265 struct fastbuf fb[ARRAY_SIZE(data)];
266 for (uns i=0;i<ARRAY_SIZE(data);i++)
267 fbbuf_init_read(&fb[i], data[i], strlen(data[i]), 0);
269 struct fastbuf* f = fbmulti_create(4, &fb[0], &fb[1], NULL);
271 int pos[] = {0, 3, 1, 4, 2, 5};
273 for (uns i=0;i<ARRAY_SIZE(pos);i++) {
283 char *data = "Insae";
284 struct fastbuf fb[4];
285 fbbuf_init_read(&fb[0], data, 1, 0);
286 fbbuf_init_read(&fb[1], data + 1, 1, 0);
287 fbbuf_init_read(&fb[2], data + 2, 2, 0);
288 fbbuf_init_read(&fb[3], data + 4, 1, 0);
290 struct fastbuf* f = fbmulti_create(8, &fb[0], &fb[1], &fb[2], &fb[1], &fb[3], NULL);
293 while(bgets(f, buffer, 9))
302 char *data[] = { "Nested", "Data", "As", "In", "Real", "Usage", };
303 struct fastbuf fb[ARRAY_SIZE(data)];
304 for (uns i=0;i<ARRAY_SIZE(data);i++)
305 fbbuf_init_read(&fb[i], data[i], strlen(data[i]), 0);
308 fbbuf_init_read(&sp, " ", 1, 0);
311 fbbuf_init_read(&nl, "\n", 1, 0);
313 struct fastbuf *f = fbmulti_create(4,
338 while (bgets(f, buffer, 20))