\
friend PIBinaryStream & operator<<(PIBinaryStream
& s, const T & v); \
template \
friend PIBinaryStream & operator>>(PIBinaryStream
& s, T & v);
#define BINARY_STREAM_WRITE(T) \
template \
inline PIBinaryStream & operator<<(PIBinaryStream
& s, const T & v)
#define BINARY_STREAM_READ(T) \
template \
inline PIBinaryStream & operator>>(PIBinaryStream
& s, T & v)
//! \ingroup Serialization
//! \~\brief
//! \~english Binary serialization interface.
//! \~russian Интерфейс бинарной сериализации.
//! \~\details
//! \~english In your class you should implement this methods:
//! \~russian В производном классе вы должны реализовать следующие методы:
//! \~\code
//! bool binaryStreamAppendImp (const void * d, size_t s);
//! bool binaryStreamTakeImp (void * d, size_t s);
//! ssize_t binaryStreamSizeImp () const;
//! \endcode
//! \~english Function binaryStreamSizeImp should return -1 if size unknown.
//! \~russian Функция binaryStreamSizeImp должна возвращать -1 если нет информации о размере.
//! \~english See details \ref iostream.
//! \~russian Подробнее \ref iostream.
template
class PIBinaryStream {
public:
//! \~english Write data
//! \~russian Записать данные
bool binaryStreamAppend(const void * d, size_t s) {
if (!static_cast(this)->binaryStreamAppendImp(d, s)) {
return false;
fprintf(stderr, "[PIBinaryStream] binaryStreamAppend() error\n");
}
return true;
}
//! \~english Read data
//! \~russian Прочитать данные
bool binaryStreamTake(void * d, size_t s) {
if (!static_cast
(this)->binaryStreamTakeImp(d, s)) {
_was_read_error_ = true;
return false;
fprintf(stderr, "[PIBinaryStream] binaryStreamTake() error\n");
}
return true;
}
//! \~english Returns remain size
//! \~russian Возвращает оставшийся размер
//! \~\details
//! \~english Returns -1 if no information about size
//! \~russian Возвращает -1 если нет информации о размере
ssize_t binaryStreamSize() const { return static_cast(this)->binaryStreamSizeImp(); }
//! \~english Write data
//! \~russian Записать данные
template
void binaryStreamAppend(T v) {
binaryStreamAppend(&v, sizeof(v));
}
//! \~english Read int
//! \~russian Прочитать int
int binaryStreamTakeInt() {
int r = 0;
binaryStreamTake(&r, sizeof(r));
return r;
}
//! \~english Returns whether there has been an incomplete read since last \a resetReadError() or after the stream was created
//! \~russian Возвращает было ли неполное чтение с момента последнего вызова \a resetReadError() или создания потока
bool wasReadError() const { return _was_read_error_; }
//! \~english Reset incomplete read flag
//! \~russian Сбрасывает флаг неполного чтения
void resetReadError() { _was_read_error_ = false; }
private:
bool _was_read_error_ = false;
};
// helper class to detect default operators
template
class PIBinaryStreamTrivialRef {
public:
PIBinaryStreamTrivialRef(PIBinaryStream & s): p(s) {}
PIBinaryStream
& p;
};
template
inline PIBinaryStream & operator<<(PIBinaryStreamTrivialRef
s, const T & v) {
s.p << v;
return s.p;
}
template
inline PIBinaryStream & operator>>(PIBinaryStreamTrivialRef
s, T & v) {
s.p >> v;
return s.p;
}
template
inline PIBinaryStream & operator<<(PIBinaryStreamTrivialRef
s, const PIMemoryBlock v) {
s.p << v;
return s.p;
}
template
inline PIBinaryStream & operator>>(PIBinaryStreamTrivialRef
s, PIMemoryBlock v) {
s.p >> v;
return s.p;
}
// specify types
template
inline PIBinaryStream & operator<<(PIBinaryStream
& s, const bool v) {
s.binaryStreamAppend((uchar)v);
return s;
}
template
inline PIBinaryStream & operator>>(PIBinaryStream
& s, bool & v) {
uchar c;
s.binaryStreamTake(&c, sizeof(c));
v = c;
return s;
}
template
inline PIBinaryStream & operator<<(PIBinaryStream
& s, const PIMemoryBlock v) {
s.binaryStreamAppend(v.data(), v.size());
return s;
}
template
inline PIBinaryStream & operator>>(PIBinaryStream
& s, PIMemoryBlock v) {
s.binaryStreamTake(v.data(), v.size());
return s;
}
// store simple types
template::value, int>::type = 0>
inline PIBinaryStream & operator<<(PIBinaryStream
& s, const T & v) {
// piCout << "<< enum";
s.binaryStreamAppend((int)v);
return s;
}
template::value, int>::type = 0,
typename std::enable_if::value, int>::type = 0>
inline PIBinaryStreamTrivialRef operator<<(PIBinaryStream
& s, const T & v) {
s.binaryStreamAppend(&v, sizeof(v));
return s;
}
//! \~english Store operator for PIVector of any trivial copyable type
//! \~russian Оператор сохранения для PIVector тривиальных типов
template::value, int>::type = 0,
typename std::enable_if<
std::is_same &>() << std::declval()), PIBinaryStreamTrivialRef>::value,
int>::type = 0>
inline PIBinaryStream
& operator<<(PIBinaryStream
& s, const PIVector & v) {
// piCout << "<< vector trivial default";
s.binaryStreamAppend((int)v.size());
s.binaryStreamAppend(v.data(), v.size() * sizeof(T));
return s;
}
template::value, int>::type = 0,
typename std::enable_if<
!std::is_same &>() << std::declval()), PIBinaryStreamTrivialRef>::value,
int>::type = 0>
inline PIBinaryStream
& operator<<(PIBinaryStream
& s, const PIVector & v) {
// piCout << "<< vector trivial custom";
s.binaryStreamAppend((int)v.size());
for (size_t i = 0; i < v.size(); ++i)
s << v[i];
return s;
}
//! \~english Store operator for PIDeque of any trivial copyable type
//! \~russian Оператор сохранения для PIDeque тривиальных типов
template::value, int>::type = 0,
typename std::enable_if<
std::is_same &>() << std::declval()), PIBinaryStreamTrivialRef>::value,
int>::type = 0>
inline PIBinaryStream
& operator<<(PIBinaryStream
& s, const PIDeque & v) {
// piCout << "<< deque trivial default";
s.binaryStreamAppend((int)v.size());
s.binaryStreamAppend(v.data(), v.size() * sizeof(T));
return s;
}
template::value, int>::type = 0,
typename std::enable_if<
!std::is_same &>() << std::declval()), PIBinaryStreamTrivialRef>::value,
int>::type = 0>
inline PIBinaryStream
& operator<<(PIBinaryStream
& s, const PIDeque & v) {
// piCout << "<< deque trivial custom";
s.binaryStreamAppend((int)v.size());
for (size_t i = 0; i < v.size(); ++i)
s << v[i];
return s;
}
//! \~english Store operator for PIVector2D of any trivial copyable type
//! \~russian Оператор сохранения для PIVector2D тривиальных типов
template::value, int>::type = 0,
typename std::enable_if<
std::is_same &>() << std::declval()), PIBinaryStreamTrivialRef>::value,
int>::type = 0>
inline PIBinaryStream
& operator<<(PIBinaryStream
& s, const PIVector2D & v) {
// piCout << "<< vector2d trivial default";
s.binaryStreamAppend((int)v.rows());
s.binaryStreamAppend((int)v.cols());
s.binaryStreamAppend(v.data(), v.size() * sizeof(T));
return s;
}
template::value, int>::type = 0,
typename std::enable_if<
!std::is_same &>() << std::declval()), PIBinaryStreamTrivialRef>::value,
int>::type = 0>
inline PIBinaryStream
& operator<<(PIBinaryStream
& s, const PIVector2D & v) {
// piCout << "<< vector2d trivial custom";
s.binaryStreamAppend((int)v.rows());
s.binaryStreamAppend((int)v.cols());
s << v.toPlainVector();
return s;
}
//! \~english Store operator
//! \~russian Оператор сохранения
template
inline PIBinaryStream & operator<<(PIBinaryStream
& s, const PIBitArray & v) {
s << v.size_ << v.data_;
return s;
}
//! \~english Store operator
//! \~russian Оператор сохранения
template
inline PIBinaryStream & operator<<(PIBinaryStream
& s, const PIPair & v) {
s << v.first << v.second;
return s;
}
// restore simple types
template::value, int>::type = 0>
inline PIBinaryStream & operator>>(PIBinaryStream
& s, T & v) {
// piCout << ">> enum";
v = (T)s.binaryStreamTakeInt();
return s;
}
template::value, int>::type = 0,
typename std::enable_if::value, int>::type = 0>
inline PIBinaryStreamTrivialRef operator>>(PIBinaryStream
& s, T & v) {
if (!s.binaryStreamTake(&v, sizeof(v))) {
fprintf(stderr, "error with %s\n", __PIP_TYPENAME__(T));
}
return s;
}
//! \~english Restore operator for PIVector of any trivial copyable type
//! \~russian Оператор извлечения для PIVector тривиальных типов
template::value, int>::type = 0,
typename std::enable_if<
std::is_same &>() >> std::declval()), PIBinaryStreamTrivialRef>::value,
int>::type = 0>
inline PIBinaryStream
& operator>>(PIBinaryStream
& s, PIVector & v) {
// piCout << ">> vector trivial default";
int sz = s.binaryStreamTakeInt();
if (s.wasReadError()) {
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
v._resizeRaw(sz);
if (!s.binaryStreamTake(v.data(), sz * sizeof(T))) {
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
v.clear();
}
return s;
}
template::value, int>::type = 0,
typename std::enable_if<
!std::is_same &>() >> std::declval()), PIBinaryStreamTrivialRef>::value,
int>::type = 0>
inline PIBinaryStream
& operator>>(PIBinaryStream
& s, PIVector & v) {
// piCout << ">> vector trivial custom";
int sz = s.binaryStreamTakeInt();
if (s.wasReadError()) {
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
v._resizeRaw(sz);
for (int i = 0; i < sz; ++i) {
s >> v[i];
if (s.wasReadError()) {
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
}
return s;
}
//! \~english Restore operator for PIDeque of any trivial copyable type
//! \~russian Оператор извлечения для PIDeque тривиальных типов
template::value, int>::type = 0,
typename std::enable_if<
std::is_same &>() >> std::declval()), PIBinaryStreamTrivialRef>::value,
int>::type = 0>
inline PIBinaryStream
& operator>>(PIBinaryStream
& s, PIDeque & v) {
// piCout << ">> deque trivial default";
int sz = s.binaryStreamTakeInt();
if (s.wasReadError()) {
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
v._resizeRaw(sz);
if (!s.binaryStreamTake(v.data(), sz * sizeof(T))) {
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
v.clear();
}
return s;
}
template::value, int>::type = 0,
typename std::enable_if<
!std::is_same &>() >> std::declval()), PIBinaryStreamTrivialRef>::value,
int>::type = 0>
inline PIBinaryStream
& operator>>(PIBinaryStream
& s, PIDeque & v) {
// piCout << ">> deque trivial custom";
int sz = s.binaryStreamTakeInt();
if (s.wasReadError()) {
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
v._resizeRaw(sz);
for (int i = 0; i < sz; ++i) {
s >> v[i];
if (s.wasReadError()) {
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
}
return s;
}
//! \~english Restore operator for PIVector2D of any trivial copyable type
//! \~russian Оператор извлечения для PIVector2D тривиальных типов
template::value, int>::type = 0,
typename std::enable_if<
std::is_same &>() >> std::declval()), PIBinaryStreamTrivialRef>::value,
int>::type = 0>
inline PIBinaryStream
& operator>>(PIBinaryStream
& s, PIVector2D & v) {
// piCout << ">> vector2d trivial default";
int r, c;
r = s.binaryStreamTakeInt();
c = s.binaryStreamTakeInt();
if (s.wasReadError()) {
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
v._resizeRaw(r, c);
if (!s.binaryStreamTake(v.data(), v.size() * sizeof(T))) {
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
v.clear();
}
return s;
}
template::value, int>::type = 0,
typename std::enable_if<
!std::is_same &>() >> std::declval()), PIBinaryStreamTrivialRef>::value,
int>::type = 0>
inline PIBinaryStream
& operator>>(PIBinaryStream
& s, PIVector2D & v) {
// piCout << ">> vector2d trivial custom";
int r, c;
PIVector tmp;
r = s.binaryStreamTakeInt();
c = s.binaryStreamTakeInt();
s >> tmp;
if (s.wasReadError()) {
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
v = PIVector2D(r, c, tmp);
return s;
}
//! \~english Restore operator
//! \~russian Оператор извлечения
template
inline PIBinaryStream & operator>>(PIBinaryStream
& s, PIBitArray & v) {
s >> v.size_ >> v.data_;
return s;
}
//! \~english Restore operator
//! \~russian Оператор извлечения
template
inline PIBinaryStream & operator>>(PIBinaryStream
& s, PIPair & v) {
s >> v.first >> v.second;
return s;
}
// store complex types
//! \~english Store operator for PIVector of any compound type
//! \~russian Оператор сохранения для PIVector сложных типов
template::value, int>::type = 0>
inline PIBinaryStream & operator<<(PIBinaryStream
& s, const PIVector & v) {
// piCout << "<< vector complex";
s.binaryStreamAppend(int(v.size_s()));
for (size_t i = 0; i < v.size(); ++i)
s << v[i];
return s;
}
//! \~english Store operator for PIDeque of any compound type
//! \~russian Оператор сохранения для PIDeque сложных типов
template::value, int>::type = 0>
inline PIBinaryStream & operator<<(PIBinaryStream
& s, const PIDeque & v) {
// piCout << "<< deque complex";
s.binaryStreamAppend(int(v.size_s()));
for (size_t i = 0; i < v.size(); ++i)
s << v[i];
return s;
}
//! \~english Store operator for PIVector2D of any compound type
//! \~russian Оператор сохранения для PIVector2D сложных типов
template::value, int>::type = 0>
inline PIBinaryStream & operator<<(PIBinaryStream
& s, const PIVector2D & v) {
// piCout << "<< vector2d complex";
s.binaryStreamAppend(int(v.rows()));
s.binaryStreamAppend(int(v.cols()));
s << v.toPlainVector();
return s;
}
// restore complex types
//! \~english Restore operator for PIVector of any compound type
//! \~russian Оператор извлечения для PIVector сложных типов
template::value, int>::type = 0>
inline PIBinaryStream & operator>>(PIBinaryStream
& s, PIVector & v) {
int sz = s.binaryStreamTakeInt();
if (s.wasReadError()) {
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
v.resize(sz);
for (size_t i = 0; i < v.size(); ++i) {
s >> v[i];
if (s.wasReadError()) {
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
}
return s;
}
//! \~english Restore operator for PIDeque of any compound type
//! \~russian Оператор извлечения для PIDeque сложных типов
template::value, int>::type = 0>
inline PIBinaryStream & operator>>(PIBinaryStream
& s, PIDeque & v) {
int sz = s.binaryStreamTakeInt();
if (s.wasReadError()) {
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
v.resize(sz);
for (size_t i = 0; i < v.size(); ++i) {
s >> v[i];
if (s.wasReadError()) {
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
}
return s;
}
//! \~english Restore operator for PIVector2D of any compound type
//! \~russian Оператор извлечения для PIVector2D сложных типов
template::value, int>::type = 0>
inline PIBinaryStream & operator>>(PIBinaryStream
& s, PIVector2D & v) {
int r, c;
PIVector tmp;
r = s.binaryStreamTakeInt();
c = s.binaryStreamTakeInt();
s >> tmp;
if (s.wasReadError()) {
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
v = PIVector2D(r, c, tmp);
return s;
}
// other types
//! \~english Store operator
//! \~russian Оператор сохранения
template
inline PIBinaryStream & operator<<(PIBinaryStream
& s, const PIMap & v) {
s.binaryStreamAppend((int)v.pim_index.size_s());
for (uint i = 0; i < v.size(); ++i) {
s.binaryStreamAppend((int)v.pim_index[i].index);
s << v.pim_index[i].key;
}
s << v.pim_content;
return s;
}
//! \~english Restore operator
//! \~russian Оператор извлечения
template
inline PIBinaryStream & operator>>(PIBinaryStream
& s, PIMap & v) {
int sz = s.binaryStreamTakeInt();
if (s.wasReadError()) {
fprintf(stderr, "error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
v.clear();
return s;
}
v.pim_index.resize(sz);
int ind = 0;
for (int i = 0; i < sz; ++i) {
ind = s.binaryStreamTakeInt();
s >> v.pim_index[i].key;
if (s.wasReadError()) {
fprintf(stderr, "error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
v.clear();
return s;
}
v.pim_index[i].index = ind;
}
s >> v.pim_content;
if (s.wasReadError()) {
fprintf(stderr, "error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
v.clear();
return s;
}
if (v.pim_content.size_s() != v.pim_index.size_s()) {
piCout << "Warning: loaded invalid PIMap, clear";
v.clear();
}
return s;
}
// non-defined complex types
template::value, int>::type = 0>
inline PIBinaryStream & operator<<(PIBinaryStream
& s, const T &) {
static_assert(std::is_trivially_copyable::value, "[PIBinaryStream] Error: using undeclared operator << for complex type!");
return s;
}
template::value, int>::type = 0>
inline PIBinaryStream & operator>>(PIBinaryStream
& s, T &) {
static_assert(std::is_trivially_copyable::value, "[PIBinaryStream] Error: using undeclared operator >> for complex type!");
return s;
}
#endif