Add support for primitive type fields in lua wrapper.

develop
Alexander Gavrilov 2012-03-20 13:56:29 +04:00
parent dbbd9acfad
commit 6c661bcaa9
7 changed files with 502 additions and 55 deletions

@ -95,17 +95,20 @@ bitfield_identity::bitfield_identity(size_t size, TAllocateFn alloc,
enum_identity::enum_identity(size_t size, TAllocateFn alloc,
compound_identity *scope_parent, const char *dfhack_name,
type_identity *base_type,
int64_t first_item_value, int64_t last_item_value,
const char *const *keys)
: compound_identity(size, alloc, scope_parent, dfhack_name),
first_item_value(first_item_value), last_item_value(last_item_value), keys(keys)
first_item_value(first_item_value), last_item_value(last_item_value),
keys(keys), base_type(base_type)
{
}
struct_identity::struct_identity(size_t size, TAllocateFn alloc,
compound_identity *scope_parent, const char *dfhack_name,
struct_identity *parent, const struct_field_info *fields)
: compound_identity(size, alloc, scope_parent, dfhack_name), parent(parent), has_children(false)
: compound_identity(size, alloc, scope_parent, dfhack_name),
parent(parent), has_children(false), fields(fields)
{
}

@ -7,6 +7,8 @@
#include "df/world_data.h"
#include "df/ui.h"
#include "DataIdentity.h"
namespace {
template<class T>
inline T &_toref(T &r) { return r; }

@ -14,30 +14,32 @@
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
namespace df {
#define ATOM_IDENTITY_TRAITS(type) \
primitive_identity identity_traits<type>::identity(sizeof(type));
ATOM_IDENTITY_TRAITS(char);
ATOM_IDENTITY_TRAITS(int8_t);
ATOM_IDENTITY_TRAITS(uint8_t);
ATOM_IDENTITY_TRAITS(int16_t);
ATOM_IDENTITY_TRAITS(uint16_t);
ATOM_IDENTITY_TRAITS(int32_t);
ATOM_IDENTITY_TRAITS(uint32_t);
ATOM_IDENTITY_TRAITS(int64_t);
ATOM_IDENTITY_TRAITS(uint64_t);
ATOM_IDENTITY_TRAITS(bool);
ATOM_IDENTITY_TRAITS(float);
ATOM_IDENTITY_TRAITS(std::string);
ATOM_IDENTITY_TRAITS(void*);
#undef ATOM_IDENTITY_TRAITS
#define NUMBER_IDENTITY_TRAITS(type) \
number_identity<type> identity_traits<type>::identity;
NUMBER_IDENTITY_TRAITS(char);
NUMBER_IDENTITY_TRAITS(int8_t);
NUMBER_IDENTITY_TRAITS(uint8_t);
NUMBER_IDENTITY_TRAITS(int16_t);
NUMBER_IDENTITY_TRAITS(uint16_t);
NUMBER_IDENTITY_TRAITS(int32_t);
NUMBER_IDENTITY_TRAITS(uint32_t);
NUMBER_IDENTITY_TRAITS(int64_t);
NUMBER_IDENTITY_TRAITS(uint64_t);
NUMBER_IDENTITY_TRAITS(float);
bool_identity identity_traits<bool>::identity;
stl_string_identity identity_traits<std::string>::identity;
pointer_identity identity_traits<void*>::identity;
stl_ptr_vector_identity identity_traits<std::vector<void*> >::identity;
#undef NUMBER_IDENTITY_TRAITS
}
#define TID(type) (&identity_traits< type >::identity)
#define FLD(mode, name) struct_field_info::mode, #name, offsetof(CUR_STRUCT, name)
#define GFLD(mode, name) struct_field_info::mode, #name, 0
#define GFLD(mode, name) struct_field_info::mode, #name, (size_t)&df::global::name
#define FLD_END struct_field_info::END
// Field definitions

@ -48,6 +48,155 @@ static luaL_Reg no_functions[] = { { NULL, NULL } };
inline void lua_dup(lua_State *state) { lua_pushvalue(state, -1); }
inline void lua_swap(lua_State *state) { lua_insert(state, -2); }
#define UPVAL_TYPETABLE lua_upvalueindex(1)
#define UPVAL_METATABLE lua_upvalueindex(2)
#define UPVAL_FIELDTABLE lua_upvalueindex(3)
namespace {
struct DFRefHeader {
void *ptr;
};
inline bool is_self_contained(DFRefHeader *ptr) {
void **pp = &ptr->ptr;
return **(void****)pp == (pp + 1);
}
}
static void field_error(lua_State *state, int index, const char *err, const char *mode = "read")
{
lua_getfield(state, UPVAL_METATABLE, "__metatable");
const char *cname = lua_tostring(state, -1);
const char *fname = lua_tostring(state, index);
luaL_error(state, "Cannot %s field %s.%s: %s.",
mode, (cname ? cname : "?"), (fname ? fname : "?"), err);
}
static int push_object_internal(lua_State *state, type_identity *type, void *ptr, bool in_method = true);
static void *get_object_internal(lua_State *state, type_identity *type, int val_index, bool in_method = true);
int DFHack::PushDFObject(lua_State *state, type_identity *type, void *ptr)
{
return push_object_internal(state, type, ptr, false);
}
void *DFHack::GetDFObject(lua_State *state, type_identity *type, int val_index)
{
return get_object_internal(state, type, val_index, false);
}
/* Primitive identity methods */
int constructed_identity::lua_read(lua_State *state, int fname_idx, void *ptr)
{
return push_object_internal(state, this, ptr);
}
void constructed_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index)
{
field_error(state, fname_idx, "complex object", "write");
}
int enum_identity::lua_read(lua_State *state, int fname_idx, void *ptr)
{
return base_type->lua_read(state, fname_idx, ptr);
}
void enum_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index)
{
base_type->lua_write(state, fname_idx, ptr, val_index);
}
int df::number_identity_base::lua_read(lua_State *state, int fname_idx, void *ptr)
{
lua_pushnumber(state, read(ptr));
return 1;
}
void df::number_identity_base::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index)
{
if (!lua_isnumber(state, val_index))
field_error(state, fname_idx, "number expected", "write");
write(ptr, lua_tonumber(state, val_index));
}
int df::bool_identity::lua_read(lua_State *state, int fname_idx, void *ptr)
{
lua_pushboolean(state, *(bool*)ptr);
return 1;
}
void df::bool_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index)
{
char *pb = (char*)ptr;
if (lua_isboolean(state, val_index))
*pb = lua_toboolean(state, val_index);
else if (lua_isnumber(state, val_index))
*pb = lua_tonumber(state, val_index);
else
field_error(state, fname_idx, "boolean or number expected", "write");
}
int df::stl_string_identity::lua_read(lua_State *state, int fname_idx, void *ptr)
{
auto pstr = (std::string*)ptr;
lua_pushlstring(state, pstr->data(), pstr->size());
return 1;
}
void df::stl_string_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index)
{
size_t size;
const char *bytes = lua_tolstring(state, val_index, &size);
if (!bytes)
field_error(state, fname_idx, "string expected", "write");
*(std::string*)ptr = std::string(bytes, size);
}
static int do_read_pointer(lua_State *state, int, void *ptr, type_identity *target)
{
void *val = *(void**)ptr;
if (val == NULL)
{
lua_pushnil(state);
return 1;
}
else
return push_object_internal(state, target, val);
}
int df::pointer_identity::lua_read(lua_State *state, int fname_idx, void *ptr)
{
return do_read_pointer(state, fname_idx, ptr, target);
}
static void do_write_pointer(lua_State *state, int fname_idx, void *ptr, type_identity *target, int val_index)
{
auto pptr = (void**)ptr;
if (lua_isnil(state, val_index))
*pptr = NULL;
else
{
void *nval = get_object_internal(state, target, val_index);
if (nval)
*pptr = nval;
else
field_error(state, fname_idx, "incompatible pointer type", "write");
}
}
void df::pointer_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index)
{
do_write_pointer(state, fname_idx, ptr, target, val_index);
}
/* */
static int change_error(lua_State *state)
{
luaL_error(state, "Attempt to change a read-only table.\n");
@ -111,6 +260,169 @@ static bool RegisterTypeInfo(lua_State *state, void *node)
return added;
}
static const struct_field_info *find_field(lua_State *state, int index, const char *mode = "read")
{
lua_pushvalue(state, index);
lua_rawget(state, UPVAL_FIELDTABLE);
if (!lua_islightuserdata(state, -1))
field_error(state, index, "not found");
void *p = lua_touserdata(state, -1);
lua_pop(state, 1);
return (struct_field_info*)p;
}
static int read_field(lua_State *state, const struct_field_info *field, void *ptr)
{
switch (field->mode)
{
case struct_field_info::STATIC_STRING:
{
int len = strnlen((char*)ptr, field->count);
lua_pushlstring(state, (char*)ptr, len);
return 1;
}
case struct_field_info::PRIMITIVE:
case struct_field_info::SUBSTRUCT:
case struct_field_info::CONTAINER:
return field->type->lua_read(state, 2, ptr);
case struct_field_info::POINTER:
return do_read_pointer(state, 2, ptr, field->type);
case struct_field_info::STATIC_ARRAY:
case struct_field_info::STL_VECTOR_PTR:
case struct_field_info::END:
return 0;
}
}
static void write_field(lua_State *state, const struct_field_info *field, void *ptr)
{
switch (field->mode)
{
case struct_field_info::STATIC_STRING:
{
size_t size;
const char *str = lua_tolstring(state, -1, &size);
if (!str)
field_error(state, 2, "string expected", "write");
memcpy(ptr, str, std::min(size+1, size_t(field->count)));
return;
}
case struct_field_info::PRIMITIVE:
case struct_field_info::SUBSTRUCT:
case struct_field_info::CONTAINER:
field->type->lua_write(state, 2, ptr, 3);
return;
case struct_field_info::POINTER:
do_write_pointer(state, 2, ptr, field->type, 3);
case struct_field_info::STATIC_ARRAY:
case struct_field_info::STL_VECTOR_PTR:
field_error(state, 2, "complex object", "write");
case struct_field_info::END:
return;
}
}
static int meta_global_index(lua_State *state)
{
const struct_field_info *field = find_field(state, 2);
void *ptr = *(void**)field->offset;
if (!ptr)
field_error(state, 2, "global address not known");
return read_field(state, field, ptr);
}
static int meta_global_newindex(lua_State *state)
{
const struct_field_info *field = find_field(state, 2);
void *ptr = *(void**)field->offset;
if (!ptr)
field_error(state, 2, "global address not known", "write");
write_field(state, field, ptr);
return 0;
}
static void IndexFields(lua_State *state, const struct_field_info *fields)
{
int base = lua_gettop(state);
lua_newtable(state); // read
lua_newtable(state); // write
for (; fields->mode != struct_field_info::END; ++fields)
{
switch (fields->mode)
{
case struct_field_info::END:
break;
case struct_field_info::PRIMITIVE:
case struct_field_info::STATIC_STRING:
case struct_field_info::POINTER:
lua_pushstring(state,fields->name);
lua_pushlightuserdata(state,(void*)fields);
lua_settable(state,base+2);
// fallthrough
case struct_field_info::STATIC_ARRAY:
case struct_field_info::SUBSTRUCT:
case struct_field_info::CONTAINER:
case struct_field_info::STL_VECTOR_PTR:
lua_pushstring(state,fields->name);
lua_pushlightuserdata(state,(void*)fields);
lua_settable(state,base+1);
break;
}
}
}
static void MakeFieldMetatable(lua_State *state, struct_identity *pstruct,
lua_CFunction reader, lua_CFunction writer)
{
int base = lua_gettop(state);
lua_newtable(state); // metatable
IndexFields(state, pstruct->getFields()); // read, write
lua_pushstring(state, pstruct->getName());
lua_setfield(state, base+1, "__metatable");
lua_pushlightuserdata(state, pstruct);
lua_setfield(state, base+1, "_identity");
lua_getfield(state, LUA_REGISTRYINDEX, "DFHack::DFTypes");
lua_pushvalue(state, base+1);
lua_pushvalue(state, base+2);
lua_pushcclosure(state, reader, 3);
lua_setfield(state, base+1, "__index");
lua_getfield(state, LUA_REGISTRYINDEX, "DFHack::DFTypes");
lua_pushvalue(state, base+1);
lua_pushvalue(state, base+3);
lua_pushcclosure(state, writer, 3);
lua_setfield(state, base+1, "__newindex");
// returns: [metatable readfields writefields];
}
static int push_object_internal(lua_State *state, type_identity *type, void *ptr, bool in_method)
{
return 0;
}
static void *get_object_internal(lua_State *state, type_identity *type, int val_index, bool in_method)
{
return NULL;
}
static void RenderTypeChildren(lua_State *state, const std::vector<compound_identity*> &children);
static void RenderType(lua_State *state, compound_identity *node)
@ -150,13 +462,11 @@ static void RenderType(lua_State *state, compound_identity *node)
if (eid->getFirstItem() <= eid->getLastItem())
{
lua_pushstring(state, "_first_item");
lua_pushinteger(state, eid->getFirstItem());
lua_settable(state, base);
lua_setfield(state, base, "_first_item");
lua_pushstring(state, "_last_item");
lua_pushinteger(state, eid->getLastItem());
lua_settable(state, base);
lua_setfield(state, base, "_last_item");
}
SaveTypeInfo(state, node);
@ -171,7 +481,26 @@ static void RenderType(lua_State *state, compound_identity *node)
assert(base == lua_gettop(state));
freeze_table(state, false, node->getName());
if (node->type() == IDTYPE_GLOBAL)
{
auto gid = (global_identity*)node;
MakeFieldMetatable(state, gid, meta_global_index, meta_global_newindex);
lua_pop(state, 2);
lua_dup(state);
lua_setmetatable(state, base);
lua_swap(state); // -> meta curtable
freeze_table(state, true, "global");
lua_getfield(state, base, "__newindex");
lua_setfield(state, -2, "__newindex");
lua_pop(state, 1);
lua_remove(state, base);
}
else
freeze_table(state, false, node->getName());
}
static void RenderTypeChildren(lua_State *state, const std::vector<compound_identity*> &children)

