diff_tables and patch_table are working and tested

This commit is contained in:
2021-08-31 20:03:33 -04:00
parent 82f1f69c25
commit 013992400e
10 changed files with 261 additions and 87 deletions

View File

@@ -13,6 +13,7 @@
#include "luastack.hpp"
#include "streambuffer.hpp"
#include "table.hpp"
#include "world.hpp"
// 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);
}
case LUA_TT_GENERAL: {
if (SLS.xtype(sval) != LUA_TT_GENERAL) return false;
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);
if (sidx == 0) return false;
return midx == sidx;
}
case LUA_TT_CLASS: {
@@ -95,8 +96,13 @@ static void transmit_value(LuaStack &MLS, LuaSlot mval, LuaSlot mtnmap, StreamBu
return;
}
case LUA_TT_GENERAL: {
sb->write_uint8(LUA_TT_GENERAL);
sb->write_uint32(get_table_number(MLS, mval, mtnmap));
int midx = 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;
}
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;
LuaVar skey, mkey, sval, mval, mnil;
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);
}
static std::string compare_tables_debug_string(StreamBuffer *sb) {
static std::string diff_tables_debug_string(StreamBuffer *sb) {
std::vector<std::string> sorted;
std::ostringstream oss;
int ndiffs = sb->read_int32();
@@ -230,7 +236,65 @@ static std::string compare_tables_debug_string(StreamBuffer *sb) {
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();
LuaVar sntmap, mntmap, stnmap, mtnmap;
LuaStack SLS(synch, sntmap, stnmap);
@@ -257,7 +321,7 @@ void World::diff_lua_tables(lua_State *master, StreamBuffer *sb) {
int tw = sb->total_writes();
sb->write_int32(id);
nmodified += 1;
if (!compare_tables(synch, master, true, sb)) {
if (!diff_tables(synch, master, true, sb)) {
sb->unwrite_to(tw);
nmodified -= 1;
}
@@ -294,7 +358,7 @@ void World::diff_tangible_databases(const IdVector &basis, lua_State *master, St
int tw = sb->total_writes();
sb->write_int64(id);
nmodified += 1;
if (!compare_tables(synch, master, false, sb)) {
if (!diff_tables(synch, master, false, sb)) {
sb->unwrite_to(tw);
nmodified -= 1;
}
@@ -309,6 +373,11 @@ LuaDefine(table_diffcompare, "c") {
LuaRet dbgstring;
LuaVar 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
// existing thread as the 'master model'.
lua_State *synch = lua_newthread(L);
@@ -320,9 +389,56 @@ LuaDefine(table_diffcompare, "c") {
lua_xmove(L, synch, 2);
lua_pushvalue(L, mtnmap.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.
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();
}