]> mj.ucw.cz Git - libucw.git/blob - lib/fastbuf.h
The StringMap file contains an end marker pointing past the last
[libucw.git] / lib / fastbuf.h
1 /*
2  *      Sherlock Library -- Fast Buffered I/O
3  *
4  *      (c) 1997--2000 Martin Mares <mj@ucw.cz>
5  */
6
7 #ifndef _SHERLOCK_FASTBUF_H
8 #define _SHERLOCK_FASTBUF_H
9
10 #ifndef EOF
11 #include <stdio.h>
12 #endif
13
14 /*
15  *  Generic buffered I/O on a top of buffer swapping functions.
16  *
17  *  Buffer layout when reading:
18  *
19  *  +----------------+---------------------------+
20  *  | read data      | free space                |
21  *  +----------------+---------------------------+
22  *  ^        ^        ^                           ^
23  *  buffer   bptr     bstop                       bufend
24  *
25  *  After the last character is read, bptr == bstop and buffer refill
26  *  is deferred to the next read attempt. This gives us an easy way
27  *  how to implement bungetc().
28  *
29  *  When writing:
30  *
31  *  +----------------+---------------------------+
32  *  | written data   | free space                |
33  *  +----------------+---------------------------+
34  *  ^                 ^                           ^
35  *  buffer=bstop      bptr                        bufend
36  */
37
38 struct fastbuf {
39   byte *bptr, *bstop;                   /* Access pointers */
40   byte *buffer, *bufend;                /* Start and end of the buffer */
41   byte *name;                           /* File name for error messages */
42   uns buflen;                           /* Size of the buffer */
43   sh_off_t pos;                         /* Position of buffer start in the file */
44   sh_off_t fdpos;                       /* Current position in the non-buffered file */
45   int fd;                               /* File descriptor, -1 if not a real file */
46   int is_temp_file;                     /* Is a temporary file, delete on close */
47   void *lldata;                         /* Data private to access functions below */
48   void *llpos;                          /* ... continued ... */
49   int (*refill)(struct fastbuf *);      /* Get a buffer with new data */
50   void (*spout)(struct fastbuf *);      /* Write buffer data to the file */
51   void (*seek)(struct fastbuf *, sh_off_t, int);  /* Slow path for bseek(), buffer already flushed */
52   void (*close)(struct fastbuf *);      /* Close the stream */
53 };
54
55 /* FastIO on standard files */
56
57 struct fastbuf *bopen(byte *name, uns mode, uns buffer);
58 struct fastbuf *bfdopen(int fd, uns buffer);
59 void bbcopy(struct fastbuf *f, struct fastbuf *t, uns l);
60
61 /* FastIO on in-memory streams */
62
63 struct fastbuf *fbmem_create(unsigned blocksize);       /* Create stream and return its writing fastbuf */
64 struct fastbuf *fbmem_clone_read(struct fastbuf *);     /* Create reading fastbuf */
65
66 /* Universal functions working on all fastbuf's */
67
68 void bclose(struct fastbuf *f);
69 void bflush(struct fastbuf *f);
70 void bseek(struct fastbuf *f, sh_off_t pos, int whence);
71 void bsetpos(struct fastbuf *f, sh_off_t pos);
72
73 static inline sh_off_t btell(struct fastbuf *f)
74 {
75   return f->pos + (f->bptr - f->buffer);
76 }
77
78 int bgetc_slow(struct fastbuf *f);
79 static inline int bgetc(struct fastbuf *f)
80 {
81   return (f->bptr < f->bstop) ? (int) *f->bptr++ : bgetc_slow(f);
82 }
83
84 int bpeekc_slow(struct fastbuf *f);
85 static inline int bpeekc(struct fastbuf *f)
86 {
87   return (f->bptr < f->bstop) ? (int) *f->bptr : bpeekc_slow(f);
88 }
89
90 static inline void bungetc(struct fastbuf *f, byte c)
91 {
92   *--f->bptr = c;
93 }
94
95 void bputc_slow(struct fastbuf *f, byte c);
96 static inline void bputc(struct fastbuf *f, byte c)
97 {
98   if (f->bptr < f->bufend)
99     *f->bptr++ = c;
100   else
101     bputc_slow(f, c);
102 }
103
104 word bgetw_slow(struct fastbuf *f);
105 static inline word bgetw(struct fastbuf *f)
106 {
107   word w;
108   if (f->bptr + 2 <= f->bstop)
109     {
110       byte *p = f->bptr;
111 #ifdef CPU_CAN_DO_UNALIGNED_WORDS
112       w = * ((word *) p);
113 #else
114 #ifdef CPU_BIG_ENDIAN
115       w = (p[0] << 8) | p[1];
116 #else
117       w = (p[1] << 8) | p[0];
118 #endif
119 #endif
120       f->bptr += 2;
121       return w;
122     }
123   else
124     return bgetw_slow(f);
125 }
126
127 u32 bgetl_slow(struct fastbuf *f);
128 static inline u32 bgetl(struct fastbuf *f)
129 {
130   u32 l;
131   if (f->bptr + 4 <= f->bstop)
132     {
133       byte *p = f->bptr;
134 #ifdef CPU_CAN_DO_UNALIGNED_LONGS
135       l = * ((u32 *) p);
136 #else
137 #ifdef CPU_BIG_ENDIAN
138       l = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
139 #else
140       l = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
141 #endif
142 #endif
143       f->bptr += 4;
144       return l;
145     }
146   else
147     return bgetl_slow(f);
148 }
149
150 u64 bgetq_slow(struct fastbuf *f);
151 static inline u64 bgetq(struct fastbuf *f)
152 {
153   if (f->bptr + 8 <= f->bstop)
154     {
155       u64 l;
156       memcpy(&l, f->bptr, 8);
157       f->bptr += 8;
158       return l;
159     }
160   else
161     return bgetq_slow(f);
162 }
163
164 u64 bget5_slow(struct fastbuf *f);
165 static inline u64 bget5(struct fastbuf *f)
166 {
167   u64 l;
168   if (f->bptr + 5 <= f->bstop)
169     {
170       byte *p = f->bptr;
171 #ifdef CPU_BIG_ENDIAN
172       l = ((u64)p[0] << 32) | (u32)((p[1] << 24) | (p[2] << 16) | (p[3] << 8) | p[4]);
173 #else
174       l = ((u64)p[4] << 32) | (u32)((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
175 #endif
176       f->bptr += 5;
177       return l;
178     }
179   else
180     return bget5_slow(f);
181 }
182
183 void bputw_slow(struct fastbuf *f, word w);
184 static inline void bputw(struct fastbuf *f, word w)
185 {
186   if (f->bptr + 2 <= f->bufend)
187     {
188       byte *p = f->bptr;
189 #ifdef CPU_CAN_DO_UNALIGNED_WORDS
190       * ((word *) p) = w;
191 #else
192 #ifdef CPU_BIG_ENDIAN
193       p[0] = w >> 8U;
194       p[1] = w;
195 #else
196       p[1] = w >> 8U;
197       p[0] = w;
198 #endif
199 #endif
200       f->bptr += 2;
201     }
202   else
203     bputw_slow(f, w);
204 }
205
206 void bputl_slow(struct fastbuf *f, u32 l);
207 static inline void bputl(struct fastbuf *f, u32 l)
208 {
209   if (f->bptr + 4 <= f->bufend)
210     {
211       byte *p = f->bptr;
212 #ifdef CPU_CAN_DO_UNALIGNED_LONGS
213       * ((u32 *) p) = l;
214 #else
215 #ifdef CPU_BIG_ENDIAN
216       p[0] = l >> 24U;
217       p[1] = l >> 16U;
218       p[2] = l >> 8U;
219       p[3] = l;
220 #else
221       p[3] = l >> 24U;
222       p[2] = l >> 16U;
223       p[1] = l >> 8U;
224       p[0] = l;
225 #endif
226 #endif
227       f->bptr += 4;
228     }
229   else
230     bputl_slow(f, l);
231 }
232
233 void bputq_slow(struct fastbuf *f, u64 l);
234 static inline void bputq(struct fastbuf *f, u64 l)
235 {
236   if (f->bptr + 8 <= f->bufend)
237     {
238       memcpy(f->bptr, &l, 8);
239       f->bptr += 8;
240     }
241   else
242     bputq_slow(f, l);
243 }
244
245 void bput5_slow(struct fastbuf *f, u64 l);
246 static inline void bput5(struct fastbuf *f, u64 l)
247 {
248   if (f->bptr + 5 <= f->bufend)
249     {
250       byte *p = f->bptr;
251       u32 low = l;
252 #ifdef CPU_BIG_ENDIAN
253       p[0] = l >> 32U;
254       p[1] = low >> 24U;
255       p[2] = low >> 16U;
256       p[3] = low >> 8U;
257       p[4] = low;
258 #else
259       p[4] = l >> 32U;
260       p[3] = low >> 24U;
261       p[2] = low >> 16U;
262       p[1] = low >> 8U;
263       p[0] = low;
264 #endif
265       f->bptr += 5;
266     }
267   else
268     bput5_slow(f, l);
269 }
270
271 uns bread_slow(struct fastbuf *f, void *b, uns l, uns check);
272 static inline uns bread(struct fastbuf *f, void *b, uns l)
273 {
274   if (f->bptr + l <= f->bstop)
275     {
276       memcpy(b, f->bptr, l);
277       f->bptr += l;
278       return l;
279     }
280   else
281     return bread_slow(f, b, l, 0);
282 }
283
284 static inline uns breadb(struct fastbuf *f, void *b, uns l)
285 {
286   if (f->bptr + l <= f->bstop)
287     {
288       memcpy(b, f->bptr, l);
289       f->bptr += l;
290       return l;
291     }
292   else
293     return bread_slow(f, b, l, 1);
294 }
295
296 void bwrite_slow(struct fastbuf *f, void *b, uns l);
297 static inline void bwrite(struct fastbuf *f, void *b, uns l)
298 {
299   if (f->bptr + l <= f->bufend)
300     {
301       memcpy(f->bptr, b, l);
302       f->bptr += l;
303     }
304   else
305     bwrite_slow(f, b, l);
306 }
307
308 byte *bgets(struct fastbuf *f, byte *b, uns l); /* Non-std */
309 byte *bgets0(struct fastbuf *f, byte *b, uns l);
310
311 static inline void
312 bputs(struct fastbuf *f, byte *b)
313 {
314   bwrite(f, b, strlen(b));
315 }
316
317 static inline void
318 bputs0(struct fastbuf *f, byte *b)
319 {
320   bwrite(f, b, strlen(b)+1);
321 }
322
323 static inline void
324 bputsn(struct fastbuf *f, byte *b)
325 {
326   bputs(f, b);
327   bputc(f, '\n');
328 }
329
330 /* Direct I/O on buffers */
331
332 int bdirect_read(struct fastbuf *f, byte **buf);
333 int bdirect_write_prepare(struct fastbuf *f, byte **buf);
334 void bdirect_write_commit(struct fastbuf *f, byte *pos);
335
336 /* Depending on compile-time configuration, we select the right function for reading/writing of file offsets */
337
338 #ifdef SHERLOCK_CONFIG_LARGE_DB
339 #define bgeto(f) bget5(f)
340 #define bputo(f,l) bput5(f,l)
341 #define bgetp(f) bgetq(f)
342 #define bputp(f,l) bputq(f,l)
343 #define FASTBUF_BYTES_PER_O 5
344 #define FASTBUF_BYTES_PER_P 8
345 #else
346 #define bgeto(f) bgetl(f)
347 #define bputo(f,l) bputl(f,l)
348 #define bgetp(f) bgetl(f)
349 #define bputp(f,l) bputl(f,l)
350 #define FASTBUF_BYTES_PER_O 4
351 #define FASTBUF_BYTES_PER_P 4
352 #endif
353
354 #endif