]> mj.ucw.cz Git - libucw.git/blob - lib/fastbuf.h
f1f0239ae8dac3177855a5919502d287e823353f
[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   void *lldata;                         /* Data private to access functions below */
47   void *llpos;                          /* ... continued ... */
48   int (*refill)(struct fastbuf *);      /* Get a buffer with new data */
49   void (*spout)(struct fastbuf *);      /* Write buffer data to the file */
50   void (*seek)(struct fastbuf *, sh_off_t, int);  /* Slow path for bseek(), buffer already flushed */
51   void (*close)(struct fastbuf *);      /* Close the stream */
52 };
53
54 /* FastIO on standard files */
55
56 struct fastbuf *bopen(byte *name, uns mode, uns buffer);
57 struct fastbuf *bfdopen(int fd, uns buffer);
58 void bbcopy(struct fastbuf *f, struct fastbuf *t, uns l);
59
60 /* FastIO on in-memory streams */
61
62 struct fastbuf *fbmem_create(unsigned blocksize);       /* Create stream and return its writing fastbuf */
63 struct fastbuf *fbmem_clone_read(struct fastbuf *);     /* Create reading fastbuf */
64
65 /* Universal functions working on all fastbuf's */
66
67 void bclose(struct fastbuf *f);
68 void bflush(struct fastbuf *f);
69 void bseek(struct fastbuf *f, sh_off_t pos, int whence);
70 void bsetpos(struct fastbuf *f, sh_off_t pos);
71
72 static inline sh_off_t btell(struct fastbuf *f)
73 {
74   return f->pos + (f->bptr - f->buffer);
75 }
76
77 int bgetc_slow(struct fastbuf *f);
78 static inline int bgetc(struct fastbuf *f)
79 {
80   return (f->bptr < f->bstop) ? (int) *f->bptr++ : bgetc_slow(f);
81 }
82
83 int bpeekc_slow(struct fastbuf *f);
84 static inline int bpeekc(struct fastbuf *f)
85 {
86   return (f->bptr < f->bstop) ? (int) *f->bptr : bpeekc_slow(f);
87 }
88
89 static inline void bungetc(struct fastbuf *f, byte c)
90 {
91   *--f->bptr = c;
92 }
93
94 void bputc_slow(struct fastbuf *f, byte c);
95 static inline void bputc(struct fastbuf *f, byte c)
96 {
97   if (f->bptr < f->bufend)
98     *f->bptr++ = c;
99   else
100     bputc_slow(f, c);
101 }
102
103 word bgetw_slow(struct fastbuf *f);
104 static inline word bgetw(struct fastbuf *f)
105 {
106   word w;
107   if (f->bptr + 2 <= f->bstop)
108     {
109       byte *p = f->bptr;
110 #ifdef CPU_CAN_DO_UNALIGNED_WORDS
111       w = * ((word *) p);
112 #else
113 #ifdef CPU_BIG_ENDIAN
114       w = (p[0] << 8) | p[1];
115 #else
116       w = (p[1] << 8) | p[0];
117 #endif
118 #endif
119       f->bptr += 2;
120       return w;
121     }
122   else
123     return bgetw_slow(f);
124 }
125
126 u32 bgetl_slow(struct fastbuf *f);
127 static inline u32 bgetl(struct fastbuf *f)
128 {
129   u32 l;
130   if (f->bptr + 4 <= f->bstop)
131     {
132       byte *p = f->bptr;
133 #ifdef CPU_CAN_DO_UNALIGNED_LONGS
134       l = * ((u32 *) p);
135 #else
136 #ifdef CPU_BIG_ENDIAN
137       l = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
138 #else
139       l = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
140 #endif
141 #endif
142       f->bptr += 4;
143       return l;
144     }
145   else
146     return bgetl_slow(f);
147 }
148
149 u64 bgetq_slow(struct fastbuf *f);
150 static inline u64 bgetq(struct fastbuf *f)
151 {
152   if (f->bptr + 8 <= f->bstop)
153     {
154       u64 l;
155       memcpy(&l, f->bptr, 8);
156       f->bptr += 8;
157       return l;
158     }
159   else
160     return bgetq_slow(f);
161 }
162
163 u64 bget5_slow(struct fastbuf *f);
164 static inline u64 bget5(struct fastbuf *f)
165 {
166   u64 l;
167   if (f->bptr + 5 <= f->bstop)
168     {
169       byte *p = f->bptr;
170 #ifdef CPU_BIG_ENDIAN
171       l = ((u64)p[0] << 32) | (u32)((p[1] << 24) | (p[2] << 16) | (p[3] << 8) | p[4]);
172 #else
173       l = ((u64)p[4] << 32) | (u32)((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
174 #endif
175       f->bptr += 5;
176       return l;
177     }
178   else
179     return bget5_slow(f);
180 }
181
182 void bputw_slow(struct fastbuf *f, word w);
183 static inline void bputw(struct fastbuf *f, word w)
184 {
185   if (f->bptr + 2 <= f->bufend)
186     {
187       byte *p = f->bptr;
188 #ifdef CPU_CAN_DO_UNALIGNED_WORDS
189       * ((word *) p) = w;
190 #else
191 #ifdef CPU_BIG_ENDIAN
192       p[0] = w >> 8U;
193       p[1] = w;
194 #else
195       p[1] = w >> 8U;
196       p[0] = w;
197 #endif
198 #endif
199       f->bptr += 2;
200     }
201   else
202     bputw_slow(f, w);
203 }
204
205 void bputl_slow(struct fastbuf *f, u32 l);
206 static inline void bputl(struct fastbuf *f, u32 l)
207 {
208   if (f->bptr + 4 <= f->bufend)
209     {
210       byte *p = f->bptr;
211 #ifdef CPU_CAN_DO_UNALIGNED_LONGS
212       * ((u32 *) p) = l;
213 #else
214 #ifdef CPU_BIG_ENDIAN
215       p[0] = l >> 24U;
216       p[1] = l >> 16U;
217       p[2] = l >> 8U;
218       p[3] = l;
219 #else
220       p[3] = l >> 24U;
221       p[2] = l >> 16U;
222       p[1] = l >> 8U;
223       p[0] = l;
224 #endif
225 #endif
226       f->bptr += 4;
227     }
228   else
229     bputl_slow(f, l);
230 }
231
232 void bputq_slow(struct fastbuf *f, u64 l);
233 static inline void bputq(struct fastbuf *f, u64 l)
234 {
235   if (f->bptr + 8 <= f->bufend)
236     {
237       memcpy(f->bptr, &l, 8);
238       f->bptr += 8;
239     }
240   else
241     bputq_slow(f, l);
242 }
243
244 void bput5_slow(struct fastbuf *f, u64 l);
245 static inline void bput5(struct fastbuf *f, u64 l)
246 {
247   if (f->bptr + 5 <= f->bufend)
248     {
249       byte *p = f->bptr;
250       u32 low = l;
251 #ifdef CPU_BIG_ENDIAN
252       p[0] = l >> 32U;
253       p[1] = low >> 24U;
254       p[2] = low >> 16U;
255       p[3] = low >> 8U;
256       p[4] = low;
257 #else
258       p[4] = l >> 32U;
259       p[3] = low >> 24U;
260       p[2] = low >> 16U;
261       p[1] = low >> 8U;
262       p[0] = low;
263 #endif
264       f->bptr += 5;
265     }
266   else
267     bput5_slow(f, l);
268 }
269
270 uns bread_slow(struct fastbuf *f, void *b, uns l);
271 static inline uns bread(struct fastbuf *f, void *b, uns l)
272 {
273   if (f->bptr + l <= f->bstop)
274     {
275       memcpy(b, f->bptr, l);
276       f->bptr += l;
277       return l;
278     }
279   else
280     return bread_slow(f, b, l);
281 }
282
283 void bwrite_slow(struct fastbuf *f, void *b, uns l);
284 static inline void bwrite(struct fastbuf *f, void *b, uns l)
285 {
286   if (f->bptr + l <= f->bufend)
287     {
288       memcpy(f->bptr, b, l);
289       f->bptr += l;
290     }
291   else
292     bwrite_slow(f, b, l);
293 }
294
295 byte *bgets(struct fastbuf *f, byte *b, uns l); /* Non-std */
296
297 static inline void
298 bputs(struct fastbuf *f, byte *b)
299 {
300   bwrite(f, b, strlen(b));
301 }
302
303 static inline void
304 bputsn(struct fastbuf *f, byte *b)
305 {
306   bputs(f, b);
307   bputc(f, '\n');
308 }
309
310 /* Direct I/O on buffers */
311
312 int bdirect_read(struct fastbuf *f, byte **buf);
313 int bdirect_write_prepare(struct fastbuf *f, byte **buf);
314 void bdirect_write_commit(struct fastbuf *f, byte *pos);
315
316 /* Depending on compile-time configuration, we select the right function for reading/writing of file offsets */
317
318 #ifdef SHERLOCK_CONFIG_LARGE_DB
319 #define bgeto(f) bget5(f)
320 #define bputo(f,l) bput5(f,l)
321 #define bgetp(f) bgetq(f)
322 #define bputp(f,l) bputq(f,l)
323 #else
324 #define bgeto(f) bgetl(f)
325 #define bputo(f,l) bputl(f,l)
326 #define bgetp(f) bgetl(f)
327 #define bputp(f,l) bputl(f,l)
328 #endif
329
330 #endif