* renamed private members for more clear code * registerExternalBufferID() method to obtain unique ID for withExternalBuffer() * PICoutManipulators::PICoutStdStream enum for select stream (stdout or stderr) * Constructors now accept optional stream * piCerr and piCerrObj macros PIDir::temporary() moved to "mkdtemp" PILog: * now 4 levels * you can set max level * Error writes to piCerr
675 lines
22 KiB
C++
675 lines
22 KiB
C++
/*! \file pibinarystream.h
|
||
* \ingroup Serialization
|
||
* \~\brief
|
||
* \~english Binary serialization interface
|
||
* \~russian Интерфейс бинарной сериализации
|
||
*/
|
||
/*
|
||
PIP - Platform Independent Primitives
|
||
Binary serialization interface
|
||
Ivan Pelipenko peri4ko@yandex.ru
|
||
|
||
This program is free software: you can redistribute it and/or modify
|
||
it under the terms of the GNU Lesser General Public License as published by
|
||
the Free Software Foundation, either version 3 of the License, or
|
||
(at your option) any later version.
|
||
|
||
This program is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
GNU Lesser General Public License for more details.
|
||
|
||
You should have received a copy of the GNU Lesser General Public License
|
||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
#ifndef PIBINARYSTREAM_H
|
||
#define PIBINARYSTREAM_H
|
||
|
||
#include "pibitarray.h"
|
||
#include "pimap.h"
|
||
#include "pimemoryblock.h"
|
||
#include "pivector2d.h"
|
||
|
||
#define PIP_BINARY_STREAM
|
||
|
||
#define BINARY_STREAM_FRIEND(T) \
|
||
template<typename P> \
|
||
friend PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const T & v); \
|
||
template<typename P> \
|
||
friend PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, T & v);
|
||
#define BINARY_STREAM_WRITE(T) \
|
||
template<typename P> \
|
||
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const T & v)
|
||
#define BINARY_STREAM_READ(T) \
|
||
template<typename P> \
|
||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & 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<typename P>
|
||
class PIBinaryStream {
|
||
public:
|
||
//! \~english Write data
|
||
//! \~russian Записать данные
|
||
bool binaryStreamAppend(const void * d, size_t s) {
|
||
if (!static_cast<P *>(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<P *>(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<const P *>(this)->binaryStreamSizeImp(); }
|
||
|
||
//! \~english Write data
|
||
//! \~russian Записать данные
|
||
template<typename T>
|
||
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<typename P>
|
||
class PIBinaryStreamTrivialRef {
|
||
public:
|
||
PIBinaryStreamTrivialRef(PIBinaryStream<P> & s): p(s) {}
|
||
PIBinaryStream<P> & p;
|
||
};
|
||
|
||
|
||
template<typename P, typename T>
|
||
inline PIBinaryStream<P> & operator<<(PIBinaryStreamTrivialRef<P> s, const T & v) {
|
||
s.p << v;
|
||
return s.p;
|
||
}
|
||
template<typename P, typename T>
|
||
inline PIBinaryStream<P> & operator>>(PIBinaryStreamTrivialRef<P> s, T & v) {
|
||
s.p >> v;
|
||
return s.p;
|
||
}
|
||
|
||
template<typename P>
|
||
inline PIBinaryStream<P> & operator<<(PIBinaryStreamTrivialRef<P> s, const PIMemoryBlock v) {
|
||
s.p << v;
|
||
return s.p;
|
||
}
|
||
template<typename P>
|
||
inline PIBinaryStream<P> & operator>>(PIBinaryStreamTrivialRef<P> s, PIMemoryBlock v) {
|
||
s.p >> v;
|
||
return s.p;
|
||
}
|
||
|
||
|
||
// specify types
|
||
template<typename P>
|
||
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const bool v) {
|
||
s.binaryStreamAppend((uchar)v);
|
||
return s;
|
||
}
|
||
template<typename P>
|
||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, bool & v) {
|
||
uchar c;
|
||
s.binaryStreamTake(&c, sizeof(c));
|
||
v = c;
|
||
return s;
|
||
}
|
||
|
||
template<typename P>
|
||
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIMemoryBlock v) {
|
||
s.binaryStreamAppend(v.data(), v.size());
|
||
return s;
|
||
}
|
||
template<typename P>
|
||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMemoryBlock v) {
|
||
s.binaryStreamTake(v.data(), v.size());
|
||
return s;
|
||
}
|
||
|
||
|
||
// store simple types
|
||
|
||
|
||
template<typename P, typename T, typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
|
||
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const T & v) {
|
||
// piCout << "<< enum";
|
||
s.binaryStreamAppend((int)v);
|
||
return s;
|
||
}
|
||
|
||
|
||
template<typename P,
|
||
typename T,
|
||
typename std::enable_if<!std::is_enum<T>::value, int>::type = 0,
|
||
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0>
|
||
inline PIBinaryStreamTrivialRef<P> operator<<(PIBinaryStream<P> & s, const T & v) {
|
||
s.binaryStreamAppend(&v, sizeof(v));
|
||
return s;
|
||
}
|
||
|
||
|
||
//! \~english Store operator for PIVector of any trivial copyable type
|
||
//! \~russian Оператор сохранения для PIVector тривиальных типов
|
||
template<typename P,
|
||
typename T,
|
||
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0,
|
||
typename std::enable_if<
|
||
std::is_same<decltype(std::declval<PIBinaryStream<P> &>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value,
|
||
int>::type = 0>
|
||
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIVector<T> & v) {
|
||
// piCout << "<< vector trivial default";
|
||
s.binaryStreamAppend((int)v.size());
|
||
s.binaryStreamAppend(v.data(), v.size() * sizeof(T));
|
||
return s;
|
||
}
|
||
template<typename P,
|
||
typename T,
|
||
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0,
|
||
typename std::enable_if<
|
||
!std::is_same<decltype(std::declval<PIBinaryStream<P> &>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value,
|
||
int>::type = 0>
|
||
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIVector<T> & 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<typename P,
|
||
typename T,
|
||
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0,
|
||
typename std::enable_if<
|
||
std::is_same<decltype(std::declval<PIBinaryStream<P> &>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value,
|
||
int>::type = 0>
|
||
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIDeque<T> & v) {
|
||
// piCout << "<< deque trivial default";
|
||
s.binaryStreamAppend((int)v.size());
|
||
s.binaryStreamAppend(v.data(), v.size() * sizeof(T));
|
||
return s;
|
||
}
|
||
template<typename P,
|
||
typename T,
|
||
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0,
|
||
typename std::enable_if<
|
||
!std::is_same<decltype(std::declval<PIBinaryStream<P> &>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value,
|
||
int>::type = 0>
|
||
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIDeque<T> & 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<typename P,
|
||
typename T,
|
||
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0,
|
||
typename std::enable_if<
|
||
std::is_same<decltype(std::declval<PIBinaryStream<P> &>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value,
|
||
int>::type = 0>
|
||
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIVector2D<T> & 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<typename P,
|
||
typename T,
|
||
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0,
|
||
typename std::enable_if<
|
||
!std::is_same<decltype(std::declval<PIBinaryStream<P> &>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value,
|
||
int>::type = 0>
|
||
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIVector2D<T> & 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<typename P>
|
||
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIBitArray & v) {
|
||
s << v.size_ << v.data_;
|
||
return s;
|
||
}
|
||
|
||
|
||
//! \~english Store operator
|
||
//! \~russian Оператор сохранения
|
||
template<typename P, typename Type0, typename Type1>
|
||
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIPair<Type0, Type1> & v) {
|
||
s << v.first << v.second;
|
||
return s;
|
||
}
|
||
|
||
|
||
// restore simple types
|
||
|
||
|
||
template<typename P, typename T, typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
|
||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, T & v) {
|
||
// piCout << ">> enum";
|
||
v = (T)s.binaryStreamTakeInt();
|
||
return s;
|
||
}
|
||
|
||
|
||
template<typename P,
|
||
typename T,
|
||
typename std::enable_if<!std::is_enum<T>::value, int>::type = 0,
|
||
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0>
|
||
inline PIBinaryStreamTrivialRef<P> operator>>(PIBinaryStream<P> & 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<typename P,
|
||
typename T,
|
||
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0,
|
||
typename std::enable_if<
|
||
std::is_same<decltype(std::declval<PIBinaryStream<P> &>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value,
|
||
int>::type = 0>
|
||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & 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<typename P,
|
||
typename T,
|
||
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0,
|
||
typename std::enable_if<
|
||
!std::is_same<decltype(std::declval<PIBinaryStream<P> &>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value,
|
||
int>::type = 0>
|
||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & 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<typename P,
|
||
typename T,
|
||
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0,
|
||
typename std::enable_if<
|
||
std::is_same<decltype(std::declval<PIBinaryStream<P> &>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value,
|
||
int>::type = 0>
|
||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & 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<typename P,
|
||
typename T,
|
||
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0,
|
||
typename std::enable_if<
|
||
!std::is_same<decltype(std::declval<PIBinaryStream<P> &>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value,
|
||
int>::type = 0>
|
||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & 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<typename P,
|
||
typename T,
|
||
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0,
|
||
typename std::enable_if<
|
||
std::is_same<decltype(std::declval<PIBinaryStream<P> &>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value,
|
||
int>::type = 0>
|
||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & 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<typename P,
|
||
typename T,
|
||
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0,
|
||
typename std::enable_if<
|
||
!std::is_same<decltype(std::declval<PIBinaryStream<P> &>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value,
|
||
int>::type = 0>
|
||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v) {
|
||
// piCout << ">> vector2d trivial custom";
|
||
int r, c;
|
||
PIVector<T> 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<T>(r, c, tmp);
|
||
return s;
|
||
}
|
||
|
||
|
||
//! \~english Restore operator
|
||
//! \~russian Оператор извлечения
|
||
template<typename P>
|
||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIBitArray & v) {
|
||
s >> v.size_ >> v.data_;
|
||
return s;
|
||
}
|
||
|
||
|
||
//! \~english Restore operator
|
||
//! \~russian Оператор извлечения
|
||
template<typename P, typename Type0, typename Type1>
|
||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIPair<Type0, Type1> & v) {
|
||
s >> v.first >> v.second;
|
||
return s;
|
||
}
|
||
|
||
|
||
// store complex types
|
||
|
||
|
||
//! \~english Store operator for PIVector of any compound type
|
||
//! \~russian Оператор сохранения для PIVector сложных типов
|
||
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIVector<T> & 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<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIDeque<T> & 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<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIVector2D<T> & 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<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & 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<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & 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<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v) {
|
||
int r, c;
|
||
PIVector<T> 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<T>(r, c, tmp);
|
||
return s;
|
||
}
|
||
|
||
|
||
// other types
|
||
|
||
|
||
//! \~english Store operator
|
||
//! \~russian Оператор сохранения
|
||
template<typename P, typename Key, typename T>
|
||
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIMap<Key, T> & 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<typename P, typename Key, typename T>
|
||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key, T> & 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<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const T &) {
|
||
static_assert(std::is_trivially_copyable<T>::value, "[PIBinaryStream] Error: using undeclared operator << for complex type!");
|
||
return s;
|
||
}
|
||
|
||
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, T &) {
|
||
static_assert(std::is_trivially_copyable<T>::value, "[PIBinaryStream] Error: using undeclared operator >> for complex type!");
|
||
return s;
|
||
}
|
||
|
||
|
||
#endif
|