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>"
27 #define FB_MULTI(f) ((struct fb_multi *)(f))
31 ucw_off_t begin, end, offset;
36 fbmulti_get_ptrs(struct fastbuf *f)
38 struct subbuf *sb = FB_MULTI(f)->cur;
39 struct fastbuf *ff = sb->fb;
41 f->buffer = ff->buffer;
44 f->bufend = ff->bufend;
45 f->pos = sb->begin + (ff->pos - sb->offset);
49 fbmulti_set_ptrs(struct fastbuf *f)
51 FB_MULTI(f)->cur->fb->bptr = f->bptr;
55 fbmulti_subbuf_next(struct fastbuf *f)
57 struct subbuf *cur = FB_MULTI(f)->cur;
58 struct subbuf *next = clist_next(&FB_MULTI(f)->subbufs, &cur->n);
62 // Get the end of current buf if not known yet.
63 if (!f->seek && !next->begin)
64 next->begin = FB_MULTI(f)->cur->end = f->pos;
66 // Set the beginning of the next buf
75 next->offset = btell(next->fb);
79 FB_MULTI(f)->cur = next;
86 fbmulti_subbuf_prev(struct fastbuf *f)
88 // Called only when seeking, assuming everything seekable
89 struct subbuf *prev = clist_prev(&FB_MULTI(f)->subbufs, &FB_MULTI(f)->cur->n);
92 // Set pos to beginning, flush offset
97 FB_MULTI(f)->cur = prev;
104 fbmulti_refill(struct fastbuf *f)
109 uns len = FB_MULTI(f)->cur->fb->refill(FB_MULTI(f)->cur->fb);
116 // Current buf returned EOF
117 // Take the next one if exists and redo
118 if (fbmulti_subbuf_next(f))
119 return fbmulti_refill(f);
125 fbmulti_seek(struct fastbuf *f, ucw_off_t pos, int whence)
131 if (pos > FB_MULTI(f)->len)
132 bthrow(f, "seek", "Seek out of range");
134 while (pos > FB_MULTI(f)->cur->end) // Moving forward
135 ASSERT(fbmulti_subbuf_next(f));
137 while (pos < FB_MULTI(f)->cur->begin) // Moving backwards
138 ASSERT(fbmulti_subbuf_prev(f));
140 // Now cur is the right buffer.
141 FB_MULTI(f)->cur->fb->seek(FB_MULTI(f)->cur->fb, (pos - FB_MULTI(f)->cur->begin), SEEK_SET);
148 return fbmulti_seek(f, FB_MULTI(f)->len+pos, SEEK_SET);
157 fbmulti_close(struct fastbuf *f)
159 CLIST_FOR_EACH(struct subbuf *, n, FB_MULTI(f)->subbufs)
162 mp_delete(FB_MULTI(f)->mp);
168 struct mempool *mp = mp_new(128);
169 struct fastbuf *fb_out = mp_alloc(mp, sizeof(struct fb_multi));
170 struct fb_multi *fbm = FB_MULTI(fb_out);
175 clist_init(&fbm->subbufs);
177 fb_out->name = FB_MULTI_NAME;
178 fb_out->refill = fbmulti_refill;
179 fb_out->seek = fbmulti_seek;
180 fb_out->close = fbmulti_close;
186 fbmulti_append(struct fastbuf *f, struct fastbuf *fb)
188 struct subbuf *last = clist_tail(&FB_MULTI(f)->subbufs);
190 struct subbuf *sb = mp_alloc(FB_MULTI(f)->mp, sizeof(struct subbuf));
192 clist_add_tail(&FB_MULTI(f)->subbufs, &(sb->n));
200 sb->begin = last ? last->end : 0;
201 bseek(fb, 0, SEEK_END);
202 FB_MULTI(f)->len = sb->end = sb->begin + btell(fb);
211 sb->offset = btell(fb);
218 FB_MULTI(f)->cur = sb;
224 fbmulti_remove(struct fastbuf *f, struct fastbuf *fb)
229 CLIST_FOR_EACH(struct subbuf *, n, FB_MULTI(f)->subbufs)
232 clist_remove(&(n->n));
236 die("Given fastbuf %p not in given fbmulti %p.", fb, f);
239 clist_init(&FB_MULTI(f)->subbufs);
244 int main(int argc, char **argv)
248 fprintf(stderr, "You must specify a test (r, w, o)\n");
255 char *data[] = { "One\nLine", "Two\nLines", "Th\nreeLi\nnes\n" };
256 struct fastbuf fb[ARRAY_SIZE(data)];
257 for (uns i=0;i<ARRAY_SIZE(data);i++)
258 fbbuf_init_read(&fb[i], data[i], strlen(data[i]), 0);
260 struct fastbuf *f = fbmulti_create();
261 fbmulti_append(f, &fb[0]);
262 fbmulti_append(f, &fb[1]);
263 fbmulti_append(f, &fb[2]);
266 while (bgets(f, buffer, 9))
274 char *data[] = { "Mnl", "ige" };
275 struct fastbuf fb[ARRAY_SIZE(data)];
276 for (uns i=0;i<ARRAY_SIZE(data);i++)
277 fbbuf_init_read(&fb[i], data[i], strlen(data[i]), 0);
279 struct fastbuf *f = fbmulti_create();
280 fbmulti_append(f, &fb[0]);
281 fbmulti_append(f, &fb[1]);
283 int pos[] = {0, 3, 1, 4, 2, 5};
285 for (uns i=0;i<ARRAY_SIZE(pos);i++)
296 char *data = "Insae";
297 struct fastbuf fb[4];
298 fbbuf_init_read(&fb[0], data, 1, 0);
299 fbbuf_init_read(&fb[1], data + 1, 1, 0);
300 fbbuf_init_read(&fb[2], data + 2, 2, 0);
301 fbbuf_init_read(&fb[3], data + 4, 1, 0);
303 struct fastbuf *f = fbmulti_create();
304 fbmulti_append(f, &fb[0]);
305 fbmulti_append(f, &fb[1]);
306 fbmulti_append(f, &fb[2]);
307 fbmulti_append(f, &fb[1]);
308 fbmulti_append(f, &fb[3]);
311 while(bgets(f, buffer, 9))
319 char *data[] = { "Nested", "Data", "As", "In", "Real", "Usage", };
320 struct fastbuf fb[ARRAY_SIZE(data)];
321 for (uns i=0;i<ARRAY_SIZE(data);i++)
322 fbbuf_init_read(&fb[i], data[i], strlen(data[i]), 0);
325 fbbuf_init_read(&sp, " ", 1, 0);
328 fbbuf_init_read(&nl, "\n", 1, 0);
330 struct fastbuf *f = fbmulti_create();
333 ff = fbmulti_create();
334 fbmulti_append(ff, &fb[0]);
335 fbmulti_append(ff, &sp);
336 fbmulti_append(ff, &fb[1]);
337 fbmulti_append(f, ff);
338 fbmulti_append(f, &nl);
340 ff = fbmulti_create();
341 fbmulti_append(ff, &fb[2]);
342 fbmulti_append(ff, &sp);
343 fbmulti_append(ff, &fb[3]);
344 fbmulti_append(f, ff);
345 fbmulti_append(f, &nl);
347 ff = fbmulti_create();
348 fbmulti_append(ff, &fb[4]);
349 fbmulti_append(ff, &sp);
350 fbmulti_append(ff, &fb[5]);
351 fbmulti_append(f, ff);
352 fbmulti_append(f, &nl);
355 while (bgets(f, buffer, 20))