More work on debug_string
This commit is contained in:
@@ -324,14 +324,15 @@ bool AnimStep::from_string(const std::string &config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AnimQueue::AnimQueue(util::WorldType wt) {
|
AnimQueue::AnimQueue(util::WorldType wt) {
|
||||||
world_type_ = wt;
|
version_autoinc_ = (wt == util::WORLD_TYPE_MASTER);
|
||||||
size_limit_ = 10; // Default size limit.
|
size_limit_ = 10; // Default size limit.
|
||||||
clear_steps();
|
steps_.emplace_back();
|
||||||
version_number_ = (wt == util::WORLD_TYPE_MASTER) ? 1 : 0;
|
steps_.front().keep_state_only();
|
||||||
|
version_number_ = version_autoinc_ ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimQueue::mutated() {
|
void AnimQueue::mutated() {
|
||||||
if (world_type_ == util::WORLD_TYPE_MASTER) {
|
if (version_autoinc_) {
|
||||||
version_number_ += 1;
|
version_number_ += 1;
|
||||||
} else {
|
} else {
|
||||||
version_number_ = 0;
|
version_number_ = 0;
|
||||||
@@ -353,30 +354,23 @@ bool AnimQueue::size_and_steps_equal(const AnimQueue &other) const {
|
|||||||
return true;
|
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) {
|
void AnimQueue::full_clear_and_set_limit(int n) {
|
||||||
assert(n >= 1);
|
assert(n >= 1);
|
||||||
clear_steps();
|
steps_.clear();
|
||||||
|
steps_.emplace_back();
|
||||||
|
steps_.front().keep_state_only();
|
||||||
size_limit_ = n;
|
size_limit_ = n;
|
||||||
version_number_ = 1;
|
version_number_ = version_autoinc_ ? 1 : 0;
|
||||||
}
|
}
|
||||||
void AnimQueue::set_limit(int n) {
|
void AnimQueue::set_limit(int n) {
|
||||||
assert(n >= 1);
|
assert(n >= 1);
|
||||||
size_limit_ = n;
|
size_limit_ = n;
|
||||||
|
if (int(steps_.size()) > n) {
|
||||||
while (int(steps_.size()) > n) {
|
while (int(steps_.size()) > n) {
|
||||||
steps_.pop_front();
|
steps_.pop_front();
|
||||||
}
|
}
|
||||||
steps_.front().keep_state_only();
|
steps_.front().keep_state_only();
|
||||||
|
}
|
||||||
mutated();
|
mutated();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -549,12 +543,23 @@ const AnimStep &AnimQueue::back() const {
|
|||||||
return steps_.back();
|
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") {
|
LuaDefine(unittests_animqueue, "c") {
|
||||||
// Check initial state.
|
// Useful objects.
|
||||||
AnimStep stp;
|
AnimStep stp;
|
||||||
AnimQueue aq(util::WORLD_TYPE_MASTER);
|
AnimQueue aq(util::WORLD_TYPE_MASTER);
|
||||||
StreamBuffer sb;
|
|
||||||
AnimQueue aqds(util::WORLD_TYPE_S_SYNC);
|
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.
|
// Test the step setters.
|
||||||
stp.clear();
|
stp.clear();
|
||||||
@@ -572,11 +577,11 @@ LuaDefine(unittests_animqueue, "c") {
|
|||||||
stp.set_graphic("something");
|
stp.set_graphic("something");
|
||||||
LuaAssertStrEq(L, stp.debug_string(), "id=0 action= plane=somewhere x=3 y=4 z=5 facing=180 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"));
|
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");
|
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);
|
aq.full_clear_and_set_limit(3);
|
||||||
LuaAssert(L, aq.valid());
|
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=");
|
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
|
// Add a single action to the queue and DT
|
||||||
LuaAssert(L, stp.from_string("action=walk x=3 y=4 z=5"));
|
LuaAssert(L, stp.from_string("action=walk x=3 y=4 z=5"));
|
||||||
aq.add(12345, stp);
|
aq.add(12345, stp);
|
||||||
sb.clear();
|
LuaAssert(L, diff_works(aq, aqds));
|
||||||
LuaAssert(L, aqds.make_patch(aq, &sb));
|
|
||||||
aqds.apply_patch(&sb);
|
|
||||||
LuaAssert(L, aqds.size_and_steps_equal(aq));
|
|
||||||
|
|
||||||
// Add another action and DT
|
// Add another action and DT
|
||||||
LuaAssert(L, stp.from_string("action=fnord plane=where facing=123"));
|
LuaAssert(L, stp.from_string("action=fnord plane=where facing=123"));
|
||||||
aq.add(232, stp);
|
aq.add(232, stp);
|
||||||
sb.clear();
|
LuaAssert(L, diff_works(aq, aqds));
|
||||||
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));
|
|
||||||
|
|
||||||
// Change the queue size limit.
|
// Change the queue size limit.
|
||||||
aq.set_limit(13);
|
aq.set_limit(13);
|
||||||
sb.clear();
|
LuaAssert(L, diff_works(aq, aqds));
|
||||||
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));
|
|
||||||
|
|
||||||
// compare again, should be no differences.
|
// compare again, should be no differences.
|
||||||
sb.clear();
|
sb.clear();
|
||||||
@@ -661,11 +654,7 @@ LuaDefine(unittests_animqueue, "c") {
|
|||||||
|
|
||||||
// Discard all but the last action.
|
// Discard all but the last action.
|
||||||
aq.set_limit(1);
|
aq.set_limit(1);
|
||||||
|
LuaAssert(L, diff_works(aq, aqds));
|
||||||
sb.clear();
|
|
||||||
LuaAssert(L, aqds.make_patch(aq, &sb));
|
|
||||||
aqds.apply_patch(&sb);
|
|
||||||
LuaAssert(L, aqds.size_and_steps_equal(aq));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
// equal to the version number in the master model, then the two animqueues are
|
// 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:
|
// 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.
|
// every time the animation queue is mutated.
|
||||||
//
|
//
|
||||||
// * In the synchronous model, the version number is set to zero every time the
|
// * 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
|
// * The routine 'update_version' should be called after difference
|
||||||
// transmission. This copies the version number from the master to the
|
// transmission. This copies the version number from the master to the
|
||||||
// synchronous model. This is guaranteed to be safe because we just finished
|
// 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.
|
||||||
//
|
//
|
||||||
///////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -69,20 +69,6 @@ public:
|
|||||||
HAS_EVERYTHING = 63,
|
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();
|
||||||
~AnimStep();
|
~AnimStep();
|
||||||
|
|
||||||
@@ -162,20 +148,25 @@ public:
|
|||||||
|
|
||||||
// Convert a string to an animstep (for testing only).
|
// Convert a string to an animstep (for testing only).
|
||||||
bool from_string(const std::string &s);
|
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 {
|
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);
|
AnimQueue(util::WorldType wt);
|
||||||
|
|
||||||
// Simple getters.
|
// Simple getters.
|
||||||
@@ -187,11 +178,6 @@ public:
|
|||||||
// Return true if the size limit and steps are identical.
|
// Return true if the size limit and steps are identical.
|
||||||
bool size_and_steps_equal(const AnimQueue &aq) const;
|
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.
|
// Mutator to create a new step.
|
||||||
void add(int64_t id, const AnimStep &step);
|
void add(int64_t id, const AnimStep &step);
|
||||||
|
|
||||||
@@ -216,6 +202,16 @@ public:
|
|||||||
|
|
||||||
// Convert to a string for debugging purposes.
|
// Convert to a string for debugging purposes.
|
||||||
std::string debug_string() const;
|
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
|
#endif // ANIMQUEUE_HPP
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
#include "idalloc.hpp"
|
#include "idalloc.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <map>
|
#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) {
|
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;
|
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) {
|
IdPlayerPool::IdPlayerPool(IdGlobalPool *g) {
|
||||||
global_ = g;
|
global_ = g;
|
||||||
fifo_capacity_ = 0;
|
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") {
|
LuaDefine(unittests_idalloc, "c") {
|
||||||
IdGlobalPool gp;
|
IdGlobalPool gp;
|
||||||
IdPlayerPool pp(&gp);
|
IdPlayerPool pp(&gp);
|
||||||
@@ -425,12 +449,10 @@ LuaDefine(unittests_idalloc, "c") {
|
|||||||
pp.test_push_back(123);
|
pp.test_push_back(123);
|
||||||
pp.test_push_back(456);
|
pp.test_push_back(456);
|
||||||
|
|
||||||
// transmit and compare. Add extra bytes
|
// transmit and compare.
|
||||||
sb.clear();
|
sb.clear();
|
||||||
LuaAssert(L, ppds.make_patch(pp, &sb));
|
LuaAssert(L, ppds.make_patch(pp, &sb));
|
||||||
sb.write_uint32(0);
|
|
||||||
ppds.apply_patch(&sb);
|
ppds.apply_patch(&sb);
|
||||||
LuaAssert(L, sb.total_writes() - sb.total_reads() == 4);
|
|
||||||
LuaAssert(L, ppds.exactly_equal(pp));
|
LuaAssert(L, ppds.exactly_equal(pp));
|
||||||
|
|
||||||
// Pop a value from master pool
|
// Pop a value from master pool
|
||||||
|
|||||||
@@ -72,12 +72,6 @@
|
|||||||
#include "streambuffer.hpp"
|
#include "streambuffer.hpp"
|
||||||
|
|
||||||
class IdGlobalPool {
|
class IdGlobalPool {
|
||||||
private:
|
|
||||||
std::vector<int64_t> salvaged_;
|
|
||||||
int64_t next_batch_;
|
|
||||||
int64_t next_id_;
|
|
||||||
friend int unittests_idalloc(lua_State *L);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Construct and destroy global pools. Note that after constructing
|
// Construct and destroy global pools. Note that after constructing
|
||||||
// a global pool, it is generally also necessary to initialize it
|
// a global pool, it is generally also necessary to initialize it
|
||||||
@@ -118,15 +112,18 @@ public:
|
|||||||
// Serialize to or deserialize from a streambuffer.
|
// Serialize to or deserialize from a streambuffer.
|
||||||
void serialize(StreamBuffer *sb);
|
void serialize(StreamBuffer *sb);
|
||||||
void deserialize(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 {
|
class IdPlayerPool {
|
||||||
private:
|
|
||||||
IdGlobalPool *global_;
|
|
||||||
int fifo_capacity_;
|
|
||||||
std::deque<int64_t> ranges_;
|
|
||||||
friend int unittests_idalloc(lua_State *L);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Construct a player pool.
|
// Construct a player pool.
|
||||||
//
|
//
|
||||||
@@ -189,6 +186,15 @@ public:
|
|||||||
//
|
//
|
||||||
bool make_patch(const IdPlayerPool &auth, StreamBuffer *sb) const;
|
bool make_patch(const IdPlayerPool &auth, StreamBuffer *sb) const;
|
||||||
void apply_patch(StreamBuffer *sb);
|
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
|
#endif // IDALLOC_HPP
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#define stat _stat
|
#define stat _stat
|
||||||
@@ -130,3 +133,23 @@ std::string XYZ::debug_string() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace util
|
} // 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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -66,6 +66,17 @@ struct XYZ {
|
|||||||
std::string debug_string() const;
|
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
|
} // 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
|
#endif // UTIL_HPP
|
||||||
|
|||||||
Reference in New Issue
Block a user