diff options
Diffstat (limited to 'src/serialization/binary_archive.h')
-rw-r--r-- | src/serialization/binary_archive.h | 90 |
1 files changed, 46 insertions, 44 deletions
diff --git a/src/serialization/binary_archive.h b/src/serialization/binary_archive.h index 49ca8aa57..acda70039 100644 --- a/src/serialization/binary_archive.h +++ b/src/serialization/binary_archive.h @@ -36,9 +36,11 @@ #include <cassert> #include <iostream> #include <iterator> +#include <boost/endian/conversion.hpp> #include <boost/type_traits/make_unsigned.hpp> #include "common/varint.h" +#include "span.h" #include "warnings.h" /* I have no clue what these lines means */ @@ -55,16 +57,15 @@ DISABLE_VS_WARNINGS(4244) * purpse is to define the functions used for the binary_archive. Its * a header, basically. I think it was declared simply to save typing... */ -template <class Stream, bool IsSaving> +template <bool IsSaving> struct binary_archive_base { - typedef Stream stream_type; - typedef binary_archive_base<Stream, IsSaving> base_type; + typedef binary_archive_base<IsSaving> base_type; typedef boost::mpl::bool_<IsSaving> is_saving; typedef uint8_t variant_tag_type; - explicit binary_archive_base(stream_type &s) : stream_(s) { } + explicit binary_archive_base() { } /* definition of standard API functions */ void tag(const char *) { } @@ -72,12 +73,6 @@ struct binary_archive_base void end_object() { } void begin_variant() { } void end_variant() { } - /* I just want to leave a comment saying how this line really shows - flaws in the ownership model of many OOP languages, that is all. */ - stream_type &stream() { return stream_; } - -protected: - stream_type &stream_; }; /* \struct binary_archive @@ -95,15 +90,18 @@ struct binary_archive; template <> -struct binary_archive<false> : public binary_archive_base<std::istream, false> +struct binary_archive<false> : public binary_archive_base<false> { + explicit binary_archive(epee::span<const std::uint8_t> s) + : base_type(), bytes_(s), begin_(s.begin()), good_(true), varint_bug_backward_compatibility_(false) + {} - explicit binary_archive(stream_type &s) : base_type(s), varint_bug_backward_compatibility_(false) { - stream_type::pos_type pos = stream_.tellg(); - stream_.seekg(0, std::ios_base::end); - eof_pos_ = stream_.tellg(); - stream_.seekg(pos); - } + bool good() const noexcept { return good_; } + void set_fail() noexcept { good_ = false; } + + //! If implementing as `std::istream`, reset stream error state after `peek()` call. + bool eof() const noexcept { return bytes_.empty(); } + std::size_t getpos() const noexcept { return bytes_.begin() - begin_; } template <class T> void serialize_int(T &v) @@ -116,24 +114,24 @@ struct binary_archive<false> : public binary_archive_base<std::istream, false> * \brief serializes an unsigned integer */ template <class T> - void serialize_uint(T &v, size_t width = sizeof(T)) + void serialize_uint(T &v) { - T ret = 0; - unsigned shift = 0; - for (size_t i = 0; i < width; i++) { - //std::cerr << "tell: " << stream_.tellg() << " value: " << ret << std::endl; - char c; - stream_.get(c); - T b = (unsigned char)c; - ret += (b << shift); // can this be changed to OR, i think it can. - shift += 8; + const std::size_t actual = bytes_.remove_prefix(sizeof(T)); + good_ &= (actual == sizeof(T)); + if (actual == sizeof(T)) + { + std::memcpy(std::addressof(v), bytes_.data() - sizeof(T), sizeof(T)); + boost::endian::little_to_native_inplace(v); // epee isn't templated } - v = ret; + else + v = 0; // ensures initialization } void serialize_blob(void *buf, size_t len, const char *delimiter="") { - stream_.read((char *)buf, len); + const std::size_t actual = bytes_.remove_prefix(len); + good_ &= (len == actual); + std::memcpy(buf, bytes_.data() - actual, actual); } template <class T> @@ -145,9 +143,11 @@ struct binary_archive<false> : public binary_archive_base<std::istream, false> template <class T> void serialize_uvarint(T &v) { - typedef std::istreambuf_iterator<char> it; - if (tools::read_varint(it(stream_), it(), v) < 0) - stream_.setstate(std::ios_base::failbit); + auto current = bytes_.cbegin(); + auto end = bytes_.cend(); + good_ &= (0 <= tools::read_varint(current, end, v)); + current = std::min(current, bytes_.cend()); + bytes_ = {current, std::size_t(bytes_.cend() - current)}; } void begin_array(size_t &s) @@ -166,26 +166,26 @@ struct binary_archive<false> : public binary_archive_base<std::istream, false> serialize_int(t); } - size_t remaining_bytes() { - if (!stream_.good()) - return 0; - //std::cerr << "tell: " << stream_.tellg() << std::endl; - assert(stream_.tellg() <= eof_pos_); - return eof_pos_ - stream_.tellg(); - } - + size_t remaining_bytes() const noexcept { return good() ? bytes_.size() : 0; } void enable_varint_bug_backward_compatibility() { varint_bug_backward_compatibility_ = true; } bool varint_bug_backward_compatibility_enabled() const { return varint_bug_backward_compatibility_; } - protected: - std::streamoff eof_pos_; + epee::span<const std::uint8_t> bytes_; + std::uint8_t const* const begin_; + bool good_; bool varint_bug_backward_compatibility_; }; template <> -struct binary_archive<true> : public binary_archive_base<std::ostream, true> +struct binary_archive<true> : public binary_archive_base<true> { - explicit binary_archive(stream_type &s) : base_type(s) { } + typedef std::ostream stream_type; + explicit binary_archive(stream_type &s) : base_type(), stream_(s) { } + + bool good() const { return stream_.good(); } + void set_fail() { stream_.setstate(std::ios::failbit); } + + std::streampos getpos() const { return stream_.tellp(); } template <class T> void serialize_int(T v) @@ -234,6 +234,8 @@ struct binary_archive<true> : public binary_archive_base<std::ostream, true> } bool varint_bug_backward_compatibility_enabled() const { return false; } +protected: + stream_type& stream_; }; POP_WARNINGS |