On Fri, Oct 03, 2014 at 02:06:34PM +0200, Mike Pall wrote: > Sorry, no. That would mean I'd have to maintain it as part of the > core and update it for any changes to the internals. I understand that this was a too big request to make. Could you take a quick look at the attached patch and test? It adds three minimal functions ffi.elemtypeof(), ffi.fieldtypeof(), and ffi.fieldsof(). ffi.fieldsof() returns an iterator to retrieve the field names of a composite type, which may then be passed to ffi.offsetof() and ffi.fieldtypeof(). Please let me know if these minimal functions would be acceptable maintainance-wise; then I will complete the contribution with documentation. Thanks, Peter
diff --git a/src/lib_ffi.c b/src/lib_ffi.c index 989fddd..7e61dc4 100644 --- a/src/lib_ffi.c +++ b/src/lib_ffi.c @@ -559,6 +559,100 @@ LJLIB_CF(ffi_typeof) LJLIB_REC(.) return 1; } +LJLIB_CF(ffi_elemtypeof) +{ + CTState *cts = ctype_cts(L); + CTypeID id = ffi_checkctype(L, cts, L->base+1); + CType *ct = ctype_raw(cts, id); + if (ctype_isref(ct->info)) + ct = ctype_rawchild(cts, ct); + if (ctype_ispointer(ct->info)) { + GCcdata *cd = lj_cdata_new(cts, CTID_CTYPEID, 4); + *(CTypeID *)cdataptr(cd) = ctype_cid(ct->info); + setcdataV(L, L->top-1, cd); + lj_gc_check(L); + return 1; + } + return 0; +} + +LJLIB_CF(ffi_fieldtypeof) +{ + CTState *cts = ctype_cts(L); + CTypeID id = ffi_checkctype(L, cts, NULL); + GCstr *name = lj_lib_checkstr(L, 2); + CType *ct = lj_ctype_rawref(cts, id); + CTSize ofs; + if ((ctype_isstruct(ct->info) || ctype_isenum(ct->info)) && + ct->size != CTSIZE_INVALID) { + CType *fct = lj_ctype_getfield(cts, ct, name, &ofs); + if (fct) { + GCcdata *cd = lj_cdata_new(cts, CTID_CTYPEID, 4); + *(CTypeID *)cdataptr(cd) = ctype_cid(fct->info); + setcdataV(L, L->top-1, cd); + lj_gc_check(L); + return 1; + } + } + return 0; +} + +CType *ffi_fieldsof_next(CTState *cts, CType *ct, int *i) +{ + while (ct->sib) { + ct = ctype_get(cts, ct->sib); + if (gcref(ct->name) != NULL) { + if (*i == 0) return ct; + (*i)--; + } + if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) { + CType *cct = ctype_child(cts, ct); + while (ctype_isattrib(cct->info)) { + cct = ctype_child(cts, cct); + } + cct = ffi_fieldsof_next(cts, cct, i); + if (cct != NULL) return cct; + } + } + return NULL; +} + +static int ffi_fieldsof_iter(lua_State *L) +{ + CTState *cts = ctype_cts(L); + GCcdata *cd = cdataV(lj_lib_upvalue(L, 1)); + CTypeID id = *(CTypeID *)cdataptr(cd); + CType *ct = lj_ctype_rawref(cts, id); + int i, n = numV(lj_lib_upvalue(L, 2)); /* FIXME why is intV() always 0? */ + i = n; + ct = ffi_fieldsof_next(cts, ct, &i); + if (ct != NULL) { + setstrV(L, L->top++, strref(ct->name)); + setintV(lj_lib_upvalue(L, 2), n+1); + lj_gc_check(L); + return 1; + } + return 0; +} + +LJLIB_CF(ffi_fieldsof) +{ + CTState *cts = ctype_cts(L); + CTypeID id = ffi_checkctype(L, cts, NULL); + CType *ct = lj_ctype_rawref(cts, id); + if ((ctype_isstruct(ct->info) || ctype_isenum(ct->info)) && + ct->size != CTSIZE_INVALID) { + GCcdata *cd = lj_cdata_new(cts, CTID_CTYPEID, 4); + *(CTypeID *)cdataptr(cd) = id; + setcdataV(L, L->top-1, cd); + setintV(L->top++, 0); + lua_pushcclosure(L, ffi_fieldsof_iter, 2); + lj_gc_check(L); + return 1; + } + return 0; +} + LJLIB_CF(ffi_istype) LJLIB_REC(.) { CTState *cts = ctype_cts(L);
local ffi = require("ffi") assert(ffi.elemtypeof("double") == nil) assert(ffi.istype("double", ffi.elemtypeof("double[5]"))) assert(ffi.istype("double", ffi.elemtypeof("double[?]"))) assert(ffi.istype("float", ffi.elemtypeof("float (&)[3]"))) assert(ffi.istype("double[3]", ffi.elemtypeof("double[5][3]"))) assert(ffi.istype("double[3][2]", ffi.elemtypeof("double[5][3][2]"))) assert(ffi.istype("double", ffi.elemtypeof("double *"))) ffi.cdef[[struct foo { double x, y, z; }]] local s = ffi.typeof("struct { double x; int y; float z; }") assert(ffi.istype("double", ffi.fieldtypeof(s, "x"))) assert(ffi.istype("int", ffi.fieldtypeof(s, "y"))) assert(ffi.istype("float", ffi.fieldtypeof(s, "z"))) local iter = ffi.fieldsof(s) assert(iter() == "x") assert(iter() == "y") assert(iter() == "z") assert(iter() == nil) local iter = ffi.fieldsof("struct { struct { struct { int a; }; int b; }; struct { int c; } d;}") assert(iter() == "a") assert(iter() == "b") assert(iter() == "d") assert(iter() == nil) local e = ffi.typeof("enum { A, B }") assert(ffi.istype("int", ffi.fieldtypeof(e, "A"))) assert(ffi.istype("int", ffi.fieldtypeof(e, "B"))) local iter = ffi.fieldsof(e) assert(iter() == "A") assert(iter() == "B") assert(iter() == nil) local u = ffi.typeof("union { int X; float Y; }") assert(ffi.istype("int", ffi.fieldtypeof(u, "X"))) assert(ffi.istype("float", ffi.fieldtypeof(u, "Y"))) local iter = ffi.fieldsof(u) assert(iter() == "X") assert(iter() == "Y") assert(iter() == nil)