[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Proposal: Constant Tables
- From: Gregory Bonik <gregory@...>
- Date: Sat, 13 Aug 2011 16:34:18 +0400
В Сб., 13/08/2011 в 00:52 +0200, Lars Doelle пишет:
> Hi All,
>
>
> reviewing the tables, i found them limited w.r.t. composed keys.
> To ensure, all keys stay the same during their existience, tables
> as possible (and only) structuring technic are only identified
> by their pointer (i.e. object name).
>
> --
>
> Practical example:
>
> Key1 = { first="John", last="Doe" }
> Key2 = { first="John", last="Doe" }
>
> When using a key like the above for an table, currently Key1
> and Key2 would identify different entries, i.e. are of no use.
A function like Table.todata in not too hard to implement since you can
use lua_topointer for tables, userdata, functions and threads. Here is a
sketch (may even not compile) of a function called table_to_string which
converts a table to its unique string representation:
static void encode_lua_value(lua_State* L, int index, std::ostream& o)
{
switch (lua_type(L, index))
{
case LUA_TNIL: o << 'l'; break;
case LUA_TNUMBER: o << 'n' << lua_tonumber(L, index); break;
case LUA_TBOOLEAN: o << 'b' << lua_toboolean(L, index); break;
case LUA_TSTRING: { o << 's';
size_t len;
const char* = lua_tolstring(L, index, &len);
o.write((char*)(void*)&len, sizeof(len));
o.write(s, len);
} break;
case LUA_TTABLE:
case LUA_TFUNCTION:
case LUA_TUSERDATA:
case LUA_TLIGHTUSERDATA:
case LUA_TTHREAD: { o << 'p';
void* p = lua_topointer(L, index);
o.write((char*)(void*)&p, sizeof(p));
} break;
}
}
int table_to_string(lua_State* L)
{
std::ostringstream o;
lua_pushnil(L);
while (lua_next(L, 1) != 0) {
encode_lua_value(L, -2, o);
encode_lua_value(L, -1, o);
lua_pop(L, 1);
}
std::string s = o.str();
lua_pushlstring(L, s.data(), s.length());
return 1;
}
Now, you could use the same idea as in interned strings to provide table
uniqueness. Set up a registry of tables:
local registry = {}
setmetatable(registry, {__mode = "v"})
local function intern_table(t)
local s = table_to_string(t)
if registry[s] then return registry[s] end
registry[s] = t
return t
end
Now use intern_table to make keys:
Key1 = intern_table { first="John", last="Doe" }
Key2 = intern_table { first="John", last="Doe" }
assert(Key1 == Key2)
Unfortunately, you cannot catch all modifications of tables in registry
because the semantics of __newindex are so that an assignment t[v] = k
ignores the metatable if there is already a key v in the table. Still,
you can implement a consistency check function which traverses the
registry and checks if tables really match their string
representations.
Alternatively, you could give up the idea of interned tables and just
use table_to_string function to produce keys, e.g.
Key1 = table_to_string { first="John", last="Doe" }
-- Gregory