Software /
code /
prosody
Comparison
util-src/ringbuffer.c @ 10901:5e33926f4b43
util.ringbuffer: Add :sub() and :byte() methods equivalent to the string methods
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Thu, 04 Jun 2020 15:19:20 +0100 |
parent | 10899:8048255ae61e |
child | 10921:6eb5d2bb11af |
comparison
equal
deleted
inserted
replaced
10900:9e6d979dd603 | 10901:5e33926f4b43 |
---|---|
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> |
9 | 8 |
10 typedef struct { | 9 typedef struct { |
13 size_t alen; /* allocated size */ | 12 size_t alen; /* allocated size */ |
14 size_t blen; /* current content size */ | 13 size_t blen; /* current content size */ |
15 char buffer[]; | 14 char buffer[]; |
16 } ringbuffer; | 15 } ringbuffer; |
17 | 16 |
17 /* Translate absolute idx to a wrapped index within the buffer, | |
18 based on current read position */ | |
19 static int wrap_pos(const ringbuffer *b, const long idx, long *pos) { | |
20 if(idx > (long)b->blen) { | |
21 return 0; | |
22 } | |
23 if(idx + (long)b->rpos > (long)b->alen) { | |
24 *pos = idx - (b->alen - b->rpos); | |
25 } else { | |
26 *pos = b->rpos + idx; | |
27 } | |
28 return 1; | |
29 } | |
30 | |
31 static int calc_splice_positions(const ringbuffer *b, long start, long end, long *out_start, long *out_end) { | |
32 if(start < 0) { | |
33 start = 1 + start + b->blen; | |
34 } | |
35 if(start <= 0) { | |
36 start = 1; | |
37 } | |
38 | |
39 if(end < 0) { | |
40 end = 1 + end + b->blen; | |
41 } | |
42 | |
43 if(end > (long)b->blen) { | |
44 end = b->blen; | |
45 } | |
46 if(start < 1) { | |
47 start = 1; | |
48 } | |
49 | |
50 if(start > end) { | |
51 return 0; | |
52 } | |
53 | |
54 start = start - 1; | |
55 | |
56 if(!wrap_pos(b, start, out_start)) { | |
57 return 0; | |
58 } | |
59 if(!wrap_pos(b, end, out_end)) { | |
60 return 0; | |
61 } | |
62 | |
63 return 1; | |
64 } | |
65 | |
18 static void writechar(ringbuffer *b, char c) { | 66 static void writechar(ringbuffer *b, char c) { |
19 b->blen++; | 67 b->blen++; |
20 b->buffer[(b->wpos++) % b->alen] = c; | 68 b->buffer[(b->wpos++) % b->alen] = c; |
21 } | 69 } |
22 | 70 |
174 | 222 |
175 static int rb_tostring(lua_State *L) { | 223 static int rb_tostring(lua_State *L) { |
176 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); | 224 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); |
177 lua_pushfstring(L, "ringbuffer: %p %d/%d", b, b->blen, b->alen); | 225 lua_pushfstring(L, "ringbuffer: %p %d/%d", b, b->blen, b->alen); |
178 return 1; | 226 return 1; |
227 } | |
228 | |
229 static int rb_sub(lua_State *L) { | |
230 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); | |
231 | |
232 long start = luaL_checkinteger(L, 2); | |
233 long end = luaL_optinteger(L, 3, -1); | |
234 | |
235 long wrapped_start, wrapped_end; | |
236 if(!calc_splice_positions(b, start, end, &wrapped_start, &wrapped_end)) { | |
237 lua_pushstring(L, ""); | |
238 } else if(wrapped_end <= wrapped_start) { | |
239 lua_pushlstring(L, &b->buffer[wrapped_start], b->alen - wrapped_start); | |
240 lua_pushlstring(L, b->buffer, wrapped_end); | |
241 lua_concat(L, 2); | |
242 } else { | |
243 lua_pushlstring(L, &b->buffer[wrapped_start], (wrapped_end - wrapped_start)); | |
244 } | |
245 | |
246 return 1; | |
247 } | |
248 | |
249 static int rb_byte(lua_State *L) { | |
250 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); | |
251 | |
252 long start = luaL_optinteger(L, 2, 1); | |
253 long end = luaL_optinteger(L, 3, start); | |
254 | |
255 long i; | |
256 | |
257 long wrapped_start, wrapped_end; | |
258 if(calc_splice_positions(b, start, end, &wrapped_start, &wrapped_end)) { | |
259 if(wrapped_end <= wrapped_start) { | |
260 for(i = wrapped_start; i < (long)b->alen; i++) { | |
261 lua_pushinteger(L, b->buffer[i]); | |
262 } | |
263 for(i = 0; i < wrapped_end; i++) { | |
264 lua_pushinteger(L, b->buffer[i]); | |
265 } | |
266 return wrapped_end + (b->alen - wrapped_start); | |
267 } else { | |
268 for(i = wrapped_start; i < wrapped_end; i++) { | |
269 lua_pushinteger(L, b->buffer[i]); | |
270 } | |
271 return wrapped_end - wrapped_start; | |
272 } | |
273 } | |
274 | |
275 return 0; | |
179 } | 276 } |
180 | 277 |
181 static int rb_length(lua_State *L) { | 278 static int rb_length(lua_State *L) { |
182 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); | 279 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); |
183 lua_pushinteger(L, b->blen); | 280 lua_pushinteger(L, b->blen); |
237 lua_setfield(L, -2, "write"); | 334 lua_setfield(L, -2, "write"); |
238 lua_pushcfunction(L, rb_size); | 335 lua_pushcfunction(L, rb_size); |
239 lua_setfield(L, -2, "size"); | 336 lua_setfield(L, -2, "size"); |
240 lua_pushcfunction(L, rb_length); | 337 lua_pushcfunction(L, rb_length); |
241 lua_setfield(L, -2, "length"); | 338 lua_setfield(L, -2, "length"); |
339 lua_pushcfunction(L, rb_sub); | |
340 lua_setfield(L, -2, "sub"); | |
341 lua_pushcfunction(L, rb_byte); | |
342 lua_setfield(L, -2, "byte"); | |
242 lua_pushcfunction(L, rb_free); | 343 lua_pushcfunction(L, rb_free); |
243 lua_setfield(L, -2, "free"); | 344 lua_setfield(L, -2, "free"); |
244 } | 345 } |
245 lua_setfield(L, -2, "__index"); | 346 lua_setfield(L, -2, "__index"); |
246 } | 347 } |