@ -50,11 +50,13 @@ namespace DFHack
enum identity_type {
IDTYPE_GLOBAL,
IDTYPE_PRIMITIVE,
IDTYPE_POINTER,
IDTYPE_CONTAINER,
IDTYPE_BITFIELD,
IDTYPE_ENUM,
IDTYPE_STRUCT,
IDTYPE_CLASS
IDTYPE_CLASS,
IDTYPE_STL_PTR_VECTOR
};
typedef void *(*TAllocateFn)(void*,const void*);
@ -80,6 +82,9 @@ namespace DFHack
size_t byte_size() { return size; }
virtual identity_type type() = 0;
virtual int lua_read(lua_State *state, int fname_idx, void *ptr) = 0;
virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index) = 0;
};
class DFHACK_EXPORT constructed_identity : public type_identity {
@ -96,6 +101,9 @@ namespace DFHack
if (allocator) allocator(tgt,src);
else type_identity::do_copy(tgt, src);
};
virtual int lua_read(lua_State *state, int fname_idx, void *ptr);
virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index);
};
class DFHACK_EXPORT compound_identity : public constructed_identity {
@ -149,9 +157,12 @@ namespace DFHack
int64_t first_item_value;
int64_t last_item_value;
type_identity *base_type;
public:
enum_identity(size_t size, TAllocateFn alloc,
compound_identity *scope_parent, const char *dfhack_name,
type_identity *base_type,
int64_t first_item_value, int64_t last_item_value,
const char *const *keys);
@ -161,6 +172,11 @@ namespace DFHack
int64_t getLastItem() { return last_item_value; }
int getCount() { return int(last_item_value-first_item_value+1); }
const char *const *getKeys() { return keys; }
type_identity *getBaseType() { return base_type; }
virtual int lua_read(lua_State *state, int fname_idx, void *ptr);
virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index);
};
struct struct_field_info {
@ -187,6 +203,8 @@ namespace DFHack
std::vector<struct_identity*> children;
bool has_children;
const struct_field_info *fields;
protected:
virtual void doInit(Core *core);
@ -201,6 +219,8 @@ namespace DFHack
const std::vector<struct_identity*> &getChildren() { return children; }
bool hasChildren() { return has_children; }
const struct_field_info *getFields() { return fields; }
bool is_subclass(struct_identity *subtype);
};
@ -286,6 +306,9 @@ namespace DFHack
DFHACK_EXPORT void AttachDFGlobals(lua_State *state);
DFHACK_EXPORT int PushDFObject(lua_State *state, type_identity *type, void *ptr);
DFHACK_EXPORT void *GetDFObject(lua_State *state, type_identity *type, int val_index);
template<class T>
T *ifnull(T *a, T *b) { return a ? a : b; }

