hessian2/reader.hpp (76 lines of code) (raw):

#pragma once #include <climits> #include <memory> #include <string> #include "byte_order.h" namespace Hessian2 { class Reader { public: Reader() = default; virtual ~Reader() = default; // Returns the current position that has been read. virtual uint64_t offset() const { return initial_offset_; } // Returns the current entire buffer size, containing the portion that has // been read. virtual uint64_t length() const = 0; // How much buffer is currently unread. virtual uint64_t byteAvailable() const { return length() - offset(); } virtual void rawReadNBytes(void* data, size_t len, size_t offset) = 0; void readNBytes(void* data, size_t len) { rawReadNBytes(data, len, 0); initial_offset_ += len; } template <typename T, ByteOrderType Endianness = ByteOrderType::Host, size_t Size = sizeof(T)> std::pair<bool, typename std::enable_if<std::is_integral<T>::value, T>::type> peek(uint64_t peek_offset = 0) { auto result = static_cast<T>(0); constexpr const auto all_bits_enabled = static_cast<T>(~static_cast<T>(0)); if (byteAvailable() - peek_offset < Size) { return std::pair<bool, T>{false, result}; } constexpr const auto displacement = Endianness == ByteOrderType::BigEndian ? sizeof(T) - Size : 0; int8_t* bytes = reinterpret_cast<int8_t*>(std::addressof(result)); rawReadNBytes(&bytes[displacement], Size, peek_offset); constexpr const auto most_significant_read_byte = Endianness == ByteOrderType::BigEndian ? displacement : Size - 1; // If Size == sizeof(T), we need to make sure we don't generate an invalid // left shift (e.g. int32 << 32), even though we know that that branch of // the conditional will. not be taken. Size % sizeof(T) gives us the correct // left shift when Size < sizeof(T), and generates a left shift of 0 bits // when Size == sizeof(T) const auto sign_extension_bits = std::is_signed<T>::value && Size < sizeof(T) && bytes[most_significant_read_byte] < 0 ? static_cast<T>(static_cast<typename std::make_unsigned<T>::type>( all_bits_enabled) << ((Size % sizeof(T)) * CHAR_BIT)) : static_cast<T>(0); return std::make_pair(true, fromEndian<Endianness>(static_cast<T>(result)) | sign_extension_bits); } template <typename T, ByteOrderType Endianness = ByteOrderType::Host, size_t Size = sizeof(T)> std::pair<bool, typename std::enable_if<std::is_integral<T>::value, T>::type> read() { auto result = peek<T, Endianness, Size>(0); if (result.first) { initial_offset_ += Size; } return result; } template <typename T> std::pair<bool, T> readLE() { return read<T, ByteOrderType::LittleEndian, sizeof(T)>(); } template <typename T> std::pair<bool, T> readBE() { return read<T, ByteOrderType::BigEndian, sizeof(T)>(); } template <typename T> std::pair<bool, T> peekLE(uint64_t peek_offset = 0) { return peek<T, ByteOrderType::LittleEndian, sizeof(T)>(peek_offset); } template <typename T> std::pair<bool, T> peekBE(uint64_t peek_offset = 0) { return peek<T, ByteOrderType::BigEndian, sizeof(T)>(peek_offset); } protected: uint64_t initial_offset_{0}; }; template <> std::pair<bool, uint8_t> Reader::peek<uint8_t>(uint64_t peek_offset); using ReaderPtr = std::unique_ptr<Reader>; } // namespace Hessian2