\
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
//! \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