123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796 |
- #define LUA_LIB
- #include <lua.h>
- #include <lauxlib.h>
- #include <stdint.h>
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
- #include "atomic.h"
- #define KEYTYPE_INTEGER 0
- #define KEYTYPE_STRING 1
- #define VALUETYPE_NIL 0
- #define VALUETYPE_REAL 1
- #define VALUETYPE_STRING 2
- #define VALUETYPE_BOOLEAN 3
- #define VALUETYPE_TABLE 4
- #define VALUETYPE_INTEGER 5
- struct table;
- union value {
- lua_Number n;
- lua_Integer d;
- struct table * tbl;
- int string;
- int boolean;
- };
- struct node {
- union value v;
- int key; // integer key or index of string table
- int next; // next slot index
- uint32_t keyhash;
- uint8_t keytype; // key type must be integer or string
- uint8_t valuetype; // value type can be number/string/boolean/table
- uint8_t nocolliding; // 0 means colliding slot
- };
- struct state {
- int dirty;
- ATOM_INT ref;
- struct table * root;
- };
- struct table {
- int sizearray;
- int sizehash;
- uint8_t *arraytype;
- union value * array;
- struct node * hash;
- lua_State * L;
- };
- struct context {
- lua_State * L;
- struct table * tbl;
- int string_index;
- };
- struct ctrl {
- struct table * root;
- struct table * update;
- };
- static int
- countsize(lua_State *L, int sizearray) {
- int n = 0;
- lua_pushnil(L);
- while (lua_next(L, 1) != 0) {
- int type = lua_type(L, -2);
- ++n;
- if (type == LUA_TNUMBER) {
- if (!lua_isinteger(L, -2)) {
- luaL_error(L, "Invalid key %f", lua_tonumber(L, -2));
- }
- lua_Integer nkey = lua_tointeger(L, -2);
- if (nkey > 0 && nkey <= sizearray) {
- --n;
- }
- } else if (type != LUA_TSTRING && type != LUA_TTABLE) {
- luaL_error(L, "Invalid key type %s", lua_typename(L, type));
- }
- lua_pop(L, 1);
- }
- return n;
- }
- static uint32_t
- calchash(const char * str, size_t l) {
- uint32_t h = (uint32_t)l;
- size_t l1;
- size_t step = (l >> 5) + 1;
- for (l1 = l; l1 >= step; l1 -= step) {
- h = h ^ ((h<<5) + (h>>2) + (uint8_t)(str[l1 - 1]));
- }
- return h;
- }
- static int
- stringindex(struct context *ctx, const char * str, size_t sz) {
- lua_State *L = ctx->L;
- lua_pushlstring(L, str, sz);
- lua_pushvalue(L, -1);
- lua_rawget(L, 1);
- int index;
- // stringmap(1) str index
- if (lua_isnil(L, -1)) {
- index = ++ctx->string_index;
- lua_pop(L, 1);
- lua_pushinteger(L, index);
- lua_rawset(L, 1);
- } else {
- index = lua_tointeger(L, -1);
- lua_pop(L, 2);
- }
- return index;
- }
- static int convtable(lua_State *L);
- static void
- setvalue(struct context * ctx, lua_State *L, int index, struct node *n) {
- int vt = lua_type(L, index);
- switch(vt) {
- case LUA_TNIL:
- n->valuetype = VALUETYPE_NIL;
- break;
- case LUA_TNUMBER:
- if (lua_isinteger(L, index)) {
- n->v.d = lua_tointeger(L, index);
- n->valuetype = VALUETYPE_INTEGER;
- } else {
- n->v.n = lua_tonumber(L, index);
- n->valuetype = VALUETYPE_REAL;
- }
- break;
- case LUA_TSTRING: {
- size_t sz = 0;
- const char * str = lua_tolstring(L, index, &sz);
- n->v.string = stringindex(ctx, str, sz);
- n->valuetype = VALUETYPE_STRING;
- break;
- }
- case LUA_TBOOLEAN:
- n->v.boolean = lua_toboolean(L, index);
- n->valuetype = VALUETYPE_BOOLEAN;
- break;
- case LUA_TTABLE: {
- struct table *tbl = ctx->tbl;
- ctx->tbl = (struct table *)malloc(sizeof(struct table));
- if (ctx->tbl == NULL) {
- ctx->tbl = tbl;
- luaL_error(L, "memory error");
- // never get here
- }
- memset(ctx->tbl, 0, sizeof(struct table));
- int absidx = lua_absindex(L, index);
- lua_pushcfunction(L, convtable);
- lua_pushvalue(L, absidx);
- lua_pushlightuserdata(L, ctx);
- lua_call(L, 2, 0);
- n->v.tbl = ctx->tbl;
- n->valuetype = VALUETYPE_TABLE;
- ctx->tbl = tbl;
- break;
- }
- default:
- luaL_error(L, "Unsupport value type %s", lua_typename(L, vt));
- break;
- }
- }
- static void
- setarray(struct context *ctx, lua_State *L, int index, int key) {
- struct node n;
- setvalue(ctx, L, index, &n);
- struct table *tbl = ctx->tbl;
- --key; // base 0
- tbl->arraytype[key] = n.valuetype;
- tbl->array[key] = n.v;
- }
- static int
- ishashkey(struct context * ctx, lua_State *L, int index, int *key, uint32_t *keyhash, int *keytype) {
- int sizearray = ctx->tbl->sizearray;
- int kt = lua_type(L, index);
- if (kt == LUA_TNUMBER) {
- *key = lua_tointeger(L, index);
- if (*key > 0 && *key <= sizearray) {
- return 0;
- }
- *keyhash = (uint32_t)*key;
- *keytype = KEYTYPE_INTEGER;
- } else {
- size_t sz = 0;
- const char * s = lua_tolstring(L, index, &sz);
- *keyhash = calchash(s, sz);
- *key = stringindex(ctx, s, sz);
- *keytype = KEYTYPE_STRING;
- }
- return 1;
- }
- static void
- fillnocolliding(lua_State *L, struct context *ctx) {
- struct table * tbl = ctx->tbl;
- lua_pushnil(L);
- while (lua_next(L, 1) != 0) {
- int key;
- int keytype;
- uint32_t keyhash;
- if (!ishashkey(ctx, L, -2, &key, &keyhash, &keytype)) {
- setarray(ctx, L, -1, key);
- } else {
- struct node * n = &tbl->hash[keyhash % tbl->sizehash];
- if (n->valuetype == VALUETYPE_NIL) {
- n->key = key;
- n->keytype = keytype;
- n->keyhash = keyhash;
- n->next = -1;
- n->nocolliding = 1;
- setvalue(ctx, L, -1, n); // set n->v , n->valuetype
- }
- }
- lua_pop(L,1);
- }
- }
- static void
- fillcolliding(lua_State *L, struct context *ctx) {
- struct table * tbl = ctx->tbl;
- int sizehash = tbl->sizehash;
- int emptyslot = 0;
- int i;
- lua_pushnil(L);
- while (lua_next(L, 1) != 0) {
- int key;
- int keytype;
- uint32_t keyhash;
- if (ishashkey(ctx, L, -2, &key, &keyhash, &keytype)) {
- struct node * mainpos = &tbl->hash[keyhash % tbl->sizehash];
- if (!(mainpos->keytype == keytype && mainpos->key == key)) {
- // the key has not insert
- struct node * n = NULL;
- for (i=emptyslot;i<sizehash;i++) {
- if (tbl->hash[i].valuetype == VALUETYPE_NIL) {
- n = &tbl->hash[i];
- emptyslot = i + 1;
- break;
- }
- }
- assert(n);
- n->next = mainpos->next;
- mainpos->next = n - tbl->hash;
- mainpos->nocolliding = 0;
- n->key = key;
- n->keytype = keytype;
- n->keyhash = keyhash;
- n->nocolliding = 0;
- setvalue(ctx, L, -1, n); // set n->v , n->valuetype
- }
- }
- lua_pop(L,1);
- }
- }
- // table need convert
- // struct context * ctx
- static int
- convtable(lua_State *L) {
- int i;
- struct context *ctx = lua_touserdata(L,2);
- struct table *tbl = ctx->tbl;
- tbl->L = ctx->L;
- int sizearray = lua_rawlen(L, 1);
- if (sizearray) {
- tbl->arraytype = (uint8_t *)malloc(sizearray * sizeof(uint8_t));
- if (tbl->arraytype == NULL) {
- goto memerror;
- }
- for (i=0;i<sizearray;i++) {
- tbl->arraytype[i] = VALUETYPE_NIL;
- }
- tbl->array = (union value *)malloc(sizearray * sizeof(union value));
- if (tbl->array == NULL) {
- goto memerror;
- }
- tbl->sizearray = sizearray;
- }
- int sizehash = countsize(L, sizearray);
- if (sizehash) {
- tbl->hash = (struct node *)malloc(sizehash * sizeof(struct node));
- if (tbl->hash == NULL) {
- goto memerror;
- }
- for (i=0;i<sizehash;i++) {
- tbl->hash[i].valuetype = VALUETYPE_NIL;
- tbl->hash[i].nocolliding = 0;
- tbl->hash[i].next = -1;
- }
- tbl->sizehash = sizehash;
- fillnocolliding(L, ctx);
- fillcolliding(L, ctx);
- } else {
- int i;
- for (i=1;i<=sizearray;i++) {
- lua_rawgeti(L, 1, i);
- setarray(ctx, L, -1, i);
- lua_pop(L,1);
- }
- }
- return 0;
- memerror:
- return luaL_error(L, "memory error");
- }
- static void
- delete_tbl(struct table *tbl) {
- int i;
- for (i=0;i<tbl->sizearray;i++) {
- if (tbl->arraytype[i] == VALUETYPE_TABLE) {
- delete_tbl(tbl->array[i].tbl);
- }
- }
- for (i=0;i<tbl->sizehash;i++) {
- if (tbl->hash[i].valuetype == VALUETYPE_TABLE) {
- delete_tbl(tbl->hash[i].v.tbl);
- }
- }
- free(tbl->arraytype);
- free(tbl->array);
- free(tbl->hash);
- free(tbl);
- }
- static int
- pconv(lua_State *L) {
- struct context *ctx = lua_touserdata(L,1);
- lua_State * pL = lua_touserdata(L, 2);
- int ret;
- lua_settop(L, 0);
- // init L (may throw memory error)
- // create a table for string map
- lua_newtable(L);
- lua_pushcfunction(pL, convtable);
- lua_pushvalue(pL,1);
- lua_pushlightuserdata(pL, ctx);
- ret = lua_pcall(pL, 2, 0, 0);
- if (ret != LUA_OK) {
- size_t sz = 0;
- const char * error = lua_tolstring(pL, -1, &sz);
- lua_pushlstring(L, error, sz);
- lua_error(L);
- // never get here
- }
- luaL_checkstack(L, ctx->string_index + 3, NULL);
- lua_settop(L,1);
- return 1;
- }
- static void
- convert_stringmap(struct context *ctx, struct table *tbl) {
- lua_State *L = ctx->L;
- lua_checkstack(L, ctx->string_index + LUA_MINSTACK);
- lua_settop(L, ctx->string_index + 1);
- lua_pushvalue(L, 1);
- struct state * s = lua_newuserdatauv(L, sizeof(*s), 1);
- s->dirty = 0;
- ATOM_INIT(&s->ref , 0);
- s->root = tbl;
- lua_replace(L, 1);
- lua_replace(L, -2);
- lua_pushnil(L);
- // ... stringmap nil
- while (lua_next(L, -2) != 0) {
- int idx = lua_tointeger(L, -1);
- lua_pop(L, 1);
- lua_pushvalue(L, -1);
- lua_replace(L, idx);
- }
- lua_pop(L, 1);
- lua_gc(L, LUA_GCCOLLECT, 0);
- }
- static int
- lnewconf(lua_State *L) {
- int ret;
- struct context ctx;
- struct table * tbl = NULL;
- luaL_checktype(L,1,LUA_TTABLE);
- ctx.L = luaL_newstate();
- ctx.tbl = NULL;
- ctx.string_index = 1; // 1 reserved for dirty flag
- if (ctx.L == NULL) {
- lua_pushliteral(L, "memory error");
- goto error;
- }
- tbl = (struct table *)malloc(sizeof(struct table));
- if (tbl == NULL) {
- // lua_pushliteral may fail because of memory error, close first.
- lua_close(ctx.L);
- ctx.L = NULL;
- lua_pushliteral(L, "memory error");
- goto error;
- }
- memset(tbl, 0, sizeof(struct table));
- ctx.tbl = tbl;
- lua_pushcfunction(ctx.L, pconv);
- lua_pushlightuserdata(ctx.L , &ctx);
- lua_pushlightuserdata(ctx.L , L);
- ret = lua_pcall(ctx.L, 2, 1, 0);
- if (ret != LUA_OK) {
- size_t sz = 0;
- const char * error = lua_tolstring(ctx.L, -1, &sz);
- lua_pushlstring(L, error, sz);
- goto error;
- }
- convert_stringmap(&ctx, tbl);
- lua_pushlightuserdata(L, tbl);
- return 1;
- error:
- if (ctx.L) {
- lua_close(ctx.L);
- }
- if (tbl) {
- delete_tbl(tbl);
- }
- lua_error(L);
- return -1;
- }
- static struct table *
- get_table(lua_State *L, int index) {
- struct table *tbl = lua_touserdata(L,index);
- if (tbl == NULL) {
- luaL_error(L, "Need a conf object");
- }
- return tbl;
- }
- static int
- ldeleteconf(lua_State *L) {
- struct table *tbl = get_table(L,1);
- lua_close(tbl->L);
- delete_tbl(tbl);
- return 0;
- }
- static void
- pushvalue(lua_State *L, lua_State *sL, uint8_t vt, union value *v) {
- switch(vt) {
- case VALUETYPE_REAL:
- lua_pushnumber(L, v->n);
- break;
- case VALUETYPE_INTEGER:
- lua_pushinteger(L, v->d);
- break;
- case VALUETYPE_STRING: {
- size_t sz = 0;
- const char *str = lua_tolstring(sL, v->string, &sz);
- lua_pushlstring(L, str, sz);
- break;
- }
- case VALUETYPE_BOOLEAN:
- lua_pushboolean(L, v->boolean);
- break;
- case VALUETYPE_TABLE:
- lua_pushlightuserdata(L, v->tbl);
- break;
- default:
- lua_pushnil(L);
- break;
- }
- }
- static struct node *
- lookup_key(struct table *tbl, uint32_t keyhash, int key, int keytype, const char *str, size_t sz) {
- if (tbl->sizehash == 0)
- return NULL;
- struct node *n = &tbl->hash[keyhash % tbl->sizehash];
- if (keyhash != n->keyhash && n->nocolliding)
- return NULL;
- for (;;) {
- if (keyhash == n->keyhash) {
- if (n->keytype == KEYTYPE_INTEGER) {
- if (keytype == KEYTYPE_INTEGER && n->key == key) {
- return n;
- }
- } else {
- // n->keytype == KEYTYPE_STRING
- if (keytype == KEYTYPE_STRING) {
- size_t sz2 = 0;
- const char * str2 = lua_tolstring(tbl->L, n->key, &sz2);
- if (sz == sz2 && memcmp(str,str2,sz) == 0) {
- return n;
- }
- }
- }
- }
- if (n->next < 0) {
- return NULL;
- }
- n = &tbl->hash[n->next];
- }
- }
- static int
- lindexconf(lua_State *L) {
- struct table *tbl = get_table(L,1);
- int kt = lua_type(L,2);
- uint32_t keyhash;
- int key = 0;
- int keytype;
- size_t sz = 0;
- const char * str = NULL;
- if (kt == LUA_TNUMBER) {
- if (!lua_isinteger(L, 2)) {
- return luaL_error(L, "Invalid key %f", lua_tonumber(L, 2));
- }
- key = (int)lua_tointeger(L, 2);
- if (key > 0 && key <= tbl->sizearray) {
- --key;
- pushvalue(L, tbl->L, tbl->arraytype[key], &tbl->array[key]);
- return 1;
- }
- keytype = KEYTYPE_INTEGER;
- keyhash = (uint32_t)key;
- } else {
- str = luaL_checklstring(L, 2, &sz);
- keyhash = calchash(str, sz);
- keytype = KEYTYPE_STRING;
- }
- struct node *n = lookup_key(tbl, keyhash, key, keytype, str, sz);
- if (n) {
- pushvalue(L, tbl->L, n->valuetype, &n->v);
- return 1;
- } else {
- return 0;
- }
- }
- static void
- pushkey(lua_State *L, lua_State *sL, struct node *n) {
- if (n->keytype == KEYTYPE_INTEGER) {
- lua_pushinteger(L, n->key);
- } else {
- size_t sz = 0;
- const char * str = lua_tolstring(sL, n->key, &sz);
- lua_pushlstring(L, str, sz);
- }
- }
- static int
- pushfirsthash(lua_State *L, struct table * tbl) {
- if (tbl->sizehash) {
- pushkey(L, tbl->L, &tbl->hash[0]);
- return 1;
- } else {
- return 0;
- }
- }
- static int
- lnextkey(lua_State *L) {
- struct table *tbl = get_table(L,1);
- if (lua_isnoneornil(L,2)) {
- if (tbl->sizearray > 0) {
- int i;
- for (i=0;i<tbl->sizearray;i++) {
- if (tbl->arraytype[i] != VALUETYPE_NIL) {
- lua_pushinteger(L, i+1);
- return 1;
- }
- }
- }
- return pushfirsthash(L, tbl);
- }
- int kt = lua_type(L,2);
- uint32_t keyhash;
- int key = 0;
- int keytype;
- size_t sz=0;
- const char *str = NULL;
- int sizearray = tbl->sizearray;
- if (kt == LUA_TNUMBER) {
- if (!lua_isinteger(L, 2)) {
- return 0;
- }
- key = (int)lua_tointeger(L, 2);
- if (key > 0 && key <= sizearray) {
- lua_Integer i;
- for (i=key;i<sizearray;i++) {
- if (tbl->arraytype[i] != VALUETYPE_NIL) {
- lua_pushinteger(L, i+1);
- return 1;
- }
- }
- return pushfirsthash(L, tbl);
- }
- keyhash = (uint32_t)key;
- keytype = KEYTYPE_INTEGER;
- } else {
- str = luaL_checklstring(L, 2, &sz);
- keyhash = calchash(str, sz);
- keytype = KEYTYPE_STRING;
- }
- struct node *n = lookup_key(tbl, keyhash, key, keytype, str, sz);
- if (n) {
- ++n;
- int index = n-tbl->hash;
- if (index == tbl->sizehash) {
- return 0;
- }
- pushkey(L, tbl->L, n);
- return 1;
- } else {
- return 0;
- }
- }
- static int
- llen(lua_State *L) {
- struct table *tbl = get_table(L,1);
- lua_pushinteger(L, tbl->sizearray);
- return 1;
- }
- static int
- lhashlen(lua_State *L) {
- struct table *tbl = get_table(L,1);
- lua_pushinteger(L, tbl->sizehash);
- return 1;
- }
- static int
- releaseobj(lua_State *L) {
- struct ctrl *c = lua_touserdata(L, 1);
- struct table *tbl = c->root;
- struct state *s = lua_touserdata(tbl->L, 1);
- ATOM_FDEC(&s->ref);
- c->root = NULL;
- c->update = NULL;
- return 0;
- }
- static int
- lboxconf(lua_State *L) {
- struct table * tbl = get_table(L,1);
- struct state * s = lua_touserdata(tbl->L, 1);
- ATOM_FINC(&s->ref);
- struct ctrl * c = lua_newuserdatauv(L, sizeof(*c), 1);
- c->root = tbl;
- c->update = NULL;
- if (luaL_newmetatable(L, "confctrl")) {
- lua_pushcfunction(L, releaseobj);
- lua_setfield(L, -2, "__gc");
- }
- lua_setmetatable(L, -2);
- return 1;
- }
- static int
- lmarkdirty(lua_State *L) {
- struct table *tbl = get_table(L,1);
- struct state * s = lua_touserdata(tbl->L, 1);
- s->dirty = 1;
- return 0;
- }
- static int
- lisdirty(lua_State *L) {
- struct table *tbl = get_table(L,1);
- struct state * s = lua_touserdata(tbl->L, 1);
- int d = s->dirty;
- lua_pushboolean(L, d);
-
- return 1;
- }
- static int
- lgetref(lua_State *L) {
- struct table *tbl = get_table(L,1);
- struct state * s = lua_touserdata(tbl->L, 1);
- lua_pushinteger(L , ATOM_LOAD(&s->ref));
- return 1;
- }
- static int
- lincref(lua_State *L) {
- struct table *tbl = get_table(L,1);
- struct state * s = lua_touserdata(tbl->L, 1);
- int ref = ATOM_FINC(&s->ref)+1;
- lua_pushinteger(L , ref);
- return 1;
- }
- static int
- ldecref(lua_State *L) {
- struct table *tbl = get_table(L,1);
- struct state * s = lua_touserdata(tbl->L, 1);
- int ref = ATOM_FDEC(&s->ref)-1;
- lua_pushinteger(L , ref);
- return 1;
- }
- static int
- lneedupdate(lua_State *L) {
- struct ctrl * c = lua_touserdata(L, 1);
- if (c->update) {
- lua_pushlightuserdata(L, c->update);
- lua_getiuservalue(L, 1, 1);
- return 2;
- }
- return 0;
- }
- static int
- lupdate(lua_State *L) {
- luaL_checktype(L, 1, LUA_TUSERDATA);
- luaL_checktype(L, 2, LUA_TLIGHTUSERDATA);
- luaL_checktype(L, 3, LUA_TTABLE);
- struct ctrl * c= lua_touserdata(L, 1);
- struct table *n = lua_touserdata(L, 2);
- if (c->root == n) {
- return luaL_error(L, "You should update a new object");
- }
- lua_settop(L, 3);
- lua_setiuservalue(L, 1, 1);
- c->update = n;
- return 0;
- }
- LUAMOD_API int
- luaopen_skynet_sharedata_core(lua_State *L) {
- luaL_Reg l[] = {
- // used by host
- { "new", lnewconf },
- { "delete", ldeleteconf },
- { "markdirty", lmarkdirty },
- { "getref", lgetref },
- { "incref", lincref },
- { "decref", ldecref },
- // used by client
- { "box", lboxconf },
- { "index", lindexconf },
- { "nextkey", lnextkey },
- { "len", llen },
- { "hashlen", lhashlen },
- { "isdirty", lisdirty },
- { "needupdate", lneedupdate },
- { "update", lupdate },
- { NULL, NULL },
- };
- luaL_checkversion(L);
- luaL_newlib(L, l);
- return 1;
- }
|