Final refactor of basebuffer
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
//
|
||||
@@ -109,12 +110,15 @@ struct BaseLuaValue {
|
||||
//
|
||||
// To serialize, first construct a DataSerializer, passing
|
||||
// in a pointer to an output device. An output device is
|
||||
// any class that has these methods:
|
||||
//
|
||||
// void write_bytes(char *data, size_t len);
|
||||
// any class that has these methods and type aliases:
|
||||
//
|
||||
// void write_bytes(const char *data, size_t len);
|
||||
// void raise_integer_truncated();
|
||||
//
|
||||
// using fvector_type = ...; // needed for write_xyz
|
||||
// using dvector_type = ...; // needed for write_dxyz
|
||||
// using luavalue_type = ...; // needed for write_lua_value
|
||||
//
|
||||
// After constructing the DataSerializer, call write_int,
|
||||
// write_float, write_string, or the like. The data will be
|
||||
// written to the output device using write_bytes. If
|
||||
@@ -176,6 +180,44 @@ public:
|
||||
write_length(s.size());
|
||||
output_->write_bytes(s.data(), s.size());
|
||||
}
|
||||
|
||||
void write_lua_value_type(LuaValueType tag) {
|
||||
write_uint8(uint8_t(tag));
|
||||
}
|
||||
|
||||
template<class FV>
|
||||
void write_xyz(const FV &v) {
|
||||
static_assert(std::is_same_v<FV, typename OutputDevice::fvector_type>);
|
||||
if constexpr (requires { v.x; }) {
|
||||
write_float(v.x); write_float(v.y); write_float(v.z);
|
||||
} else {
|
||||
write_float(v.X); write_float(v.Y); write_float(v.Z);
|
||||
}
|
||||
}
|
||||
|
||||
template<class DV>
|
||||
void write_dxyz(const DV &v) {
|
||||
static_assert(std::is_same_v<DV, typename OutputDevice::dvector_type>);
|
||||
if constexpr (requires { v.x; }) {
|
||||
write_double(v.x); write_double(v.y); write_double(v.z);
|
||||
} else {
|
||||
write_double(v.X); write_double(v.Y); write_double(v.Z);
|
||||
}
|
||||
}
|
||||
|
||||
template<class LV>
|
||||
void write_lua_value(const LV &sd) {
|
||||
static_assert(std::is_same_v<LV, typename OutputDevice::luavalue_type>);
|
||||
write_lua_value_type(sd.type);
|
||||
switch(sd.type) {
|
||||
case LuaValueType::STRING: write_string(sd.s); break;
|
||||
case LuaValueType::TOKEN: write_string(sd.s); break;
|
||||
case LuaValueType::NUMBER: write_double(sd.x); break;
|
||||
case LuaValueType::BOOLEAN: write_bool(sd.x == 1.0); break;
|
||||
case LuaValueType::VECTOR: write_double(sd.x); write_double(sd.y); write_double(sd.z); break;
|
||||
default: assert(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -189,11 +231,16 @@ public:
|
||||
//
|
||||
// To deserialize, first construct a DataDeserializer, passing
|
||||
// in a pointer to an input device. An input device is
|
||||
// any class that has these methods:
|
||||
// any class that has these methods and type aliases:
|
||||
//
|
||||
// void read_bytes_into(char *data, size_t len);
|
||||
// void raise_string_too_long();
|
||||
//
|
||||
// using string_type = ...; // needed for read_string
|
||||
// using fvector_type = ...; // needed for read_xyz
|
||||
// using dvector_type = ...; // needed for read_dxyz
|
||||
// using luavalue_type = ...; // needed for read_lua_value
|
||||
//
|
||||
// After constructing the DataDeserializer, call read_int,
|
||||
// read_float, read_string, or the like. The data will be
|
||||
// read from the input device using read_bytes_into. If
|
||||
@@ -208,7 +255,7 @@ public:
|
||||
//
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
template<class InputDevice, class StringType = std::string>
|
||||
template<class InputDevice>
|
||||
class DataDeserializer {
|
||||
private:
|
||||
InputDevice *input_;
|
||||
@@ -243,20 +290,57 @@ public:
|
||||
return len;
|
||||
}
|
||||
|
||||
StringType read_string_limit(uint64_t limit) {
|
||||
auto read_string_limit(uint64_t limit) {
|
||||
using ST = typename InputDevice::string_type;
|
||||
size_t len = read_length();
|
||||
if (len > limit) {
|
||||
input_->raise_string_too_long();
|
||||
len = 0;
|
||||
}
|
||||
StringType result(len, ' ');
|
||||
ST result(len, ' ');
|
||||
input_->read_bytes_into(&(result[0]), len);
|
||||
return result;
|
||||
}
|
||||
|
||||
StringType read_string() {
|
||||
auto read_string() {
|
||||
return read_string_limit(0x1000000); // 16MB limit default
|
||||
}
|
||||
|
||||
auto read_xyz() {
|
||||
using FV = typename InputDevice::fvector_type;
|
||||
float x = read_float(), y = read_float(), z = read_float();
|
||||
return FV(x, y, z);
|
||||
}
|
||||
|
||||
auto read_dxyz() {
|
||||
using DV = typename InputDevice::dvector_type;
|
||||
double x = read_double(), y = read_double(), z = read_double();
|
||||
return DV(x, y, z);
|
||||
}
|
||||
|
||||
LuaValueType read_lua_value_type() {
|
||||
return LuaValueType(read_uint8());
|
||||
}
|
||||
|
||||
template<class LV>
|
||||
void read_lua_value(LV *result) {
|
||||
static_assert(std::is_same_v<LV, typename InputDevice::luavalue_type>);
|
||||
LuaValueType type = read_lua_value_type();
|
||||
switch (type) {
|
||||
case LuaValueType::STRING: result->set_string(read_string()); break;
|
||||
case LuaValueType::TOKEN: result->set_token(read_string()); break;
|
||||
case LuaValueType::NUMBER: result->set_number(read_double()); break;
|
||||
case LuaValueType::BOOLEAN: result->set_boolean(read_bool()); break;
|
||||
case LuaValueType::VECTOR: {
|
||||
double x=read_double();
|
||||
double y=read_double();
|
||||
double z=read_double();
|
||||
result->set_vector(x,y,z);
|
||||
break;
|
||||
}
|
||||
default: result->set_uninitialized(); break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
@@ -265,9 +349,13 @@ public:
|
||||
//
|
||||
// You must supply a BaseBufferConfig which must define these:
|
||||
//
|
||||
// using string_type = std::string; // or compatible
|
||||
// using string_type = ...; // string type for read_string
|
||||
// using fvector_type = ...; // vector type for read/write_xyz
|
||||
// using dvector_type = ...; // vector type for read/write_dxyz
|
||||
// using luavalue_type = ...; // lua value type for read/write_lua_value
|
||||
// void *basebuffer_malloc(size_t size);
|
||||
// void basebuffer_free(void *data);
|
||||
// void clear_error_flags();
|
||||
// void raise_eof_on_read();
|
||||
// void raise_string_too_long();
|
||||
// void raise_integer_truncated();
|
||||
@@ -297,10 +385,13 @@ private:
|
||||
|
||||
public:
|
||||
using string_type = typename BaseBufferConfig::string_type;
|
||||
using fvector_type = typename BaseBufferConfig::fvector_type;
|
||||
using dvector_type = typename BaseBufferConfig::dvector_type;
|
||||
using luavalue_type = typename BaseBufferConfig::luavalue_type;
|
||||
|
||||
private:
|
||||
using DS = DataSerializer<BaseBuffer<BaseBufferConfig>>;
|
||||
using DD = DataDeserializer<BaseBuffer<BaseBufferConfig>, string_type>;
|
||||
using DD = DataDeserializer<BaseBuffer<BaseBufferConfig>>;
|
||||
|
||||
void init(bool fixed, bool owned, char *buf, int64_t size) {
|
||||
BaseBufferConfig::clear_error_flags();
|
||||
@@ -441,46 +532,17 @@ public:
|
||||
void write_bytes(std::string_view s) {
|
||||
write_bytes(s.data(), s.size());
|
||||
}
|
||||
|
||||
// Write methods — delegate to DataSerializer.
|
||||
//
|
||||
void write_uint8(uint64_t data) { DS(this).write_uint8(data); }
|
||||
void write_uint16(uint64_t data) { DS(this).write_uint16(data); }
|
||||
void write_uint32(uint64_t data) { DS(this).write_uint32(data); }
|
||||
void write_uint64(uint64_t data) { DS(this).write_uint64(data); }
|
||||
void write_int8(int64_t data) { DS(this).write_int8(data); }
|
||||
void write_int16(int64_t data) { DS(this).write_int16(data); }
|
||||
void write_int32(int64_t data) { DS(this).write_int32(data); }
|
||||
void write_int64(int64_t data) { DS(this).write_int64(data); }
|
||||
void write_bool(bool b) { DS(this).write_bool(b); }
|
||||
void write_char(char c) { DS(this).write_char(c); }
|
||||
void write_float(float arg) { DS(this).write_float(arg); }
|
||||
void write_double(double arg) { DS(this).write_double(arg); }
|
||||
void write_length(size_t len) { DS(this).write_length(len); }
|
||||
void write_string(std::string_view s) { DS(this).write_string(s); }
|
||||
|
||||
// Write a LuaValueType.
|
||||
// Copy the contents of this buffer into another buffer.
|
||||
//
|
||||
void write_simple_dynamic_tag(LuaValueType tag) {
|
||||
write_uint8(uint8_t(tag));
|
||||
void copy_into(BaseBuffer *sb) {
|
||||
sb->write_bytes(view());
|
||||
}
|
||||
|
||||
// Write a BaseLuaValue value.
|
||||
// Check if the contents of this buffer are equal to another.
|
||||
//
|
||||
// This works regardless of what kind of data is present in the
|
||||
// BaseLuaValue.
|
||||
//
|
||||
template<class STRING>
|
||||
void write_simple_dynamic(const BaseLuaValue<STRING> &sd) {
|
||||
write_simple_dynamic_tag(sd.type);
|
||||
switch(sd.type) {
|
||||
case LuaValueType::STRING: write_string(sd.s); break;
|
||||
case LuaValueType::TOKEN: write_string(sd.s); break;
|
||||
case LuaValueType::NUMBER: write_double(sd.x); break;
|
||||
case LuaValueType::BOOLEAN: write_bool(sd.x == 1.0); break;
|
||||
case LuaValueType::VECTOR: write_double(sd.x); write_double(sd.y); write_double(sd.z); break;
|
||||
default: assert(false);
|
||||
}
|
||||
bool contents_equal(const BaseBuffer *sb) const {
|
||||
return view() == sb->view();
|
||||
}
|
||||
|
||||
// Read bytes into a caller-supplied buffer.
|
||||
@@ -517,6 +579,28 @@ public:
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
// Write methods — delegate to DataSerializer.
|
||||
//
|
||||
void write_uint8(uint64_t data) { DS(this).write_uint8(data); }
|
||||
void write_uint16(uint64_t data) { DS(this).write_uint16(data); }
|
||||
void write_uint32(uint64_t data) { DS(this).write_uint32(data); }
|
||||
void write_uint64(uint64_t data) { DS(this).write_uint64(data); }
|
||||
void write_int8(int64_t data) { DS(this).write_int8(data); }
|
||||
void write_int16(int64_t data) { DS(this).write_int16(data); }
|
||||
void write_int32(int64_t data) { DS(this).write_int32(data); }
|
||||
void write_int64(int64_t data) { DS(this).write_int64(data); }
|
||||
void write_bool(bool b) { DS(this).write_bool(b); }
|
||||
void write_char(char c) { DS(this).write_char(c); }
|
||||
void write_float(float arg) { DS(this).write_float(arg); }
|
||||
void write_double(double arg) { DS(this).write_double(arg); }
|
||||
void write_length(size_t len) { DS(this).write_length(len); }
|
||||
void write_string(std::string_view s) { DS(this).write_string(s); }
|
||||
void write_lua_value_type(LuaValueType tag) { DS(this).write_lua_value_type(tag); }
|
||||
void write_xyz(const fvector_type &v) { DS(this).write_xyz(v); }
|
||||
void write_dxyz(const dvector_type &v) { DS(this).write_dxyz(v); }
|
||||
void write_lua_value(const luavalue_type &sd) { DS(this).write_lua_value(sd); }
|
||||
|
||||
// Read methods — delegate to DataDeserializer.
|
||||
//
|
||||
uint8_t read_uint8() { return DD(this).read_uint8(); }
|
||||
@@ -534,6 +618,10 @@ public:
|
||||
size_t read_length() { return DD(this).read_length(); }
|
||||
string_type read_string_limit(uint64_t limit) { return DD(this).read_string_limit(limit); }
|
||||
string_type read_string() { return DD(this).read_string(); }
|
||||
LuaValueType read_lua_value_type() { return DD(this).read_lua_value_type(); }
|
||||
fvector_type read_xyz() { return DD(this).read_xyz(); }
|
||||
dvector_type read_dxyz() { return DD(this).read_dxyz(); }
|
||||
void read_lua_value(luavalue_type *result) { DD(this).read_lua_value(result); }
|
||||
|
||||
// Read a string as a string_view.
|
||||
//
|
||||
@@ -561,33 +649,6 @@ public:
|
||||
std::string_view read_string_view() {
|
||||
return read_string_view_limit(0x1000000);
|
||||
}
|
||||
|
||||
// Read a LuaValueType
|
||||
//
|
||||
LuaValueType read_simple_dynamic_tag() {
|
||||
return LuaValueType(read_uint8());
|
||||
}
|
||||
|
||||
// Read a BaseLuaValue
|
||||
//
|
||||
template<class STRING>
|
||||
void read_simple_dynamic(BaseLuaValue<STRING> *result) {
|
||||
LuaValueType type = read_simple_dynamic_tag();
|
||||
switch (type) {
|
||||
case LuaValueType::STRING: result->set_string(read_string()); break;
|
||||
case LuaValueType::TOKEN: result->set_token(read_string()); break;
|
||||
case LuaValueType::NUMBER: result->set_number(read_double()); break;
|
||||
case LuaValueType::BOOLEAN: result->set_boolean(read_bool()); break;
|
||||
case LuaValueType::VECTOR: {
|
||||
double x=read_double();
|
||||
double y=read_double();
|
||||
double z=read_double();
|
||||
result->set_vector(x,y,z);
|
||||
break;
|
||||
}
|
||||
default: result->set_uninitialized(); break;
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to do a "readline". If there is no newline in
|
||||
// the buffer, returns empty string. If there is a newline,
|
||||
|
||||
Reference in New Issue
Block a user