Mercurial > prosody-hg
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 } |
