More tweaks to base-writer
This commit is contained in:
@@ -1,169 +0,0 @@
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: This is a header-only library that is included
|
||||
// by the graphics engine as well. It cannot contain references
|
||||
// to anything else in the engine.
|
||||
//
|
||||
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <string_view>
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
//
|
||||
// BaseWriter
|
||||
//
|
||||
// This base class provides the following methods:
|
||||
//
|
||||
// void write_uint8(uint64_t data)
|
||||
// void write_uint16(uint64_t data)
|
||||
// void write_uint32(uint64_t data)
|
||||
// void write_uint64(uint64_t data)
|
||||
// void write_int8(int64_t data)
|
||||
// void write_int16(int64_t data)
|
||||
// void write_int32(int64_t data)
|
||||
// void write_int64(int64_t data)
|
||||
// void write_char(char c)
|
||||
// void write_float(float data)
|
||||
// void write_double(double data)
|
||||
// void write_bytes(std::string_view bytes)
|
||||
// void write_string(std::string_view bytes)
|
||||
//
|
||||
// In order to derive from BaseWriter, you must use the CRTP pattern:
|
||||
//
|
||||
// class DerivedWriter : public BaseWriter<DerivedWriter>
|
||||
//
|
||||
// And you must provide two methods in the derived class:
|
||||
//
|
||||
// write_bytes(const char *n, size_t size)
|
||||
//
|
||||
// raise_truncated()
|
||||
//
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
template<class Derived>
|
||||
class BaseWriter {
|
||||
protected:
|
||||
template<class T>
|
||||
void write_value_core(T arg) {
|
||||
static_cast<Derived*>(this)->write_bytes((const char *)&arg, sizeof(arg));
|
||||
}
|
||||
|
||||
template<class T, class XT>
|
||||
void write_int_core(XT arg) {
|
||||
T reduced = arg;
|
||||
if (XT(reduced) != arg) static_cast<Derived*>(this)->raise_truncated();
|
||||
write_value_core(reduced);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void write_uint8(uint64_t data) { write_int_core<uint8_t, uint64_t>(data); }
|
||||
void write_uint16(uint64_t data) { write_int_core<uint16_t, uint64_t>(data); }
|
||||
void write_uint32(uint64_t data) { write_int_core<uint32_t, uint64_t>(data); }
|
||||
void write_uint64(uint64_t data) { write_int_core<uint64_t, uint64_t>(data); }
|
||||
void write_int8(int64_t data) { write_int_core<int8_t, int64_t>(data); }
|
||||
void write_int16(int64_t data) { write_int_core<int16_t, int64_t>(data); }
|
||||
void write_int32(int64_t data) { write_int_core<int32_t, int64_t>(data); }
|
||||
void write_int64(int64_t data) { write_int_core<int64_t, int64_t>(data); }
|
||||
|
||||
void write_bool(bool b) { write_uint8(b ? 1:0); }
|
||||
void write_char(char c) { write_value_core(c); }
|
||||
void write_float(float arg) { write_value_core(arg); }
|
||||
void write_double(double arg) { write_value_core(arg); }
|
||||
|
||||
void write_string(std::string_view s) {
|
||||
if (s.size() >= 255) {
|
||||
write_uint8(0xFF);
|
||||
write_uint64(s.size());
|
||||
static_cast<Derived*>(this)->write_bytes(s.data(), s.size());
|
||||
} else {
|
||||
write_uint8(s.size());
|
||||
static_cast<Derived*>(this)->write_bytes(s.data(), s.size());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
//
|
||||
// BaseReader
|
||||
//
|
||||
// This base class provides the following methods:
|
||||
//
|
||||
// uint8_t read_uint8();
|
||||
// uint16_t read_uint16();
|
||||
// uint32_t read_uint32();
|
||||
// uint64_t read_uint64();
|
||||
// int8_t read_int8();
|
||||
// int16_t read_int16();
|
||||
// int32_t read_int32();
|
||||
// int64_t read_int64();
|
||||
// bool read_bool();
|
||||
// char read_char();
|
||||
// float read_float();
|
||||
// double read_double();
|
||||
// string read_string_limit(int64_t size);
|
||||
// string read_string();
|
||||
//
|
||||
// In order to derive from BaseReader, you must use the CRTP pattern:
|
||||
//
|
||||
// class DerivedReader : public BaseReader<DerivedReader>
|
||||
//
|
||||
// The derived class must provide:
|
||||
//
|
||||
// using string = std::string (or similar)
|
||||
//
|
||||
// void read_bytes_into(char *n, size_t size)
|
||||
//
|
||||
// void raise_string_too_long();
|
||||
//
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
template<class Derived, class String>
|
||||
class BaseReader {
|
||||
protected:
|
||||
|
||||
template<class T>
|
||||
T read_value_core() {
|
||||
T result;
|
||||
static_cast<Derived*>(this)->read_bytes_into((char *)(&result), sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
uint8_t read_uint8() { return read_value_core<uint8_t>(); }
|
||||
uint16_t read_uint16() { return read_value_core<uint16_t>(); }
|
||||
uint32_t read_uint32() { return read_value_core<uint32_t>(); }
|
||||
uint64_t read_uint64() { return read_value_core<uint64_t>(); }
|
||||
int8_t read_int8() { return read_value_core<int8_t>(); }
|
||||
int16_t read_int16() { return read_value_core<int16_t>(); }
|
||||
int32_t read_int32() { return read_value_core<int32_t>(); }
|
||||
int64_t read_int64() { return read_value_core<int64_t>(); }
|
||||
|
||||
bool read_bool() { return read_uint8(); }
|
||||
char read_char() { return read_value_core<char>(); }
|
||||
float read_float() { return read_value_core<float>(); }
|
||||
double read_double() { return read_value_core<double>(); }
|
||||
|
||||
String read_string_limit(int64_t limit) {
|
||||
uint64_t size = read_uint8();
|
||||
if (size == 255) {
|
||||
size = read_uint64();
|
||||
}
|
||||
if ((limit < 0)||(size > uint64_t(limit))) {
|
||||
static_cast<Derived*>(this)->raise_string_too_long();
|
||||
}
|
||||
String result;
|
||||
result.resize(size);
|
||||
static_cast<Derived*>(this)->read_bytes_into(&result[0], size);
|
||||
return result;
|
||||
}
|
||||
|
||||
String read_string() {
|
||||
return read_string_limit(0xFFFFFFF);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -169,7 +169,6 @@ void StreamBuffer::read_bytes_into(char *data, int64_t size) {
|
||||
read_cursor_ += size;
|
||||
}
|
||||
|
||||
|
||||
void StreamBuffer::write_xyz(const util::XYZ &xyz) {
|
||||
make_space(12);
|
||||
memcpy(write_cursor_, &xyz.x, 4);
|
||||
|
||||
@@ -241,8 +241,10 @@ public:
|
||||
virtual char const *what() const { return "Stream contained invalid data"; }
|
||||
};
|
||||
|
||||
class StreamBuffer : public eng::nevernew, public BaseReader<StreamBuffer, eng::string>, public BaseWriter<StreamBuffer> {
|
||||
class StreamBuffer : public eng::nevernew, public BaseReader<StreamBuffer>, public BaseWriter<StreamBuffer> {
|
||||
public:
|
||||
using read_string_type = eng::string;
|
||||
|
||||
// Construct an empty buffer.
|
||||
StreamBuffer();
|
||||
|
||||
@@ -290,10 +292,6 @@ public:
|
||||
void write_bytes(const char *bytes, int64_t len);
|
||||
void write_bytes(std::string_view s);
|
||||
|
||||
// Copy bytes from the StreamBuffer into an external buffer.
|
||||
//
|
||||
void read_bytes_into(char *target, int64_t len);
|
||||
|
||||
// Read a block of bytes from the buffer.
|
||||
//
|
||||
// Caution: the pointer returned is a pointer to the stream's buffer. It is
|
||||
@@ -302,6 +300,10 @@ public:
|
||||
//
|
||||
const char *read_bytes(int64_t bytes);
|
||||
|
||||
// Copy bytes from the StreamBuffer into an external buffer.
|
||||
//
|
||||
void read_bytes_into(char *target, int64_t len);
|
||||
|
||||
// Read and write larger types.
|
||||
//
|
||||
// Throws StreamEof if the specified number of bytes aren't present.
|
||||
|
||||
Reference in New Issue
Block a user