Files
pip/libs/main/serialization/pibinarystream.h
2024-10-21 13:47:28 +03:00

716 lines
24 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*! \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 "piset.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;
}
//! \~english Store operator
//! \~russian Оператор сохранения
template<typename P, typename Key>
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PISet<Key> & 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;
}
return s;
}
//! \~english Restore operator
//! \~russian Оператор извлечения
template<typename P, typename Key>
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PISet<Key> & v) {
int sz = s.binaryStreamTakeInt();
if (s.wasReadError()) {
fprintf(stderr, "error with PISet<%s>\n", __PIP_TYPENAME__(Key));
v.clear();
return s;
}
v.pim_index.resize(sz);
v.pim_content.resize(sz, 0);
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 PISet<%s>\n", __PIP_TYPENAME__(Key));
v.clear();
return s;
}
v.pim_index[i].index = ind;
}
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