/*! \file pibinarystream.h * \ingroup Core * \~\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 "pimemoryblock.h" #include "pibitarray.h" #include "pimap.h" #include "pivector2d.h" #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_STORE(T) \ template inline PIBinaryStream

& operator <<(PIBinaryStream

& s, const T & v) #define BINARY_STREAM_RESTORE(T) \ template inline PIBinaryStream

& operator >>(PIBinaryStream

& s, T & v) //! \ingroup Core //! \~\brief //! \~english Binary serialization interface. //! \~russian Интерфейс бинарной сериализации. template class PIBinaryStream { public: // one should implement next methods: // // bool binaryStreamAppendImp(const void * d, size_t s); // bool binaryStreamTakeImp ( void * d, size_t s); bool binaryStreamAppend(const void * d, size_t s) { if (!static_cast(this)->binaryStreamAppendImp(d, s)) { return false; printf("[PIBinaryStream] binaryStreamAppend() error\n"); } return true; } bool binaryStreamTake(void * d, size_t s) { if (!static_cast(this)->binaryStreamTakeImp(d, s)) { return false; printf("[PIBinaryStream] binaryStreamTake() error\n"); } return true; } template void binaryStreamAppend(T v) {binaryStreamAppend(&v, sizeof(v));} uchar binaryStreamTakeByte() {uchar r = 0; binaryStreamTake(&r, sizeof(r)); return r;} int binaryStreamTakeInt() {int r = 0; binaryStreamTake(&r, sizeof(r)); return r;} }; // helper class to detect default operators template class PIBinaryStreamTrivialRef { public: PIBinaryStreamTrivialRef(PIBinaryStream

& s): p(s) {} PIBinaryStream

& p; }; template inline PIBinaryStream

& operator <<(PIBinaryStreamTrivialRef

s, const T & v) {s.p << v; return s.p;} template inline PIBinaryStream

& operator >>(PIBinaryStreamTrivialRef

s, T & v) {s.p >> v; return s.p;} // specify types template inline PIBinaryStreamTrivialRef

operator <<(PIBinaryStream

& s, const bool v) {s.binaryStreamAppend((uchar)v); return s;} template inline PIBinaryStreamTrivialRef

operator <<(PIBinaryStream

& s, const char v) {s.binaryStreamAppend((uchar)v); return s;} template inline PIBinaryStreamTrivialRef

operator <<(PIBinaryStream

& s, const uchar v) {s.binaryStreamAppend((uchar)v); return s;} template inline PIBinaryStreamTrivialRef

operator >>(PIBinaryStream

& s, bool & v) {v = s.binaryStreamTakeByte(); return s;} template inline PIBinaryStreamTrivialRef

operator >>(PIBinaryStream

& s, char & v) {v = s.binaryStreamTakeByte(); return s;} template inline PIBinaryStreamTrivialRef

operator >>(PIBinaryStream

& s, uchar & v) {v = s.binaryStreamTakeByte(); return s;} template inline PIBinaryStream

& operator <<(PIBinaryStream

& s, const PIMemoryBlock v) { s.binaryStreamAppend(v.data(), v.size()); return s; } template inline PIBinaryStream

& operator >>(PIBinaryStream

& s, PIMemoryBlock v) { s.binaryStreamTake(v.data(), v.size()); return s; } // store simple types template::value, int>::type = 0> inline PIBinaryStreamTrivialRef

operator <<(PIBinaryStream

& s, const T & v) { //piCout << "<< enum"; s.binaryStreamAppend((int)v); return s; } template::value, int>::type = 0, typename std::enable_if< std::is_trivially_copyable::value, int>::type = 0> inline PIBinaryStreamTrivialRef

operator <<(PIBinaryStream

& s, const T & v) { s.binaryStreamAppend(&v, sizeof(v)); return s; } //! \~english Store operator for PIVector of any trivial copyable type //! \~russian Оператор сохранения для PIVector тривиальных типов template::value, int>::type = 0, typename std::enable_if< std::is_same&>() << std::declval()), PIBinaryStreamTrivialRef

>::value, int>::type = 0> inline PIBinaryStream

& operator <<(PIBinaryStream

& s, const PIVector & v) { //piCout << "<< vector trivial default"; s.binaryStreamAppend((int)v.size()); s.binaryStreamAppend(v.data(), v.size() * sizeof(T)); return s; } template::value, int>::type = 0, typename std::enable_if&>() << std::declval()), PIBinaryStreamTrivialRef

>::value, int>::type = 0> inline PIBinaryStream

& operator <<(PIBinaryStream

& s, const PIVector & v) { //piCout << "<< vector trivial custom"; s.binaryStreamAppend((int)v.size()); for (size_t i = 0; i < v.size(); ++i) s << v[i]; return s; } //! \~english Store operator for PIDeque of any trivial copyable type //! \~russian Оператор сохранения для PIDeque тривиальных типов template::value, int>::type = 0, typename std::enable_if< std::is_same&>() << std::declval()), PIBinaryStreamTrivialRef

>::value, int>::type = 0> inline PIBinaryStream

& operator <<(PIBinaryStream

& s, const PIDeque & v) { //piCout << "<< deque trivial default"; s.binaryStreamAppend((int)v.size()); s.binaryStreamAppend(v.data(), v.size() * sizeof(T)); return s; } template::value, int>::type = 0, typename std::enable_if&>() << std::declval()), PIBinaryStreamTrivialRef

>::value, int>::type = 0> inline PIBinaryStream

& operator <<(PIBinaryStream

& s, const PIDeque & v) { //piCout << "<< deque trivial custom"; s.binaryStreamAppend((int)v.size()); for (size_t i = 0; i < v.size(); ++i) s << v[i]; return s; } //! \~english Store operator for PIVector2D of any trivial copyable type //! \~russian Оператор сохранения для PIVector2D тривиальных типов template::value, int>::type = 0, typename std::enable_if< std::is_same&>() << std::declval()), PIBinaryStreamTrivialRef

>::value, int>::type = 0> inline PIBinaryStream

& operator <<(PIBinaryStream

& s, const PIVector2D & v) { //piCout << "<< vector2d trivial default"; s.binaryStreamAppend((int)v.rows()); s.binaryStreamAppend((int)v.cols()); s.binaryStreamAppend(v.data(), v.size() * sizeof(T)); return s; } template::value, int>::type = 0, typename std::enable_if&>() << std::declval()), PIBinaryStreamTrivialRef

>::value, int>::type = 0> inline PIBinaryStream

& operator <<(PIBinaryStream

& s, const PIVector2D & v) { //piCout << "<< vector2d trivial custom"; s.binaryStreamAppend((int)v.rows()); s.binaryStreamAppend((int)v.cols()); s << v.toPlainVector(); return s; } //! \~english Store operator //! \~russian Оператор сохранения template inline PIBinaryStream

& operator <<(PIBinaryStream

& s, const PIBitArray & v) {s << v.size_ << v.data_; return s;} //! \~english Store operator //! \~russian Оператор сохранения template inline PIBinaryStream

& operator <<(PIBinaryStream

& s, const PIPair & v) {s << v.first << v.second; return s;} // restore simple types template::value, int>::type = 0> inline PIBinaryStreamTrivialRef

operator >>(PIBinaryStream

& s, T & v) { //piCout << ">> enum"; v = (T)s.binaryStreamTakeInt(); return s; } template::value, int>::type = 0, typename std::enable_if< std::is_trivially_copyable::value, int>::type = 0> inline PIBinaryStreamTrivialRef

operator >>(PIBinaryStream

& s, T & v) { if (!s.binaryStreamTake(&v, sizeof(v))) { printf("error with %s\n", __PIP_TYPENAME__(T)); assert(false); } return s; } //! \~english Restore operator for PIVector of any trivial copyable type //! \~russian Оператор извлечения для PIVector тривиальных типов template::value, int>::type = 0, typename std::enable_if< std::is_same&>() >> std::declval()), PIBinaryStreamTrivialRef

>::value, int>::type = 0> inline PIBinaryStream

& operator >>(PIBinaryStream

& s, PIVector & v) { //piCout << ">> vector trivial default"; int sz = s.binaryStreamTakeInt(); v._resizeRaw(sz); if (!s.binaryStreamTake(v.data(), sz * sizeof(T))) { printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T)); assert(false); } return s; } template::value, int>::type = 0, typename std::enable_if&>() >> std::declval()), PIBinaryStreamTrivialRef

>::value, int>::type = 0> inline PIBinaryStream

& operator >>(PIBinaryStream

& s, PIVector & v) { //piCout << ">> vector trivial custom"; int sz = s.binaryStreamTakeInt(); v._resizeRaw(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s; } //! \~english Restore operator for PIDeque of any trivial copyable type //! \~russian Оператор извлечения для PIDeque тривиальных типов template::value, int>::type = 0, typename std::enable_if< std::is_same&>() >> std::declval()), PIBinaryStreamTrivialRef

>::value, int>::type = 0> inline PIBinaryStream

& operator >>(PIBinaryStream

& s, PIDeque & v) { //piCout << ">> deque trivial default"; int sz = s.binaryStreamTakeInt(); v._resizeRaw(sz); if (!s.binaryStreamTake(v.data(), sz * sizeof(T))) { printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T)); assert(false); } return s; } template::value, int>::type = 0, typename std::enable_if&>() >> std::declval()), PIBinaryStreamTrivialRef

>::value, int>::type = 0> inline PIBinaryStream

& operator >>(PIBinaryStream

& s, PIDeque & v) { //piCout << ">> deque trivial custom"; int sz = s.binaryStreamTakeInt(); v._resizeRaw(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s; } //! \~english Restore operator for PIVector2D of any trivial copyable type //! \~russian Оператор извлечения для PIVector2D тривиальных типов template::value, int>::type = 0, typename std::enable_if< std::is_same&>() >> std::declval()), PIBinaryStreamTrivialRef

>::value, int>::type = 0> inline PIBinaryStream

& operator >>(PIBinaryStream

& s, PIVector2D & v) { //piCout << ">> vector2d trivial default"; int r, c; r = s.binaryStreamTakeInt(); c = s.binaryStreamTakeInt(); v._resizeRaw(r, c); if (!s.binaryStreamTake(v.data(), v.size() * sizeof(T))) { printf("error with PIVector2D<%s>\n", __PIP_TYPENAME__(T)); assert(false); } return s; } template::value, int>::type = 0, typename std::enable_if&>() >> std::declval()), PIBinaryStreamTrivialRef

>::value, int>::type = 0> inline PIBinaryStream

& operator >>(PIBinaryStream

& s, PIVector2D & v) { //piCout << ">> vector2d trivial custom"; int r, c; PIVector tmp; r = s.binaryStreamTakeInt(); c = s.binaryStreamTakeInt(); s >> tmp; v = PIVector2D(r, c, tmp); return s; } //! \~english Restore operator //! \~russian Оператор извлечения template inline PIBinaryStream

& operator >>(PIBinaryStream

& s, PIBitArray & v) {s >> v.size_ >> v.data_; return s;} //! \~english Restore operator //! \~russian Оператор извлечения template inline PIBinaryStream

& operator >>(PIBinaryStream

& s, PIPair & v) {s >> v.first >> v.second; return s;} // store complex types //! \~english Store operator for PIVector of any compound type //! \~russian Оператор сохранения для PIVector сложных типов template::value, int>::type = 0> inline PIBinaryStream

& operator <<(PIBinaryStream

& s, const PIVector & v) { //piCout << "<< vector complex"; s.binaryStreamAppend(int(v.size_s())); for (size_t i = 0; i < v.size(); ++i) s << v[i]; return s; } //! \~english Store operator for PIDeque of any compound type //! \~russian Оператор сохранения для PIDeque сложных типов template::value, int>::type = 0> inline PIBinaryStream

& operator <<(PIBinaryStream

& s, const PIDeque & v) { //piCout << "<< deque complex"; s.binaryStreamAppend(int(v.size_s())); for (size_t i = 0; i < v.size(); ++i) s << v[i]; return s; } //! \~english Store operator for PIVector2D of any compound type //! \~russian Оператор сохранения для PIVector2D сложных типов template::value, int>::type = 0> inline PIBinaryStream

& operator <<(PIBinaryStream

& s, const PIVector2D & v) { //piCout << "<< vector2d complex"; s.binaryStreamAppend(int(v.rows())); s.binaryStreamAppend(int(v.cols())); s << v.toPlainVector(); return s; } // restore complex types //! \~english Restore operator for PIVector of any compound type //! \~russian Оператор извлечения для PIVector сложных типов template::value, int>::type = 0> inline PIBinaryStream

& operator >>(PIBinaryStream

& s, PIVector & v) { //piCout << ">> vector complex"; /*if (s.size_s() < 4) { printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T)); assert(s.size_s() >= 4); }*/ v.resize(s.binaryStreamTakeInt()); for (size_t i = 0; i < v.size(); ++i) s >> v[i]; return s; } //! \~english Restore operator for PIDeque of any compound type //! \~russian Оператор извлечения для PIDeque сложных типов template::value, int>::type = 0> inline PIBinaryStream

