diff_tables and patch_table are working and tested
This commit is contained in:
@@ -1,16 +1,6 @@
|
|||||||
#include "luastack.hpp"
|
#include "luastack.hpp"
|
||||||
#include "globaldb.hpp"
|
#include "globaldb.hpp"
|
||||||
|
|
||||||
LuaDefine(globaldb_enable, "c") {
|
|
||||||
LuaVar globaldb;
|
|
||||||
LuaStack LS(L, globaldb);
|
|
||||||
LS.rawget(globaldb, LuaRegistry, "globaldb");
|
|
||||||
if (!LS.istable(globaldb)) {
|
|
||||||
LS.newtable(globaldb);
|
|
||||||
LS.rawset(LuaRegistry, "globaldb", globaldb);
|
|
||||||
}
|
|
||||||
return LS.result();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a table from the global database.
|
// Get a table from the global database.
|
||||||
//
|
//
|
||||||
@@ -25,7 +15,7 @@ LuaDefine(globaldb_global, "f") {
|
|||||||
LuaVar globaldb;
|
LuaVar globaldb;
|
||||||
LuaStack LS(L, globalname, globaltab, globaldb);
|
LuaStack LS(L, globalname, globaltab, globaldb);
|
||||||
|
|
||||||
// Get a pointer to the globaldb.
|
// Get a pointer to the globaldb.
|
||||||
LS.rawget(globaldb, LuaRegistry, "globaldb");
|
LS.rawget(globaldb, LuaRegistry, "globaldb");
|
||||||
if (!LS.istable(globaldb)) {
|
if (!LS.istable(globaldb)) {
|
||||||
luaL_error(L, "globaldb is not enabled");
|
luaL_error(L, "globaldb is not enabled");
|
||||||
|
|||||||
@@ -28,14 +28,6 @@
|
|||||||
|
|
||||||
#include "luastack.hpp"
|
#include "luastack.hpp"
|
||||||
|
|
||||||
// globaldb_enable
|
|
||||||
//
|
|
||||||
// Enable the use of the global DB. This is meant to be invoked in
|
|
||||||
// the master world model only. In other world models, you should simply
|
|
||||||
// not call this function.
|
|
||||||
//
|
|
||||||
int globaldb_enable(lua_State *L);
|
|
||||||
|
|
||||||
// The lua 'global' operator.
|
// The lua 'global' operator.
|
||||||
//
|
//
|
||||||
// Given a global name, returns a table for that global.
|
// Given a global name, returns a table for that global.
|
||||||
|
|||||||
@@ -243,7 +243,14 @@ void LuaStack::makeclass(LuaSlot classtab, LuaSlot classname) const {
|
|||||||
LS.result();
|
LS.result();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaStack::makeclass(LuaSlot tab, const char *name) {
|
void LuaStack::makeclass(LuaSlot tab, const char *name) const {
|
||||||
|
push_any_value(name);
|
||||||
|
LuaSpecial classname(lua_gettop(L_));
|
||||||
|
makeclass(tab, classname);
|
||||||
|
lua_pop(L_, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaStack::makeclass(LuaSlot tab, const std::string &name) const {
|
||||||
push_any_value(name);
|
push_any_value(name);
|
||||||
LuaSpecial classname(lua_gettop(L_));
|
LuaSpecial classname(lua_gettop(L_));
|
||||||
makeclass(tab, classname);
|
makeclass(tab, classname);
|
||||||
|
|||||||
@@ -420,7 +420,8 @@ public:
|
|||||||
|
|
||||||
void getclass(LuaSlot tab, LuaSlot name) const;
|
void getclass(LuaSlot tab, LuaSlot name) const;
|
||||||
void makeclass(LuaSlot tab, LuaSlot name) const;
|
void makeclass(LuaSlot tab, LuaSlot name) const;
|
||||||
void makeclass(LuaSlot tab, const char *name);
|
void makeclass(LuaSlot tab, const char *name) const;
|
||||||
|
void makeclass(LuaSlot tab, const std::string &name) const;
|
||||||
std::string classname(LuaSlot tab);
|
std::string classname(LuaSlot tab);
|
||||||
|
|
||||||
void movesortablekey(LuaSlot val, LuaStack &other, LuaSlot otherslot);
|
void movesortablekey(LuaSlot val, LuaStack &other, LuaSlot otherslot);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include "luastack.hpp"
|
#include "luastack.hpp"
|
||||||
#include "streambuffer.hpp"
|
#include "streambuffer.hpp"
|
||||||
|
#include "table.hpp"
|
||||||
#include "world.hpp"
|
#include "world.hpp"
|
||||||
|
|
||||||
// Given a table and an tnmap, return the table number of the table.
|
// Given a table and an tnmap, return the table number of the table.
|
||||||
@@ -52,11 +53,11 @@ static bool equivalent_values(LuaStack &MLS, LuaSlot mval, LuaSlot mtnmap,
|
|||||||
return SLS.type(sval) == MLS.type(mval);
|
return SLS.type(sval) == MLS.type(mval);
|
||||||
}
|
}
|
||||||
case LUA_TT_GENERAL: {
|
case LUA_TT_GENERAL: {
|
||||||
if (SLS.xtype(sval) != LUA_TT_GENERAL) return false;
|
|
||||||
int midx = get_table_number(MLS, mval, mtnmap);
|
int midx = get_table_number(MLS, mval, mtnmap);
|
||||||
if (midx == 0) return false;
|
if (midx == 0) {
|
||||||
|
return SLS.isnil(sval);
|
||||||
|
}
|
||||||
int sidx = get_table_number(SLS, sval, stnmap);
|
int sidx = get_table_number(SLS, sval, stnmap);
|
||||||
if (sidx == 0) return false;
|
|
||||||
return midx == sidx;
|
return midx == sidx;
|
||||||
}
|
}
|
||||||
case LUA_TT_CLASS: {
|
case LUA_TT_CLASS: {
|
||||||
@@ -95,8 +96,13 @@ static void transmit_value(LuaStack &MLS, LuaSlot mval, LuaSlot mtnmap, StreamBu
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case LUA_TT_GENERAL: {
|
case LUA_TT_GENERAL: {
|
||||||
sb->write_uint8(LUA_TT_GENERAL);
|
int midx = get_table_number(MLS, mval, mtnmap);
|
||||||
sb->write_uint32(get_table_number(MLS, mval, mtnmap));
|
if (midx == 0) {
|
||||||
|
sb->write_uint8(LUA_TNIL);
|
||||||
|
} else {
|
||||||
|
sb->write_uint8(LUA_TT_GENERAL);
|
||||||
|
sb->write_uint32(midx);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case LUA_TT_CLASS: {
|
case LUA_TT_CLASS: {
|
||||||
@@ -160,7 +166,7 @@ static void transmit_value_debug_string(StreamBuffer *sb, std::ostringstream &os
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool compare_tables(lua_State *synch, lua_State *master, bool cmeta, StreamBuffer *sb) {
|
static bool diff_tables(lua_State *synch, lua_State *master, bool cmeta, StreamBuffer *sb) {
|
||||||
LuaArg mtnmap, mtab, stnmap, stab;
|
LuaArg mtnmap, mtab, stnmap, stab;
|
||||||
LuaVar skey, mkey, sval, mval, mnil;
|
LuaVar skey, mkey, sval, mval, mnil;
|
||||||
LuaStack SLS(synch, stnmap, stab, skey, sval);
|
LuaStack SLS(synch, stnmap, stab, skey, sval);
|
||||||
@@ -212,7 +218,7 @@ static bool compare_tables(lua_State *synch, lua_State *master, bool cmeta, Stre
|
|||||||
return (nupdates > 0);
|
return (nupdates > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string compare_tables_debug_string(StreamBuffer *sb) {
|
static std::string diff_tables_debug_string(StreamBuffer *sb) {
|
||||||
std::vector<std::string> sorted;
|
std::vector<std::string> sorted;
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
int ndiffs = sb->read_int32();
|
int ndiffs = sb->read_int32();
|
||||||
@@ -230,7 +236,65 @@ static std::string compare_tables_debug_string(StreamBuffer *sb) {
|
|||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::diff_lua_tables(lua_State *master, StreamBuffer *sb) {
|
static void set_transmitted_value(LuaStack &LS, LuaSlot tangibles, LuaSlot ntmap, LuaSlot target, StreamBuffer *sb) {
|
||||||
|
int kind = sb->read_uint8();
|
||||||
|
switch (kind) {
|
||||||
|
case LUA_TBOOLEAN: {
|
||||||
|
LS.set(target, sb->read_bool());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LUA_TNUMBER: {
|
||||||
|
LS.set(target, sb->read_double());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LUA_TSTRING: {
|
||||||
|
LS.set(target, sb->read_string());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LUA_TT_GENERAL: {
|
||||||
|
LS.rawgeti(target, ntmap, sb->read_int32());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LUA_TT_CLASS: {
|
||||||
|
LS.makeclass(target, sb->read_string());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LUA_TT_TANGIBLE: {
|
||||||
|
int64_t id = sb->read_int64();
|
||||||
|
LS.rawgeti(target, tangibles, id);
|
||||||
|
if (LS.isnil(target)) {
|
||||||
|
World *w = World::fetch_global_pointer(LS.state());
|
||||||
|
w->tangible_make(LS.state(), id, true);
|
||||||
|
lua_replace(LS.state(), target.index());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LUA_TT_GLOBALENV: {
|
||||||
|
LS.getglobaltable(target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LUA_TNIL: {
|
||||||
|
LS.set(target, LuaNil);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
assert(false); // Should not get here.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void patch_table(LuaStack &LS0, LuaSlot tangibles, LuaSlot ntmap, LuaSlot tab, StreamBuffer *sb) {
|
||||||
|
LuaVar key, val;
|
||||||
|
LuaStack LS(LS0.state(), key, val);
|
||||||
|
int ndiffs = sb->read_int32();
|
||||||
|
for (int i = 0; i < ndiffs; i++) {
|
||||||
|
set_transmitted_value(LS, tangibles, ntmap, key, sb);
|
||||||
|
set_transmitted_value(LS, tangibles, ntmap, val, sb);
|
||||||
|
LS.rawset(tab, key, val);
|
||||||
|
}
|
||||||
|
LS.result();
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::diff_numbered_tables(lua_State *master, StreamBuffer *sb) {
|
||||||
lua_State *synch = state();
|
lua_State *synch = state();
|
||||||
LuaVar sntmap, mntmap, stnmap, mtnmap;
|
LuaVar sntmap, mntmap, stnmap, mtnmap;
|
||||||
LuaStack SLS(synch, sntmap, stnmap);
|
LuaStack SLS(synch, sntmap, stnmap);
|
||||||
@@ -257,7 +321,7 @@ void World::diff_lua_tables(lua_State *master, StreamBuffer *sb) {
|
|||||||
int tw = sb->total_writes();
|
int tw = sb->total_writes();
|
||||||
sb->write_int32(id);
|
sb->write_int32(id);
|
||||||
nmodified += 1;
|
nmodified += 1;
|
||||||
if (!compare_tables(synch, master, true, sb)) {
|
if (!diff_tables(synch, master, true, sb)) {
|
||||||
sb->unwrite_to(tw);
|
sb->unwrite_to(tw);
|
||||||
nmodified -= 1;
|
nmodified -= 1;
|
||||||
}
|
}
|
||||||
@@ -294,7 +358,7 @@ void World::diff_tangible_databases(const IdVector &basis, lua_State *master, St
|
|||||||
int tw = sb->total_writes();
|
int tw = sb->total_writes();
|
||||||
sb->write_int64(id);
|
sb->write_int64(id);
|
||||||
nmodified += 1;
|
nmodified += 1;
|
||||||
if (!compare_tables(synch, master, false, sb)) {
|
if (!diff_tables(synch, master, false, sb)) {
|
||||||
sb->unwrite_to(tw);
|
sb->unwrite_to(tw);
|
||||||
nmodified -= 1;
|
nmodified -= 1;
|
||||||
}
|
}
|
||||||
@@ -309,6 +373,11 @@ LuaDefine(table_diffcompare, "c") {
|
|||||||
LuaRet dbgstring;
|
LuaRet dbgstring;
|
||||||
LuaVar tthread;
|
LuaVar tthread;
|
||||||
LuaStack LS(L, mtnmap, mtab, stnmap, stab, dbgstring, tthread);
|
LuaStack LS(L, mtnmap, mtab, stnmap, stab, dbgstring, tthread);
|
||||||
|
// Check the arguments.
|
||||||
|
LS.checktable(mtnmap);
|
||||||
|
LS.checktable(stnmap);
|
||||||
|
LS.checktable(mtab);
|
||||||
|
LS.checktable(stab);
|
||||||
// Create a temporary thread to be the 'synch model'. We'll use the
|
// Create a temporary thread to be the 'synch model'. We'll use the
|
||||||
// existing thread as the 'master model'.
|
// existing thread as the 'master model'.
|
||||||
lua_State *synch = lua_newthread(L);
|
lua_State *synch = lua_newthread(L);
|
||||||
@@ -320,9 +389,56 @@ LuaDefine(table_diffcompare, "c") {
|
|||||||
lua_xmove(L, synch, 2);
|
lua_xmove(L, synch, 2);
|
||||||
lua_pushvalue(L, mtnmap.index());
|
lua_pushvalue(L, mtnmap.index());
|
||||||
lua_pushvalue(L, mtab.index());
|
lua_pushvalue(L, mtab.index());
|
||||||
compare_tables(synch, L, true, &sb);
|
diff_tables(synch, L, true, &sb);
|
||||||
// Convert the output to a debug string.
|
// Convert the output to a debug string.
|
||||||
LS.set(dbgstring, compare_tables_debug_string(&sb));
|
LS.set(dbgstring, diff_tables_debug_string(&sb));
|
||||||
|
return LS.result();
|
||||||
|
}
|
||||||
|
|
||||||
|
LuaDefine(table_diffapply, "c") {
|
||||||
|
LuaArg tnmap, mtab, stab;
|
||||||
|
LuaRet eql, eqlstr, rtab;
|
||||||
|
LuaVar tthread, tangibles, ntmap, key, val;
|
||||||
|
LuaStack LS(L, tnmap, mtab, stab, eql, eqlstr, rtab, tthread, tangibles, ntmap, key, val);
|
||||||
|
// Check the arguments.
|
||||||
|
LS.checktable(tnmap);
|
||||||
|
LS.checktable(mtab);
|
||||||
|
LS.checktable(stab);
|
||||||
|
|
||||||
|
// Get the tangibles map.
|
||||||
|
LS.rawget(tangibles, LuaRegistry, "tangibles");
|
||||||
|
|
||||||
|
// Invert the tnmap to make the ntmap.
|
||||||
|
LS.set(ntmap, LuaNewTable);
|
||||||
|
LS.set(key, LuaNil);
|
||||||
|
while (LS.next(tnmap, key, val)) {
|
||||||
|
LS.rawset(ntmap, val, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a temporary thread to be the 'synch model'. We'll use the
|
||||||
|
// existing thread as the 'master model'.
|
||||||
|
lua_State *synch = lua_newthread(L);
|
||||||
|
lua_replace(L, tthread.index());
|
||||||
|
// Call tablecmp_diff.
|
||||||
|
StreamBuffer sb;
|
||||||
|
lua_pushvalue(L, tnmap.index());
|
||||||
|
lua_pushvalue(L, stab.index());
|
||||||
|
lua_xmove(L, synch, 2);
|
||||||
|
lua_pushvalue(L, tnmap.index());
|
||||||
|
lua_pushvalue(L, mtab.index());
|
||||||
|
diff_tables(synch, L, true, &sb);
|
||||||
|
|
||||||
|
patch_table(LS, tangibles, ntmap, stab, &sb);
|
||||||
|
|
||||||
|
LS.call(eql, table_equal, stab, mtab);
|
||||||
|
bool e = LS.ckboolean(eql);
|
||||||
|
if (e) {
|
||||||
|
LS.set(eqlstr, "tables equal");
|
||||||
|
} else {
|
||||||
|
LS.set(eqlstr, "tables were supposed to be equal");
|
||||||
|
}
|
||||||
|
LS.set(rtab, stab);
|
||||||
|
|
||||||
return LS.result();
|
return LS.result();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
// routines in this file:
|
// routines in this file:
|
||||||
//
|
//
|
||||||
// World::number_lua_tables
|
// World::number_lua_tables
|
||||||
// World::unnumber_lua_tables
|
|
||||||
// World::pair_lua_tables
|
// World::pair_lua_tables
|
||||||
// World::pair_new_tables
|
// World::number_remaining_tables
|
||||||
// World::create_new_tables
|
// World::create_new_tables
|
||||||
|
// World::unnumber_lua_tables
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -76,13 +76,6 @@ int World::number_lua_tables(const IdVector &basis) {
|
|||||||
return nextid - 1;
|
return nextid - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::unnumber_lua_tables() {
|
|
||||||
// All we have to do is remove these tables from the registry.
|
|
||||||
LuaStack LS(state());
|
|
||||||
LS.rawset(LuaRegistry, "tnmap", LuaNil);
|
|
||||||
LS.rawset(LuaRegistry, "ntmap", LuaNil);
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::pair_lua_tables(const IdVector &basis, lua_State *master) {
|
void World::pair_lua_tables(const IdVector &basis, lua_State *master) {
|
||||||
lua_State *synch = state();
|
lua_State *synch = state();
|
||||||
LuaVar stangibles, mtangibles, sntmap, mntmap, stnmap, mtnmap, stab, mtab, skey, mkey, sval, mval, sidx, midx;
|
LuaVar stangibles, mtangibles, sntmap, mntmap, stnmap, mtnmap, stab, mtab, skey, mkey, sval, mval, sidx, midx;
|
||||||
@@ -182,7 +175,7 @@ void World::pair_lua_tables(const IdVector &basis, lua_State *master) {
|
|||||||
SLS.result();
|
SLS.result();
|
||||||
}
|
}
|
||||||
|
|
||||||
int World::pair_new_tables(const IdVector &basis, lua_State *master) {
|
int World::number_remaining_tables(const IdVector &basis, lua_State *master) {
|
||||||
// This is conceptually recursive, but we're going to use an
|
// This is conceptually recursive, but we're going to use an
|
||||||
// explicit stack (the lua stack).
|
// explicit stack (the lua stack).
|
||||||
lua_State *L = master;
|
lua_State *L = master;
|
||||||
@@ -268,4 +261,10 @@ void World::create_new_tables(int n) {
|
|||||||
assert(stack_is_clear());
|
assert(stack_is_clear());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void World::unnumber_lua_tables() {
|
||||||
|
// All we have to do is remove these tables from the registry.
|
||||||
|
LuaStack LS(state());
|
||||||
|
LS.rawset(LuaRegistry, "tnmap", LuaNil);
|
||||||
|
LS.rawset(LuaRegistry, "ntmap", LuaNil);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,9 @@ World::World(util::WorldType wt) {
|
|||||||
// Create the tangibles table in the registry.
|
// Create the tangibles table in the registry.
|
||||||
LS.rawset(LuaRegistry, "tangibles", LuaNewTable);
|
LS.rawset(LuaRegistry, "tangibles", LuaNewTable);
|
||||||
|
|
||||||
|
// Create the globaldb in the registry.
|
||||||
|
LS.rawset(LuaRegistry, "globaldb", LuaNewTable);
|
||||||
|
|
||||||
// Initialize the SourceDB. At this stage, the sourcedb is
|
// Initialize the SourceDB. At this stage, the sourcedb is
|
||||||
// empty, so it's just populating the lua builtins.
|
// empty, so it's just populating the lua builtins.
|
||||||
source_db_.init(state());
|
source_db_.init(state());
|
||||||
@@ -755,7 +758,7 @@ void World::difference_transmit(int64_t actor_id, World *master, StreamBuffer *s
|
|||||||
|
|
||||||
// Pair tables from the synchronous and master models.
|
// Pair tables from the synchronous and master models.
|
||||||
pair_lua_tables(closetans, master->state());
|
pair_lua_tables(closetans, master->state());
|
||||||
int ncreate = pair_new_tables(closetans, master->state());
|
int ncreate = number_remaining_tables(closetans, master->state());
|
||||||
sb->write_int32(ncreate);
|
sb->write_int32(ncreate);
|
||||||
create_new_tables(ncreate);
|
create_new_tables(ncreate);
|
||||||
|
|
||||||
@@ -1113,7 +1116,7 @@ LuaDefine(unittests_world, "c") {
|
|||||||
// The master world model above has two tables that couldn't be paired
|
// The master world model above has two tables that couldn't be paired
|
||||||
// to the client: inventory.cplx, and transactions. These two tables
|
// to the client: inventory.cplx, and transactions. These two tables
|
||||||
// should be paired to new, created tables.
|
// should be paired to new, created tables.
|
||||||
ncreate = m->pair_new_tables(util::id_vector_create(123), m->state());
|
ncreate = m->number_remaining_tables(util::id_vector_create(123), m->state());
|
||||||
LuaAssert(L, ncreate == 2);
|
LuaAssert(L, ncreate == 2);
|
||||||
ss->create_new_tables(ncreate);
|
ss->create_new_tables(ncreate);
|
||||||
LuaAssertStrEq(L, ss->paired_tables_debug_string(m->state()),
|
LuaAssertStrEq(L, ss->paired_tables_debug_string(m->state()),
|
||||||
|
|||||||
@@ -285,9 +285,9 @@ private:
|
|||||||
static void diff_visible_animations(const TanVector &mvis, const TanVector &svis, StreamBuffer *sb);
|
static void diff_visible_animations(const TanVector &mvis, const TanVector &svis, StreamBuffer *sb);
|
||||||
void patch_visible_animations(StreamBuffer *sb);
|
void patch_visible_animations(StreamBuffer *sb);
|
||||||
|
|
||||||
// Compare the general tables.
|
// Compare the numbered general tables.
|
||||||
//
|
//
|
||||||
void diff_lua_tables(lua_State *master, StreamBuffer *sb);
|
void diff_numbered_tables(lua_State *master, StreamBuffer *sb);
|
||||||
|
|
||||||
// Compare the tangible databases.
|
// Compare the tangible databases.
|
||||||
//
|
//
|
||||||
@@ -298,36 +298,55 @@ public:
|
|||||||
//
|
//
|
||||||
// Numbering and pairing of lua tables.
|
// Numbering and pairing of lua tables.
|
||||||
//
|
//
|
||||||
|
// The following routines pair up tables in the synchronous
|
||||||
|
// model with tables in the master model, by assigning matching
|
||||||
|
// table numbers. This is not one subroutine but several, because
|
||||||
|
// some of the steps happen on the server, some on the client,
|
||||||
|
// and so forth.
|
||||||
|
//
|
||||||
|
// The goal of these routines is to build these data structures:
|
||||||
|
//
|
||||||
// Table-to-number mapping is stored in registry.tnmap
|
// Table-to-number mapping is stored in registry.tnmap
|
||||||
// Number-to-table mapping is stored in registry.ntmap
|
// Number-to-table mapping is stored in registry.ntmap
|
||||||
//
|
//
|
||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// numbering of tables.
|
// In the synchronous models, number tables recursively.
|
||||||
//
|
//
|
||||||
// Returns the total number of tables numbered.
|
// This is a simple recursive traversal, which numbers tables.
|
||||||
|
// This creates the initial ntmap in the synchronous models.
|
||||||
//
|
//
|
||||||
int number_lua_tables(const IdVector &basis);
|
int number_lua_tables(const IdVector &basis);
|
||||||
|
|
||||||
// Deletes registry.tnmap and registry.ntmap
|
// Pair tables in the master model to tables in the synch model.
|
||||||
//
|
//
|
||||||
void unnumber_lua_tables();
|
// Recursively walk the master and synchronous model in parallel,
|
||||||
|
// copying table numbers from the synchronous ntmap into the master's ntmap.
|
||||||
// Number tables in the master model to match already-numbered tables in the synch model.
|
|
||||||
//
|
//
|
||||||
void pair_lua_tables(const IdVector &basis, lua_State *master);
|
void pair_lua_tables(const IdVector &basis, lua_State *master);
|
||||||
|
|
||||||
// Pairs every not-yet-paired master table to a virtually-created table in the synch model.
|
// Number previously unpaired tables in the master model.
|
||||||
//
|
//
|
||||||
// Returns the number of new tables that need to be created in the synch model.
|
// This finds every not-yet-numbered table in the master model,
|
||||||
|
// and appends these tables to the master's ntmap. Once they're
|
||||||
|
// in the ntmap, they can be paired by simply creating new tables
|
||||||
|
// in the synchronous model.
|
||||||
//
|
//
|
||||||
int pair_new_tables(const IdVector &basis, lua_State *master);
|
int number_remaining_tables(const IdVector &basis, lua_State *master);
|
||||||
|
|
||||||
// This is followup for pair_new_tables: actually create the new tables that
|
// Create new tables in the synchronous models.
|
||||||
// were virtually created in the pair_new_tables step.
|
//
|
||||||
|
// Creates new tables in the synchronous model and appends these
|
||||||
|
// new tables to the synchronous model's ntmap.
|
||||||
//
|
//
|
||||||
void create_new_tables(int n);
|
void create_new_tables(int n);
|
||||||
|
|
||||||
|
// Delete the table numbering.
|
||||||
|
//
|
||||||
|
// This simply removes registry.tnmap and registry.ntmap
|
||||||
|
//
|
||||||
|
void unnumber_lua_tables();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Type of model
|
// Type of model
|
||||||
util::WorldType world_type_;
|
util::WorldType world_type_;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
makeclass("unittests")
|
makeclass("unittests")
|
||||||
|
|
||||||
function unittests.globaldb()
|
function unittests.globaldb()
|
||||||
globaldb.enable()
|
|
||||||
local g1a = global("unittest-g1")
|
local g1a = global("unittest-g1")
|
||||||
local g2a = global("unittest-g2")
|
local g2a = global("unittest-g2")
|
||||||
local g1b = global("unittest-g1")
|
local g1b = global("unittest-g1")
|
||||||
|
|||||||
@@ -1,63 +1,67 @@
|
|||||||
|
|
||||||
|
-- the tdc function calculates diffs, and returns those
|
||||||
|
-- diffs as a human-readable string.
|
||||||
local tdc = table.diffcompare
|
local tdc = table.diffcompare
|
||||||
|
|
||||||
function unittests.tablecmp()
|
-- the tda function calculates diffs, applies the diffs to the second
|
||||||
|
-- table, and then returns true if the second table equals the first.
|
||||||
|
local tda = table.diffapply
|
||||||
|
|
||||||
|
function unittests.diffcompare()
|
||||||
|
local rtab = nil
|
||||||
|
|
||||||
-- No differences in these simple-valued tables.
|
-- No differences in these simple-valued tables.
|
||||||
assert(tdc(nil, {a=true}, nil, {a=true}) == "")
|
assert(tdc({}, {a=true}, {}, {a=true}) == "")
|
||||||
assert(tdc(nil, {a=5}, nil, {a=5}) == "");
|
assert(tdc({}, {a=5}, {}, {a=5}) == "");
|
||||||
assert(tdc(nil, {a="foo"}, nil, {a="foo"}) == "")
|
assert(tdc({}, {a="foo"}, {}, {a="foo"}) == "")
|
||||||
|
|
||||||
-- Test transmission of missing simple values.
|
-- Test transmission of missing simple values.
|
||||||
assert(tdc(nil, {a=true}, nil, {}) == "a=true;")
|
assert(tdc({}, {a=true}, {}, {}) == "a=true;")
|
||||||
assert(tdc(nil, {a=5}, nil, {}) == "a=5;");
|
assert(tdc({}, {a=5}, {}, {}) == "a=5;");
|
||||||
assert(tdc(nil, {a="foo"}, nil, {}) == "a=foo;")
|
assert(tdc({}, {a="foo"}, {}, {}) == "a=foo;")
|
||||||
|
|
||||||
-- Test the replacement of simple values.
|
-- Test the replacement of simple values.
|
||||||
assert(tdc(nil, {a=true}, nil, {a=false}) == "a=true;")
|
assert(tdc({}, {a=true}, {}, {a=false}) == "a=true;")
|
||||||
assert(tdc(nil, {a=5}, nil, {a=4}) == "a=5;");
|
assert(tdc({}, {a=5}, {}, {a=4}) == "a=5;");
|
||||||
assert(tdc(nil, {a="foo"}, nil, {a="bar"}) == "a=foo;")
|
assert(tdc({}, {a="foo"}, {}, {a="bar"}) == "a=foo;")
|
||||||
|
|
||||||
-- Test the clearing of values.
|
-- Test the clearing of values.
|
||||||
assert(tdc(nil, {}, nil, {a=true}) == "a=nil;")
|
assert(tdc({}, {}, {}, {a=true}) == "a=nil;")
|
||||||
assert(tdc(nil, {}, nil, {a=5}) == "a=nil;");
|
assert(tdc({}, {}, {}, {a=5}) == "a=nil;");
|
||||||
assert(tdc(nil, {}, nil, {a="foo"}) == "a=nil;")
|
assert(tdc({}, {}, {}, {a="foo"}) == "a=nil;")
|
||||||
|
|
||||||
-- Try boolean keys.
|
-- Try boolean keys.
|
||||||
assert(tdc(nil, {[true]=3}, nil, {}) == "true=3;")
|
assert(tdc({}, {[true]=3}, {}, {}) == "true=3;")
|
||||||
assert(tdc(nil, {}, nil, {[true]=3}) == "true=nil;")
|
assert(tdc({}, {}, {}, {[true]=3}) == "true=nil;")
|
||||||
|
|
||||||
-- Try number keys.
|
-- Try number keys.
|
||||||
assert(tdc(nil, {[7]=3}, nil, {}) == "7=3;")
|
assert(tdc({}, {[7]=3}, {}, {}) == "7=3;")
|
||||||
assert(tdc(nil, {}, nil, {[7]=3}) == "7=nil;")
|
assert(tdc({}, {}, {}, {[7]=3}) == "7=nil;")
|
||||||
|
|
||||||
-- Try a table with multiple keys.
|
-- Try a table with multiple keys.
|
||||||
assert(tdc(nil, {a=4, b=5, c=6}, nil, {b=5, c=7, d=8}) == "a=4;c=6;d=nil;")
|
assert(tdc({}, {a=4, b=5, c=6}, {}, {b=5, c=7, d=8}) == "a=4;c=6;d=nil;")
|
||||||
|
|
||||||
-- Nonsortable keys should be ignored (no diffs).
|
-- Nonsortable keys should be ignored (no diffs).
|
||||||
assert(tdc(nil, {[{}]=3}, nil, {}) == "")
|
assert(tdc({}, {[{}]=3}, {}, {}) == "")
|
||||||
|
|
||||||
-- Try a table containing a class.
|
-- Try a table containing a class.
|
||||||
assert(tdc(nil, {a=deque}, nil, {}) == "a=class deque;")
|
assert(tdc({}, {a=deque}, {}, {}) == "a=class deque;")
|
||||||
|
|
||||||
-- Try a table containing a pointer to the global environment.
|
-- Try a table containing a pointer to the global environment.
|
||||||
assert(tdc(nil, {a=_G}, nil, {}) == "a=globals;")
|
assert(tdc({}, {a=_G}, {}, {}) == "a=globals;")
|
||||||
|
|
||||||
-- GlobalDB tables should be forced to NIL.
|
-- GlobalDB tables should be forced to NIL.
|
||||||
assert(tdc(nil, {a=global("foo")}, nil, {a=global("foo")}) == "a=nil;");
|
assert(tdc({}, {a=global("foo")}, {}, {a=global("foo")}) == "a=nil;");
|
||||||
assert(tdc(nil, {}, nil, {a=global("foo")}) == "a=nil;");
|
assert(tdc({}, {}, {}, {a=global("foo")}) == "a=nil;");
|
||||||
assert(tdc(nil, {a=global("foo")}, nil, {}) == "");
|
assert(tdc({}, {a=global("foo")}, {}, {}) == "");
|
||||||
|
|
||||||
-- Set up some numbered tables for tests involving such.
|
-- Set up some numbered tables for tests involving such.
|
||||||
local mtab10 = {}
|
local mtab10 = {}
|
||||||
local stab10 = {}
|
local stab10 = {}
|
||||||
local mtab11 = {}
|
|
||||||
local stab11 = {}
|
|
||||||
local mtnmap = {}
|
local mtnmap = {}
|
||||||
local stnmap = {}
|
local stnmap = {}
|
||||||
mtnmap[mtab10] = 10
|
mtnmap[mtab10] = 10
|
||||||
stnmap[stab10] = 10
|
stnmap[stab10] = 10
|
||||||
mtnmap[mtab11] = 11
|
|
||||||
stnmap[stab11] = 11
|
|
||||||
|
|
||||||
-- confirm that numbered tables are being transmitted.
|
-- confirm that numbered tables are being transmitted.
|
||||||
assert(tdc(mtnmap, {a=mtab10}, stnmap, {}) == "a=table 10;")
|
assert(tdc(mtnmap, {a=mtab10}, stnmap, {}) == "a=table 10;")
|
||||||
@@ -65,7 +69,51 @@ function unittests.tablecmp()
|
|||||||
assert(tdc(mtnmap, {a=3}, stnmap, {a=stab10}) == "a=3;")
|
assert(tdc(mtnmap, {a=3}, stnmap, {a=stab10}) == "a=3;")
|
||||||
assert(tdc(mtnmap, {}, stnmap, {a=stab10}) == "a=nil;")
|
assert(tdc(mtnmap, {}, stnmap, {a=stab10}) == "a=nil;")
|
||||||
|
|
||||||
|
-- confirm that unnumbered tables are forced to nil.
|
||||||
|
assert(tdc(mtnmap, {a={}}, stnmap, {}) == "")
|
||||||
|
assert(tdc(mtnmap, {a={}}, stnmap, {a=3}) == "a=nil;")
|
||||||
|
|
||||||
-- we're not going to test tangibles
|
-- we're not going to test tangibles
|
||||||
-- creating tangibles here is too difficult.
|
-- creating tangibles here is too difficult.
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function unittests.diffapply()
|
||||||
|
local tab10={id=tab10}
|
||||||
|
local tab11={id=tab11}
|
||||||
|
local tnmap={}
|
||||||
|
tnmap[tab10] = 10
|
||||||
|
tnmap[tab11] = 11
|
||||||
|
|
||||||
|
-- verify some simple values.
|
||||||
|
assert(tda(tnmap, {a=1}, {}))
|
||||||
|
assert(tda(tnmap, {[true]="foo"}, {}))
|
||||||
|
assert(tda(tnmap, {[3]=false}, {}))
|
||||||
|
|
||||||
|
-- verify a table with multiple simple values.
|
||||||
|
assert(tda(tnmap, {a=1, b=2, c=3}, {}))
|
||||||
|
|
||||||
|
-- verify that it can remove or replace wrong values.
|
||||||
|
assert(tda(tnmap, {a=1,b=2}, {b=3,c=4}))
|
||||||
|
|
||||||
|
-- verify a table containing another table.
|
||||||
|
assert(tda(tnmap, {a=tab10, b=tab11}, {}))
|
||||||
|
|
||||||
|
-- verify a table containing a class.
|
||||||
|
assert(tda(tnmap, {a=deque, b=table}, {}))
|
||||||
|
|
||||||
|
-- verify a table containing the global environment.
|
||||||
|
assert(tda(tnmap, {a=_G}, {}))
|
||||||
|
|
||||||
|
-- GlobalDB tables should be forced to NIL.
|
||||||
|
rtab={a=3}
|
||||||
|
assert(not tda({}, {a=global("foo")}, rtab))
|
||||||
|
assert(rtab.a == nil)
|
||||||
|
|
||||||
|
-- Unnumbered tables should be forced to NIL.
|
||||||
|
rtab={a=3}
|
||||||
|
assert(not tda({}, {a={}}, rtab))
|
||||||
|
assert(rtab.a == nil)
|
||||||
|
|
||||||
|
-- don't test tangibles.
|
||||||
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user