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