summaryrefslogtreecommitdiff
path: root/zen/serialize.h
diff options
context:
space:
mode:
Diffstat (limited to 'zen/serialize.h')
-rw-r--r--zen/serialize.h137
1 files changed, 65 insertions, 72 deletions
diff --git a/zen/serialize.h b/zen/serialize.h
index 54baf75a..4af12af1 100644
--- a/zen/serialize.h
+++ b/zen/serialize.h
@@ -25,12 +25,13 @@ binary container for data storage: must support "basic" std::vector interface (e
//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 ByteArray; //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, but no COW! => *almost* value type semantics, but not quite
+
+class ByteArray //essentially a std::vector<char> with ref-counted semantics, but no COW! => *almost* value type semantics, but not quite
{
public:
- BinaryStream() : buffer(std::make_shared<std::vector<char>>()) {}
+ ByteArray() : buffer(std::make_shared<std::vector<char>>()) {}
typedef std::vector<char>::value_type value_type;
typedef std::vector<char>::iterator iterator;
@@ -46,7 +47,7 @@ public:
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; }
+ inline friend bool operator==(const ByteArray& lhs, const ByteArray& rhs) { return *lhs.buffer == *rhs.buffer; }
private:
std::shared_ptr<std::vector<char>> buffer; //always bound!
@@ -65,7 +66,7 @@ template <class BinContainer> BinContainer loadBinStream(const Zstring& filepath
-----------------------------
struct BinInputStream
{
- const void* requestRead(size_t len); //expect external read of len bytes
+ size_t read(void* data, size_t len); //return "len" bytes unless end of stream!
};
------------------------------
@@ -73,58 +74,62 @@ struct BinInputStream
------------------------------
struct BinOutputStream
{
- void* requestWrite(size_t len); //expect external write of len bytes
+ void write(const void* data, size_t len);
};
*/
-//binary input/output stream reference implementation
-class UnexpectedEndOfStreamError {};
+//binary input/output stream reference implementations:
-struct BinStreamIn //throw UnexpectedEndOfStreamError
+template <class BinContainer>
+struct MemoryStreamIn
{
- BinStreamIn(const BinaryStream& cont) : buffer(cont), pos(0) {} //this better be cheap!
+ MemoryStreamIn(const BinContainer& cont) : buffer(cont), pos(0) {} //this better be cheap!
- const void* requestRead(size_t len) //throw UnexpectedEndOfStreamError
+ size_t read(void* data, size_t len) //return "len" bytes unless end of stream!
{
- if (len == 0) return nullptr; //don't allow for possibility to access empty buffer
- if (pos + len > buffer.size())
- throw UnexpectedEndOfStreamError();
- size_t oldPos = pos;
- pos += len;
- return &*buffer.begin() + oldPos;
+ static_assert(sizeof(typename BinContainer::value_type) == 1, ""); //expect: bytes
+ const size_t bytesRead = std::min(len, buffer.size() - pos);
+ auto itFirst = buffer.begin() + pos;
+ std::copy(itFirst, itFirst + bytesRead, static_cast<char*>(data));
+ pos += bytesRead;
+ return bytesRead;
}
private:
- BinaryStream buffer;
+ const BinContainer buffer;
size_t pos;
};
-struct BinStreamOut
+template <class BinContainer>
+struct MemoryStreamOut
{
- void* requestWrite(size_t len)
+ void write(const void* data, size_t len)
{
- if (len == 0) return nullptr; //don't allow for possibility to access empty buffer
+ static_assert(sizeof(typename BinContainer::value_type) == 1, ""); //expect: bytes
const size_t oldSize = buffer.size();
buffer.resize(oldSize + len);
- return &*buffer.begin() + oldSize;
+ std::copy(static_cast<const char*>(data), static_cast<const char*>(data) + len, buffer.begin() + oldSize);
}
- BinaryStream get() { return buffer; }
+ const BinContainer& ref() const { return buffer; }
private:
- BinaryStream buffer;
+ BinContainer buffer;
};
//----------------------------------------------------------------------
//functions based on binary stream abstraction
+template <class BinInputStream, class BinOutputStream>
+void copyStream(BinInputStream& streamIn, BinOutputStream& streamOut, const std::function<void(std::int64_t bytesDelta)>& onNotifyCopyStatus); //optional
+
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)
+class UnexpectedEndOfStreamError {};
+template <class N, class BinInputStream> N readNumber (BinInputStream& stream); //throw UnexpectedEndOfStreamError (corrupted data)
+template <class C, class BinInputStream> C readContainer(BinInputStream& stream); //
template < class BinInputStream> void readArray (BinInputStream& stream, void* data, size_t len); //
@@ -135,66 +140,54 @@ template < class BinInputStream> void readArray (BinInputStream& stre
//-----------------------implementation-------------------------------
-template <class BinContainer> inline
-void saveBinStream(const Zstring& filepath, //throw FileError
- const BinContainer& cont,
- const std::function<void(std::int64_t bytesDelta)>& onUpdateStatus) //optional
+template <class BinInputStream, class BinOutputStream> inline
+void copyStream(BinInputStream& streamIn, BinOutputStream& streamOut, size_t blockSize,
+ const std::function<void(std::int64_t bytesDelta)>& onNotifyCopyStatus) //optional
{
- static_assert(sizeof(typename BinContainer::value_type) == 1, ""); //expect: bytes (until further)
-
- FileOutput fileOut(filepath, zen::FileOutput::ACC_OVERWRITE); //throw FileError
- if (!cont.empty())
+ assert(blockSize > 0);
+ std::vector<char> buffer(blockSize);
+ for (;;)
{
- const size_t blockSize = 128 * 1024;
- auto bytePtr = &*cont.begin();
- size_t bytesLeft = cont.size();
+ const size_t bytesRead = streamIn.read(&buffer[0], buffer.size());
+ streamOut.write(&buffer[0], bytesRead);
- while (bytesLeft > blockSize)
- {
- fileOut.write(bytePtr, blockSize); //throw FileError
- bytePtr += blockSize;
- bytesLeft -= blockSize;
- if (onUpdateStatus) onUpdateStatus(blockSize);
- }
+ if (onNotifyCopyStatus)
+ onNotifyCopyStatus(bytesRead); //throw X!
- fileOut.write(bytePtr, bytesLeft); //throw FileError
- if (onUpdateStatus) onUpdateStatus(bytesLeft);
+ if (bytesRead != buffer.size()) //end of file
+ break;
}
}
template <class BinContainer> inline
-BinContainer loadBinStream(const Zstring& filepath, //throw FileError
- const std::function<void(std::int64_t bytesDelta)>& onUpdateStatus) //optional
+void saveBinStream(const Zstring& filepath, //throw FileError
+ const BinContainer& cont,
+ const std::function<void(std::int64_t bytesDelta)>& onUpdateStatus) //optional
{
- static_assert(sizeof(typename BinContainer::value_type) == 1, ""); //expect: bytes (until further)
-
- FileInput fileIn(filepath); //throw FileError
-
- BinContainer contOut;
- const size_t blockSize = 128 * 1024;
- do
- {
- contOut.resize(contOut.size() + blockSize); //container better implement exponential growth!
-
- 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
+ MemoryStreamIn<BinContainer> streamIn(cont);
+ FileOutput streamOut(filepath, zen::FileOutput::ACC_OVERWRITE); //throw FileError, (ErrorTargetExisting)
+ if (onUpdateStatus) onUpdateStatus(0); //throw X!
+ copyStream(streamIn, streamOut, streamOut.optimalBlockSize(), onUpdateStatus); //throw FileError
+}
- if (onUpdateStatus) onUpdateStatus(bytesRead);
- }
- while (!fileIn.eof());
- return contOut;
+template <class BinContainer> inline
+BinContainer loadBinStream(const Zstring& filepath, //throw FileError
+ const std::function<void(std::int64_t bytesDelta)>& onUpdateStatus) //optional
+{
+ FileInput streamIn(filepath); //throw FileError, ErrorFileLocked
+ if (onUpdateStatus) onUpdateStatus(0); //throw X!
+ MemoryStreamOut<BinContainer> streamOut;
+ copyStream(streamIn, streamOut, streamIn.optimalBlockSize(), onUpdateStatus); //throw FileError
+ return streamOut.ref();
}
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)));
+ stream.write(data, len);
}
@@ -219,9 +212,9 @@ void writeContainer(BinOutputStream& stream, const C& cont) //don't even conside
template <class BinInputStream> inline
void readArray(BinInputStream& stream, void* data, size_t len) //throw UnexpectedEndOfStreamError
{
- //expect external write of len bytes:
- const char* const src = static_cast<const char*>(stream.requestRead(len)); //throw UnexpectedEndOfStreamError
- std::copy(src, src + len, static_cast<char*>(data));
+ const size_t bytesRead = stream.read(data, len);
+ if (bytesRead < len)
+ throw UnexpectedEndOfStreamError();
}
bgstack15