Make primitive refs (i.e. pointers to numbers, etc) behave as arrays.

develop
Alexander Gavrilov 2012-06-13 22:40:39 +04:00
parent c50b605dfc
commit 149f175909
3 changed files with 34 additions and 2 deletions

@ -121,6 +121,12 @@ or as a result of calling the ``_field()`` method.
They behave as structs with one field ``value`` of the right type.
To make working with numeric buffers easier, they also allow
numeric indices. Note that other than excluding negative values
no bound checking is performed, since buffer length is not available.
Index 0 is equivalent to the ``value`` field.
Struct references
-----------------

@ -453,6 +453,10 @@ that don't fit any of the other reference types. Such
references can only appear as a value of a pointer field,
or as a result of calling the <tt class="docutils literal">_field()</tt> method.</p>
<p>They behave as structs with one field <tt class="docutils literal">value</tt> of the right type.</p>
<p>To make working with numeric buffers easier, they also allow
numeric indices. Note that other than excluding negative values
no bound checking is performed, since buffer length is not available.
Index 0 is equivalent to the <tt class="docutils literal">value</tt> field.</p>
</div>
<div class="section" id="struct-references">
<h3><a class="toc-backref" href="#id4">Struct references</a></h3>

@ -635,6 +635,28 @@ static int meta_struct_next(lua_State *state)
return 2;
}
/**
* Field lookup for primitive refs: behave as a quasi-array with numeric indices.
*/
static type_identity *find_primitive_field(lua_State *state, int field, const char *mode, uint8_t **ptr)
{
if (lua_type(state, field) == LUA_TNUMBER)
{
int idx = lua_tointeger(state, field);
if (idx < 0)
field_error(state, 2, "negative index", mode);
lua_rawgetp(state, UPVAL_METATABLE, &DFHACK_IDENTITY_FIELD_TOKEN);
auto id = (type_identity *)lua_touserdata(state, -1);
lua_pop(state, 1);
*ptr += int(id->byte_size()) * idx;
return id;
}
return (type_identity*)find_field(state, field, mode);
}
/**
* Metamethod: __index for primitives, i.e. simple object references.
* Fields point to identity, or NULL for metafields.
@ -642,7 +664,7 @@ static int meta_struct_next(lua_State *state)
static int meta_primitive_index(lua_State *state)
{
uint8_t *ptr = get_object_addr(state, 1, 2, "read");
auto type = (type_identity*)find_field(state, 2, "read");
auto type = find_primitive_field(state, 2, "read", &ptr);
if (!type)
return 1;
type->lua_read(state, 2, ptr);
@ -655,7 +677,7 @@ static int meta_primitive_index(lua_State *state)
static int meta_primitive_newindex(lua_State *state)
{
uint8_t *ptr = get_object_addr(state, 1, 2, "write");
auto type = (type_identity*)find_field(state, 2, "write");
auto type = find_primitive_field(state, 2, "write", &ptr);
if (!type)
field_error(state, 2, "builtin property or method", "write");
type->lua_write(state, 2, ptr, 3);