summaryrefslogtreecommitdiff
path: root/wx+/serialize.h
diff options
context:
space:
mode:
Diffstat (limited to 'wx+/serialize.h')
-rw-r--r--wx+/serialize.h322
1 files changed, 296 insertions, 26 deletions
diff --git a/wx+/serialize.h b/wx+/serialize.h
index f49bff04..030b55c7 100644
--- a/wx+/serialize.h
+++ b/wx+/serialize.h
@@ -8,14 +8,306 @@
#define SERIALIZE_H_INCLUDED
#include <cstdint>
-#include <wx/stream.h>
+#include <zen/string_base.h>
#include <zen/file_io.h>
+#ifdef FFS_WIN
+warn_static("get rid of wx, then move to zen")
+#endif
+
+#include <wx/stream.h>
+
namespace zen
{
+//high-performance unformatted serialization (avoiding wxMemoryOutputStream/wxMemoryInputStream inefficiencies)
+
+/*
+--------------------------
+|Binary Container Concept|
+--------------------------
+binary container for data storage: must support "basic" std::vector interface (e.g. std::vector<char>, std::string, Zbase<char>)
+*/
+
+//binary container reference implementations
+typedef Zbase<char> Utf8String; //ref-counted + COW text stream + guaranteed performance: exponential growth
+class BinaryStream; //ref-counted byte stream + guaranteed performance: exponential growth -> no COW, but 12% faster than Utf8String (due to no null-termination?)
+
+class BinaryStream //essentially a std::vector<char> with ref-counted semantics
+{
+public:
+ BinaryStream() : buffer(std::make_shared<std::vector<char>>()) {}
+
+ typedef std::vector<char>::value_type value_type;
+ typedef std::vector<char>::iterator iterator;
+ typedef std::vector<char>::const_iterator const_iterator;
+
+ iterator begin() { return buffer->begin(); }
+ iterator end () { return buffer->end (); }
+
+ const_iterator begin() const { return buffer->begin(); }
+ const_iterator end () const { return buffer->end (); }
+
+ void resize(size_t len) { buffer->resize(len); }
+ size_t size() const { return buffer->size(); }
+ bool empty() const { return buffer->empty(); }
+
+ inline friend bool operator==(const BinaryStream& lhs, const BinaryStream& rhs) { return *lhs.buffer == *rhs.buffer; }
+
+private:
+ std::shared_ptr<std::vector<char>> buffer; //always bound!
+ //perf: shared_ptr indirection irrelevant: less than 1% slower!
+};
+
+//----------------------------------------------------------------------
+//functions based on binary container abstraction
+template <class BinContainer> void saveBinStream(const Zstring& filename, const BinContainer& cont); //throw FileError
+template <class BinContainer> BinContainer loadBinStream(const Zstring& filename); //throw FileError, ErrorNotExisting
+
+
+/*
+-----------------------------
+|Binary Input Stream Concept|
+-----------------------------
+struct BinInputStream
+{
+ const void* requestRead(size_t len); //expect external read of len bytes
+};
+
+------------------------------
+|Binary Output Stream Concept|
+------------------------------
+struct BinOutputStream
+{
+ void* requestWrite(size_t len); //expect external write of len bytes
+};
+*/
+
+//binary input/output stream reference implementation
+class UnexpectedEndOfStreamError {};
+
+struct BinStreamIn //throw UnexpectedEndOfStreamError
+{
+ BinStreamIn(const BinaryStream& cont) : buffer(cont), pos(0) {} //this better be cheap!
+
+ const void* requestRead(size_t len) //throw UnexpectedEndOfStreamError
+ {
+ if (pos + len > buffer.size())
+ throw UnexpectedEndOfStreamError();
+ size_t oldPos = pos;
+ pos += len;
+ return &*buffer.begin() + oldPos;
+ }
+
+private:
+ const BinaryStream buffer;
+ size_t pos;
+};
+
+struct BinStreamOut
+{
+ void* requestWrite(size_t len)
+ {
+ size_t oldSize = buffer.size();
+ buffer.resize(buffer.size() + len);
+ return &*buffer.begin() + oldSize;
+ }
+
+ BinaryStream get() { return buffer; }
+
+private:
+ BinaryStream buffer;
+};
+
+//----------------------------------------------------------------------
+//functions based on binary stream abstraction
+template <class N, class BinOutputStream> void writeNumber (BinOutputStream& stream, const N& num); //
+template <class C, class BinOutputStream> void writeContainer(BinOutputStream& stream, const C& str); //throw ()
+template < class BinOutputStream> void writeArray (BinOutputStream& stream, const void* data, size_t len); //
+
+//----------------------------------------------------------------------
+
+template <class N, class BinInputStream> N readNumber (BinInputStream& stream); //
+template <class C, class BinInputStream> C readContainer(BinInputStream& stream); //throw UnexpectedEndOfStreamError (corrupted data)
+template < class BinInputStream> void readArray (BinInputStream& stream, void* data, size_t len); //
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//-----------------------implementation-------------------------------
+template <class BinContainer> inline
+void saveBinStream(const Zstring& filename, const BinContainer& cont) //throw FileError
+{
+ assert_static(sizeof(typename BinContainer::value_type) == 1); //expect: bytes (until further)
+
+ FileOutput fileOut(filename, zen::FileOutput::ACC_OVERWRITE); //throw FileError
+ if (!cont.empty())
+ fileOut.write(&*cont.begin(), cont.size()); //throw FileError
+}
+
+
+template <class BinContainer> inline
+BinContainer loadBinStream(const Zstring& filename) //throw FileError, ErrorNotExisting
+{
+ assert_static(sizeof(typename BinContainer::value_type) == 1); //expect: bytes (until further)
+
+ FileInput fileIn(filename); //throw FileError, ErrorNotExisting
+
+ BinContainer contOut;
+ const size_t blockSize = 64 * 1024;
+ do
+ {
+ contOut.resize(contOut.size() + blockSize);
+
+ const size_t bytesRead = fileIn.read(&*contOut.begin() + contOut.size() - blockSize, blockSize); //throw FileError
+ if (bytesRead < blockSize)
+ contOut.resize(contOut.size() - (blockSize - bytesRead)); //caveat: unsigned arithmetics
+ }
+ while (!fileIn.eof());
+
+ return contOut;
+}
+
+
+template <class BinOutputStream> inline
+void writeArray(BinOutputStream& stream, const void* data, size_t len)
+{
+ std::copy(static_cast<const char*>(data),
+ static_cast<const char*>(data) + len,
+ static_cast< char*>(stream.requestWrite(len)));
+}
+
+
+template <class N, class BinOutputStream> inline
+void writeNumber(BinOutputStream& stream, const N& num)
+{
+ assert_static((IsArithmetic<N>::value || IsSameType<N, bool>::value));
+ writeArray(stream, &num, sizeof(N));
+}
+
+
+template <class C, class BinOutputStream> inline
+void writeContainer(BinOutputStream& stream, const C& cont) //don't even consider UTF8 conversions here! "string" is expected to handle arbitrary binary data!
+{
+ const auto len = cont.size();
+ writeNumber(stream, static_cast<std::uint32_t>(len));
+ if (len > 0)
+ writeArray(stream, &*cont.begin(), sizeof(typename C::value_type) * len); //don't use c_str(), but access uniformly via STL interface
+}
+
+
+template <class BinInputStream> inline
+void readArray(BinInputStream& stream, void* data, size_t len)
+{
+ const char* const src = static_cast<const char*>(stream.requestRead(len)); //expect external write of len bytes
+ std::copy(src, src + len, static_cast<char*>(data));
+}
+
+
+template <class N, class BinInputStream> inline
+N readNumber(BinInputStream& stream)
+{
+ assert_static((IsArithmetic<N>::value || IsSameType<N, bool>::value));
+ N num = 0;
+ readArray(stream, &num, sizeof(N));
+ return num;
+}
+
+
+template <class C, class BinInputStream> inline
+C readContainer(BinInputStream& stream)
+{
+ C cont;
+ auto strLength = readNumber<std::uint32_t>(stream);
+ if (strLength > 0)
+ try
+ {
+ cont.resize(strLength); //throw std::bad_alloc
+ readArray(stream, &*cont.begin(), sizeof(typename C::value_type) * strLength);
+ }
+ catch (std::bad_alloc&) //most likely this is due to data corruption!
+ {
+ throw UnexpectedEndOfStreamError();
+ }
+ return cont;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#ifdef FFS_WIN
+warn_static("get rid of wx, then move to zen")
+#endif
+
+
+
//unchecked, unformatted serialization
-template <class T> T readPOD (wxInputStream& stream);
+template <class T> T readPOD (wxInputStream& stream);
template <class T> void readPOD (wxInputStream& stream, T& pod);
template <class T> void writePOD(wxOutputStream& stream, const T& pod);
@@ -116,29 +408,6 @@ private:
};
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-//-----------------------implementation-------------------------------
template <class T> inline
T readPOD(wxInputStream& stream)
{
@@ -235,7 +504,7 @@ void CheckedReader::readString(S& str) const //checked read operation
}
catch (std::exception&) { throwException(); }
check();
- if (stream_.LastRead() != str.length() * sizeof(typename S::value_type)) //some additional check
+ if (stream_.LastRead() != str.size() * sizeof(typename S::value_type)) //some additional check
throwException();
}
@@ -260,6 +529,7 @@ void CheckedWriter::writeString(const S& str) const //checked write operation
{
zen::writeString(stream_, str);
check();
+ //warn_static("buggy check if length 0!")
if (stream_.LastWrite() != str.length() * sizeof(typename S::value_type)) //some additional check
throwException();
}
bgstack15