& operator >>(PIBinaryStream

& s, PIDeque & v) { //piCout << ">> deque complex"; /*if (s.size_s() < 4) { printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T)); assert(s.size_s() >= 4); }*/ v.resize(s.binaryStreamTakeInt()); for (size_t i = 0; i < v.size(); ++i) s >> v[i]; return s; } //! \~english Restore operator for PIVector2D of any compound type //! \~russian Оператор извлечения для PIVector2D сложных типов template::value, int>::type = 0> inline PIBinaryStream

& operator >>(PIBinaryStream

& s, PIVector2D & v) { //piCout << ">> vector2d complex"; /*if (s.size_s() < 8) { printf("error with PIVecto2Dr<%s>\n", __PIP_TYPENAME__(T)); assert(s.size_s() >= 8); }*/ int r, c; PIVector tmp; r = s.binaryStreamTakeInt(); c = s.binaryStreamTakeInt(); s >> tmp; v = PIVector2D(r, c, tmp); return s; } // other types //! \~english Store operator //! \~russian Оператор сохранения template inline PIBinaryStream

& operator <<(PIBinaryStream

& s, const PIMap & v) { s.binaryStreamAppend((int)v.pim_index.size_s()); for (uint i = 0; i < v.size(); ++i) { s.binaryStreamAppend((int)v.pim_index[i].index); s << v.pim_index[i].key; } s << v.pim_content; return s; } //! \~english Restore operator //! \~russian Оператор извлечения template inline PIBinaryStream

& operator >>(PIBinaryStream

& s, PIMap & v) { /*if (s.size_s() < 4) { printf("error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T)); assert(s.size_s() >= 4); }*/ int sz = s.binaryStreamTakeInt(); v.pim_index.resize(sz); int ind = 0; for (int i = 0; i < sz; ++i) { ind = s.binaryStreamTakeInt(); s >> v.pim_index[i].key; v.pim_index[i].index = ind; } s >> v.pim_content; if (v.pim_content.size_s() != v.pim_index.size_s()) { piCout << "Warning: loaded invalid PIMap, clear"; v.clear(); } return s; } // non-defined complex types template::value, int>::type = 0> inline PIBinaryStream

& operator <<(PIBinaryStream

& s, const T & ) { static_assert(std::is_trivially_copyable::value, "[PIBinaryStream] Error: using undeclared operator << for complex type!"); return s; } template::value, int>::type = 0> inline PIBinaryStream

& operator >>(PIBinaryStream

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