Implemented PrintBuffer class. (Whew).
This commit is contained in:
156
luprex/core/cpp/printbuffer.cpp
Normal file
156
luprex/core/cpp/printbuffer.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
#include "printbuffer.hpp"
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
PrintBuffer::PrintBuffer(util::WorldType wt) {
|
||||
world_type_ = wt;
|
||||
clear();
|
||||
}
|
||||
|
||||
static int first_line_len(const char *text, int len) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (text[i] == '\n') return i;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
void PrintBuffer::add_line(const char *text, int len) {
|
||||
lines_.emplace_back(text, len);
|
||||
if ((world_type_ == util::WORLD_TYPE_MASTER)||(world_type_ == util::WORLD_TYPE_STANDALONE)) {
|
||||
first_unchecked_ = first_line_ + int(lines_.size());
|
||||
}
|
||||
}
|
||||
|
||||
void PrintBuffer::add_string(const char *text, int len) {
|
||||
while (true) {
|
||||
int fll = first_line_len(text, len);
|
||||
if (fll == len) {
|
||||
if (len > 0) {
|
||||
add_line(text, len);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
add_line(text, fll);
|
||||
text += (fll + 1);
|
||||
len -= (fll + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrintBuffer::add_string(const std::string &s) {
|
||||
add_string(s.c_str(), s.size());
|
||||
}
|
||||
|
||||
void PrintBuffer::discard_upto(int n) {
|
||||
while ((!lines_.empty()) && (first_line_ < n)) {
|
||||
lines_.pop_front();
|
||||
first_line_ += 1;
|
||||
}
|
||||
if (first_line_ < n) {
|
||||
first_line_ = n;
|
||||
}
|
||||
if (first_unchecked_ < first_line_) {
|
||||
first_unchecked_ = first_line_;
|
||||
}
|
||||
}
|
||||
|
||||
void PrintBuffer::clear() {
|
||||
first_line_ = 0;
|
||||
first_unchecked_ = 0;
|
||||
lines_.clear();
|
||||
}
|
||||
|
||||
std::string PrintBuffer::debug_string() const {
|
||||
std::ostringstream oss;
|
||||
oss << first_line_ << "," << first_unchecked_ << ":";
|
||||
for (int i = 0; i < int(lines_.size()); i++) {
|
||||
oss << lines_[i] << ";";
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
|
||||
void PrintBuffer::diff(const PrintBuffer &auth, StreamBuffer *sb) const {
|
||||
// Currently, the implementation is simple. The synchronous model discards
|
||||
// all prediction lines from its buffer, then the server retransmits all
|
||||
// those lines. So this barely counts as difference transmission - it's
|
||||
// just transmission, regardless of what was in the synchronous model. I
|
||||
// think that's okay for the text console.
|
||||
// Ask the client to discard anything that precedes auth_first.
|
||||
sb->write_int32(auth.first_line_);
|
||||
sb->write_int32(auth.last_line());
|
||||
for (int i = first_unchecked_; i < auth.last_line(); i++) {
|
||||
std::string line;
|
||||
if (i >= auth.first_line_) line = auth.nth(i);
|
||||
sb->write_string(line);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintBuffer::patch(StreamBuffer *sb) {
|
||||
int auth_first = sb->read_int32();
|
||||
int auth_last = sb->read_int32();
|
||||
lines_.resize(first_unchecked_ - first_line_);
|
||||
for (int i = first_unchecked_; i < auth_last; i++) {
|
||||
lines_.emplace_back(sb->read_string());
|
||||
}
|
||||
first_unchecked_ = first_line_ + lines_.size();
|
||||
discard_upto(auth_first);
|
||||
}
|
||||
|
||||
LuaDefine(unittests_printbuffer, "c") {
|
||||
PrintBuffer pbm(util::WORLD_TYPE_MASTER);
|
||||
PrintBuffer pbs(util::WORLD_TYPE_S_SYNC);
|
||||
StreamBuffer sb;
|
||||
|
||||
LuaAssertStrEq(L, pbm.debug_string(), "0,0:");
|
||||
pbm.add_string("foo\nbar\nbaz\n");
|
||||
LuaAssertStrEq(L, pbm.debug_string(), "0,3:foo;bar;baz;");
|
||||
pbm.add_string("a\nb\nc");
|
||||
LuaAssertStrEq(L, pbm.debug_string(), "0,6:foo;bar;baz;a;b;c;");
|
||||
pbm.discard_upto(2);
|
||||
LuaAssertStrEq(L, pbm.debug_string(), "2,6:baz;a;b;c;");
|
||||
pbm.discard_upto(8);
|
||||
LuaAssertStrEq(L, pbm.debug_string(), "8,8:");
|
||||
|
||||
LuaAssertStrEq(L, pbs.debug_string(), "0,0:");
|
||||
pbs.add_string("foo\nbar\nbaz\n");
|
||||
LuaAssertStrEq(L, pbs.debug_string(), "0,0:foo;bar;baz;");
|
||||
pbs.add_string("a\nb\nc");
|
||||
LuaAssertStrEq(L, pbs.debug_string(), "0,0:foo;bar;baz;a;b;c;");
|
||||
pbs.discard_upto(2);
|
||||
LuaAssertStrEq(L, pbs.debug_string(), "2,2:baz;a;b;c;");
|
||||
pbs.discard_upto(8);
|
||||
LuaAssertStrEq(L, pbs.debug_string(), "8,8:");
|
||||
|
||||
pbm.clear();
|
||||
pbs.clear();
|
||||
sb.clear();
|
||||
pbm.add_string("foo\nbar\n");
|
||||
pbs.diff(pbm, &sb);
|
||||
pbs.patch(&sb);
|
||||
LuaAssertStrEq(L, pbs.debug_string(), "0,2:foo;bar;");
|
||||
pbm.clear();
|
||||
pbm.add_string("foo\nyow\nding\ndong\n");
|
||||
pbs.diff(pbm, &sb);
|
||||
pbs.patch(&sb);
|
||||
LuaAssertStrEq(L, pbs.debug_string(), "0,4:foo;bar;ding;dong;");
|
||||
pbs.discard_upto(2);
|
||||
LuaAssertStrEq(L, pbs.debug_string(), "2,4:ding;dong;");
|
||||
pbs.diff(pbm, &sb);
|
||||
pbs.patch(&sb);
|
||||
LuaAssertStrEq(L, pbs.debug_string(), "2,4:ding;dong;");
|
||||
pbs.add_string("boy\nhowdy\n");
|
||||
LuaAssertStrEq(L, pbs.debug_string(), "2,4:ding;dong;boy;howdy;");
|
||||
pbs.diff(pbm, &sb);
|
||||
pbs.patch(&sb);
|
||||
LuaAssertStrEq(L, pbs.debug_string(), "2,4:ding;dong;");
|
||||
pbs.add_string("boy\nhowdy\nyeah\nbaby\nget\ndown\n");
|
||||
LuaAssertStrEq(L, pbs.debug_string(), "2,4:ding;dong;boy;howdy;yeah;baby;get;down;");
|
||||
pbs.discard_upto(5);
|
||||
LuaAssertStrEq(L, pbs.debug_string(), "5,5:howdy;yeah;baby;get;down;");
|
||||
pbs.diff(pbm, &sb);
|
||||
pbs.patch(&sb);
|
||||
LuaAssertStrEq(L, pbs.debug_string(), "5,5:");
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user