Added base-writer class
This commit is contained in:
169
luprex/cpp/core/base-writer.hpp
Normal file
169
luprex/cpp/core/base-writer.hpp
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@@ -145,41 +145,6 @@ eng::string StreamBuffer::readline() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// These routines return true if you can losslessly cast the
|
|
||||||
// specified value to the specified type.
|
|
||||||
|
|
||||||
static inline bool safe_to_cast_to_int8(int64_t vv) {
|
|
||||||
return ((vv + 0x80LL) & 0xFFFFFFFFFFFFFF00LL) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool safe_to_cast_to_int16(int64_t vv) {
|
|
||||||
return ((vv + 0x8000LL) & 0xFFFFFFFFFFFF0000LL) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool safe_to_cast_to_int32(int64_t vv) {
|
|
||||||
return ((vv + 0x80000000LL) & 0xFFFFFFFF00000000LL) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool safe_to_cast_to_int64(int64_t vv) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool safe_to_cast_to_uint8(uint64_t vv) {
|
|
||||||
return (vv & 0xFFFFFFFFFFFFFF00LL) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool safe_to_cast_to_uint16(uint64_t vv) {
|
|
||||||
return (vv & 0xFFFFFFFFFFFF0000LL) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool safe_to_cast_to_uint32(uint64_t vv) {
|
|
||||||
return (vv & 0xFFFFFFFF00000000LL) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool safe_to_cast_to_uint64(uint64_t vv) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamBuffer::write_bytes(const char *s, int64_t len) {
|
void StreamBuffer::write_bytes(const char *s, int64_t len) {
|
||||||
make_space(len);
|
make_space(len);
|
||||||
memcpy(write_cursor_, s, len);
|
memcpy(write_cursor_, s, len);
|
||||||
@@ -187,11 +152,10 @@ void StreamBuffer::write_bytes(const char *s, int64_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void StreamBuffer::write_bytes(std::string_view s) {
|
void StreamBuffer::write_bytes(std::string_view s) {
|
||||||
make_space(s.size());
|
write_bytes(s.data(), s.size());
|
||||||
memcpy(write_cursor_, s.data(), s.size());
|
|
||||||
write_cursor_ += s.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char *StreamBuffer::read_bytes(int64_t bytes) {
|
const char *StreamBuffer::read_bytes(int64_t bytes) {
|
||||||
check_available(bytes);
|
check_available(bytes);
|
||||||
char *data = read_cursor_;
|
char *data = read_cursor_;
|
||||||
@@ -199,87 +163,12 @@ const char *StreamBuffer::read_bytes(int64_t bytes) {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamBuffer::write_int8(int64_t vv) {
|
void StreamBuffer::read_bytes_into(char *data, int64_t size) {
|
||||||
assert(safe_to_cast_to_int8(vv));
|
check_available(size);
|
||||||
int8_t v = vv;
|
memcpy(data, read_cursor_, size);
|
||||||
make_space(1);
|
read_cursor_ += size;
|
||||||
memcpy(write_cursor_, &v, 1);
|
|
||||||
write_cursor_ += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamBuffer::write_int16(int64_t vv) {
|
|
||||||
assert(safe_to_cast_to_int16(vv));
|
|
||||||
int16_t v = vv;
|
|
||||||
make_space(2);
|
|
||||||
memcpy(write_cursor_, &v, 2);
|
|
||||||
write_cursor_ += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamBuffer::write_int32(int64_t vv) {
|
|
||||||
assert(safe_to_cast_to_int32(vv));
|
|
||||||
int32_t v = vv;
|
|
||||||
make_space(4);
|
|
||||||
memcpy(write_cursor_, &v, 4);
|
|
||||||
write_cursor_ += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamBuffer::write_int64(int64_t vv) {
|
|
||||||
assert(safe_to_cast_to_int64(vv));
|
|
||||||
int64_t v = vv;
|
|
||||||
make_space(8);
|
|
||||||
memcpy(write_cursor_, &v, 8);
|
|
||||||
write_cursor_ += 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamBuffer::write_uint8(uint64_t vv) {
|
|
||||||
assert(safe_to_cast_to_uint8(vv));
|
|
||||||
uint8_t v = vv;
|
|
||||||
make_space(1);
|
|
||||||
memcpy(write_cursor_, &v, 1);
|
|
||||||
write_cursor_ += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamBuffer::write_uint16(uint64_t vv) {
|
|
||||||
assert(safe_to_cast_to_uint16(vv));
|
|
||||||
uint16_t v = vv;
|
|
||||||
make_space(2);
|
|
||||||
memcpy(write_cursor_, &v, 2);
|
|
||||||
write_cursor_ += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamBuffer::write_uint32(uint64_t vv) {
|
|
||||||
assert(safe_to_cast_to_uint32(vv));
|
|
||||||
uint32_t v = vv;
|
|
||||||
make_space(4);
|
|
||||||
memcpy(write_cursor_, &v, 4);
|
|
||||||
write_cursor_ += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamBuffer::write_uint64(uint64_t vv) {
|
|
||||||
assert(safe_to_cast_to_uint64(vv));
|
|
||||||
uint64_t v = vv;
|
|
||||||
make_space(8);
|
|
||||||
memcpy(write_cursor_, &v, 8);
|
|
||||||
write_cursor_ += 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamBuffer::write_char(char c) {
|
|
||||||
make_space(1);
|
|
||||||
write_cursor_[0] = c;
|
|
||||||
write_cursor_ += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamBuffer::write_float(float f) {
|
|
||||||
make_space(4);
|
|
||||||
memcpy(write_cursor_, &f, 4);
|
|
||||||
write_cursor_ += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamBuffer::write_double(double d) {
|
|
||||||
make_space(8);
|
|
||||||
memcpy(write_cursor_, &d, 8);
|
|
||||||
write_cursor_ += 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamBuffer::write_xyz(const util::XYZ &xyz) {
|
void StreamBuffer::write_xyz(const util::XYZ &xyz) {
|
||||||
make_space(12);
|
make_space(12);
|
||||||
@@ -301,61 +190,6 @@ void StreamBuffer::write_dxyz(const util::DXYZ &xyz) {
|
|||||||
write_cursor_ += 8;
|
write_cursor_ += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
int8_t StreamBuffer::read_int8() {
|
|
||||||
check_available(1);
|
|
||||||
int8_t v;
|
|
||||||
memcpy(&v, read_cursor_, 1);
|
|
||||||
read_cursor_ += 1;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
int16_t StreamBuffer::read_int16() {
|
|
||||||
check_available(2);
|
|
||||||
int16_t v;
|
|
||||||
memcpy(&v, read_cursor_, 2);
|
|
||||||
read_cursor_ += 2;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t StreamBuffer::read_int32() {
|
|
||||||
check_available(4);
|
|
||||||
int32_t v;
|
|
||||||
memcpy(&v, read_cursor_, 4);
|
|
||||||
read_cursor_ += 4;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t StreamBuffer::read_int64() {
|
|
||||||
check_available(8);
|
|
||||||
int64_t v;
|
|
||||||
memcpy(&v, read_cursor_, 8);
|
|
||||||
read_cursor_ += 8;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
char StreamBuffer::read_char() {
|
|
||||||
check_available(1);
|
|
||||||
char c = read_cursor_[0];
|
|
||||||
read_cursor_ += 1;
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
float StreamBuffer::read_float() {
|
|
||||||
check_available(4);
|
|
||||||
float f;
|
|
||||||
memcpy(&f, read_cursor_, 4);
|
|
||||||
read_cursor_ += 4;
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
double StreamBuffer::read_double() {
|
|
||||||
check_available(8);
|
|
||||||
double d;
|
|
||||||
memcpy(&d, read_cursor_, 8);
|
|
||||||
read_cursor_ += 8;
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
util::XYZ StreamBuffer::read_xyz() {
|
util::XYZ StreamBuffer::read_xyz() {
|
||||||
check_available(12);
|
check_available(12);
|
||||||
util::XYZ result;
|
util::XYZ result;
|
||||||
@@ -380,45 +214,17 @@ util::DXYZ StreamBuffer::read_dxyz() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void StreamBuffer::write_hashvalue(const util::HashValue &hv) {
|
void StreamBuffer::write_hashvalue(const util::HashValue &hv) {
|
||||||
write_uint64(hv.first);
|
write_uint64(hv.first);
|
||||||
write_uint64(hv.second);
|
write_uint64(hv.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamBuffer::write_string(std::string_view s) {
|
|
||||||
if (s.size() >= 255) {
|
|
||||||
write_uint8(0xFF);
|
|
||||||
write_uint64(s.size());
|
|
||||||
write_bytes(s);
|
|
||||||
} else {
|
|
||||||
write_uint8(s.size());
|
|
||||||
write_bytes(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
util::HashValue StreamBuffer::read_hashvalue() {
|
util::HashValue StreamBuffer::read_hashvalue() {
|
||||||
uint64_t f = read_uint64();
|
uint64_t f = read_uint64();
|
||||||
uint64_t s = read_uint64();
|
uint64_t s = read_uint64();
|
||||||
return util::HashValue(f,s);
|
return util::HashValue(f,s);
|
||||||
}
|
}
|
||||||
|
|
||||||
eng::string StreamBuffer::read_string() {
|
|
||||||
return read_string_limit(0xFFFFFFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
eng::string StreamBuffer::read_string_limit(int64_t max_allowed) {
|
|
||||||
int64_t len = read_uint8();
|
|
||||||
if (len == 255) {
|
|
||||||
len = read_int64();
|
|
||||||
}
|
|
||||||
if (len < 0) throw StreamCorruption();
|
|
||||||
if (len > max_allowed) throw StreamCorruption();
|
|
||||||
const char *bytes = read_bytes(len);
|
|
||||||
return eng::string(bytes, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
eng::string StreamBuffer::read_entire_contents() {
|
eng::string StreamBuffer::read_entire_contents() {
|
||||||
eng::string result(read_cursor_, fill());
|
eng::string result(read_cursor_, fill());
|
||||||
read_cursor_ = write_cursor_;
|
read_cursor_ = write_cursor_;
|
||||||
@@ -426,57 +232,57 @@ eng::string StreamBuffer::read_entire_contents() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void StreamBuffer::overwrite_int8(int64_t write_count_after, int64_t vv) {
|
void StreamBuffer::overwrite_int8(int64_t write_count_after, int64_t vv) {
|
||||||
assert(safe_to_cast_to_int8(vv));
|
|
||||||
int8_t v = vv;
|
int8_t v = vv;
|
||||||
|
assert(int64_t(v) == vv);
|
||||||
char *target = get_overwrite(1, write_count_after);
|
char *target = get_overwrite(1, write_count_after);
|
||||||
memcpy(target, &v, 1);
|
memcpy(target, &v, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamBuffer::overwrite_int16(int64_t write_count_after, int64_t vv) {
|
void StreamBuffer::overwrite_int16(int64_t write_count_after, int64_t vv) {
|
||||||
assert(safe_to_cast_to_int16(vv));
|
|
||||||
int16_t v = vv;
|
int16_t v = vv;
|
||||||
|
assert(int64_t(v) == vv);
|
||||||
char *target = get_overwrite(2, write_count_after);
|
char *target = get_overwrite(2, write_count_after);
|
||||||
memcpy(target, &v, 2);
|
memcpy(target, &v, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamBuffer::overwrite_int32(int64_t write_count_after, int64_t vv) {
|
void StreamBuffer::overwrite_int32(int64_t write_count_after, int64_t vv) {
|
||||||
assert(safe_to_cast_to_int32(vv));
|
|
||||||
int32_t v = vv;
|
int32_t v = vv;
|
||||||
|
assert(int64_t(v) == vv);
|
||||||
char *target = get_overwrite(4, write_count_after);
|
char *target = get_overwrite(4, write_count_after);
|
||||||
memcpy(target, &v, 4);
|
memcpy(target, &v, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamBuffer::overwrite_int64(int64_t write_count_after, int64_t vv) {
|
void StreamBuffer::overwrite_int64(int64_t write_count_after, int64_t vv) {
|
||||||
assert(safe_to_cast_to_int64(vv));
|
|
||||||
int64_t v = vv;
|
int64_t v = vv;
|
||||||
|
assert(int64_t(v) == vv);
|
||||||
char *target = get_overwrite(8, write_count_after);
|
char *target = get_overwrite(8, write_count_after);
|
||||||
memcpy(target, &v, 8);
|
memcpy(target, &v, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamBuffer::overwrite_uint8(int64_t write_count_after, uint64_t vv) {
|
void StreamBuffer::overwrite_uint8(int64_t write_count_after, uint64_t vv) {
|
||||||
assert(safe_to_cast_to_uint8(vv));
|
|
||||||
uint8_t v = vv;
|
uint8_t v = vv;
|
||||||
|
assert(uint64_t(v) == vv);
|
||||||
char *target = get_overwrite(1, write_count_after);
|
char *target = get_overwrite(1, write_count_after);
|
||||||
memcpy(target, &v, 1);
|
memcpy(target, &v, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamBuffer::overwrite_uint16(int64_t write_count_after, uint64_t vv) {
|
void StreamBuffer::overwrite_uint16(int64_t write_count_after, uint64_t vv) {
|
||||||
assert(safe_to_cast_to_uint16(vv));
|
|
||||||
uint16_t v = vv;
|
uint16_t v = vv;
|
||||||
|
assert(uint64_t(v) == vv);
|
||||||
char *target = get_overwrite(2, write_count_after);
|
char *target = get_overwrite(2, write_count_after);
|
||||||
memcpy(target, &v, 2);
|
memcpy(target, &v, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamBuffer::overwrite_uint32(int64_t write_count_after, uint64_t vv) {
|
void StreamBuffer::overwrite_uint32(int64_t write_count_after, uint64_t vv) {
|
||||||
assert(safe_to_cast_to_uint32(vv));
|
|
||||||
uint32_t v = vv;
|
uint32_t v = vv;
|
||||||
|
assert(uint64_t(v) == vv);
|
||||||
char *target = get_overwrite(4, write_count_after);
|
char *target = get_overwrite(4, write_count_after);
|
||||||
memcpy(target, &v, 4);
|
memcpy(target, &v, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamBuffer::overwrite_uint64(int64_t write_count_after, uint64_t vv) {
|
void StreamBuffer::overwrite_uint64(int64_t write_count_after, uint64_t vv) {
|
||||||
assert(safe_to_cast_to_uint64(vv));
|
|
||||||
uint64_t v = vv;
|
uint64_t v = vv;
|
||||||
|
assert(uint64_t(v) == vv);
|
||||||
char *target = get_overwrite(8, write_count_after);
|
char *target = get_overwrite(8, write_count_after);
|
||||||
memcpy(target, &v, 8);
|
memcpy(target, &v, 8);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -219,6 +219,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "base-writer.hpp"
|
||||||
#include "luastack.hpp"
|
#include "luastack.hpp"
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
|
|
||||||
@@ -240,7 +241,7 @@ public:
|
|||||||
virtual char const *what() const { return "Stream contained invalid data"; }
|
virtual char const *what() const { return "Stream contained invalid data"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class StreamBuffer : public eng::nevernew {
|
class StreamBuffer : public eng::nevernew, public BaseReader<StreamBuffer, eng::string>, public BaseWriter<StreamBuffer> {
|
||||||
public:
|
public:
|
||||||
// Construct an empty buffer.
|
// Construct an empty buffer.
|
||||||
StreamBuffer();
|
StreamBuffer();
|
||||||
@@ -287,7 +288,11 @@ public:
|
|||||||
// It just writes the bytes.
|
// It just writes the bytes.
|
||||||
//
|
//
|
||||||
void write_bytes(const char *bytes, int64_t len);
|
void write_bytes(const char *bytes, int64_t len);
|
||||||
void write_bytes(std::string_view bytes);
|
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.
|
// Read a block of bytes from the buffer.
|
||||||
//
|
//
|
||||||
@@ -297,63 +302,19 @@ public:
|
|||||||
//
|
//
|
||||||
const char *read_bytes(int64_t bytes);
|
const char *read_bytes(int64_t bytes);
|
||||||
|
|
||||||
// Write integers and floats into the buffer.
|
// Read and write larger types.
|
||||||
//
|
|
||||||
// Note that integral parameters are all 64 bits. That's so that I can do
|
|
||||||
// runtime error checking to verify that the numbers are all in-range.
|
|
||||||
//
|
|
||||||
void write_int8(int64_t v);
|
|
||||||
void write_int16(int64_t v);
|
|
||||||
void write_int32(int64_t v);
|
|
||||||
void write_int64(int64_t v);
|
|
||||||
void write_uint8(uint64_t v);
|
|
||||||
void write_uint16(uint64_t v);
|
|
||||||
void write_uint32(uint64_t v);
|
|
||||||
void write_uint64(uint64_t v);
|
|
||||||
void write_char(char c);
|
|
||||||
void write_float(float f);
|
|
||||||
void write_double(double d);
|
|
||||||
void write_xyz(const util::XYZ &xyz);
|
|
||||||
void write_dxyz(const util::DXYZ &xyz);
|
|
||||||
|
|
||||||
// Read fixed-size integers from the buffer.
|
|
||||||
//
|
|
||||||
// May throw StreamEof if the specified number of bytes aren't present.
|
|
||||||
//
|
|
||||||
int8_t read_int8();
|
|
||||||
int16_t read_int16();
|
|
||||||
int32_t read_int32();
|
|
||||||
int64_t read_int64();
|
|
||||||
uint8_t read_uint8() { return read_int8(); }
|
|
||||||
uint16_t read_uint16() { return read_int16(); }
|
|
||||||
uint32_t read_uint32() { return read_int32(); }
|
|
||||||
uint64_t read_uint64() { return read_int64(); }
|
|
||||||
char read_char();
|
|
||||||
float read_float();
|
|
||||||
double read_double();
|
|
||||||
util::XYZ read_xyz();
|
|
||||||
util::DXYZ read_dxyz();
|
|
||||||
|
|
||||||
// Write other types into the buffer.
|
|
||||||
//
|
|
||||||
// Note that strings are preceded by a length field. Reading
|
|
||||||
// a string works by reading the length field, and then reading
|
|
||||||
// the correct number of bytes.
|
|
||||||
//
|
|
||||||
void write_bool(bool b) { write_int8(b ? 1 : 0); }
|
|
||||||
void write_hashvalue(const util::HashValue &hv);
|
|
||||||
void write_string(std::string_view s);
|
|
||||||
|
|
||||||
// Read other types from the buffer.
|
|
||||||
//
|
//
|
||||||
// Throws StreamEof if the specified number of bytes aren't present.
|
// Throws StreamEof if the specified number of bytes aren't present.
|
||||||
// Read string with a length limit will throw 'StreamCorruption' if the
|
// Read string with a length limit will throw 'StreamCorruption' if the
|
||||||
// length is too long.
|
// length is too long.
|
||||||
//
|
//
|
||||||
bool read_bool() { return read_int8(); }
|
void write_xyz(const util::XYZ &xyz);
|
||||||
|
void write_dxyz(const util::DXYZ &xyz);
|
||||||
|
util::XYZ read_xyz();
|
||||||
|
util::DXYZ read_dxyz();
|
||||||
|
|
||||||
|
void write_hashvalue(const util::HashValue &hv);
|
||||||
util::HashValue read_hashvalue();
|
util::HashValue read_hashvalue();
|
||||||
eng::string read_string();
|
|
||||||
eng::string read_string_limit(int64_t max_allowed);
|
|
||||||
|
|
||||||
// Read the entire contents of the buffer as a string.
|
// Read the entire contents of the buffer as a string.
|
||||||
//
|
//
|
||||||
@@ -415,6 +376,10 @@ public:
|
|||||||
// Get an ostream that writes into the StreamBuffer.
|
// Get an ostream that writes into the StreamBuffer.
|
||||||
std::ostream &ostream();
|
std::ostream &ostream();
|
||||||
|
|
||||||
|
// Throw a StreamCorruption exception.
|
||||||
|
void raise_truncated() { throw StreamCorruption(); }
|
||||||
|
void raise_string_too_long() { throw StreamCorruption(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Start and end of the allocated block.
|
// Start and end of the allocated block.
|
||||||
char *buf_lo_;
|
char *buf_lo_;
|
||||||
|
|||||||
Reference in New Issue
Block a user