Add a _displace method that implements offsetting a pointer by an int.

develop
Alexander Gavrilov 2012-03-23 11:54:59 +04:00
parent 78437310d0
commit 6b2006361d
1 changed files with 73 additions and 2 deletions

@ -68,6 +68,7 @@ inline void lua_swap(lua_State *state) { lua_insert(state, -2); }
#define DFHACK_COMPARE_NAME "DFHack::ComparePtrs"
#define DFHACK_TYPE_TOSTRING_NAME "DFHack::TypeToString"
#define DFHACK_SIZEOF_NAME "DFHack::Sizeof"
#define DFHACK_DISPLACE_NAME "DFHack::Displace"
/*
* Upvalue: contents of DFHACK_TYPETABLE_NAME
@ -514,7 +515,8 @@ static void *get_object_internal(lua_State *state, type_identity *type, int val_
/**
* Given a DF object reference or type, safely retrieve its identity pointer.
*/
static type_identity *get_object_identity(lua_State *state, int objidx, const char *ctx)
static type_identity *get_object_identity(lua_State *state, int objidx,
const char *ctx, bool allow_type = false)
{
if (!lua_getmetatable(state, objidx))
luaL_error(state, "Invalid object in %s", ctx);
@ -527,6 +529,9 @@ static type_identity *get_object_identity(lua_State *state, int objidx, const ch
}
else
{
if (!allow_type)
luaL_error(state, "Object expected in %s", ctx);
lua_pushvalue(state, objidx);
LookupInTable(state, DFHACK_TYPEID_TABLE_NAME);
}
@ -604,7 +609,7 @@ static int meta_sizeof(lua_State *state)
return 2;
}
type_identity *id = get_object_identity(state, 1, "df.sizeof()");
type_identity *id = get_object_identity(state, 1, "df.sizeof()", true);
lua_pushinteger(state, id->byte_size());
@ -617,6 +622,62 @@ static int meta_sizeof(lua_State *state)
return 1;
}
/**
* Method: displace for DF object references.
*
* Returns: a reference with the same type, but modified address
*/
static int meta_displace(lua_State *state)
{
int argc = lua_gettop(state);
bool has_step = (argc >= 3);
if ((argc < 2 || argc > 3) ||
!lua_isnumber(state, 2) ||
(has_step && !lua_isnumber(state, 3)))
{
luaL_error(state, "Usage: object:_displace(index[,step]) or df._displace(object,...)");
}
int index = lua_tointeger(state, 2);
int step = has_step ? lua_tointeger(state, 3) : 1;
// Two special cases: nil and lightuserdata for NULL and void*
if (lua_isnil(state, 1))
{
lua_pushnil(state);
return 1;
}
if (lua_islightuserdata(state, 1))
{
if (!has_step)
luaL_error(state, "Step is mandatory in _displace of void*");
auto ptr = (uint8_t*)lua_touserdata(state, 1);
lua_pushlightuserdata(state, ptr + index*step);
return 1;
}
type_identity *id = get_object_identity(state, 1, "df._displace()");
if (!has_step)
step = id->byte_size();
if (index == 0 || step == 0)
{
lua_pushvalue(state, 1);
}
else
{
auto ptr = (uint8_t*)get_object_ref(state, 1);
lua_getmetatable(state, 1);
push_object_ref(state, ptr + index*step);
}
return 1;
}
/**
* Resolve the field name in UPVAL_FIELDTABLE, die if not found.
*/
@ -1063,9 +1124,14 @@ static void SetPtrMethods(lua_State *state, int meta_idx, int read_idx)
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_SIZEOF_NAME);
lua_setfield(state, meta_idx, "sizeof");
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_DISPLACE_NAME);
lua_setfield(state, meta_idx, "_displace");
EnableMetaField(state, read_idx, "_type");
EnableMetaField(state, read_idx, "_kind");
EnableMetaField(state, read_idx, "sizeof");
EnableMetaField(state, read_idx, "_displace");
}
/**
@ -1485,6 +1551,9 @@ static void DoAttach(lua_State *state)
lua_pushcfunction(state, meta_sizeof);
lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_SIZEOF_NAME);
lua_pushcfunction(state, meta_displace);
lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_DISPLACE_NAME);
luaL_register(state, "df", no_functions);
{
@ -1496,6 +1565,8 @@ static void DoAttach(lua_State *state)
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_SIZEOF_NAME);
lua_setfield(state, -2, "sizeof");
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_DISPLACE_NAME);
lua_setfield(state, -2, "_displace");
freeze_table(state, true, "df");
lua_remove(state, -2);