More refactors in basebuffer
This commit is contained in:
@@ -3,13 +3,13 @@
|
|||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "lpx-basebuffer.hpp"
|
#include "lpx-basebuffer.hpp"
|
||||||
|
|
||||||
class FlxStreamBufferCore {
|
class FlxStreamBufferConfig {
|
||||||
private:
|
private:
|
||||||
bool err_eof_on_read_;
|
bool err_eof_on_read_;
|
||||||
bool err_string_too_long_;
|
bool err_string_too_long_;
|
||||||
bool err_integer_truncated_;
|
bool err_integer_truncated_;
|
||||||
protected:
|
protected:
|
||||||
|
using string_type = std::string;
|
||||||
void *basebuffer_malloc(size_t size) { return malloc(size); }
|
void *basebuffer_malloc(size_t size) { return malloc(size); }
|
||||||
void basebuffer_free(void *p) { free(p); }
|
void basebuffer_free(void *p) { free(p); }
|
||||||
void clear_error_flags() { err_eof_on_read_ = err_string_too_long_ = err_integer_truncated_ = false; }
|
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_; }
|
bool any_error() const { return err_eof_on_read_ || err_string_too_long_ || err_integer_truncated_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class FlxStreamBuffer : public BaseBuffer<FlxStreamBufferCore, std::string> {
|
class FlxStreamBuffer : public BaseBuffer<FlxStreamBufferConfig> {
|
||||||
public:
|
public:
|
||||||
using BaseBuffer::BaseBuffer;
|
using BaseBuffer::BaseBuffer;
|
||||||
using BaseBuffer::write_string;
|
using BaseBuffer::write_string;
|
||||||
|
|||||||
@@ -245,8 +245,9 @@ public:
|
|||||||
|
|
||||||
using LuaValue = BaseLuaValue<eng::string>;
|
using LuaValue = BaseLuaValue<eng::string>;
|
||||||
|
|
||||||
class StreamBufferCore {
|
class StreamBufferConfig {
|
||||||
protected:
|
protected:
|
||||||
|
using string_type = eng::string;
|
||||||
void *basebuffer_malloc(size_t size) { return eng::malloc(size); }
|
void *basebuffer_malloc(size_t size) { return eng::malloc(size); }
|
||||||
void basebuffer_free(void *p) { eng::free(p); }
|
void basebuffer_free(void *p) { eng::free(p); }
|
||||||
void clear_error_flags() { }
|
void clear_error_flags() { }
|
||||||
@@ -255,7 +256,7 @@ protected:
|
|||||||
void raise_integer_truncated() { throw StreamIntegerTruncated(); }
|
void raise_integer_truncated() { throw StreamIntegerTruncated(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class StreamBuffer : public eng::nevernew, public BaseBuffer<StreamBufferCore, eng::string> {
|
class StreamBuffer : public eng::nevernew, public BaseBuffer<StreamBufferConfig> {
|
||||||
public:
|
public:
|
||||||
using BaseBuffer::BaseBuffer;
|
using BaseBuffer::BaseBuffer;
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,10 @@ struct BaseLuaValue {
|
|||||||
//
|
//
|
||||||
// BaseWriteMethods
|
// 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_uint8(uint64_t data)
|
||||||
// void write_uint16(uint64_t data)
|
// void write_uint16(uint64_t data)
|
||||||
@@ -119,15 +122,21 @@ struct BaseLuaValue {
|
|||||||
// void write_length(size_t data)
|
// void write_length(size_t data)
|
||||||
// void write_string(std::string_view 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<DerivedWriter>
|
// class MyWriter : public BaseWriteMethods<MyWriter>
|
||||||
//
|
//
|
||||||
// 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)
|
// write_bytes(const char *n, size_t size)
|
||||||
// raise_integer_truncated()
|
// 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<class Derived>
|
template<class Derived>
|
||||||
@@ -181,7 +190,10 @@ public:
|
|||||||
//
|
//
|
||||||
// BaseReadMethods
|
// 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();
|
// uint8_t read_uint8();
|
||||||
// uint16_t read_uint16();
|
// uint16_t read_uint16();
|
||||||
@@ -196,38 +208,40 @@ public:
|
|||||||
// float read_float();
|
// float read_float();
|
||||||
// double read_double();
|
// double read_double();
|
||||||
// size_t read_length();
|
// size_t read_length();
|
||||||
// String read_string_limit(uint64_t size);
|
// string read_string_limit(uint64_t size);
|
||||||
// String read_string();
|
// string read_string();
|
||||||
//
|
//
|
||||||
// You should derive from BaseReadMethods using the CRTP pattern:
|
// Here is how you should derive from BaseReadMethods:
|
||||||
//
|
//
|
||||||
// class DerivedReader : public BaseReadMethods<DerivedReader>
|
// class MyReader : public BaseReadMethods<MyReader>
|
||||||
//
|
//
|
||||||
// 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 read_bytes_into(char *n, size_t size)
|
||||||
// void raise_string_too_long();
|
// 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
|
// If you call read_string_limit(100), and this finds
|
||||||
// to report errors using exceptions or flags.
|
// a string of length 200 in the incoming data, then
|
||||||
//
|
// read_string_limit will call raise_string_too_long.
|
||||||
// If read_bytes_into discovers there's not enough bytes,
|
// That function can throw an exception, set a flag,
|
||||||
// there are two valid options: throw an exception, OR,
|
// or otherwise handle the error - you can implement it
|
||||||
// set an error flag and fill the buffer with zeros.
|
// to do whatever you wish.
|
||||||
//
|
|
||||||
// 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.
|
|
||||||
//
|
//
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
template<class Derived>
|
template<class Derived>
|
||||||
class BaseReadMethods {
|
class BaseReadMethods {
|
||||||
protected:
|
protected:
|
||||||
|
using string_type = typename Derived::string_type;
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
T read_value_core() {
|
T read_value_core() {
|
||||||
T result;
|
T result;
|
||||||
@@ -254,50 +268,48 @@ public:
|
|||||||
|
|
||||||
size_t read_length() {
|
size_t read_length() {
|
||||||
uint64_t len = read_uint8();
|
uint64_t len = read_uint8();
|
||||||
if (len == 255) {
|
if (len == 255) len = read_uint64();
|
||||||
len = read_uint64();
|
|
||||||
}
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto read_string_limit(uint64_t limit) {
|
string_type read_string_limit(uint64_t limit) {
|
||||||
size_t len = read_length();
|
size_t len = read_length();
|
||||||
Derived *dthis = static_cast<Derived*>(this);
|
Derived *dthis = static_cast<Derived*>(this);
|
||||||
if (len > limit) {
|
if (len > limit) {
|
||||||
dthis->raise_string_too_long();
|
dthis->raise_string_too_long();
|
||||||
len = 0;
|
len = 0;
|
||||||
}
|
}
|
||||||
typename Derived::read_string_type result(len, ' ');
|
string_type result(len, ' ');
|
||||||
dthis->read_bytes_into(&(result[0]), len);
|
dthis->read_bytes_into(&(result[0]), len);
|
||||||
return result;
|
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
|
// Class BaseBuffer
|
||||||
//
|
//
|
||||||
// You must supply a CoreHandler which must define these
|
// You must supply a BaseBufferConfig which must define these:
|
||||||
// methods:
|
|
||||||
//
|
//
|
||||||
// void *basebuffer_malloc(size_t size);
|
// using string_type = std::string; // or compatible
|
||||||
// void basebuffer_free(void *data);
|
// void *basebuffer_malloc(size_t size);
|
||||||
// void raise_eof_on_read();
|
// void basebuffer_free(void *data);
|
||||||
// void raise_string_too_long();
|
// void raise_eof_on_read();
|
||||||
// void raise_integer_truncated();
|
// 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.
|
|
||||||
//
|
//
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
template<class CoreHandler, class StringType>
|
template<class BaseBufferConfig>
|
||||||
class BaseBuffer : public CoreHandler {
|
class BaseBuffer : public BaseBufferConfig {
|
||||||
private:
|
private:
|
||||||
|
// Used for all strings in BaseBuffer.
|
||||||
|
using string_type = typename BaseBufferConfig::string_type;
|
||||||
|
|
||||||
// True if we own this buffer.
|
// True if we own this buffer.
|
||||||
bool owned_;
|
bool owned_;
|
||||||
|
|
||||||
@@ -317,7 +329,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void init(bool fixed, bool owned, char *buf, int64_t size) {
|
void init(bool fixed, bool owned, char *buf, int64_t size) {
|
||||||
CoreHandler::clear_error_flags();
|
BaseBufferConfig::clear_error_flags();
|
||||||
owned_ = owned;
|
owned_ = owned;
|
||||||
fixed_size_ = fixed;
|
fixed_size_ = fixed;
|
||||||
buf_lo_ = buf;
|
buf_lo_ = buf;
|
||||||
@@ -328,8 +340,6 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using string_type = StringType;
|
|
||||||
|
|
||||||
// Construct an empty buffer.
|
// Construct an empty buffer.
|
||||||
//
|
//
|
||||||
BaseBuffer() {
|
BaseBuffer() {
|
||||||
@@ -340,7 +350,7 @@ public:
|
|||||||
//
|
//
|
||||||
BaseBuffer(int64_t size, bool fixed) {
|
BaseBuffer(int64_t size, bool fixed) {
|
||||||
assert(size >= 0);
|
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.
|
// 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.
|
// Modify an existing streambuffer to read from an external block of bytes.
|
||||||
//
|
//
|
||||||
void open(std::string_view data) {
|
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<char *>(data.data()), data.size());
|
init(true, false, const_cast<char *>(data.data()), data.size());
|
||||||
write_cursor_ = buf_hi_;
|
write_cursor_ = buf_hi_;
|
||||||
}
|
}
|
||||||
@@ -361,7 +371,7 @@ public:
|
|||||||
// Destructor. Frees the buffer, if any.
|
// Destructor. Frees the buffer, if any.
|
||||||
//
|
//
|
||||||
~BaseBuffer() {
|
~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.
|
// Return the total number of bytes ever read.
|
||||||
@@ -435,7 +445,7 @@ public:
|
|||||||
open("");
|
open("");
|
||||||
} else {
|
} else {
|
||||||
if ((!fixed_size_) && (buf_lo_ != nullptr) && ((buf_hi_ - buf_lo_) > 100000)) {
|
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_lo_ = nullptr;
|
||||||
buf_hi_ = nullptr;
|
buf_hi_ = nullptr;
|
||||||
}
|
}
|
||||||
@@ -529,7 +539,7 @@ public:
|
|||||||
const char *read_bytes(int64_t bytes) {
|
const char *read_bytes(int64_t bytes) {
|
||||||
int64_t avail = write_cursor_ - read_cursor_;
|
int64_t avail = write_cursor_ - read_cursor_;
|
||||||
if (avail < bytes) {
|
if (avail < bytes) {
|
||||||
CoreHandler::raise_eof_on_read();
|
BaseBufferConfig::raise_eof_on_read();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
char *data = read_cursor_;
|
char *data = read_cursor_;
|
||||||
@@ -576,12 +586,12 @@ public:
|
|||||||
std::string_view read_string_view_limit(uint64_t limit) {
|
std::string_view read_string_view_limit(uint64_t limit) {
|
||||||
size_t length = read_length();
|
size_t length = read_length();
|
||||||
if (length > limit) {
|
if (length > limit) {
|
||||||
CoreHandler::raise_string_too_long();
|
BaseBufferConfig::raise_string_too_long();
|
||||||
return std::string_view();
|
return std::string_view();
|
||||||
}
|
}
|
||||||
int64_t avail = write_cursor_ - read_cursor_;
|
int64_t avail = write_cursor_ - read_cursor_;
|
||||||
if (avail < int64_t(length)) {
|
if (avail < int64_t(length)) {
|
||||||
CoreHandler::raise_eof_on_read();
|
BaseBufferConfig::raise_eof_on_read();
|
||||||
return std::string_view();
|
return std::string_view();
|
||||||
}
|
}
|
||||||
std::string_view result(read_cursor_, length);
|
std::string_view result(read_cursor_, length);
|
||||||
@@ -600,12 +610,12 @@ public:
|
|||||||
string_type read_string_limit(uint64_t limit) {
|
string_type read_string_limit(uint64_t limit) {
|
||||||
size_t len = read_length();
|
size_t len = read_length();
|
||||||
if (len > limit) {
|
if (len > limit) {
|
||||||
CoreHandler::raise_string_too_long();
|
BaseBufferConfig::raise_string_too_long();
|
||||||
return string_type();
|
return string_type();
|
||||||
}
|
}
|
||||||
int64_t avail = write_cursor_ - read_cursor_;
|
int64_t avail = write_cursor_ - read_cursor_;
|
||||||
if (avail < int64_t(len)) {
|
if (avail < int64_t(len)) {
|
||||||
CoreHandler::raise_eof_on_read();
|
BaseBufferConfig::raise_eof_on_read();
|
||||||
return string_type();
|
return string_type();
|
||||||
}
|
}
|
||||||
string_type result(len, ' ');
|
string_type result(len, ' ');
|
||||||
@@ -706,9 +716,9 @@ private:
|
|||||||
} else if (existing_size >= desired_size) {
|
} else if (existing_size >= desired_size) {
|
||||||
if (data_size > 0) memcpy(buf_lo_, read_cursor_, data_size);
|
if (data_size > 0) memcpy(buf_lo_, read_cursor_, data_size);
|
||||||
} else {
|
} 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 (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_lo_ = nbuf;
|
||||||
buf_hi_ = nbuf + desired_size;
|
buf_hi_ = nbuf + desired_size;
|
||||||
}
|
}
|
||||||
@@ -728,7 +738,7 @@ private:
|
|||||||
template<class T, class XT>
|
template<class T, class XT>
|
||||||
void write_int_core(XT arg) {
|
void write_int_core(XT arg) {
|
||||||
T reduced = arg;
|
T reduced = arg;
|
||||||
if (XT(reduced) != arg) CoreHandler::raise_integer_truncated();
|
if (XT(reduced) != arg) BaseBufferConfig::raise_integer_truncated();
|
||||||
write_value_core(reduced);
|
write_value_core(reduced);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -737,7 +747,7 @@ private:
|
|||||||
T result;
|
T result;
|
||||||
int64_t avail = write_cursor_ - read_cursor_;
|
int64_t avail = write_cursor_ - read_cursor_;
|
||||||
if (avail < int64_t(sizeof(result))) {
|
if (avail < int64_t(sizeof(result))) {
|
||||||
CoreHandler::raise_eof_on_read();
|
BaseBufferConfig::raise_eof_on_read();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
memcpy(&result, read_cursor_, sizeof(result));
|
memcpy(&result, read_cursor_, sizeof(result));
|
||||||
|
|||||||
Reference in New Issue
Block a user