More work on debug_string

This commit is contained in:
2021-07-21 16:10:29 -04:00
parent c2a69b5b23
commit 49a4ec220d
6 changed files with 142 additions and 95 deletions

View File

@@ -324,14 +324,15 @@ bool AnimStep::from_string(const std::string &config) {
}
AnimQueue::AnimQueue(util::WorldType wt) {
world_type_ = wt;
version_autoinc_ = (wt == util::WORLD_TYPE_MASTER);
size_limit_ = 10; // Default size limit.
clear_steps();
version_number_ = (wt == util::WORLD_TYPE_MASTER) ? 1 : 0;
steps_.emplace_back();
steps_.front().keep_state_only();
version_number_ = version_autoinc_ ? 1 : 0;
}
void AnimQueue::mutated() {
if (world_type_ == util::WORLD_TYPE_MASTER) {
if (version_autoinc_) {
version_number_ += 1;
} else {
version_number_ = 0;
@@ -353,30 +354,23 @@ bool AnimQueue::size_and_steps_equal(const AnimQueue &other) const {
return true;
}
void AnimQueue::clear_steps() {
steps_.clear();
steps_.emplace_back();
AnimStep &init = steps_.back();
init.bits_ = AnimStep::HAS_EVERYTHING;
init.action_ = "";
init.graphic_ = "";
init.plane_ = "";
mutated();
}
void AnimQueue::full_clear_and_set_limit(int n) {
assert(n >= 1);
clear_steps();
steps_.clear();
steps_.emplace_back();
steps_.front().keep_state_only();
size_limit_ = n;
version_number_ = 1;
version_number_ = version_autoinc_ ? 1 : 0;
}
void AnimQueue::set_limit(int n) {
assert(n >= 1);
size_limit_ = n;
while (int(steps_.size()) > n) {
steps_.pop_front();
if (int(steps_.size()) > n) {
while (int(steps_.size()) > n) {
steps_.pop_front();
}
steps_.front().keep_state_only();
}
steps_.front().keep_state_only();
mutated();
}
@@ -549,12 +543,23 @@ const AnimStep &AnimQueue::back() const {
return steps_.back();
}
static bool diff_works(const AnimQueue &master, AnimQueue &sync) {
StreamBuffer sb;
sync.make_patch(master, &sb);
sync.apply_patch(&sb);
return sync.size_and_steps_equal(master);
}
LuaDefine(unittests_animqueue, "c") {
// Check initial state.
// Useful objects.
AnimStep stp;
AnimQueue aq(util::WORLD_TYPE_MASTER);
StreamBuffer sb;
AnimQueue aqds(util::WORLD_TYPE_S_SYNC);
StreamBuffer sb;
// Debug string of a newly initialized queue
LuaAssert(L, aq.valid());
LuaAssertStrEq(L, aq.debug_string(), "version=1; limit=10; id=0 action= plane= x=0 y=0 z=0 facing=0 graphic=");
// Test the step setters.
stp.clear();
@@ -572,11 +577,11 @@ LuaDefine(unittests_animqueue, "c") {
stp.set_graphic("something");
LuaAssertStrEq(L, stp.debug_string(), "id=0 action= plane=somewhere x=3 y=4 z=5 facing=180 graphic=something");
// Test the step parser.
// Test the step debug string parser.
LuaAssert(L, stp.from_string("id=123 action=walk x=1 y=2 z=3 facing=4 plane=p graphic=g"));
LuaAssertStrEq(L, stp.debug_string(), "id=123 action=walk plane=p x=1 y=2 z=3 facing=4 graphic=g");
// Test a blank queue.
// Test that we can clear a queue.
aq.full_clear_and_set_limit(3);
LuaAssert(L, aq.valid());
LuaAssertStrEq(L, aq.debug_string(), "version=1; limit=3; id=0 action= plane= x=0 y=0 z=0 facing=0 graphic=");
@@ -630,28 +635,16 @@ LuaDefine(unittests_animqueue, "c") {
// Add a single action to the queue and DT
LuaAssert(L, stp.from_string("action=walk x=3 y=4 z=5"));
aq.add(12345, stp);
sb.clear();
LuaAssert(L, aqds.make_patch(aq, &sb));
aqds.apply_patch(&sb);
LuaAssert(L, aqds.size_and_steps_equal(aq));
LuaAssert(L, diff_works(aq, aqds));
// Add another action and DT
LuaAssert(L, stp.from_string("action=fnord plane=where facing=123"));
aq.add(232, stp);
sb.clear();
LuaAssert(L, aqds.make_patch(aq, &sb));
sb.write_uint32(0);
aqds.apply_patch(&sb);
LuaAssert(L, sb.total_writes() - sb.total_reads() == 4);
LuaAssert(L, aqds.size_and_steps_equal(aq));
LuaAssert(L, diff_works(aq, aqds));
// Change the queue size limit.
aq.set_limit(13);
sb.clear();
LuaAssert(L, !aqds.size_and_steps_equal(aq));
LuaAssert(L, aqds.make_patch(aq, &sb));
aqds.apply_patch(&sb);
LuaAssert(L, aqds.size_and_steps_equal(aq));
LuaAssert(L, diff_works(aq, aqds));
// compare again, should be no differences.
sb.clear();
@@ -661,11 +654,7 @@ LuaDefine(unittests_animqueue, "c") {
// Discard all but the last action.
aq.set_limit(1);
sb.clear();
LuaAssert(L, aqds.make_patch(aq, &sb));
aqds.apply_patch(&sb);
LuaAssert(L, aqds.size_and_steps_equal(aq));
LuaAssert(L, diff_works(aq, aqds));
return 0;
}

View File

@@ -25,7 +25,7 @@
// equal to the version number in the master model, then the two animqueues are
// guaranteed to be equal. Here's how we achieve that invariant:
//
// * In the master model, the version number starts at 1 and is incremented
// * In the master model, the version number starts at 1 and is auto-incremented
// every time the animation queue is mutated.
//
// * In the synchronous model, the version number is set to zero every time the
@@ -38,7 +38,7 @@
// * The routine 'update_version' should be called after difference
// transmission. This copies the version number from the master to the
// synchronous model. This is guaranteed to be safe because we just finished
// difference transmission, therefore, the animatio queues should match.
// difference transmission, therefore, the queues should match.
//
///////////////////////////////////////////////////////////////////
@@ -67,22 +67,8 @@ public:
HAS_GRAPHIC = 16,
HAS_PLANE = 32,
HAS_EVERYTHING = 63,
};
};
private:
int64_t id_;
int16_t bits_;
std::string action_;
float facing_;
util::XYZ xyz_;
std::string graphic_;
std::string plane_;
void from_lua_store_string(lua_State *L, int idx, std::string *target, int16_t bits, const char *name);
void from_lua_store_number(lua_State *L, int idx, float *target, float offset, int16_t bits, const char *name);
public:
AnimStep();
~AnimStep();
@@ -162,22 +148,27 @@ public:
// Convert a string to an animstep (for testing only).
bool from_string(const std::string &s);
private:
int64_t id_;
int16_t bits_;
std::string action_;
float facing_;
util::XYZ xyz_;
std::string graphic_;
std::string plane_;
void from_lua_store_string(lua_State *L, int idx, std::string *target, int16_t bits, const char *name);
void from_lua_store_number(lua_State *L, int idx, float *target, float offset, int16_t bits, const char *name);
};
class AnimQueue {
private:
util::WorldType world_type_;
int32_t size_limit_;
std::deque<AnimStep> steps_;
int64_t version_number_;
// Called whenever the animation queue is mutated.
// serialization and deserialization
void mutated();
public:
public:
// World type determines whether versions increment or autozero
AnimQueue(util::WorldType wt);
// Simple getters.
const AnimStep &nth(int n) const { return steps_[n]; }
size_t size() const { return steps_.size(); }
@@ -187,11 +178,6 @@ public:
// Return true if the size limit and steps are identical.
bool size_and_steps_equal(const AnimQueue &aq) const;
// Clear the steps. Doesn't affect size_limit.
// The resulting steps aren't empty. There will be one
// step in the queue, which will be on the plane "", at (0,0,0).
void clear_steps();
// Mutator to create a new step.
void add(int64_t id, const AnimStep &step);
@@ -216,6 +202,16 @@ public:
// Convert to a string for debugging purposes.
std::string debug_string() const;
private:
bool version_autoinc_;
int32_t size_limit_;
std::deque<AnimStep> steps_;
int64_t version_number_;
// Called whenever the animation queue is mutated.
// serialization and deserialization
void mutated();
};
#endif // ANIMQUEUE_HPP

View File

@@ -1,11 +1,10 @@
#include "idalloc.hpp"
#include <iostream>
#include <map>
#include <sstream>
#include <ostream>
static int64_t nthbatch(int64_t n) {
return int64_t(0x0001000000000000) + n*256;
}
static bool ranges_equal(const std::deque<int64_t> &dq, int64_t a, int64_t b, int64_t c) {
if (dq.size() != 3) return false;
@@ -100,6 +99,17 @@ void IdGlobalPool::deserialize(StreamBuffer *sb) {
}
}
std::string IdGlobalPool::debug_string() const {
std::ostringstream oss;
oss << "next_batch:" << util::hex64() << next_batch_ << " ";
oss << "next_id:" << util::hex64() << next_id_ << " ";
oss << "salvaged:";
for (const int64_t val : salvaged_) {
oss << " " << util::hex64() << val;
}
return oss.str();
}
IdPlayerPool::IdPlayerPool(IdGlobalPool *g) {
global_ = g;
fifo_capacity_ = 0;
@@ -252,6 +262,20 @@ void IdPlayerPool::apply_patch(StreamBuffer *sb) {
}
}
std::string IdPlayerPool::debug_string() const {
std::ostringstream oss;
oss << "cap:" << fifo_capacity_ << " ids:";
for (int i = 0; i < int(ranges_.size()); i++) {
if (i > 0) oss << ",";
oss << util::hex64() << ranges_[i];
}
return oss.str();
}
static int64_t nthbatch(int64_t n) {
return int64_t(0x0001000000000000) + n*256;
}
LuaDefine(unittests_idalloc, "c") {
IdGlobalPool gp;
IdPlayerPool pp(&gp);
@@ -425,12 +449,10 @@ LuaDefine(unittests_idalloc, "c") {
pp.test_push_back(123);
pp.test_push_back(456);
// transmit and compare. Add extra bytes
// transmit and compare.
sb.clear();
LuaAssert(L, ppds.make_patch(pp, &sb));
sb.write_uint32(0);
ppds.apply_patch(&sb);
LuaAssert(L, sb.total_writes() - sb.total_reads() == 4);
LuaAssert(L, ppds.exactly_equal(pp));
// Pop a value from master pool

View File

@@ -72,12 +72,6 @@
#include "streambuffer.hpp"
class IdGlobalPool {
private:
std::vector<int64_t> salvaged_;
int64_t next_batch_;
int64_t next_id_;
friend int unittests_idalloc(lua_State *L);
public:
// Construct and destroy global pools. Note that after constructing
// a global pool, it is generally also necessary to initialize it
@@ -118,15 +112,18 @@ public:
// Serialize to or deserialize from a streambuffer.
void serialize(StreamBuffer *sb);
void deserialize(StreamBuffer *sb);
// Generate a debug string.
std::string debug_string() const;
private:
std::vector<int64_t> salvaged_;
int64_t next_batch_;
int64_t next_id_;
friend int unittests_idalloc(lua_State *L);
};
class IdPlayerPool {
private:
IdGlobalPool *global_;
int fifo_capacity_;
std::deque<int64_t> ranges_;
friend int unittests_idalloc(lua_State *L);
public:
// Construct a player pool.
//
@@ -189,6 +186,15 @@ public:
//
bool make_patch(const IdPlayerPool &auth, StreamBuffer *sb) const;
void apply_patch(StreamBuffer *sb);
// Debug string.
std::string debug_string() const;
private:
IdGlobalPool *global_;
int fifo_capacity_;
std::deque<int64_t> ranges_;
friend int unittests_idalloc(lua_State *L);
};
#endif // IDALLOC_HPP

View File

@@ -6,6 +6,9 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <cmath>
#include <iostream>
#include <iomanip>
#ifndef WIN32
#include <unistd.h>
#define stat _stat
@@ -130,3 +133,23 @@ std::string XYZ::debug_string() const {
}
} // namespace util
std::ostream &operator<<(std::ostream &oss, const util::hex64 &v) {
oss << "0x" << std::setw(16) << std::setfill('0') << std::hex;
return oss;
}
std::ostream &operator<<(std::ostream &oss, const util::hex32 &v) {
oss << "0x" << std::setw(8) << std::setfill('0') << std::hex;
return oss;
}
std::ostream &operator<<(std::ostream &oss, const util::hex16 &v) {
oss << "0x" << std::setw(4) << std::setfill('0') << std::hex;
return oss;
}
std::ostream &operator<<(std::ostream &oss, const util::hex8 &v) {
oss << "0x" << std::setw(2) << std::setfill('0') << std::hex;
return oss;
}

View File

@@ -66,6 +66,17 @@ struct XYZ {
std::string debug_string() const;
};
// These are formatting directives that can be sent to a std::ostream.
class hex64 {};
class hex32 {};
class hex16 {};
class hex8 {};
} // namespace util
std::ostream &operator<<(std::ostream &oss, const util::hex64 &v);
std::ostream &operator<<(std::ostream &oss, const util::hex32 &v);
std::ostream &operator<<(std::ostream &oss, const util::hex16 &v);
std::ostream &operator<<(std::ostream &oss, const util::hex8 &v);
#endif // UTIL_HPP