comparison util-src/ringbuffer.c @ 11200:bf8f2da84007

Merge 0.11->trunk
author Kim Alvefur <zash@zash.se>
date Thu, 05 Nov 2020 22:31:25 +0100
parents c3b3ac63f4c3
children 1f6f05a98fcd
comparison
equal deleted inserted replaced
11199:6c7c50a4de32 11200:bf8f2da84007
1 1
2 #include <stdlib.h> 2 #include <stdlib.h>
3 #include <unistd.h> 3 #include <unistd.h>
4 #include <string.h> 4 #include <string.h>
5 #include <stdio.h>
6 5
7 #include <lua.h> 6 #include <lua.h>
8 #include <lauxlib.h> 7 #include <lauxlib.h>
8
9 #if (LUA_VERSION_NUM < 504)
10 #define luaL_pushfail lua_pushnil
11 #endif
9 12
10 typedef struct { 13 typedef struct {
11 size_t rpos; /* read position */ 14 size_t rpos; /* read position */
12 size_t wpos; /* write position */ 15 size_t wpos; /* write position */
13 size_t alen; /* allocated size */ 16 size_t alen; /* allocated size */
14 size_t blen; /* current content size */ 17 size_t blen; /* current content size */
15 char buffer[]; 18 char buffer[];
16 } ringbuffer; 19 } ringbuffer;
17 20
18 char readchar(ringbuffer *b) { 21 /* Translate absolute idx to a wrapped index within the buffer,
19 b->blen--; 22 based on current read position */
20 return b->buffer[(b->rpos++) % b->alen]; 23 static int wrap_pos(const ringbuffer *b, const long idx, long *pos) {
21 } 24 if(idx > (long)b->blen) {
22 25 return 0;
23 void writechar(ringbuffer *b, char c) { 26 }
27 if(idx + (long)b->rpos > (long)b->alen) {
28 *pos = idx - (b->alen - b->rpos);
29 } else {
30 *pos = b->rpos + idx;
31 }
32 return 1;
33 }
34
35 static int calc_splice_positions(const ringbuffer *b, long start, long end, long *out_start, long *out_end) {
36 if(start < 0) {
37 start = 1 + start + b->blen;
38 }
39 if(start <= 0) {
40 start = 1;
41 }
42
43 if(end < 0) {
44 end = 1 + end + b->blen;
45 }
46
47 if(end > (long)b->blen) {
48 end = b->blen;
49 }
50 if(start < 1) {
51 start = 1;
52 }
53
54 if(start > end) {
55 return 0;
56 }
57
58 start = start - 1;
59
60 if(!wrap_pos(b, start, out_start)) {
61 return 0;
62 }
63 if(!wrap_pos(b, end, out_end)) {
64 return 0;
65 }
66
67 return 1;
68 }
69
70 static void writechar(ringbuffer *b, char c) {
24 b->blen++; 71 b->blen++;
25 b->buffer[(b->wpos++) % b->alen] = c; 72 b->buffer[(b->wpos++) % b->alen] = c;
26 } 73 }
27 74
28 /* make sure position counters stay within the allocation */ 75 /* make sure position counters stay within the allocation */
29 void modpos(ringbuffer *b) { 76 static void modpos(ringbuffer *b) {
30 b->rpos = b->rpos % b->alen; 77 b->rpos = b->rpos % b->alen;
31 b->wpos = b->wpos % b->alen; 78 b->wpos = b->wpos % b->alen;
32 } 79 }
33 80
34 int find(ringbuffer *b, const char *s, size_t l) { 81 static int find(ringbuffer *b, const char *s, size_t l) {
35 size_t i, j; 82 size_t i, j;
36 int m; 83 int m;
37 84
38 if(b->rpos == b->wpos) { /* empty */ 85 if(b->rpos == b->wpos) { /* empty */
39 return 0; 86 return 0;
62 109
63 /* 110 /*
64 * Find first position of a substring in buffer 111 * Find first position of a substring in buffer
65 * (buffer, string) -> number 112 * (buffer, string) -> number
66 */ 113 */
67 int rb_find(lua_State *L) { 114 static int rb_find(lua_State *L) {
68 size_t l, m; 115 size_t l, m;
69 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); 116 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
70 const char *s = luaL_checklstring(L, 2, &l); 117 const char *s = luaL_checklstring(L, 2, &l);
71 m = find(b, s, l); 118 m = find(b, s, l);
72 119
80 127
81 /* 128 /*
82 * Move read position forward without returning the data 129 * Move read position forward without returning the data
83 * (buffer, number) -> boolean 130 * (buffer, number) -> boolean
84 */ 131 */
85 int rb_discard(lua_State *L) { 132 static int rb_discard(lua_State *L) {
86 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); 133 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
87 size_t r = luaL_checkinteger(L, 2); 134 size_t r = luaL_checkinteger(L, 2);
88 135
89 if(r > b->blen) { 136 if(r > b->blen) {
90 lua_pushboolean(L, 0); 137 lua_pushboolean(L, 0);
101 148
102 /* 149 /*
103 * Read bytes from buffer 150 * Read bytes from buffer
104 * (buffer, number, boolean?) -> string 151 * (buffer, number, boolean?) -> string
105 */ 152 */
106 int rb_read(lua_State *L) { 153 static int rb_read(lua_State *L) {
107 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); 154 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
108 size_t r = luaL_checkinteger(L, 2); 155 size_t r = luaL_checkinteger(L, 2);
109 int peek = lua_toboolean(L, 3); 156 int peek = lua_toboolean(L, 3);
110 157
111 if(r > b->blen) { 158 if(r > b->blen) {
112 lua_pushnil(L); 159 luaL_pushfail(L);
113 return 1; 160 return 1;
114 } 161 }
115 162
116 if((b->rpos + r) > b->alen) { 163 if((b->rpos + r) > b->alen) {
117 /* Substring wraps around to the beginning of the buffer */ 164 /* Substring wraps around to the beginning of the buffer */
133 180
134 /* 181 /*
135 * Read buffer until first occurrence of a substring 182 * Read buffer until first occurrence of a substring
136 * (buffer, string) -> string 183 * (buffer, string) -> string
137 */ 184 */
138 int rb_readuntil(lua_State *L) { 185 static int rb_readuntil(lua_State *L) {
139 size_t l, m; 186 size_t l, m;
140 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); 187 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
141 const char *s = luaL_checklstring(L, 2, &l); 188 const char *s = luaL_checklstring(L, 2, &l);
142 m = find(b, s, l); 189 m = find(b, s, l);
143 190
152 199
153 /* 200 /*
154 * Write bytes into the buffer 201 * Write bytes into the buffer
155 * (buffer, string) -> integer 202 * (buffer, string) -> integer
156 */ 203 */
157 int rb_write(lua_State *L) { 204 static int rb_write(lua_State *L) {
158 size_t l, w = 0; 205 size_t l, w = 0;
159 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); 206 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
160 const char *s = luaL_checklstring(L, 2, &l); 207 const char *s = luaL_checklstring(L, 2, &l);
161 208
162 /* Does `l` bytes fit? */ 209 /* Does `l` bytes fit? */
163 if((l + b->blen) > b->alen) { 210 if((l + b->blen) > b->alen) {
164 lua_pushnil(L); 211 luaL_pushfail(L);
165 return 1; 212 return 1;
166 } 213 }
167 214
168 while(l-- > 0) { 215 while(l-- > 0) {
169 writechar(b, *s++); 216 writechar(b, *s++);
175 lua_pushinteger(L, w); 222 lua_pushinteger(L, w);
176 223
177 return 1; 224 return 1;
178 } 225 }
179 226
180 int rb_tostring(lua_State *L) { 227 static int rb_tostring(lua_State *L) {
181 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); 228 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
182 lua_pushfstring(L, "ringbuffer: %p %d/%d", b, b->blen, b->alen); 229 lua_pushfstring(L, "ringbuffer: %p %d/%d", b, b->blen, b->alen);
183 return 1; 230 return 1;
184 } 231 }
185 232
186 int rb_length(lua_State *L) { 233 static int rb_sub(lua_State *L) {
234 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
235
236 long start = luaL_checkinteger(L, 2);
237 long end = luaL_optinteger(L, 3, -1);
238
239 long wrapped_start, wrapped_end;
240 if(!calc_splice_positions(b, start, end, &wrapped_start, &wrapped_end)) {
241 lua_pushstring(L, "");
242 } else if(wrapped_end <= wrapped_start) {
243 lua_pushlstring(L, &b->buffer[wrapped_start], b->alen - wrapped_start);
244 lua_pushlstring(L, b->buffer, wrapped_end);
245 lua_concat(L, 2);
246 } else {
247 lua_pushlstring(L, &b->buffer[wrapped_start], (wrapped_end - wrapped_start));
248 }
249
250 return 1;
251 }
252
253 static int rb_byte(lua_State *L) {
254 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
255
256 long start = luaL_optinteger(L, 2, 1);
257 long end = luaL_optinteger(L, 3, start);
258
259 long i;
260
261 long wrapped_start, wrapped_end;
262 if(calc_splice_positions(b, start, end, &wrapped_start, &wrapped_end)) {
263 if(wrapped_end <= wrapped_start) {
264 for(i = wrapped_start; i < (long)b->alen; i++) {
265 lua_pushinteger(L, (unsigned char)b->buffer[i]);
266 }
267 for(i = 0; i < wrapped_end; i++) {
268 lua_pushinteger(L, (unsigned char)b->buffer[i]);
269 }
270 return wrapped_end + (b->alen - wrapped_start);
271 } else {
272 for(i = wrapped_start; i < wrapped_end; i++) {
273 lua_pushinteger(L, (unsigned char)b->buffer[i]);
274 }
275 return wrapped_end - wrapped_start;
276 }
277 }
278
279 return 0;
280 }
281
282 static int rb_length(lua_State *L) {
187 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); 283 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
188 lua_pushinteger(L, b->blen); 284 lua_pushinteger(L, b->blen);
189 return 1; 285 return 1;
190 } 286 }
191 287
192 int rb_size(lua_State *L) { 288 static int rb_size(lua_State *L) {
193 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); 289 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
194 lua_pushinteger(L, b->alen); 290 lua_pushinteger(L, b->alen);
195 return 1; 291 return 1;
196 } 292 }
197 293
198 int rb_free(lua_State *L) { 294 static int rb_free(lua_State *L) {
199 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); 295 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
200 lua_pushinteger(L, b->alen - b->blen); 296 lua_pushinteger(L, b->alen - b->blen);
201 return 1; 297 return 1;
202 } 298 }
203 299
204 int rb_new(lua_State *L) { 300 static int rb_new(lua_State *L) {
205 size_t size = luaL_optinteger(L, 1, sysconf(_SC_PAGESIZE)); 301 lua_Integer size = luaL_optinteger(L, 1, sysconf(_SC_PAGESIZE));
302 luaL_argcheck(L, size > 0, 1, "positive integer expected");
206 ringbuffer *b = lua_newuserdata(L, sizeof(ringbuffer) + size); 303 ringbuffer *b = lua_newuserdata(L, sizeof(ringbuffer) + size);
207 304
208 b->rpos = 0; 305 b->rpos = 0;
209 b->wpos = 0; 306 b->wpos = 0;
210 b->alen = size; 307 b->alen = size;
241 lua_setfield(L, -2, "write"); 338 lua_setfield(L, -2, "write");
242 lua_pushcfunction(L, rb_size); 339 lua_pushcfunction(L, rb_size);
243 lua_setfield(L, -2, "size"); 340 lua_setfield(L, -2, "size");
244 lua_pushcfunction(L, rb_length); 341 lua_pushcfunction(L, rb_length);
245 lua_setfield(L, -2, "length"); 342 lua_setfield(L, -2, "length");
343 lua_pushcfunction(L, rb_sub);
344 lua_setfield(L, -2, "sub");
345 lua_pushcfunction(L, rb_byte);
346 lua_setfield(L, -2, "byte");
246 lua_pushcfunction(L, rb_free); 347 lua_pushcfunction(L, rb_free);
247 lua_setfield(L, -2, "free"); 348 lua_setfield(L, -2, "free");
248 } 349 }
249 lua_setfield(L, -2, "__index"); 350 lua_setfield(L, -2, "__index");
250 } 351 }