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 = 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
136 int r = fbmulti_subbuf_next(f);
140 while (pos < FB_MULTI(f)->cur->begin) // Moving backwards
142 int r = fbmulti_subbuf_prev(f);
146 // Now cur is the right buffer.
147 FB_MULTI(f)->cur->fb->seek(FB_MULTI(f)->cur->fb, (pos - FB_MULTI(f)->cur->begin), SEEK_SET);
153 return fbmulti_seek(f, FB_MULTI(f)->len + pos, SEEK_SET);
161 fbmulti_close(struct fastbuf *f)
163 CLIST_FOR_EACH(struct subbuf *, n, FB_MULTI(f)->subbufs)
166 mp_delete(FB_MULTI(f)->mp);
172 struct mempool *mp = mp_new(1024);
173 struct fastbuf *fb_out = mp_alloc_zero(mp, sizeof(struct fb_multi));
174 struct fb_multi *fbm = FB_MULTI(fb_out);
179 clist_init(&fbm->subbufs);
181 fb_out->name = FB_MULTI_NAME;
182 fb_out->refill = fbmulti_refill;
183 fb_out->seek = fbmulti_seek;
184 fb_out->close = fbmulti_close;
190 fbmulti_append(struct fastbuf *f, struct fastbuf *fb)
192 struct subbuf *last = clist_tail(&FB_MULTI(f)->subbufs);
194 struct subbuf *sb = mp_alloc(FB_MULTI(f)->mp, sizeof(*sb));
196 clist_add_tail(&FB_MULTI(f)->subbufs, &(sb->n));
204 sb->begin = last ? last->end : 0;
205 bseek(fb, 0, SEEK_END);
206 FB_MULTI(f)->len = sb->end = sb->begin + btell(fb);
215 sb->offset = btell(fb);
222 FB_MULTI(f)->cur = sb;
228 fbmulti_remove(struct fastbuf *f, struct fastbuf *fb)
233 CLIST_FOR_EACH(struct subbuf *, n, FB_MULTI(f)->subbufs)
236 clist_remove(&(n->n));
240 die("Given fastbuf %p not in given fbmulti %p", fb, f);
243 clist_init(&FB_MULTI(f)->subbufs);
248 int main(int argc, char **argv)
252 fprintf(stderr, "You must specify a test (r, m, i, n)\n");
259 char *data[] = { "One\nLine", "Two\nLines", "Th\nreeLi\nnes\n" };
260 struct fastbuf fb[ARRAY_SIZE(data)];
261 for (uns i=0;i<ARRAY_SIZE(data);i++)
262 fbbuf_init_read(&fb[i], data[i], strlen(data[i]), 0);
264 struct fastbuf *f = fbmulti_create();
265 fbmulti_append(f, &fb[0]);
266 fbmulti_append(f, &fb[1]);
267 fbmulti_append(f, &fb[2]);
270 while (bgets(f, buffer, 9))
278 char *data[] = { "Mnl", "ige" };
279 struct fastbuf fb[ARRAY_SIZE(data)];
280 for (uns i=0;i<ARRAY_SIZE(data);i++)
281 fbbuf_init_read(&fb[i], data[i], strlen(data[i]), 0);
283 struct fastbuf *f = fbmulti_create();
284 fbmulti_append(f, &fb[0]);
285 fbmulti_append(f, &fb[1]);
287 int pos[] = {0, 3, 1, 4, 2, 5};
289 for (uns i=0;i<ARRAY_SIZE(pos);i++)
300 char *data = "Insae";
301 struct fastbuf fb[4];
302 fbbuf_init_read(&fb[0], data, 1, 0);
303 fbbuf_init_read(&fb[1], data + 1, 1, 0);
304 fbbuf_init_read(&fb[2], data + 2, 2, 0);
305 fbbuf_init_read(&fb[3], data + 4, 1, 0);
307 struct fastbuf *f = fbmulti_create();
308 fbmulti_append(f, &fb[0]);
309 fbmulti_append(f, &fb[1]);
310 fbmulti_append(f, &fb[2]);
311 fbmulti_append(f, &fb[1]);
312 fbmulti_append(f, &fb[3]);
315 while(bgets(f, buffer, 9))
323 char *data[] = { "Nested", "Data", "As", "In", "Real", "Usage", };
324 struct fastbuf fb[ARRAY_SIZE(data)];
325 for (uns i=0;i<ARRAY_SIZE(data);i++)
326 fbbuf_init_read(&fb[i], data[i], strlen(data[i]), 0);
329 fbbuf_init_read(&sp, " ", 1, 0);
332 fbbuf_init_read(&nl, "\n", 1, 0);
334 struct fastbuf *f = fbmulti_create();
337 ff = fbmulti_create();
338 fbmulti_append(ff, &fb[0]);
339 fbmulti_append(ff, &sp);
340 fbmulti_append(ff, &fb[1]);
341 fbmulti_append(f, ff);
342 fbmulti_append(f, &nl);
344 ff = fbmulti_create();
345 fbmulti_append(ff, &fb[2]);
346 fbmulti_append(ff, &sp);
347 fbmulti_append(ff, &fb[3]);
348 fbmulti_append(f, ff);
349 fbmulti_append(f, &nl);
351 ff = fbmulti_create();
352 fbmulti_append(ff, &fb[4]);
353 fbmulti_append(ff, &sp);
354 fbmulti_append(ff, &fb[5]);
355 fbmulti_append(f, ff);
356 fbmulti_append(f, &nl);
359 while (bgets(f, buffer, 20))