Final refactor of basebuffer
This commit is contained in:
@@ -130,7 +130,7 @@ eng::string AnimStepEditor::encode() const {
|
||||
const AnimValue &value = pair.second;
|
||||
sb.write_string(name);
|
||||
sb.write_bool(value.persistent);
|
||||
sb.write_simple_dynamic(value);
|
||||
sb.write_lua_value(value);
|
||||
}
|
||||
return eng::string(sb.view());
|
||||
}
|
||||
@@ -142,7 +142,7 @@ void AnimStepEditor::decode(std::string_view s) {
|
||||
eng::string name = sb.read_string();
|
||||
AnimValue &value = map_[name];
|
||||
value.persistent = sb.read_bool();
|
||||
sb.read_simple_dynamic(&value);
|
||||
sb.read_lua_value(&value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,9 +156,9 @@ void AnimStepEditor::decode_persistent(std::string_view s) {
|
||||
if (persistent) {
|
||||
AnimValue &value = map_[name];
|
||||
value.persistent = persistent;
|
||||
sb.read_simple_dynamic(&value);
|
||||
sb.read_lua_value(&value);
|
||||
} else {
|
||||
sb.read_simple_dynamic(&dummy);
|
||||
sb.read_lua_value(&dummy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -349,7 +349,7 @@ void AnimCoreState::decode(std::string_view s) {
|
||||
while (!sb.empty()) {
|
||||
eng::string name = sb.read_string();
|
||||
bool persistent = sb.read_bool();
|
||||
sb.read_simple_dynamic(&value);
|
||||
sb.read_lua_value(&value);
|
||||
if (persistent) {
|
||||
if ((name == "xyz") && (value.type == LuaValueType::VECTOR)) xyz = util::DXYZ(value.x, value.y, value.z);
|
||||
if ((name == "plane") && (value.type == LuaValueType::STRING)) plane = value.s;
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
// for all key-value pairs do:
|
||||
// write_string(key)
|
||||
// write_bool(persistent)
|
||||
// write_simple_dynamic(value)
|
||||
// write_lua_value(value)
|
||||
//
|
||||
// The encoded string produced by the loop above is called an "encstep".
|
||||
// That's short for "encoded animation step". The encstep has a hash
|
||||
|
||||
@@ -255,6 +255,7 @@ class ReplayLogfile : public std::ifstream {
|
||||
using std::ifstream::ifstream;
|
||||
using DD = DataDeserializer<ReplayLogfile>;
|
||||
public:
|
||||
using string_type = std::string;
|
||||
void read_bytes_into(char *n, size_t size) {
|
||||
read(n, size);
|
||||
if (!good()) {
|
||||
|
||||
@@ -248,6 +248,9 @@ using LuaValue = BaseLuaValue<eng::string>;
|
||||
class StreamBufferConfig {
|
||||
public:
|
||||
using string_type = eng::string;
|
||||
using fvector_type = util::XYZ;
|
||||
using dvector_type = util::DXYZ;
|
||||
using luavalue_type = LuaValue;
|
||||
void *basebuffer_malloc(size_t size) { return eng::malloc(size); }
|
||||
void basebuffer_free(void *p) { eng::free(p); }
|
||||
void clear_error_flags() { }
|
||||
@@ -260,50 +263,16 @@ class StreamBuffer : public eng::nevernew, public BaseBuffer<StreamBufferConfig>
|
||||
public:
|
||||
using BaseBuffer::BaseBuffer;
|
||||
|
||||
void write_xyz(const util::XYZ &xyz) {
|
||||
write_float(xyz.x);
|
||||
write_float(xyz.y);
|
||||
write_float(xyz.z);
|
||||
}
|
||||
|
||||
void write_dxyz(const util::DXYZ &xyz) {
|
||||
write_double(xyz.x);
|
||||
write_double(xyz.y);
|
||||
write_double(xyz.z);
|
||||
}
|
||||
|
||||
void write_hashvalue(const util::HashValue &h) {
|
||||
write_uint64(h.first);
|
||||
write_uint64(h.second);
|
||||
}
|
||||
|
||||
util::XYZ read_xyz() {
|
||||
float x = read_float();
|
||||
float y = read_float();
|
||||
float z = read_float();
|
||||
return util::XYZ(x, y, z);
|
||||
}
|
||||
|
||||
util::DXYZ read_dxyz() {
|
||||
double x = read_double();
|
||||
double y = read_double();
|
||||
double z = read_double();
|
||||
return util::DXYZ(x, y, z);
|
||||
}
|
||||
|
||||
util::HashValue read_hashvalue() {
|
||||
uint64_t f = read_uint64();
|
||||
uint64_t s = read_uint64();
|
||||
return util::HashValue(f, s);
|
||||
}
|
||||
|
||||
bool contents_equal(const StreamBuffer *sb) {
|
||||
return view() == sb->view();
|
||||
}
|
||||
|
||||
void copy_into(StreamBuffer *sb) {
|
||||
sb->write_bytes(view());
|
||||
}
|
||||
};
|
||||
|
||||
// Use a streambuffer as a lua_writer.
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
// Read a serialized LuaValue value from the
|
||||
// streambuffer and push it onto the lua stack.
|
||||
void push_simple_dynamic(lua_State *L, StreamBuffer *sb) {
|
||||
LuaValueType type = sb->read_simple_dynamic_tag();
|
||||
LuaValueType type = sb->read_lua_value_type();
|
||||
switch (type) {
|
||||
case LuaValueType::STRING: {
|
||||
std::string_view s = sb->read_string_view();
|
||||
@@ -56,25 +56,25 @@ void push_simple_dynamic(lua_State *L, StreamBuffer *sb) {
|
||||
bool encode_simple_dynamic(LuaCoreStack &LS, LuaSlot &slot, StreamBuffer *sb) {
|
||||
switch (LS.type(slot)) {
|
||||
case LUA_TSTRING:
|
||||
sb->write_simple_dynamic_tag(LuaValueType::STRING);
|
||||
sb->write_lua_value_type(LuaValueType::STRING);
|
||||
sb->write_string(LS.ckstringview(slot));
|
||||
return true;
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
sb->write_simple_dynamic_tag(LuaValueType::TOKEN);
|
||||
sb->write_lua_value_type(LuaValueType::TOKEN);
|
||||
sb->write_string(LS.cktoken(slot).str());
|
||||
return true;
|
||||
case LUA_TNUMBER:
|
||||
sb->write_simple_dynamic_tag(LuaValueType::NUMBER);
|
||||
sb->write_lua_value_type(LuaValueType::NUMBER);
|
||||
sb->write_double(LS.cknumber(slot));
|
||||
return true;
|
||||
case LUA_TBOOLEAN:
|
||||
sb->write_simple_dynamic_tag(LuaValueType::BOOLEAN);
|
||||
sb->write_lua_value_type(LuaValueType::BOOLEAN);
|
||||
sb->write_bool(LS.ckboolean(slot));
|
||||
return true;
|
||||
case LUA_TTABLE: {
|
||||
std::optional<util::DXYZ> xyz = LS.tryxyz(slot);
|
||||
if (!xyz.has_value()) return false;
|
||||
sb->write_simple_dynamic_tag(LuaValueType::VECTOR);
|
||||
sb->write_lua_value_type(LuaValueType::VECTOR);
|
||||
sb->write_dxyz(xyz.value());
|
||||
return true;
|
||||
}
|
||||
@@ -480,7 +480,7 @@ void World::probe_lua_call(int64_t actor_id, int64_t place_id, std::string_view
|
||||
// return value of the function.
|
||||
//
|
||||
int64_t rv_base = retvals->total_writes();
|
||||
retvals->write_simple_dynamic_tag(LuaValueType::STRING);
|
||||
retvals->write_lua_value_type(LuaValueType::STRING);
|
||||
retvals->write_string(msg);
|
||||
|
||||
if (msg.empty()) {
|
||||
@@ -509,7 +509,7 @@ void World::probe_lua_call(int64_t actor_id, int64_t place_id, std::string_view
|
||||
if (!ok) {
|
||||
msg = util::ss("Lua function ",classname,".",funcname," returned a non-serializable value");
|
||||
retvals->unwrite_to(rv_base);
|
||||
retvals->write_simple_dynamic_tag(LuaValueType::STRING);
|
||||
retvals->write_lua_value_type(LuaValueType::STRING);
|
||||
retvals->write_string(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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