@ -44,6 +44,21 @@ namespace DFHack
virtual identity_type type() { return IDTYPE_PRIMITIVE; }
};
class DFHACK_EXPORT pointer_identity : public primitive_identity {
type_identity *target;
public:
pointer_identity(type_identity *target = NULL)
: primitive_identity(sizeof(void*)), target(target) {};
virtual identity_type type() { return IDTYPE_POINTER; }
type_identity *getTarget() { return target; }
virtual int lua_read(lua_State *state, int fname_idx, void *ptr);
virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index);
};
class DFHACK_EXPORT container_identity : public constructed_identity {
type_identity *item;
enum_identity *ienum;
@ -53,35 +68,101 @@ namespace DFHack
: constructed_identity(size, alloc), item(item), ienum(ienum) {};
virtual identity_type type() { return IDTYPE_CONTAINER; }
type_identity *getItemType() { return item; }
};
}
namespace df
{
using DFHack::primitive_identity;
using DFHack::pointer_identity;
using DFHack::container_identity;
#define ATOM_IDENTITY_TRAITS(type) \
class number_identity_base : public primitive_identity {
public:
number_identity_base(size_t size) : primitive_identity(size) {};
virtual int lua_read(lua_State *state, int fname_idx, void *ptr);
virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index);
protected:
virtual double read(void *ptr) = 0;
virtual void write(void *ptr, double val) = 0;
};
template<class T>
class number_identity : public number_identity_base {
public:
number_identity() : number_identity_base(sizeof(T)) {}
protected:
virtual double read(void *ptr) { return double(*(T*)ptr); }
virtual void write(void *ptr, double val) { *(T*)ptr = T(val); }
};
class bool_identity : public primitive_identity {
public:
bool_identity() : primitive_identity(sizeof(bool)) {};
virtual int lua_read(lua_State *state, int fname_idx, void *ptr);
virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index);
};
class stl_string_identity : public primitive_identity {
public:
stl_string_identity() : primitive_identity(sizeof(std::string)) {};
virtual int lua_read(lua_State *state, int fname_idx, void *ptr);
virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index);
};
class stl_ptr_vector_identity : public container_identity {
public:
stl_ptr_vector_identity(type_identity *item = NULL, enum_identity *ienum = NULL)
: container_identity(sizeof(std::vector<void*>),allocator_fn<std::vector<void*> >,item, ienum)
{};
virtual DFHack::identity_type type() { return DFHack::IDTYPE_STL_PTR_VECTOR; }
};
#define NUMBER_IDENTITY_TRAITS(type) \
template<> struct identity_traits<type> { \
static primitive_identity identity; \
static primitive_identity *get() { return &identity; } \
};
ATOM_IDENTITY_TRAITS(char);
ATOM_IDENTITY_TRAITS(int8_t);
ATOM_IDENTITY_TRAITS(uint8_t);
ATOM_IDENTITY_TRAITS(int16_t);
ATOM_IDENTITY_TRAITS(uint16_t);
ATOM_IDENTITY_TRAITS(int32_t);
ATOM_IDENTITY_TRAITS(uint32_t);
ATOM_IDENTITY_TRAITS(int64_t);
ATOM_IDENTITY_TRAITS(uint64_t);
ATOM_IDENTITY_TRAITS(bool);
ATOM_IDENTITY_TRAITS(float);
ATOM_IDENTITY_TRAITS(std::string);
ATOM_IDENTITY_TRAITS(void*);
#undef ATOM_IDENTITY_TRAITS
static number_identity<type> identity; \
static number_identity_base *get() { return &identity; } \
};
NUMBER_IDENTITY_TRAITS(char);
NUMBER_IDENTITY_TRAITS(int8_t);
NUMBER_IDENTITY_TRAITS(uint8_t);
NUMBER_IDENTITY_TRAITS(int16_t);
NUMBER_IDENTITY_TRAITS(uint16_t);
NUMBER_IDENTITY_TRAITS(int32_t);
NUMBER_IDENTITY_TRAITS(uint32_t);
NUMBER_IDENTITY_TRAITS(int64_t);
NUMBER_IDENTITY_TRAITS(uint64_t);
NUMBER_IDENTITY_TRAITS(float);
template<> struct identity_traits<bool> {
static bool_identity identity;
static bool_identity *get() { return &identity; }
};
template<> struct identity_traits<std::string> {
static stl_string_identity identity;
static stl_string_identity *get() { return &identity; }
};
template<> struct identity_traits<void*> {
static pointer_identity identity;
static pointer_identity *get() { return &identity; }
};
template<> struct identity_traits<std::vector<void*> > {
static stl_ptr_vector_identity identity;
static stl_ptr_vector_identity *get() { return &identity; }
};
#undef NUMBER_IDENTITY_TRAITS
// Container declarations
@ -90,7 +171,7 @@ namespace df
};
template<class T> struct identity_traits<T *> {
static container_identity *get();
static pointer_identity *get();
};
template<class T, int sz> struct identity_traits<T [sz]> {
@ -101,6 +182,10 @@ namespace df
static container_identity *get();
};
template<class T> struct identity_traits<std::vector<T*> > {
static stl_ptr_vector_identity *get();
};
template<class T> struct identity_traits<std::deque<T> > {
static container_identity *get();
};
@ -117,15 +202,12 @@ namespace df
template<class Enum, class FT>
primitive_identity *identity_traits<enum_field<Enum,FT> >::get() {
static primitive_identity identity(sizeof(FT));
return &identity;
return identity_traits<FT>::get();
}
template<class T>
container_identity *identity_traits<T *>::get() {
typedef T * container;
static container_identity identity(sizeof(container), &allocator_fn<container>,
identity_traits<T>::get());
pointer_identity *identity_traits<T *>::get() {
static pointer_identity identity(identity_traits<T>::get());
return &identity;
}
@ -145,6 +227,12 @@ namespace df
return &identity;
}
template<class T>
stl_ptr_vector_identity *identity_traits<std::vector<T*> >::get() {
static stl_ptr_vector_identity identity(identity_traits<T>::get());
return &identity;
}
template<class T>
container_identity *identity_traits<std::deque<T> >::get() {
typedef std::deque<T> container;

@ -1 +1 @@
Subproject commit 70eb6b5f35680655d04d9fda79ff7251e21b45ae
Subproject commit c90a2d499024319ea9aa4f98b3b61df7bba2fc62