From 8d8fdc0002597f6ebd275e51f2672ebdd6ff492a Mon Sep 17 00:00:00 2001 From: Krisztian Litkey Date: Tue, 12 Nov 2013 17:44:00 +0200 Subject: [PATCH] lua-utils: support arrays as automatic members. --- src/core/lua-utils/object.c | 321 +++++++++++++++++++++++++++++++++++++++++--- src/core/lua-utils/object.h | 71 ++++++++-- 2 files changed, 361 insertions(+), 31 deletions(-) diff --git a/src/core/lua-utils/object.c b/src/core/lua-utils/object.c index 6d4f761..c4408de 100644 --- a/src/core/lua-utils/object.c +++ b/src/core/lua-utils/object.c @@ -434,6 +434,8 @@ static int default_setter(void *data, lua_State *L, int member, userdata_t *u = (userdata_t *)data - 1; mrp_lua_class_member_t *m; mrp_lua_value_t *vptr; + void **itemsp; + size_t *nitemp; m = u->def->members + member; vptr = data + m->offs; @@ -448,6 +450,15 @@ static int default_setter(void *data, lua_State *L, int member, case MRP_LUA_ANY: vptr->any = LUA_NOREF; goto ok; + case MRP_LUA_STRING_ARRAY: + case MRP_LUA_BOOLEAN_ARRAY: + case MRP_LUA_INTEGER_ARRAY: + case MRP_LUA_DOUBLE_ARRAY: + itemsp = data + m->offs; + nitemp = data + m->size; + *itemsp = NULL; + *nitemp = 0; + goto ok; default: goto error; } @@ -488,6 +499,17 @@ static int default_setter(void *data, lua_State *L, int member, vptr->any = v->any; goto ok; + case MRP_LUA_STRING_ARRAY: + case MRP_LUA_BOOLEAN_ARRAY: + case MRP_LUA_INTEGER_ARRAY: + case MRP_LUA_DOUBLE_ARRAY: + itemsp = data + m->offs; + nitemp = data + m->size; + mrp_lua_object_free_array(itemsp, nitemp, m->type); + *itemsp = *v->array.items; + *nitemp = *v->array.nitem; + goto ok; + default: goto error; } @@ -539,6 +561,16 @@ static int default_getter(void *data, lua_State *L, int member, case MRP_LUA_ANY: v->any = vptr->any; goto ok; + + case MRP_LUA_STRING_ARRAY: + case MRP_LUA_BOOLEAN_ARRAY: + case MRP_LUA_INTEGER_ARRAY: + case MRP_LUA_DOUBLE_ARRAY: + v->array = vptr->array; + goto ok; + + default: + goto error; } ok: @@ -658,11 +690,20 @@ int mrp_lua_declare_members(mrp_lua_classdef_t *def, mrp_lua_class_flag_t flags, if ((m->name = mrp_strdup(members[i].name)) == NULL) goto fail; + *m = members[i]; + if (m->setter == NULL) + m->setter = default_setter; + if (m->getter == NULL) + m->getter = default_getter; + m->flags |= (flags & MRP_LUA_CLASS_READONLY); + +#if 0 m->type = members[i].type; m->offs = members[i].offs; m->setter = members[i].setter ? members[i].setter : default_setter; m->getter = members[i].getter ? members[i].getter : default_getter; m->flags = members[i].flags | (flags & MRP_LUA_CLASS_READONLY); +#endif def->nmember++; } @@ -723,7 +764,6 @@ static void init_members(userdata_t *u) mrp_debug("initializing %s.%s of Lua object %p(%p)", u->def->class_name, m->name, data, u); m->setter(data, NULL, i, NULL); - } u->initializing = false; } @@ -750,14 +790,18 @@ static int class_member(userdata_t *u, lua_State *L, int index) } -static int seterr(char *err, size_t esize, const char *format, ...) +static int seterr(lua_State *L, char *e, size_t size, const char *format, ...) { va_list ap; + char msg[256]; - if (err != NULL) { - va_start(ap, format); - vsnprintf(err, esize, format, ap); - va_end(ap); + va_start(ap, format); + vsnprintf(e ? e : msg, e ? size : sizeof(msg), format, ap); + va_end(ap); + + if (!e && L) { + lua_pushstring(L, msg); + lua_error(L); } return -1; @@ -884,7 +928,7 @@ int mrp_lua_object_setext(void *data, lua_State *L, const char *name, if (u->exttbl == LUA_NOREF) { if (err) - return seterr(err, esize, "trying to set user-defined field %s " + return seterr(L, err, esize, "trying to set user-defined field %s " "for non-extensible object %s", name, u->def->class_name); else @@ -938,13 +982,218 @@ void mrp_lua_object_getiext(void *data, lua_State *L, int idx) } +static inline int array_lua_type(int type) +{ + switch (type) { + case MRP_LUA_STRING_ARRAY: return LUA_TSTRING; + case MRP_LUA_BOOLEAN_ARRAY: return LUA_TBOOLEAN; + case MRP_LUA_INTEGER_ARRAY: return LUA_TNUMBER; + case MRP_LUA_DOUBLE_ARRAY: return LUA_TNUMBER; + default: return LUA_TNONE; + } +} + + +static inline int array_murphy_type(int type) +{ + switch (type) { + case LUA_TSTRING: return MRP_LUA_STRING_ARRAY; + case LUA_TBOOLEAN: return MRP_LUA_BOOLEAN_ARRAY; + case LUA_TNUMBER: return MRP_LUA_INTEGER_ARRAY; + default: return MRP_LUA_NONE; + } +} + + +static inline int array_item_size(int type) +{ + switch (type) { + case MRP_LUA_STRING_ARRAY: return sizeof(char *); + case MRP_LUA_BOOLEAN_ARRAY: return sizeof(bool); + case MRP_LUA_INTEGER_ARRAY: return sizeof(int32_t); + case MRP_LUA_DOUBLE_ARRAY: return sizeof(double); + default: return 0; + } +} + + +static inline const char *array_type_name(int type) +{ + switch (type) { + case MRP_LUA_STRING_ARRAY: return "string"; + case MRP_LUA_BOOLEAN_ARRAY: return "boolean"; + case MRP_LUA_INTEGER_ARRAY: return "integer"; + case MRP_LUA_DOUBLE_ARRAY: return "double"; + case MRP_LUA_ANY: return "any"; + default: return ""; + } +} + + +int mrp_lua_object_collect_array(lua_State *L, int tidx, void **itemsp, + size_t *nitemp, int expected, int copy, + char *e, size_t esize) +{ + const char *name, *str; + int ktype, vtype, ltype, i; + size_t max, idx, isize; + void *items; + + max = *nitemp; + tidx = mrp_lua_absidx(L, tidx); + items = NULL; + + if (expected != MRP_LUA_ANY) { + ltype = array_lua_type(expected); + isize = array_item_size(expected); + + if (ltype == LUA_TNONE || !isize) + goto type_error; + } + + lua_pushnil(L); + MRP_LUA_FOREACH_ALL(L, i, tidx, ktype, name, idx) { + vtype = lua_type(L, -1); + + mrp_debug("collecting <%s>:<%s> element for %s array", + lua_typename(L, ktype), lua_typename(L, vtype), + array_type_name(expected)); + + if (ktype != LUA_TNUMBER) + goto not_pure; + + if (expected == MRP_LUA_ANY) { + expected = array_murphy_type(vtype); + + if (!expected) + goto type_error; + + ltype = array_lua_type(expected); + isize = array_item_size(expected); + } + else + if (vtype != ltype && + !(expected && MRP_LUA_STRING_ARRAY && vtype == LUA_TNIL)) + goto type_error; + + if (max != (size_t)-1 && i >= (int)max) + goto overflow; + + if (mrp_realloc(items, (i + 1) * isize) == NULL) + goto nomem; + + switch (expected) { + case MRP_LUA_STRING_ARRAY: + str = (vtype != LUA_TNIL ? lua_tostring(L, -1) : NULL); + if (copy) { + ((char **)items)[i] = str ? mrp_strdup(str) : NULL; + if (!((char **)items)[i] && str) + goto nomem; + } + else + ((char **)items)[i] = (char *)str; + break; + case MRP_LUA_BOOLEAN_ARRAY: + ((bool *)items)[i] = lua_toboolean(L, -1); + break; + case MRP_LUA_INTEGER_ARRAY: + ((int32_t *)items)[i] = lua_tointeger(L, -1); + break; + case MRP_LUA_DOUBLE_ARRAY: + ((double *)items)[i] = lua_tonumber(L, -1); + break; + default: + goto type_error; + } + } + + *itemsp = items; + *nitemp = i; + + return 0; + + +#define CLEANUP() do { \ + mrp_lua_object_free_array(itemsp, nitemp, expected); \ + } while (0) + + type_error: + CLEANUP(); return seterr(L, e, esize, "array or element of wrong type"); + not_pure: + CLEANUP(); return seterr(L, e, esize, "not a pure array"); + nomem: + CLEANUP(); return seterr(L, e, esize, "could not allocate array"); + overflow: + CLEANUP(); return seterr(L, e, esize, "array too large"); +#undef CLEANUP +} + + +void mrp_lua_object_free_array(void **itemsp, size_t *nitemp, int type) +{ + size_t nitem = *nitemp; + char **saptr; + size_t i; + + switch (type) { + case MRP_LUA_STRING_ARRAY: + saptr = *itemsp; + for (i = 0; i < nitem; i++) + mrp_free(saptr[i]); + case MRP_LUA_BOOLEAN_ARRAY: + case MRP_LUA_INTEGER_ARRAY: + case MRP_LUA_DOUBLE_ARRAY: + mrp_free(*itemsp); + *itemsp = NULL; + *nitemp = 0; + break; + default: + break; + } +} + + +int mrp_lua_object_push_array(lua_State *L, int type, void *items, size_t nitem) +{ + int i; + + lua_createtable(L, nitem, 0); + + for (i = 0; i < (int)nitem; i++) { + switch (type) { + case MRP_LUA_STRING_ARRAY: + lua_pushstring(L, ((char **)items)[i]); + break; + case MRP_LUA_BOOLEAN_ARRAY: + lua_pushboolean(L, ((bool *)items)[i]); + break; + case MRP_LUA_INTEGER_ARRAY: + lua_pushinteger(L, ((int32_t *)items)[i]); + break; + case MRP_LUA_DOUBLE_ARRAY: + lua_pushnumber(L, ((double *)items)[i]); + break; + default: + lua_pop(L, 1); + return -1; + } + + lua_rawseti(L, -2, i + 1); + } + + return 1; +} + + int mrp_lua_set_member(void *data, lua_State *L, char *err, size_t esize) { userdata_t *u = (userdata_t *)data - 1; int midx = class_member(u, L, -2); mrp_lua_class_member_t *m; mrp_lua_value_t v; - int vtype; + int vtype, etype; + void *items; + size_t nitem; if (midx < 0) goto notfound; @@ -956,13 +1205,13 @@ int mrp_lua_set_member(void *data, lua_State *L, char *err, size_t esize) m->name, data, u); if (m->flags & MRP_LUA_CLASS_READONLY && !u->initializing) - return seterr(err, esize, "%s.%s of Lua object is readonly", + return seterr(L, err, esize, "%s.%s of Lua object is readonly", u->def->class_name, m->name); switch (m->type) { case MRP_LUA_STRING: if (vtype != LUA_TSTRING && vtype != LUA_TNIL) - return seterr(err, esize, "%s.%s expects string or nil, got %s", + return seterr(L, err, esize, "%s.%s expects string or nil, got %s", u->def->class_name, m->name, lua_typename(L, vtype), m->name); @@ -983,7 +1232,7 @@ int mrp_lua_set_member(void *data, lua_State *L, char *err, size_t esize) case MRP_LUA_INTEGER: if (vtype != LUA_TNUMBER) - return seterr(err, esize, "%s.%s expects number, got %s", + return seterr(L, err, esize, "%s.%s expects number, got %s", u->def->class_name, m->name, lua_typename(L, vtype)); v.s32 = lua_tointeger(L, -1); @@ -995,7 +1244,7 @@ int mrp_lua_set_member(void *data, lua_State *L, char *err, size_t esize) case MRP_LUA_DOUBLE: if (vtype != LUA_TNUMBER) - return seterr(err, esize, "%s.%s expects number, got %s", + return seterr(L, err, esize, "%s.%s expects number, got %s", u->def->class_name, m->name, lua_typename(L, vtype)); v.dbl = lua_tonumber(L, -1); @@ -1007,7 +1256,7 @@ int mrp_lua_set_member(void *data, lua_State *L, char *err, size_t esize) case MRP_LUA_LFUNC: if (vtype != LUA_TFUNCTION && vtype != LUA_TNIL) - return seterr(err, esize, "%s.%s expects function, got %s", + return seterr(L, err, esize, "%s.%s expects function, got %s", u->def->class_name, m->name, lua_typename(L, vtype)); v.lfn = mrp_lua_object_ref_value(data, L, -1); @@ -1018,7 +1267,7 @@ int mrp_lua_set_member(void *data, lua_State *L, char *err, size_t esize) goto error; case MRP_LUA_CFUNC: - seterr(err, esize, "CFUNC is not implemented"); + seterr(L, err, esize, "CFUNC is not implemented"); goto error; case MRP_LUA_ANY: @@ -1029,8 +1278,26 @@ int mrp_lua_set_member(void *data, lua_State *L, char *err, size_t esize) else goto error; + case MRP_LUA_STRING_ARRAY: + case MRP_LUA_BOOLEAN_ARRAY: + case MRP_LUA_INTEGER_ARRAY: + case MRP_LUA_DOUBLE_ARRAY: + items = NULL; + nitem = (size_t)-1; + etype = m->type; + if (mrp_lua_object_collect_array(L, -1, &items, &nitem, etype, true, + err, esize) < 0) + return -1; + else { + v.array.items = data + m->offs; + v.array.nitem = data + m->size; + *v.array.items = items; + *v.array.nitem = nitem; + } + goto ok; + default: - seterr(err, esize, "type %d not implemented"); + seterr(L, err, esize, "type %d not implemented"); break; } @@ -1053,6 +1320,8 @@ int mrp_lua_get_member(void *data, lua_State *L, char *err, size_t esize) int midx = class_member(u, L, -1); mrp_lua_class_member_t *m; mrp_lua_value_t v; + void **items; + size_t *nitem; if (midx < 0) goto notfound; @@ -1087,12 +1356,29 @@ int mrp_lua_get_member(void *data, lua_State *L, char *err, size_t esize) goto ok; case MRP_LUA_CFUNC: - seterr(err, esize, "CFUNC is not implemented"); + seterr(L, err, esize, "CFUNC is not implemented"); goto error; case MRP_LUA_ANY: mrp_lua_object_deref_value(data, L, v.any, true); goto ok; + + case MRP_LUA_STRING_ARRAY: + case MRP_LUA_BOOLEAN_ARRAY: + case MRP_LUA_INTEGER_ARRAY: + case MRP_LUA_DOUBLE_ARRAY: + items = data + m->offs; + nitem = data + m->size; + if (mrp_lua_object_push_array(L, m->type, *items, *nitem) > 0) + goto ok; + else { + seterr(L, err, esize, "failed to push array"); + goto error; + } + + case MRP_LUA_NONE: + seterr(L, err, esize, "invalid type"); + goto error; } ok: @@ -1135,7 +1421,8 @@ int mrp_lua_init_members(void *data, lua_State *L, int idx, goto error; } else { - seterr(err, esize, "trying toinitialize unknown member %s.%s", + seterr(L, err, esize, + "trying toinitialize unknown member %s.%s", u->def->class_name, n); lua_pop(L, 2 + 1); goto error; diff --git a/src/core/lua-utils/object.h b/src/core/lua-utils/object.h index 0db339e..87bc6ff 100644 --- a/src/core/lua-utils/object.h +++ b/src/core/lua-utils/object.h @@ -122,11 +122,33 @@ \ lua_pop(_L, 1)) + +/** _i=loopcount, _t=table idx, _type=key type, _n=field, _l=len or idx */ +#define MRP_LUA_FOREACH_ALL(_L, _i, _t, _type, _n, _l) \ + for (lua_pushnil(_L), _i = 0; \ + \ + (lua_next(_L, _t) && \ + (((_type = lua_type(_L, -2)) == LUA_TSTRING ? \ + (_n = lua_tolstring(_L, -2, &_l)) : (_n = NULL)) || \ + ((_type == LUA_TNIL ? \ + !(_n = NULL, _l = 0) : \ + (_type == LUA_TNUMBER ? \ + (_n = NULL, _l = lua_tointeger(_L, -2)) : \ + !(_n = NULL, _l = 0)) || \ + _type != LUA_TSTRING)))); \ + \ + lua_pop(_L, 1), _i++) + + enum mrp_lua_event_type_e { MRP_LUA_OBJECT_DESTRUCTION = 1, }; +static inline int mrp_lua_absidx(lua_State *L, int idx) { + return ((idx < 0) ? lua_gettop(L) + idx + 1 : idx); +} + /* * pre-declared class members */ @@ -156,12 +178,17 @@ typedef enum { */ typedef enum { + MRP_LUA_NONE = 0, MRP_LUA_STRING = 1, /* string member */ MRP_LUA_BOOLEAN, /* boolean member */ MRP_LUA_INTEGER, /* integer member */ MRP_LUA_DOUBLE, /* double member */ MRP_LUA_LFUNC, /* Lua function member */ MRP_LUA_CFUNC, /* C-function member */ + MRP_LUA_STRING_ARRAY, /* string array member */ + MRP_LUA_BOOLEAN_ARRAY, /* boolean array member */ + MRP_LUA_INTEGER_ARRAY, /* integer array member */ + MRP_LUA_DOUBLE_ARRAY, /* double array member */ MRP_LUA_ANY /* member of any type */ } mrp_lua_type_t; @@ -177,6 +204,10 @@ union mrp_lua_value_u { double dbl; /* double value */ int lfn; /* Lua function (ref) value */ void *cfn; /* C function (bridge) value */ + struct { /* array value */ + void **items; /* array items */ + size_t *nitem; /* number of items */ + } array; int any; /* Lua reference */ }; @@ -189,6 +220,7 @@ struct mrp_lua_class_member_s { char *name; /* member name */ mrp_lua_type_t type; /* memebr type */ size_t offs; /* offset within type buffer */ + size_t size; /* offset to size within type buffer */ mrp_lua_setter_t setter; /* setter if any */ mrp_lua_getter_t getter; /* getter if any */ int flags; /* member flags */ @@ -319,11 +351,12 @@ struct mrp_lua_class_member_s { * MRP_LUA_CLASS_NOTIFY. MRP_LUA_CLASS_NOFLAGS is available * to denote no specific flag set. */ -#define MRP_LUA_CLASS_MEMBER(_type, _name, _offs, _set, _get, _flags) \ +#define MRP_LUA_CLASS_MEMBER(_type, _name, _offs, _size, _set, _get, _flags) \ { \ .name = _name, \ .type = _type, \ .offs = _offs, \ + .size = _size, \ .setter = _set, \ .getter = _get, \ .flags = _flags, \ @@ -334,32 +367,37 @@ struct mrp_lua_class_member_s { */ /** Declare an automatic string member. */ -#define MRP_LUA_CLASS_STRING(_name, _offs, _set, _get, _flags) \ - MRP_LUA_CLASS_MEMBER(MRP_LUA_STRING, _name, _offs, _set, _get, _flags) +#define MRP_LUA_CLASS_STRING(_name, _offs, _set, _get, _flags) \ + MRP_LUA_CLASS_MEMBER(MRP_LUA_STRING, _name, _offs, 0, _set, _get, _flags) /** Declare an automatic (signed 32-bit) integer member. */ -#define MRP_LUA_CLASS_INTEGER(_name, _offs, _set, _get, _flags) \ - MRP_LUA_CLASS_MEMBER(MRP_LUA_INTEGER, _name, _offs, _set, _get, _flags) +#define MRP_LUA_CLASS_INTEGER(_name, _offs, _set, _get, _flags) \ + MRP_LUA_CLASS_MEMBER(MRP_LUA_INTEGER, _name, _offs, 0, _set, _get, _flags) /** Declare an automatic double-precision floating point member. */ -#define MRP_LUA_CLASS_DOUBLE(_name, _offs, _set, _get, _flags) \ - MRP_LUA_CLASS_MEMBER(MRP_LUA_DOUBLE, _name, _offs, _set, _get, _flags), +#define MRP_LUA_CLASS_DOUBLE(_name, _offs, _set, _get, _flags) \ + MRP_LUA_CLASS_MEMBER(MRP_LUA_DOUBLE, _name, _offs, 0, _set, _get, _flags), /** Declare an automatic boolean member. */ -#define MRP_LUA_CLASS_BOOLEAN(_name, _offs, _set, _get, _flags) \ - MRP_LUA_CLASS_MEMBER(MRP_LUA_BOOLEAN, _name, _offs, _set, _get, _flags) +#define MRP_LUA_CLASS_BOOLEAN(_name, _offs, _set, _get, _flags) \ + MRP_LUA_CLASS_MEMBER(MRP_LUA_BOOLEAN, _name, _offs, 0, _set, _get, _flags) /** Declare an automatic Lua function member. */ -#define MRP_LUA_CLASS_LFUNC(_name, _offs, _set, _get, _flags) \ - MRP_LUA_CLASS_MEMBER(MRP_LUA_LFUNC, _name, _offs, _set, _get, _flags) +#define MRP_LUA_CLASS_LFUNC(_name, _offs, _set, _get, _flags) \ + MRP_LUA_CLASS_MEMBER(MRP_LUA_LFUNC, _name, _offs, 0, _set, _get, _flags) /** Declare an automatic C function member. */ -#define MRP_LUA_CLASS_CFUNC(_name, _offs, _set, _get, _flags) \ - MRP_LUA_CLASS_MEMBER(MRP_LUA_CFUNC, _name, _offs, _set, _get, _flags) +#define MRP_LUA_CLASS_CFUNC(_name, _offs, _set, _get, _flags) \ + MRP_LUA_CLASS_MEMBER(MRP_LUA_CFUNC, _name, _offs, 0, _set, _get, _flags) /** Declare an automatic member with a value of any acceptable type. */ #define MRP_LUA_CLASS_ANY(_name, _offs, _set, _get, _flags) \ - MRP_LUA_CLASS_MEMBER(MRP_LUA_ANY, _name, _offs, _set, _get, _flags) + MRP_LUA_CLASS_MEMBER(MRP_LUA_ANY, _name, _offs, 0, _set, _get, _flags) + +/** Declare an automatic array and size member of the given type. */ +#define MRP_LUA_CLASS_ARRAY(_name, _type, _poffs, _noffs, _set, _get, _flags) \ + MRP_LUA_CLASS_MEMBER(MRP_LUA_##_type##_ARRAY, _name, \ + _poffs, _noffs, _set, _get, _flags) typedef struct mrp_lua_classdef_s mrp_lua_classdef_t; @@ -367,6 +405,7 @@ typedef enum mrp_lua_event_type_e mrp_lua_event_type_t; typedef void (*mrp_lua_class_notify_t)(void *data, lua_State *L, int member); + struct mrp_lua_classdef_s { const char *class_name; const char *class_id; @@ -435,6 +474,10 @@ int mrp_lua_get_member(void *data, lua_State *L, char *err, size_t esize); int mrp_lua_init_members(void *data, lua_State *L, int idx, char *err, size_t esize); +int mrp_lua_object_collect_array(lua_State *L, int tidx, void **itemsp, + size_t *nitemp, int expected, int copy, + char *e, size_t esize); +void mrp_lua_object_free_array(void **itemsp, size_t *nitemp, int type); #endif /* __MURPHY_LUA_OBJECT_H__ */ -- 2.7.4