Comparison

util-src/ringbuffer.c @ 7117:2b4432cc9c29

Add util.ringbuffer, a ringbuffer with a file handle like interface
author Kim Alvefur <zash@zash.se>
date Tue, 02 Feb 2016 20:24:27 +0100
child 7818:54669df178c2
comparison
equal deleted inserted replaced
7115:805d068d2fd5 7117:2b4432cc9c29
1
2
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <string.h>
6 #include <stdio.h>
7
8 #include <lua.h>
9 #include <lauxlib.h>
10
11 #define MIN(a, b) ((a)>(b)?(b):(a))
12 #define MAX(a, b) ((a)>(b)?(a):(b))
13
14 typedef struct {
15 size_t rpos; /* read position */
16 size_t wpos; /* write position */
17 size_t alen; /* allocated size */
18 size_t blen; /* current content size */
19 char* buffer;
20 } ringbuffer;
21
22 char readchar(ringbuffer* b) {
23 b->blen--;
24 return b->buffer[(b->rpos++) % b->alen];
25 }
26
27 void writechar(ringbuffer* b, char c) {
28 b->blen++;
29 b->buffer[(b->wpos++) % b->alen] = c;
30 }
31
32 /* make sure position counters stay within the allocation */
33 void modpos(ringbuffer* b) {
34 b->rpos = b->rpos % b->alen;
35 b->wpos = b->wpos % b->alen;
36 }
37
38 int find(ringbuffer* b, const char* s, int l) {
39 size_t i, j;
40 int m;
41
42 if(b->rpos == b->wpos) { /* empty */
43 return 0;
44 }
45
46 for(i = 0; i <= b->blen - l; i++) {
47 if(b->buffer[(b->rpos + i) % b->alen] == *s) {
48 m = 1;
49
50 for(j = 1; j < l; j++)
51 if(b->buffer[(b->rpos + i + j) % b->alen] != s[j]) {
52 m = 0;
53 break;
54 }
55
56 if(m) {
57 return i + l;
58 }
59 }
60 }
61
62 return 0;
63 }
64
65 int rb_find(lua_State* L) {
66 size_t l, m;
67 ringbuffer* b = luaL_checkudata(L, 1, "ringbuffer_mt");
68 const char* s = luaL_checklstring(L, 2, &l);
69 m = find(b, s, l);
70
71 if(m > 0) {
72 lua_pushinteger(L, m);
73 return 1;
74 }
75
76 return 0;
77 }
78
79
80 int rb_read(lua_State* L) {
81 ringbuffer* b = luaL_checkudata(L, 1, "ringbuffer_mt");
82 int r = luaL_checkinteger(L, 2);
83 int peek = lua_toboolean(L, 3);
84
85 if(r > b->blen) {
86 lua_pushnil(L);
87 return 1;
88 }
89
90 if((b->rpos + r) > b->alen) {
91 lua_pushlstring(L, &b->buffer[b->rpos], b->alen - b->rpos);
92 lua_pushlstring(L, b->buffer, r - (b->alen - b->rpos));
93 lua_concat(L, 2);
94 } else {
95 lua_pushlstring(L, &b->buffer[b->rpos], r);
96 }
97
98 if(!peek) {
99 b->blen -= r;
100 b->rpos += r;
101 modpos(b);
102 }
103
104 return 1;
105 }
106
107
108 int rb_readuntil(lua_State* L) {
109 size_t l, m;
110 ringbuffer* b = luaL_checkudata(L, 1, "ringbuffer_mt");
111 const char* s = luaL_checklstring(L, 2, &l);
112 m = find(b, s, l);
113
114 if(m > 0) {
115 lua_settop(L, 1);
116 lua_pushinteger(L, m);
117 return rb_read(L);
118 }
119
120 return 0;
121 }
122
123 int rb_write(lua_State* L) {
124 size_t l, w = 0;
125 ringbuffer* b = luaL_checkudata(L, 1, "ringbuffer_mt");
126 const char* s = luaL_checklstring(L, 2, &l);
127
128 /* Does `l` bytes fit? */
129 if((l + b->blen) > b->alen) {
130 lua_pushnil(L);
131 return 1;
132 }
133
134 while(l-- > 0) {
135 writechar(b, *s++);
136 w++;
137 }
138
139 modpos(b);
140
141 lua_pushinteger(L, w);
142
143 return 1;
144 }
145
146 int rb_tostring(lua_State* L) {
147 ringbuffer* b = luaL_checkudata(L, 1, "ringbuffer_mt");
148 lua_pushfstring(L, "ringbuffer: %p->%p %d/%d", b, b->buffer, b->blen, b->alen);
149 return 1;
150 }
151
152 int rb_length(lua_State* L) {
153 ringbuffer* b = luaL_checkudata(L, 1, "ringbuffer_mt");
154 lua_pushinteger(L, b->blen);
155 return 1;
156 }
157
158 int rb_size(lua_State* L) {
159 ringbuffer* b = luaL_checkudata(L, 1, "ringbuffer_mt");
160 lua_pushinteger(L, b->alen);
161 return 1;
162 }
163
164 int rb_free(lua_State* L) {
165 ringbuffer* b = luaL_checkudata(L, 1, "ringbuffer_mt");
166 lua_pushinteger(L, b->alen - b->blen);
167 return 1;
168 }
169
170 int rb_new(lua_State* L) {
171 size_t size = luaL_optinteger(L, 1, sysconf(_SC_PAGESIZE));
172 ringbuffer* b = lua_newuserdata(L, sizeof(ringbuffer));
173 b->rpos = 0;
174 b->wpos = 0;
175 b->alen = size;
176 b->blen = 0;
177 b->buffer = malloc(size);
178
179 if(b->buffer == NULL) {
180 return 0;
181 }
182
183 luaL_getmetatable(L, "ringbuffer_mt");
184 lua_setmetatable(L, -2);
185
186 return 1;
187 }
188
189 int rb_gc(lua_State* L) {
190 ringbuffer* b = luaL_checkudata(L, 1, "ringbuffer_mt");
191
192 if(b->buffer != NULL) {
193 free(b->buffer);
194 }
195
196 return 0;
197 }
198
199 int luaopen_util_ringbuffer(lua_State* L) {
200 if(luaL_newmetatable(L, "ringbuffer_mt")) {
201 lua_pushcfunction(L, rb_tostring);
202 lua_setfield(L, -2, "__tostring");
203 lua_pushcfunction(L, rb_length);
204 lua_setfield(L, -2, "__len");
205 lua_pushcfunction(L, rb_gc);
206 lua_setfield(L, -2, "__gc");
207
208 lua_newtable(L); /* __index */
209 {
210 lua_pushcfunction(L, rb_find);
211 lua_setfield(L, -2, "find");
212 lua_pushcfunction(L, rb_read);
213 lua_setfield(L, -2, "read");
214 lua_pushcfunction(L, rb_readuntil);
215 lua_setfield(L, -2, "readuntil");
216 lua_pushcfunction(L, rb_write);
217 lua_setfield(L, -2, "write");
218 lua_pushcfunction(L, rb_size);
219 lua_setfield(L, -2, "size");
220 lua_pushcfunction(L, rb_length);
221 lua_setfield(L, -2, "length");
222 lua_pushcfunction(L, rb_free);
223 lua_setfield(L, -2, "free");
224 }
225 lua_setfield(L, -2, "__index");
226 }
227
228 lua_newtable(L);
229 lua_pushcfunction(L, rb_new);
230 lua_setfield(L, -2, "new");
231 return 1;
232 }