Mercurial > prosody-hg
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 |
| parents | 8048255ae61e |
| children | 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 } |
