From 5c258be507d2e0c5c90dcf61282911a36a699c4e Mon Sep 17 00:00:00 2001 From: jyelon Date: Sun, 22 Feb 2026 20:59:02 -0500 Subject: [PATCH] More refactors in basebuffer --- Source/Integration/StringDecoder.h | 6 +- luprex/cpp/core/streambuffer.hpp | 5 +- luprex/ext/base-buffer.hpp | 128 ++++++++++++++++------------- 3 files changed, 75 insertions(+), 64 deletions(-) diff --git a/Source/Integration/StringDecoder.h b/Source/Integration/StringDecoder.h index f7da2558..36ce091f 100644 --- a/Source/Integration/StringDecoder.h +++ b/Source/Integration/StringDecoder.h @@ -3,13 +3,13 @@ #include "CoreMinimal.h" #include "lpx-basebuffer.hpp" -class FlxStreamBufferCore { +class FlxStreamBufferConfig { private: bool err_eof_on_read_; bool err_string_too_long_; bool err_integer_truncated_; protected: - + using string_type = std::string; void *basebuffer_malloc(size_t size) { return malloc(size); } void basebuffer_free(void *p) { free(p); } void clear_error_flags() { err_eof_on_read_ = err_string_too_long_ = err_integer_truncated_ = false; } @@ -24,7 +24,7 @@ public: bool any_error() const { return err_eof_on_read_ || err_string_too_long_ || err_integer_truncated_; } }; -class FlxStreamBuffer : public BaseBuffer { +class FlxStreamBuffer : public BaseBuffer { public: using BaseBuffer::BaseBuffer; using BaseBuffer::write_string; diff --git a/luprex/cpp/core/streambuffer.hpp b/luprex/cpp/core/streambuffer.hpp index 9ca636d6..d54e183c 100644 --- a/luprex/cpp/core/streambuffer.hpp +++ b/luprex/cpp/core/streambuffer.hpp @@ -245,8 +245,9 @@ public: using LuaValue = BaseLuaValue; -class StreamBufferCore { +class StreamBufferConfig { protected: + using string_type = eng::string; void *basebuffer_malloc(size_t size) { return eng::malloc(size); } void basebuffer_free(void *p) { eng::free(p); } void clear_error_flags() { } @@ -255,7 +256,7 @@ protected: void raise_integer_truncated() { throw StreamIntegerTruncated(); } }; -class StreamBuffer : public eng::nevernew, public BaseBuffer { +class StreamBuffer : public eng::nevernew, public BaseBuffer { public: using BaseBuffer::BaseBuffer; diff --git a/luprex/ext/base-buffer.hpp b/luprex/ext/base-buffer.hpp index f3c61080..d87da073 100644 --- a/luprex/ext/base-buffer.hpp +++ b/luprex/ext/base-buffer.hpp @@ -103,7 +103,10 @@ struct BaseLuaValue { // // BaseWriteMethods // -// This base class provides the following methods: +// Suppose you've written a class MyWriter that contains a +// write_bytes method. Now you want to add write_int, +// write_string, and so forth. By deriving from +// BaseWriteMethods, you add all of the following methods: // // void write_uint8(uint64_t data) // void write_uint16(uint64_t data) @@ -119,15 +122,21 @@ struct BaseLuaValue { // void write_length(size_t data) // void write_string(std::string_view data) // -// You should derive from BaseWriteMethods using the CRTP pattern: +// Here is how you should derive from BaseWriteMethods: // -// class DerivedWriter : public BaseWriteMethods +// class MyWriter : public BaseWriteMethods // -// You must provide two methods in the derived class: +// Your class MyWriter must implement these two methods: // // write_bytes(const char *n, size_t size) // raise_integer_truncated() // +// If you call write_uint8(1000), that is an error, because +// 1000 doesn't fit in a uint8. So, write_uint8 will call +// raise_integer_truncated. That function can throw an +// exception, set a flag, or otherwise handle the error - +// you can implement it to do whatever you wish. +// /////////////////////////////////////////////////////////////// template @@ -181,7 +190,10 @@ public: // // BaseReadMethods // -// This base class provides the following methods: +// Suppose you've written a class MyReader that contains a +// read_bytes method. Now you want to add read_int, +// read_string, and so forth. By deriving from +// BaseReadMethods, you add all of the following methods: // // uint8_t read_uint8(); // uint16_t read_uint16(); @@ -196,38 +208,40 @@ public: // float read_float(); // double read_double(); // size_t read_length(); -// String read_string_limit(uint64_t size); -// String read_string(); +// string read_string_limit(uint64_t size); +// string read_string(); // -// You should derive from BaseReadMethods using the CRTP pattern: +// Here is how you should derive from BaseReadMethods: // -// class DerivedReader : public BaseReadMethods +// class MyReader : public BaseReadMethods // -// The derived class must provide: +// Your class MyReader must implement these: // -// using read_string_type = std::string; // or compatible +// using string_type = std::string; // or compatible // void read_bytes_into(char *n, size_t size) // void raise_string_too_long(); // -// Error Handling: +// The read_string function will return a string. +// Usually, you want it to return std::string, but +// you might be using some other string type. Supply +// string_type = std::string or any other type +// with a (bytes, len) constructor, and read_string +// will return that type. // -// It is up to the derived class whether it wants -// to report errors using exceptions or flags. -// -// If read_bytes_into discovers there's not enough bytes, -// there are two valid options: throw an exception, OR, -// set an error flag and fill the buffer with zeros. -// -// If read_string discovers that the string is longer than -// the allowed limit, it will call raise_string_too_long. -// This function may either throw an exception, or set an -// error flag. +// If you call read_string_limit(100), and this finds +// a string of length 200 in the incoming data, then +// read_string_limit will call raise_string_too_long. +// That function can throw an exception, set a flag, +// or otherwise handle the error - you can implement it +// to do whatever you wish. // /////////////////////////////////////////////////////////////// template class BaseReadMethods { protected: + using string_type = typename Derived::string_type; + template T read_value_core() { T result; @@ -254,50 +268,48 @@ public: size_t read_length() { uint64_t len = read_uint8(); - if (len == 255) { - len = read_uint64(); - } + if (len == 255) len = read_uint64(); return len; } - auto read_string_limit(uint64_t limit) { + string_type read_string_limit(uint64_t limit) { size_t len = read_length(); Derived *dthis = static_cast(this); if (len > limit) { dthis->raise_string_too_long(); len = 0; } - typename Derived::read_string_type result(len, ' '); + string_type result(len, ' '); dthis->read_bytes_into(&(result[0]), len); return result; } - auto read_string() { return read_string_limit(0x1000000); } // 16MB limit default + string_type read_string() { + return read_string_limit(0x1000000); // 16MB limit default + } }; /////////////////////////////////////////////////////////////// // // Class BaseBuffer // -// You must supply a CoreHandler which must define these -// methods: +// You must supply a BaseBufferConfig which must define these: // -// void *basebuffer_malloc(size_t size); -// void basebuffer_free(void *data); -// void raise_eof_on_read(); -// void raise_string_too_long(); -// void raise_integer_truncated(); -// -// You must also select a StringType. Typically this would -// be std::string. This only affects the return value of -// read_string. You can always use read_string_view to read -// strings into other string types. +// using string_type = std::string; // or compatible +// void *basebuffer_malloc(size_t size); +// void basebuffer_free(void *data); +// void raise_eof_on_read(); +// void raise_string_too_long(); +// void raise_integer_truncated(); // /////////////////////////////////////////////////////////////// -template -class BaseBuffer : public CoreHandler { +template +class BaseBuffer : public BaseBufferConfig { private: + // Used for all strings in BaseBuffer. + using string_type = typename BaseBufferConfig::string_type; + // True if we own this buffer. bool owned_; @@ -317,7 +329,7 @@ private: private: void init(bool fixed, bool owned, char *buf, int64_t size) { - CoreHandler::clear_error_flags(); + BaseBufferConfig::clear_error_flags(); owned_ = owned; fixed_size_ = fixed; buf_lo_ = buf; @@ -328,8 +340,6 @@ private: } public: - using string_type = StringType; - // Construct an empty buffer. // BaseBuffer() { @@ -340,7 +350,7 @@ public: // BaseBuffer(int64_t size, bool fixed) { assert(size >= 0); - init(fixed, true, (char *)CoreHandler::basebuffer_malloc(size), size); + init(fixed, true, (char *)BaseBufferConfig::basebuffer_malloc(size), size); } // Construct a streambuffer that reads from an external block of bytes. @@ -353,7 +363,7 @@ public: // Modify an existing streambuffer to read from an external block of bytes. // void open(std::string_view data) { - if (owned_ && (buf_lo_ != 0)) CoreHandler::basebuffer_free(buf_lo_); + if (owned_ && (buf_lo_ != 0)) BaseBufferConfig::basebuffer_free(buf_lo_); init(true, false, const_cast(data.data()), data.size()); write_cursor_ = buf_hi_; } @@ -361,7 +371,7 @@ public: // Destructor. Frees the buffer, if any. // ~BaseBuffer() { - if (owned_ && (buf_lo_ != 0)) CoreHandler::basebuffer_free(buf_lo_); + if (owned_ && (buf_lo_ != 0)) BaseBufferConfig::basebuffer_free(buf_lo_); } // Return the total number of bytes ever read. @@ -435,7 +445,7 @@ public: open(""); } else { if ((!fixed_size_) && (buf_lo_ != nullptr) && ((buf_hi_ - buf_lo_) > 100000)) { - CoreHandler::basebuffer_free(buf_lo_); + BaseBufferConfig::basebuffer_free(buf_lo_); buf_lo_ = nullptr; buf_hi_ = nullptr; } @@ -529,7 +539,7 @@ public: const char *read_bytes(int64_t bytes) { int64_t avail = write_cursor_ - read_cursor_; if (avail < bytes) { - CoreHandler::raise_eof_on_read(); + BaseBufferConfig::raise_eof_on_read(); return nullptr; } char *data = read_cursor_; @@ -576,12 +586,12 @@ public: std::string_view read_string_view_limit(uint64_t limit) { size_t length = read_length(); if (length > limit) { - CoreHandler::raise_string_too_long(); + BaseBufferConfig::raise_string_too_long(); return std::string_view(); } int64_t avail = write_cursor_ - read_cursor_; if (avail < int64_t(length)) { - CoreHandler::raise_eof_on_read(); + BaseBufferConfig::raise_eof_on_read(); return std::string_view(); } std::string_view result(read_cursor_, length); @@ -600,12 +610,12 @@ public: string_type read_string_limit(uint64_t limit) { size_t len = read_length(); if (len > limit) { - CoreHandler::raise_string_too_long(); + BaseBufferConfig::raise_string_too_long(); return string_type(); } int64_t avail = write_cursor_ - read_cursor_; if (avail < int64_t(len)) { - CoreHandler::raise_eof_on_read(); + BaseBufferConfig::raise_eof_on_read(); return string_type(); } string_type result(len, ' '); @@ -706,9 +716,9 @@ private: } else if (existing_size >= desired_size) { if (data_size > 0) memcpy(buf_lo_, read_cursor_, data_size); } else { - char *nbuf = (char *)CoreHandler::basebuffer_malloc(desired_size); + char *nbuf = (char *)BaseBufferConfig::basebuffer_malloc(desired_size); if (data_size > 0) memcpy(nbuf, read_cursor_, data_size); - if (buf_lo_ != nullptr) CoreHandler::basebuffer_free(buf_lo_); + if (buf_lo_ != nullptr) BaseBufferConfig::basebuffer_free(buf_lo_); buf_lo_ = nbuf; buf_hi_ = nbuf + desired_size; } @@ -728,7 +738,7 @@ private: template void write_int_core(XT arg) { T reduced = arg; - if (XT(reduced) != arg) CoreHandler::raise_integer_truncated(); + if (XT(reduced) != arg) BaseBufferConfig::raise_integer_truncated(); write_value_core(reduced); } @@ -737,7 +747,7 @@ private: T result; int64_t avail = write_cursor_ - read_cursor_; if (avail < int64_t(sizeof(result))) { - CoreHandler::raise_eof_on_read(); + BaseBufferConfig::raise_eof_on_read(); return 0; } memcpy(&result, read_cursor_, sizeof(result));