From 49a4ec220d89854660c58664793082ca9c475de8 Mon Sep 17 00:00:00 2001 From: Josh Yelon Date: Wed, 21 Jul 2021 16:10:29 -0400 Subject: [PATCH] More work on debug_string --- luprex/core/cpp/animqueue.cpp | 77 +++++++++++++++-------------------- luprex/core/cpp/animqueue.hpp | 62 +++++++++++++--------------- luprex/core/cpp/idalloc.cpp | 34 +++++++++++++--- luprex/core/cpp/idalloc.hpp | 30 ++++++++------ luprex/core/cpp/util.cpp | 23 +++++++++++ luprex/core/cpp/util.hpp | 11 +++++ 6 files changed, 142 insertions(+), 95 deletions(-) diff --git a/luprex/core/cpp/animqueue.cpp b/luprex/core/cpp/animqueue.cpp index 9e5bd1d3..4f93ee8b 100644 --- a/luprex/core/cpp/animqueue.cpp +++ b/luprex/core/cpp/animqueue.cpp @@ -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; } diff --git a/luprex/core/cpp/animqueue.hpp b/luprex/core/cpp/animqueue.hpp index 6076898c..9c199140 100644 --- a/luprex/core/cpp/animqueue.hpp +++ b/luprex/core/cpp/animqueue.hpp @@ -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 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 steps_; + int64_t version_number_; + + // Called whenever the animation queue is mutated. + // serialization and deserialization + void mutated(); }; #endif // ANIMQUEUE_HPP diff --git a/luprex/core/cpp/idalloc.cpp b/luprex/core/cpp/idalloc.cpp index 6ed5f9f4..c6b54c44 100644 --- a/luprex/core/cpp/idalloc.cpp +++ b/luprex/core/cpp/idalloc.cpp @@ -1,11 +1,10 @@ #include "idalloc.hpp" #include #include +#include +#include -static int64_t nthbatch(int64_t n) { - return int64_t(0x0001000000000000) + n*256; -} static bool ranges_equal(const std::deque &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 diff --git a/luprex/core/cpp/idalloc.hpp b/luprex/core/cpp/idalloc.hpp index b0b41bd6..a7cde813 100644 --- a/luprex/core/cpp/idalloc.hpp +++ b/luprex/core/cpp/idalloc.hpp @@ -72,12 +72,6 @@ #include "streambuffer.hpp" class IdGlobalPool { -private: - std::vector 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 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 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 ranges_; + friend int unittests_idalloc(lua_State *L); }; #endif // IDALLOC_HPP diff --git a/luprex/core/cpp/util.cpp b/luprex/core/cpp/util.cpp index a4054bf6..dbbbd474 100644 --- a/luprex/core/cpp/util.cpp +++ b/luprex/core/cpp/util.cpp @@ -6,6 +6,9 @@ #include #include #include +#include +#include + #ifndef WIN32 #include #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; +} diff --git a/luprex/core/cpp/util.hpp b/luprex/core/cpp/util.hpp index ab512277..e03fc420 100644 --- a/luprex/core/cpp/util.hpp +++ b/luprex/core/cpp/util.hpp @@ -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