Lots of work on printbuffers

This commit is contained in:
2021-11-14 15:57:18 -05:00
parent c1c0b02926
commit f933f451ad
10 changed files with 229 additions and 108 deletions

View File

@@ -9,8 +9,8 @@
//
// Class PrintBuffer is a buffer for storing the output of the print statement.
// It is part of the actor tangible. When a lua thread calls 'print', the print
// goes into stringstream lthread_console. When the thread stops or yields, the
// contents of lthread_console are converted to lines and transferred to the
// goes into stringstream lthread_prints. When the thread stops or yields, the
// contents of lthread_prints are converted to lines and transferred to the
// PrintBuffer of the actor. From there, it gets difference transmitted, and the
// client can probe it.
//
@@ -19,12 +19,12 @@
// model and the synchronous model. When the thread finishes, the PrintBuffer
// in the actor in the master model will contain this:
//
// * Block 0: Whose woods these are I think I know. [authoritative]
// * Block 1: His house is in the village though; [authoritative]
// * Block 2: He will not see me stopping here [authoritative]
// * Block 3: To watch his woods fill up with snow. [authoritative]
// * Block 4: My little horse must think it queer [authoritative]
// * Block 5: To stop without a farmhouse near. [authoritative]
// * Line 0: Whose woods these are I think I know. [authoritative]
// * Line 1: His house is in the village though; [authoritative]
// * Line 2: He will not see me stopping here [authoritative]
// * Line 3: To watch his woods fill up with snow. [authoritative]
// * Line 4: My little horse must think it queer [authoritative]
// * Line 5: To stop without a farmhouse near. [authoritative]
//
// Note that the buffer stores line numbers, which start from zero the moment
// the player logs in. In the master model, all lines are always authoritative
@@ -63,6 +63,14 @@
// processed. Therefore, the client must be prepared that it might see some
// redundant lines for a little while.
//
// MEMORY EFFICIENCY.
//
// Every tangible will contain a printbuffer. To avoid memory waste, the
// implementation of PrintBuffer stores everything inside a dynamically
// allocated "core" struct. All printbuffers that contain nothing share a
// common empty core. That way, the empty printbuffers that will exist in 99% of
// all tangibles will take up very little space.
//
////////////////////////////////////////////////////////////////////////////////
@@ -77,66 +85,56 @@
#include <memory>
#include <ostream>
struct PrintBufferCore;
class PrintBuffer {
private:
// The most recent lines printed.
std::deque<std::string> lines_;
// Line number of the first line in the buffer. From this, all other
// line numbers can be inferred.
int first_line_;
// Line number of the first unchecked line in the buffer. All line
// numbers including this one and beyond are unchecked.
int first_unchecked_;
// The world type of the enclosing model. This is used to determine
// whether add_string increments the n_checked counter or not.
util::WorldType world_type_;
// Add a line of text (internal). Line is expected to NOT contain
// a newline (or any other weird control characters).
void add_line(const char *line, int len);
PrintBufferCore *core_;
public:
PrintBuffer(util::WorldType wt);
PrintBuffer();
~PrintBuffer();
// Get the current first line.
int first_line() const { return first_line_; }
int first_line() const;
// Return the line number beyond the end of the buffer.
int last_line() const { return first_line_ + int(lines_.size()); }
int last_line() const;
// Get the current first unchecked line.
int first_unchecked() const { return first_unchecked_; }
// Guaranteed to be between first_line and last_line inclusive.
int first_unchecked() const;
// Return true if the printbuffer is in the initial state.
// Note: if you clear the buffer, it's back in the initial state.
bool never_printed() const;
// Get the specified line number.
const std::string &nth(int n) const { return lines_[n - first_line_]; }
const std::string &nth(int n) const;
// Print the entire contents of the buffer to a string (for unit testing).
std::string debug_string() const;
// Clear the buffer
void clear();
// Add a string. If the string doesn't end in a newline, a newline
// is added. The string is broken into lines, and the lines are added
// to the PrintBuffer.
void add_string(const char *text, int len);
void add_string(const std::string &s);
void add_string(const std::string &s, bool auth);
// Discard lines up to but not including line N.
void discard_upto(int n);
// Serialization and deserialization
void serialize(StreamBuffer *sb) const;
void deserialize(StreamBuffer *sb);
// Difference transmission
void diff(const PrintBuffer &auth, StreamBuffer *sb) const;
void patch(StreamBuffer *sb);
// Clear the buffer (for unit testing)
void clear();
// Print the entire contents of the buffer to a string (for unit testing).
std::string debug_string() const;
};
using UniquePrintBuffer = std::unique_ptr<PrintBuffer>;
class PrintChanneler {
private: