/*! \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 . */ #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 #ifdef DOXYGEN //! \relatesalso PIBinaryStream //! \~\brief //! \~english Declares templated binary stream operators as friends of \c T. //! \~russian Объявляет шаблонные операторы бинарного потока дружественными для \c T. # define BINARY_STREAM_FRIEND(T) //! \relatesalso PIBinaryStream //! \~\brief //! \~english Starts definition of a templated binary write operator for \c T. //! \~russian Начинает определение шаблонного оператора записи в бинарный поток для \c T. # define BINARY_STREAM_WRITE(T) //! \relatesalso PIBinaryStream //! \~\brief //! \~english Starts definition of a templated binary read operator for \c T. //! \~russian Начинает определение шаблонного оператора чтения из бинарного потока для \c T. # define BINARY_STREAM_READ(T) #else # define BINARY_STREAM_FRIEND(T) \ template \ 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) #endif //! \~\ingroup Serialization //! \~\brief //! \~english CRTP interface for binary serialization streams. //! \~russian CRTP-интерфейс для потоков бинарной сериализации. //! \~\details //! \~english //! Derived stream classes should implement: //! \~\code //! bool binaryStreamAppendImp (const void * d, size_t s); //! bool binaryStreamTakeImp (void * d, size_t s); //! ssize_t binaryStreamSizeImp () const; //! \endcode //! \~english //! \a binaryStreamSizeImp() should return \c -1 when the remaining size is unknown. See details \ref iostream. //! \~russian //! Производные классы потока должны реализовать методы из примера выше. \a binaryStreamSizeImp() должен возвращать \c -1, когда оставшийся //! размер неизвестен. Подробнее \ref iostream. template class PIBinaryStream { public: //! \~english Writes raw bytes to the underlying stream. //! \~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 Reads raw bytes from the underlying stream and sets read error state on short reads. //! \~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 remaining readable byte count. //! \~russian Возвращает число байтов, доступных для чтения. //! \~\details //! \~english //! Returns \c -1 when the stream cannot report its remaining size. //! \~russian //! Возвращает \c -1, если поток не может сообщить оставшийся размер. ssize_t binaryStreamSize() const { return static_cast(this)->binaryStreamSizeImp(); } //! \~english Writes one trivially copied value as raw bytes. //! \~russian Записывает одно значение прямым копированием его байтов. template void binaryStreamAppend(T v) { binaryStreamAppend(&v, sizeof(v)); } //! \~english Reads one \c int value from the stream. //! \~russian Читает одно значение \c 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; }; //! \~\ingroup Serialization //! \~\brief //! \~english Helper wrapper used to detect default trivial streaming operators. //! \~russian Вспомогательная обертка для определения операторов потоковой обработки тривиальных типов по умолчанию. //! \~english Helper class to detect default operators //! \~russian Вспомогательный класс для обнаружения операторов по умолчанию template class PIBinaryStreamTrivialRef { public: //! \~english Constructs helper reference for stream \a s. //! \~russian Создает вспомогательную ссылку на поток \a s. PIBinaryStreamTrivialRef(PIBinaryStream

& s): p(s) {} //! \~english Referenced stream. //! \~russian Связанный поток. PIBinaryStream

& p; }; template //! \~english Forwards write operation through %PIBinaryStreamTrivialRef. //! \~russian Перенаправляет операцию записи через %PIBinaryStreamTrivialRef. inline PIBinaryStream

& operator<<(PIBinaryStreamTrivialRef

s, const T & v) { s.p << v; return s.p; } template //! \~english Forwards read operation through %PIBinaryStreamTrivialRef. //! \~russian Перенаправляет операцию чтения через %PIBinaryStreamTrivialRef. inline PIBinaryStream

& operator>>(PIBinaryStreamTrivialRef

s, T & v) { s.p >> v; return s.p; } template //! \~english Forwards raw memory block write through %PIBinaryStreamTrivialRef. //! \~russian Перенаправляет запись блока памяти через %PIBinaryStreamTrivialRef. inline PIBinaryStream

& operator<<(PIBinaryStreamTrivialRef

s, const PIMemoryBlock v) { s.p << v; return s.p; } template //! \~english Forwards raw memory block read through %PIBinaryStreamTrivialRef. //! \~russian Перенаправляет чтение блока памяти через %PIBinaryStreamTrivialRef. inline PIBinaryStream

& operator>>(PIBinaryStreamTrivialRef

s, PIMemoryBlock v) { s.p >> v; return s.p; } // specify types template //! \~english Stores \c bool as one unsigned byte. //! \~russian Сохраняет \c bool как один беззнаковый байт. inline PIBinaryStream

& operator<<(PIBinaryStream

& s, const bool v) { s.binaryStreamAppend((uchar)v); return s; } template //! \~english Restores \c bool from one unsigned byte. //! \~russian Восстанавливает \c bool из одного беззнакового байта. inline PIBinaryStream

& operator>>(PIBinaryStream

& s, bool & v) { uchar c = 0; s.binaryStreamTake(&c, sizeof(c)); v = c; return s; } template //! \~english Writes raw bytes from %PIMemoryBlock. //! \~russian Записывает сырые байты из %PIMemoryBlock. inline PIBinaryStream

& operator<<(PIBinaryStream

& s, const PIMemoryBlock v) { s.binaryStreamAppend(v.data(), v.size()); return s; } template //! \~english Reads raw bytes into %PIMemoryBlock. //! \~russian Читает сырые байты в %PIMemoryBlock. inline PIBinaryStream

& operator>>(PIBinaryStream

& s, PIMemoryBlock v) { s.binaryStreamTake(v.data(), v.size()); return s; } // store simple types template::value, int>::type = 0> //! \~english Stores enum values as \c int. //! \~russian Сохраняет значения перечислений как \c int. 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> //! \~english Stores trivially copyable values by raw memory copy and returns a helper marker for bulk container paths. //! \~russian Сохраняет тривиально копируемые значения прямым копированием памяти и возвращает вспомогательный маркер для контейнерных путей //! с пакетной записью. inline PIBinaryStreamTrivialRef

operator<<(PIBinaryStream

& s, const T & v) { s.binaryStreamAppend(&v, sizeof(v)); return s; } //! \~english Stores %PIVector of trivial elements in bulk. //! \~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> //! \~english Stores %PIVector element-by-element when the element type has custom binary streaming. //! \~russian Сохраняет %PIVector поэлементно, когда тип элемента использует собственные операторы бинарного потока. 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; } template::value, int>::type = 0, typename std::enable_if< std::is_same &>() << std::declval()), PIBinaryStreamTrivialRef

>::value, int>::type = 0> //! \~english Stores %PIDeque of trivial elements in bulk. //! \~russian Сохраняет %PIDeque из тривиальных элементов пакетно. 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> //! \~english Stores %PIDeque element-by-element when the element type has custom binary streaming. //! \~russian Сохраняет %PIDeque поэлементно, когда тип элемента использует собственные операторы бинарного потока. 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; } template::value, int>::type = 0, typename std::enable_if< std::is_same &>() << std::declval()), PIBinaryStreamTrivialRef

>::value, int>::type = 0> //! \~english Stores %PIVector2D of trivial elements in bulk. //! \~russian Сохраняет %PIVector2D из тривиальных элементов пакетно. 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> //! \~english Stores %PIVector2D row data through the element streaming path. //! \~russian Сохраняет данные %PIVector2D через путь потоковой обработки элементов. 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; } template //! \~english Stores %PIBitArray content. //! \~russian Сохраняет содержимое %PIBitArray. inline PIBinaryStream

& operator<<(PIBinaryStream

& s, const PIBitArray & v) { s << v.size_ << v.data_; return s; } template //! \~english Stores both members of %PIPair. //! \~russian Сохраняет оба элемента %PIPair. inline PIBinaryStream

& operator<<(PIBinaryStream

& s, const PIPair & v) { s << v.first << v.second; return s; } // restore simple types template::value, int>::type = 0> //! \~english Restores enum values from \c int. //! \~russian Восстанавливает значения перечислений из \c int. 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> //! \~english Restores trivially copyable values by raw memory copy and returns a helper marker for bulk container paths. //! \~russian Восстанавливает тривиально копируемые значения прямым копированием памяти и возвращает вспомогательный маркер для контейнерных //! путей с пакетным чтением. inline PIBinaryStreamTrivialRef

operator>>(PIBinaryStream

& s, T & v) { if (!s.binaryStreamTake(&v, sizeof(v))) { fprintf(stderr, "error with %s\n", __PIP_TYPENAME__(T)); } return s; } template::value, int>::type = 0, typename std::enable_if< std::is_same &>() >> std::declval()), PIBinaryStreamTrivialRef

>::value, int>::type = 0> //! \~english Restores %PIVector of trivial elements in bulk. //! \~russian Восстанавливает %PIVector из тривиальных элементов пакетно. 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> //! \~english Restores %PIVector element-by-element when the element type has custom binary streaming. //! \~russian Восстанавливает %PIVector поэлементно, когда тип элемента использует собственные операторы бинарного потока. 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; } template::value, int>::type = 0, typename std::enable_if< std::is_same &>() >> std::declval()), PIBinaryStreamTrivialRef

>::value, int>::type = 0> //! \~english Restores %PIDeque of trivial elements in bulk. //! \~russian Восстанавливает %PIDeque из тривиальных элементов пакетно. 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> //! \~english Restores %PIDeque element-by-element when the element type has custom binary streaming. //! \~russian Восстанавливает %PIDeque поэлементно, когда тип элемента использует собственные операторы бинарного потока. 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; } template::value, int>::type = 0, typename std::enable_if< std::is_same &>() >> std::declval()), PIBinaryStreamTrivialRef

>::value, int>::type = 0> //! \~english Restores %PIVector2D of trivial elements in bulk. //! \~russian Восстанавливает %PIVector2D из тривиальных элементов пакетно. 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> //! \~english Restores %PIVector2D through the element streaming path. //! \~russian Восстанавливает %PIVector2D через путь потоковой обработки элементов. 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; } template //! \~english Restores %PIBitArray content. //! \~russian Восстанавливает содержимое %PIBitArray. inline PIBinaryStream

& operator>>(PIBinaryStream

& s, PIBitArray & v) { s >> v.size_ >> v.data_; return s; } template //! \~english Restores both members of %PIPair. //! \~russian Восстанавливает оба элемента %PIPair. inline PIBinaryStream

& operator>>(PIBinaryStream

& s, PIPair & v) { s >> v.first >> v.second; return s; } // store complex types template::value, int>::type = 0> //! \~english Stores %PIVector of non-trivial elements one-by-one. //! \~russian Сохраняет %PIVector из нетривиальных элементов по одному. 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; } template::value, int>::type = 0> //! \~english Stores %PIDeque of non-trivial elements one-by-one. //! \~russian Сохраняет %PIDeque из нетривиальных элементов по одному. 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; } template::value, int>::type = 0> //! \~english Stores %PIVector2D of non-trivial elements via its plain vector representation. //! \~russian Сохраняет %PIVector2D из нетривиальных элементов через его плоское векторное представление. 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 template::value, int>::type = 0> //! \~english Restores %PIVector of non-trivial elements one-by-one. //! \~russian Восстанавливает %PIVector из нетривиальных элементов по одному. 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; } template::value, int>::type = 0> //! \~english Restores %PIDeque of non-trivial elements one-by-one. //! \~russian Восстанавливает %PIDeque из нетривиальных элементов по одному. 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; } template::value, int>::type = 0> //! \~english Restores %PIVector2D of non-trivial elements via an intermediate plain vector. //! \~russian Восстанавливает %PIVector2D из нетривиальных элементов через промежуточный плоский вектор. 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 template //! \~english Stores %PIMap keys and values. //! \~russian Сохраняет ключи и значения %PIMap. 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; } template //! \~english Restores %PIMap keys and values. //! \~russian Восстанавливает ключи и значения %PIMap. 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; } template //! \~english Stores %PISet keys. //! \~russian Сохраняет ключи %PISet. inline PIBinaryStream

& operator<<(PIBinaryStream

& s, const PISet & 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; } template //! \~english Restores %PISet keys. //! \~russian Восстанавливает ключи %PISet. inline PIBinaryStream

& operator>>(PIBinaryStream

& s, PISet & 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::value, int>::type = 0> //! \~english Fallback overload that intentionally fails for unsupported non-trivial write types. //! \~russian Резервная перегрузка, которая намеренно завершает компиляцию ошибкой для неподдерживаемых нетривиальных типов записи. 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> //! \~english Fallback overload that intentionally fails for unsupported non-trivial read types. //! \~russian Резервная перегрузка, которая намеренно завершает компиляцию ошибкой для неподдерживаемых нетривиальных типов чтения. inline PIBinaryStream

& operator>>(PIBinaryStream

& s, T &) { static_assert(std::is_trivially_copyable::value, "[PIBinaryStream] Error: using undeclared operator >> for complex type!"); return s; } #endif