]> mj.ucw.cz Git - libucw.git/blob - ucw/fb-grow.c
7d4a8f84237601eba702e2285ec0ebf8d30ba1ad
[libucw.git] / ucw / fb-grow.c
1 /*
2  *      UCW Library -- Fast Buffered I/O on Growing Buffers
3  *
4  *      (c) 2006 Martin Mares <mj@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #include "ucw/lib.h"
11 #include "ucw/fastbuf.h"
12
13 #include <stdio.h>
14 #include <stdlib.h>
15
16 struct fb_gbuf {
17   struct fastbuf fb;
18   byte *last_written;
19 };
20 #define FB_GBUF(f) ((struct fb_gbuf *)(f)->is_fastbuf)
21
22 static int
23 fbgrow_refill(struct fastbuf *b)
24 {
25   if (b->bstop != FB_GBUF(b)->last_written)
26     {
27       /* There was an intervening flush */
28       b->bstop = FB_GBUF(b)->last_written;
29       b->pos = b->bstop - b->buffer;
30       return 1;
31     }
32   /* We are at the end */
33   return 0;
34 }
35
36 static void
37 fbgrow_spout(struct fastbuf *b)
38 {
39   if (b->bptr >= b->bufend)
40     {
41       uns len = b->bufend - b->buffer;
42       b->buffer = xrealloc(b->buffer, 2*len);
43       b->bufend = b->buffer + 2*len;
44       b->bstop = b->buffer;
45       b->bptr = b->buffer + len;
46     }
47 }
48
49 static int
50 fbgrow_seek(struct fastbuf *b, ucw_off_t pos, int whence)
51 {
52   ASSERT(FB_GBUF(b)->last_written);     /* Seeks allowed only in read mode */
53   ucw_off_t len = FB_GBUF(b)->last_written - b->buffer;
54   if (whence == SEEK_END)
55     pos += len;
56   ASSERT(pos >= 0 && pos <= len);
57   b->bptr = b->buffer + pos;
58   b->bstop = FB_GBUF(b)->last_written;
59   b->pos = len;
60   return 1;
61 }
62
63 static void
64 fbgrow_close(struct fastbuf *b)
65 {
66   xfree(b->buffer);
67   xfree(b);
68 }
69
70 struct fastbuf *
71 fbgrow_create(unsigned basic_size)
72 {
73   struct fastbuf *b = xmalloc_zero(sizeof(struct fb_gbuf));
74   b->buffer = xmalloc(basic_size);
75   b->bufend = b->buffer + basic_size;
76   b->bptr = b->bstop = b->buffer;
77   b->name = "<fbgbuf>";
78   b->refill = fbgrow_refill;
79   b->spout = fbgrow_spout;
80   b->seek = fbgrow_seek;
81   b->close = fbgrow_close;
82   b->can_overwrite_buffer = 1;
83   fb_tie(b);
84   return b;
85 }
86
87 void
88 fbgrow_reset(struct fastbuf *b)
89 {
90   b->bptr = b->bstop = b->buffer;
91   b->pos = 0;
92   FB_GBUF(b)->last_written = NULL;
93 }
94
95 void
96 fbgrow_rewind(struct fastbuf *b)
97 {
98   if (!FB_GBUF(b)->last_written)
99     {
100       /* Last operation was a write, so remember the end position */
101       FB_GBUF(b)->last_written = b->bptr;
102     }
103   b->bptr = b->buffer;
104   b->bstop = FB_GBUF(b)->last_written;
105   b->pos = b->bstop - b->buffer;
106 }
107
108 #ifdef TEST
109
110 int main(void)
111 {
112   struct fastbuf *f;
113   uns t;
114
115   f = fbgrow_create(3);
116   for (uns i=0; i<5; i++)
117     {
118       fbgrow_reset(f);
119       bwrite(f, "12345", 5);
120       bwrite(f, "12345", 5);
121       printf("<%d>", (int)btell(f));
122       bflush(f);
123       printf("<%d>", (int)btell(f));
124       fbgrow_rewind(f);
125       printf("<%d>", (int)btell(f));
126       while ((t = bgetc(f)) != ~0U)
127         putchar(t);
128       printf("<%d>", (int)btell(f));
129       fbgrow_rewind(f);
130       bseek(f, -1, SEEK_END);
131       printf("<%d>", (int)btell(f));
132       while ((t = bgetc(f)) != ~0U)
133         putchar(t);
134       printf("<%d>\n", (int)btell(f));
135     }
136   bclose(f);
137   return 0;
138 }
139
140 #endif