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