]> mj.ucw.cz Git - libucw.git/blob - lib/fastbuf.h
f3a05952c9db60a16021f66da5e1eaf2d9e2badd
[libucw.git] / lib / fastbuf.h
1 /*
2  *      Sherlock Library -- Fast Buffered I/O
3  *
4  *      (c) 1997--2002 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 #ifndef _SHERLOCK_FASTBUF_H
11 #define _SHERLOCK_FASTBUF_H
12
13 #ifndef EOF
14 #include <stdio.h>
15 #endif
16
17 #include <string.h>
18
19 #include "lib/unaligned.h"
20
21 /*
22  *  Generic buffered I/O. You supply hooks to be called for low-level operations
23  *  (swapping of buffers, seeking and closing), we do the rest.
24  *
25  *  Buffer layout when reading:
26  *
27  *  +----------------+---------------------------+
28  *  | read data      | free space                |
29  *  +----------------+---------------------------+
30  *  ^        ^        ^                           ^
31  *  buffer   bptr     bstop                       bufend
32  *
33  *  After the last character is read, bptr == bstop and buffer refill
34  *  is deferred to the next read attempt. This gives us an easy way
35  *  how to implement bungetc().
36  *
37  *  When writing:
38  *
39  *  +----------------+---------------------------+
40  *  | written data   | free space                |
41  *  +----------------+---------------------------+
42  *  ^                 ^                           ^
43  *  buffer=bstop      bptr                        bufend
44  *
45  *  Dirty tricks:
46  *
47  *    - You can mix reads and writes on the same stream, but you must
48  *      call bflush() in between and remember that the file position
49  *      points after the flushed buffer which is not necessarily the same
50  *      as after the data you've read.
51  *    - The spout/refill hooks can change not only bptr and bstop, but also
52  *      the location of the buffer; fb-mem.c takes advantage of it.
53  */
54
55 struct fastbuf {
56   byte is_fastbuf[0];                   /* Dummy field for checking of type casts */
57   byte *bptr, *bstop;                   /* Access pointers */
58   byte *buffer, *bufend;                /* Start and end of the buffer */
59   byte *name;                           /* File name for error messages */
60   sh_off_t pos;                         /* Position of bstop in the file */
61   int (*refill)(struct fastbuf *);      /* Get a buffer with new data */
62   void (*spout)(struct fastbuf *);      /* Write buffer data to the file */
63   void (*seek)(struct fastbuf *, sh_off_t, int);  /* Slow path for bseek(), buffer already flushed */
64   void (*close)(struct fastbuf *);      /* Close the stream */
65 };
66
67 /* FastIO on standard files */
68
69 struct fb_file {
70   struct fastbuf fb;
71   int fd;                               /* File descriptor, -1 if not a real file */
72   int is_temp_file;                     /* Is a temporary file, delete on close */
73 };
74 #define FB_FILE(f) ((struct fb_file *)(f)->is_fastbuf)
75
76 struct fastbuf *bopen(byte *name, uns mode, uns buffer);
77 struct fastbuf *bopen_tmp(uns buffer);
78 struct fastbuf *bfdopen(int fd, uns buffer);
79 void bbcopy(struct fastbuf *f, struct fastbuf *t, uns l);
80 #define FB_IS_TEMP_FILE(f) FB_FILE(f)->is_temp_file
81
82 /* FastIO on in-memory streams */
83
84 struct fastbuf *fbmem_create(unsigned blocksize);       /* Create stream and return its writing fastbuf */
85 struct fastbuf *fbmem_clone_read(struct fastbuf *);     /* Create reading fastbuf */
86
87 /* Universal functions working on all fastbuf's */
88
89 void bclose(struct fastbuf *f);
90 void bflush(struct fastbuf *f);
91 void bseek(struct fastbuf *f, sh_off_t pos, int whence);
92 void bsetpos(struct fastbuf *f, sh_off_t pos);
93
94 static inline sh_off_t btell(struct fastbuf *f)
95 {
96   return f->pos + (f->bptr - f->bstop);
97 }
98
99 int bgetc_slow(struct fastbuf *f);
100 static inline int bgetc(struct fastbuf *f)
101 {
102   return (f->bptr < f->bstop) ? (int) *f->bptr++ : bgetc_slow(f);
103 }
104
105 int bpeekc_slow(struct fastbuf *f);
106 static inline int bpeekc(struct fastbuf *f)
107 {
108   return (f->bptr < f->bstop) ? (int) *f->bptr : bpeekc_slow(f);
109 }
110
111 static inline void bungetc(struct fastbuf *f)
112 {
113   f->bptr--;
114 }
115
116 void bputc_slow(struct fastbuf *f, uns c);
117 static inline void bputc(struct fastbuf *f, uns c)
118 {
119   if (f->bptr < f->bufend)
120     *f->bptr++ = c;
121   else
122     bputc_slow(f, c);
123 }
124
125 int bgetw_slow(struct fastbuf *f);
126 static inline int bgetw(struct fastbuf *f)
127 {
128   int w;
129   if (f->bptr + 2 <= f->bstop)
130     {
131       w = GET_U16(f->bptr);
132       f->bptr += 2;
133       return w;
134     }
135   else
136     return bgetw_slow(f);
137 }
138
139 u32 bgetl_slow(struct fastbuf *f);
140 static inline u32 bgetl(struct fastbuf *f)
141 {
142   u32 l;
143   if (f->bptr + 4 <= f->bstop)
144     {
145       l = GET_U32(f->bptr);
146       f->bptr += 4;
147       return l;
148     }
149   else
150     return bgetl_slow(f);
151 }
152
153 u64 bgetq_slow(struct fastbuf *f);
154 static inline u64 bgetq(struct fastbuf *f)
155 {
156   u64 l;
157   if (f->bptr + 8 <= f->bstop)
158     {
159       l = GET_U64(f->bptr);
160       f->bptr += 8;
161       return l;
162     }
163   else
164     return bgetq_slow(f);
165 }
166
167 u64 bget5_slow(struct fastbuf *f);
168 static inline u64 bget5(struct fastbuf *f)
169 {
170   u64 l;
171   if (f->bptr + 5 <= f->bstop)
172     {
173       l = GET_U40(f->bptr);
174       f->bptr += 5;
175       return l;
176     }
177   else
178     return bget5_slow(f);
179 }
180
181 void bputw_slow(struct fastbuf *f, uns w);
182 static inline void bputw(struct fastbuf *f, uns w)
183 {
184   if (f->bptr + 2 <= f->bufend)
185     {
186       PUT_U16(f->bptr, w);
187       f->bptr += 2;
188     }
189   else
190     bputw_slow(f, w);
191 }
192
193 void bputl_slow(struct fastbuf *f, u32 l);
194 static inline void bputl(struct fastbuf *f, u32 l)
195 {
196   if (f->bptr + 4 <= f->bufend)
197     {
198       PUT_U32(f->bptr, l);
199       f->bptr += 4;
200     }
201   else
202     bputl_slow(f, l);
203 }
204
205 void bputq_slow(struct fastbuf *f, u64 l);
206 static inline void bputq(struct fastbuf *f, u64 l)
207 {
208   if (f->bptr + 8 <= f->bufend)
209     {
210       PUT_U64(f->bptr, l);
211       f->bptr += 8;
212     }
213   else
214     bputq_slow(f, l);
215 }
216
217 void bput5_slow(struct fastbuf *f, u64 l);
218 static inline void bput5(struct fastbuf *f, u64 l)
219 {
220   if (f->bptr + 5 <= f->bufend)
221     {
222       PUT_U40(f->bptr, l);
223       f->bptr += 5;
224     }
225   else
226     bput5_slow(f, l);
227 }
228
229 uns bread_slow(struct fastbuf *f, void *b, uns l, uns check);
230 static inline uns bread(struct fastbuf *f, void *b, uns l)
231 {
232   if (f->bptr + l <= f->bstop)
233     {
234       memcpy(b, f->bptr, l);
235       f->bptr += l;
236       return l;
237     }
238   else
239     return bread_slow(f, b, l, 0);
240 }
241
242 static inline uns breadb(struct fastbuf *f, void *b, uns l)
243 {
244   if (f->bptr + l <= f->bstop)
245     {
246       memcpy(b, f->bptr, l);
247       f->bptr += l;
248       return l;
249     }
250   else
251     return bread_slow(f, b, l, 1);
252 }
253
254 void bwrite_slow(struct fastbuf *f, void *b, uns l);
255 static inline void bwrite(struct fastbuf *f, void *b, uns l)
256 {
257   if (f->bptr + l <= f->bufend)
258     {
259       memcpy(f->bptr, b, l);
260       f->bptr += l;
261     }
262   else
263     bwrite_slow(f, b, l);
264 }
265
266 byte *bgets(struct fastbuf *f, byte *b, uns l); /* Non-std */
267 byte *bgets0(struct fastbuf *f, byte *b, uns l);
268
269 static inline void
270 bputs(struct fastbuf *f, byte *b)
271 {
272   bwrite(f, b, strlen(b));
273 }
274
275 static inline void
276 bputs0(struct fastbuf *f, byte *b)
277 {
278   bwrite(f, b, strlen(b)+1);
279 }
280
281 static inline void
282 bputsn(struct fastbuf *f, byte *b)
283 {
284   bputs(f, b);
285   bputc(f, '\n');
286 }
287
288 /* I/O on addr_int_t */
289
290 #ifdef CPU_64BIT_POINTERS
291 #define bputa(x,p) bputq(x,p)
292 #define bgeta(x) bgetq(x)
293 #else
294 #define bputa(x,p) bputl(x,p)
295 #define bgeta(x) bgetl(x)
296 #endif
297
298 /* Direct I/O on buffers */
299
300 int bdirect_read_prepare(struct fastbuf *f, byte **buf);
301 void bdirect_read_commit(struct fastbuf *f, byte *pos);
302 int bdirect_write_prepare(struct fastbuf *f, byte **buf);
303 void bdirect_write_commit(struct fastbuf *f, byte *pos);
304
305 #endif