12#ifndef _RD_STREAMOPS_H
13#define _RD_STREAMOPS_H
20#include <unordered_set>
21#include <boost/cstdint.hpp>
22#include <boost/predef.h>
30#if defined(BOOST_ENDIAN_LITTLE_BYTE) || defined(BOOST_ENDIAN_LITTLE_WORD)
32#elif defined(BOOST_ENDIAN_BIG_BYTE)
34#elif defined(BOOST_ENDIAN_BIG_WORD)
35#error "Cannot compile on word-swapped big-endian systems"
37#error "Failed to determine the system endian value"
43template <
class T,
unsigned int size>
56 for (
unsigned int i = 0; i < size; ++i) {
57 out.bytes[i] = in.bytes[size - 1 - i];
71template <EEndian from, EEndian to,
class T>
74 BOOST_STATIC_ASSERT(
sizeof(T) == 1 ||
sizeof(T) == 2 ||
sizeof(T) == 4 ||
91template <EEndian from, EEndian to>
96template <EEndian from, EEndian to>
101template <EEndian from, EEndian to>
110 boost::uint32_t num) {
112 unsigned int val, res;
117 if (res < (1 << 7)) {
123 if (res < (1 << 14)) {
124 val = ((res << 2) | 1);
129 if (res < (1 << 21)) {
130 val = ((res << 3) | 3);
135 if (res < (1 << 29)) {
136 val = ((res << 3) | 7);
145 for (bix = 0; bix < nbytes; bix++) {
146 tc = (char)(val & 255);
154 boost::uint32_t val, num;
157 ss.read(&tmp,
sizeof(tmp));
159 throw std::runtime_error(
"failed to read from stream");
164 if ((val & 1) == 0) {
166 }
else if ((val & 3) == 1) {
167 ss.read((
char *)&tmp,
sizeof(tmp));
169 throw std::runtime_error(
"failed to read from stream");
172 val |= (
UCHAR(tmp) << 8);
175 }
else if ((val & 7) == 3) {
176 ss.read((
char *)&tmp,
sizeof(tmp));
178 throw std::runtime_error(
"failed to read from stream");
181 val |= (
UCHAR(tmp) << 8);
182 ss.read((
char *)&tmp,
sizeof(tmp));
184 throw std::runtime_error(
"failed to read from stream");
187 val |= (
UCHAR(tmp) << 16);
189 offset = (1 << 7) + (1 << 14);
191 ss.read((
char *)&tmp,
sizeof(tmp));
193 throw std::runtime_error(
"failed to read from stream");
196 val |= (
UCHAR(tmp) << 8);
197 ss.read((
char *)&tmp,
sizeof(tmp));
199 throw std::runtime_error(
"failed to read from stream");
202 val |= (
UCHAR(tmp) << 16);
203 ss.read((
char *)&tmp,
sizeof(tmp));
205 throw std::runtime_error(
"failed to read from stream");
208 val |= (
UCHAR(tmp) << 24);
210 offset = (1 << 7) + (1 << 14) + (1 << 21);
212 num = (val >> shift) + offset;
220 boost::uint32_t val, num;
227 if ((val & 1) == 0) {
229 }
else if ((val & 3) == 1) {
232 val |= (
UCHAR(tmp) << 8);
235 }
else if ((val & 7) == 3) {
238 val |= (
UCHAR(tmp) << 8);
241 val |= (
UCHAR(tmp) << 16);
243 offset = (1 << 7) + (1 << 14);
247 val |= (
UCHAR(tmp) << 8);
250 val |= (
UCHAR(tmp) << 16);
253 val |= (
UCHAR(tmp) << 24);
255 offset = (1 << 7) + (1 << 14) + (1 << 21);
257 num = (val >> shift) + offset;
266 ss.write((
const char *)&tval,
sizeof(T));
270inline void streamWrite(std::ostream &ss,
const std::string &what) {
271 unsigned int l =
static_cast<unsigned int>(what.length());
273 ss.write(what.c_str(),
sizeof(
char) * l);
278 streamWrite(ss,
static_cast<boost::uint64_t
>(val.size()));
279 for (
size_t i = 0; i < val.size(); ++i) {
288 ss.read((
char *)&tloc,
sizeof(T));
290 throw std::runtime_error(
"failed to read from stream");
302inline void streamRead(std::istream &ss, std::string &what,
int version) {
306 auto buff = std::make_unique<char[]>(l);
307 ss.read(buff.get(),
sizeof(
char) * l);
309 throw std::runtime_error(
"failed to read from stream");
311 what = std::string(buff.get(), l);
316 boost::uint64_t size;
318 val.resize(boost::numeric_cast<size_t>(size));
320 for (
size_t i = 0; i < size; ++i) {
327 boost::uint64_t size;
331 for (
size_t i = 0; i < size; ++i) {
337inline std::string
getLine(std::istream *inStream) {
339 std::getline(*inStream, res);
340 if (!res.empty() && (res.back() ==
'\r')) {
341 res.resize(res.length() - 1);
347inline std::string
getLine(std::istream &inStream) {
386typedef std::vector<std::shared_ptr<const CustomPropHandler>>
406 for (
auto &handler : handlers) {
407 if (handler->canSerialize(pair.
val)) {
424 switch (pair.val.getTag()) {
471 for (
auto &handler : handlers) {
472 if (handler->canSerialize(pair.val)) {
478 streamWrite(ss, std::string(handler->getPropName()));
479 handler->write(ss, pair.val);
489template <
typename COUNT_TYPE =
unsigned int>
491 std::ostream &ss,
const RDProps &props,
bool savePrivate =
false,
493 const std::unordered_set<std::string> &ignore = {}) {
495 std::unordered_set<std::string> propnames;
496 for (
const auto &pn : propsToSave) {
497 if (ignore.empty() || ignore.find(pn) == ignore.end()) {
498 propnames.insert(pn);
503 COUNT_TYPE count = 0;
504 for (
const auto &elem : dict.getData()) {
505 if (propnames.find(elem.key) != propnames.end()) {
516 COUNT_TYPE writtenCount = 0;
517 for (
const auto &elem : dict.getData()) {
518 if (propnames.find(elem.key) != propnames.end()) {
529 "Estimated property count not equal to written");
555 std::vector<std::string> v;
588 dictHasNonPOD =
true;
592 dictHasNonPOD =
true;
596 dictHasNonPOD =
true;
600 dictHasNonPOD =
true;
604 dictHasNonPOD =
true;
608 dictHasNonPOD =
true;
611 std::string propType;
614 for (
auto &handler : handlers) {
615 if (propType == handler->getPropName()) {
616 handler->read(ss, pair.
val);
617 dictHasNonPOD =
true;
630template <
typename COUNT_TYPE =
unsigned int>
641 auto startSz = dict.
getData().size();
642 dict.getData().resize(startSz + count);
643 for (
unsigned index = 0; index < count; ++index) {
645 dict.getNonPODStatus(), handlers),
646 "Corrupted property serialization detected");
649 return static_cast<unsigned int>(count);
#define CHECK_INVARIANT(expr, mess)
#define POSTCONDITION(expr, mess)
#define RDUNUSED_PARAM(x)
virtual bool read(std::istream &ss, RDValue &value) const =0
virtual bool write(std::ostream &ss, const RDValue &value) const =0
virtual const char * getPropName() const =0
virtual CustomPropHandler * clone() const =0
virtual ~CustomPropHandler()
virtual bool canSerialize(const RDValue &value) const =0
The Dict class can be used to store objects of arbitrary type keyed by strings.
const DataType & getData() const
Access to the underlying data.
const Dict & getDict() const
gets the underlying Dictionary
STR_VECT getPropList(bool includePrivate=true, bool includeComputed=true) const
returns a list with the names of our properties
static const boost::uint64_t UnsignedIntTag
static const boost::uint64_t StringTag
static const boost::uint64_t VecStringTag
static const boost::uint64_t VecIntTag
static const boost::uint64_t FloatTag
static const boost::uint64_t VecUnsignedIntTag
static const boost::uint64_t DoubleTag
static const boost::uint64_t IntTag
static const boost::uint64_t AnyTag
static const boost::uint64_t VecFloatTag
static const boost::uint64_t VecDoubleTag
static const boost::uint64_t BoolTag
std::vector< std::string > STR_VECT
boost::uint32_t pullPackedIntFromString(const char *&text)
void readRDStringVecValue(std::istream &ss, RDValue &value)
void streamRead(std::istream &ss, T &loc)
does a binary read of an object from a stream
std::string getLine(std::istream *inStream)
grabs the next line from an instream and returns it.
void readRDValueString(std::istream &ss, RDValue &value)
boost::uint32_t readPackedIntFromStream(std::stringstream &ss)
Reads an integer from a stream in packed format and returns the result.
bool isSerializable(const Dict::Pair &pair, const CustomPropHandlerVec &handlers={})
void streamReadStringVec(std::istream &ss, std::vector< std::string > &val, int version)
void readRDVecValue(std::istream &ss, RDValue &value)
void streamWriteVec(std::ostream &ss, const T &val)
T rdvalue_cast(RDValue_cast_t v)
void streamReadVec(std::istream &ss, T &val)
void readRDValue(std::istream &ss, RDValue &value)
T EndianSwapBytes(T value)
bool streamWriteProps(std::ostream &ss, const RDProps &props, bool savePrivate=false, bool saveComputed=false, const CustomPropHandlerVec &handlers={}, const std::unordered_set< std::string > &ignore={})
bool streamReadProp(std::istream &ss, Dict::Pair &pair, bool &dictHasNonPOD, const CustomPropHandlerVec &handlers={})
bool streamWriteProp(std::ostream &ss, const Dict::Pair &pair, const CustomPropHandlerVec &handlers={})
void streamWrite(std::ostream &ss, const T &val)
does a binary write of an object to a stream
void appendPackedIntToStream(std::stringstream &ss, boost::uint32_t num)
Packs an integer and outputs it to a stream.
std::vector< std::shared_ptr< const CustomPropHandler > > CustomPropHandlerVec
unsigned int streamReadProps(std::istream &ss, RDProps &props, const CustomPropHandlerVec &handlers={}, bool reset=true)
boost::uint64_t getTag() const