1 #ifndef PEEK_FILE_READER_H
2 #define PEEK_FILE_READER_H
3
4 #include <stdio.h>
5 #include "lib/mlrutil.h"
6 #include "lib/mlrmath.h"
7 #include "lib/mlr_globals.h"
8 #include "input/byte_reader.h"
9
10 // This is a ring-buffered peekahead file/string reader.
11
12 // Note: Throughout Miller as a general rule I treat struct attributes as if
13 // they were private attributes. However, for performance, parse_trie_ring_match
14 // accesses this ring buffer directly.
15 typedef struct _peek_file_reader_t {
16 byte_reader_t* pbr;
17 int peekbuflen;
18 int peekbuflenmask;
19 char* peekbuf;
20 int sob; // start of ring-buffer
21 int npeeked;
22 } peek_file_reader_t;
23
24 // ----------------------------------------------------------------
pfr_alloc(byte_reader_t * pbr,int maxnpeek)25 static inline peek_file_reader_t* pfr_alloc(byte_reader_t* pbr, int maxnpeek) {
26 peek_file_reader_t* pfr = mlr_malloc_or_die(sizeof(peek_file_reader_t));
27 pfr->pbr = pbr;
28 pfr->peekbuflen = power_of_two_above(maxnpeek);
29 pfr->peekbuflenmask = pfr->peekbuflen - 1;
30 // The peek-buffer doesn't contain null-terminated C strings, but we
31 // nonetheless null-terminate the buffer with an extra never-touched byte
32 // so that print statements in the debugger, etc. will be nice.
33 pfr->peekbuf = mlr_malloc_or_die(pfr->peekbuflen + 1);
34 memset(pfr->peekbuf, 0, pfr->peekbuflen + 1);
35 pfr->sob = 0;
36 pfr->npeeked = 0;
37
38 return pfr;
39 }
40
41 // ----------------------------------------------------------------
pfr_free(peek_file_reader_t * pfr)42 static inline void pfr_free(peek_file_reader_t* pfr) {
43 if (pfr == NULL)
44 return;
45 free(pfr->peekbuf);
46 free(pfr);
47 }
48
49 // ----------------------------------------------------------------
pfr_reset(peek_file_reader_t * pfr)50 static inline void pfr_reset(peek_file_reader_t* pfr) {
51 memset(pfr->peekbuf, 0, pfr->peekbuflen);
52 pfr->sob = 0;
53 pfr->npeeked = 0;
54 }
55
56 // ----------------------------------------------------------------
pfr_peek_char(peek_file_reader_t * pfr)57 static inline char pfr_peek_char(peek_file_reader_t* pfr) {
58 if (pfr->npeeked < 1) {
59 pfr->peekbuf[pfr->sob] = pfr->pbr->pread_func(pfr->pbr);
60 pfr->npeeked++;
61 }
62 return pfr->peekbuf[pfr->sob];
63 }
64
65 // ----------------------------------------------------------------
pfr_read_char(peek_file_reader_t * pfr)66 static inline char pfr_read_char(peek_file_reader_t* pfr) {
67 if (pfr->npeeked < 1) {
68 return pfr->pbr->pread_func(pfr->pbr);
69 } else {
70 char c = pfr->peekbuf[pfr->sob];
71 pfr->sob = (pfr->sob + 1) & pfr->peekbuflenmask;
72 pfr->npeeked--;
73 return c;
74 }
75 }
76
77 // ----------------------------------------------------------------
pfr_buffer_by(peek_file_reader_t * pfr,int len)78 static inline void pfr_buffer_by(peek_file_reader_t* pfr, int len) {
79 while (pfr->npeeked < len) {
80 pfr->peekbuf[(pfr->sob + pfr->npeeked++) & pfr->peekbuflenmask] = pfr->pbr->pread_func(pfr->pbr);
81 }
82 }
83
84 // ----------------------------------------------------------------
pfr_advance_by(peek_file_reader_t * pfr,int len)85 static inline void pfr_advance_by(peek_file_reader_t* pfr, int len) {
86 MLR_INTERNAL_CODING_ERROR_IF(len > pfr->npeeked);
87 pfr->sob = (pfr->sob + len) & pfr->peekbuflenmask;
88 pfr->npeeked -= len;
89 }
90
91 // ----------------------------------------------------------------
92 void pfr_print(peek_file_reader_t* pfr);
93
94 #endif // PEEK_FILE_READER_H
95