]> mj.ucw.cz Git - libucw.git/blob - ucw/fb-grow.c
FbGrow: Fixed assertion error after a refill of empty fastbuf.
[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 #include <ucw/mempool.h>
13
14 #include <stdio.h>
15 #include <stdlib.h>
16
17 struct fb_gbuf {
18   struct fastbuf fb;
19   struct mempool *mp;
20   byte *end;
21 };
22 #define FB_GBUF(f) ((struct fb_gbuf *)(f))
23
24 static int fbgrow_refill(struct fastbuf *b)
25 {
26   b->bstop = FB_GBUF(b)->end;
27   b->pos = b->bstop - b->buffer;
28   return b->bstop > b->bptr;
29 }
30
31 static void fbgrow_spout(struct fastbuf *b)
32 {
33   if (b->bptr == b->bufend)
34     {
35       uint len = b->bufend - b->buffer;
36       if (FB_GBUF(b)->mp)
37         {
38           byte *old = b->buffer;
39           b->buffer = mp_alloc(FB_GBUF(b)->mp, 2 * len);
40           memcpy(b->buffer, old, len);
41         }
42       else
43         b->buffer = xrealloc(b->buffer, 2 * len);
44       b->bufend = b->buffer + 2 * len;
45       FB_GBUF(b)->end = b->bptr = b->buffer + len;
46     }
47   else if (FB_GBUF(b)->end < b->bptr)
48     FB_GBUF(b)->end = b->bptr;
49   b->bstop = b->buffer;
50   b->pos = 0;
51 }
52
53 static int fbgrow_seek(struct fastbuf *b, ucw_off_t pos, int whence)
54 {
55   ucw_off_t len = FB_GBUF(b)->end - b->buffer;
56   if (whence == SEEK_END)
57     pos += len;
58   if (pos < 0 || pos > len)
59     bthrow(b, "seek", "Seek out of range");
60   b->bptr = b->buffer + pos;
61   b->bstop = b->buffer;
62   b->pos = 0;
63   return 1;
64 }
65
66 static void fbgrow_close(struct fastbuf *b)
67 {
68   xfree(b->buffer);
69   xfree(b);
70 }
71
72 struct fastbuf *fbgrow_create_mp(struct mempool *mp, uint basic_size)
73 {
74   ASSERT(basic_size);
75   struct fastbuf *b;
76   if (mp)
77     {
78       b = mp_alloc_zero(mp, sizeof(struct fb_gbuf));
79       b->buffer = mp_alloc(mp, basic_size);
80       FB_GBUF(b)->mp = mp;
81     }
82   else
83     {
84       b = xmalloc_zero(sizeof(struct fb_gbuf));
85       b->buffer = xmalloc(basic_size);
86       b->close = fbgrow_close;
87     }
88   b->bufend = b->buffer + basic_size;
89   b->bptr = b->bstop = b->buffer;
90   FB_GBUF(b)->end = b->buffer;
91   b->name = "<fbgbuf>";
92   b->refill = fbgrow_refill;
93   b->spout = fbgrow_spout;
94   b->seek = fbgrow_seek;
95   b->can_overwrite_buffer = 1;
96   return b;
97 }
98
99 struct fastbuf *fbgrow_create(uint basic_size)
100 {
101   return fbgrow_create_mp(NULL, basic_size);
102 }
103
104 void fbgrow_reset(struct fastbuf *b)
105 {
106   FB_GBUF(b)->end = b->bptr = b->bstop = b->buffer;
107   b->pos = 0;
108 }
109
110 void fbgrow_rewind(struct fastbuf *b)
111 {
112   brewind(b);
113 }
114
115 uint fbgrow_get_buf(struct fastbuf *b, byte **buf)
116 {
117   byte *end = FB_GBUF(b)->end;
118   end = MAX(end, b->bptr);
119   if (buf)
120     *buf = b->buffer;
121   return end - b->buffer;
122 }
123
124 #ifdef TEST
125
126 int main(void)
127 {
128   struct fastbuf *f;
129   uint t;
130
131   f = fbgrow_create(3);
132   for (uint i=0; i<5; i++)
133     {
134       fbgrow_reset(f);
135       bwrite(f, "12345", 5);
136       bwrite(f, "12345", 5);
137       printf("<%d>", (int)btell(f));
138       bflush(f);
139       printf("<%d>", (int)btell(f));
140       fbgrow_rewind(f);
141       printf("<%d>", (int)btell(f));
142       while ((t = bgetc(f)) != ~0U)
143         putchar(t);
144       printf("<%d>", (int)btell(f));
145       fbgrow_rewind(f);
146       bseek(f, -1, SEEK_END);
147       printf("<%d>", (int)btell(f));
148       while ((t = bgetc(f)) != ~0U)
149         putchar(t);
150       printf("<%d>\n", (int)btell(f));
151     }
152   bclose(f);
153   return 0;
154 }
155
156 #endif