#ifndef BYTE_BUFFER_H #define BYTE_BUFFER_H #include #include #include namespace FLOAT { static const uint32_t positive_infinity = 0x007FFFFE; static const uint32_t negative_infinity = 0x00800002; static const uint32_t NaN = 0x007FFFFF; static const uint32_t NRes = 0x00800000; static const uint32_t FLAOT_reserved_value = 0x00800001; // (2^23 - 3) * 10^127 static const double max = 8.388604999999999e+133; static const double min = -max; static const double mantissa_max = 0x007FFFFD; static const double exponent_max = 127; static const double exponent_min = -128; // 10^-128 static const double epsilon = 1e-128; // 10^upper(23 * log(2) / log(10)) static const double precision = 10000000; } class ByteBufferException : public std::runtime_error { public: explicit ByteBufferException(std::string const &what) : std::runtime_error(what) {} }; class ByteBuffer { public: ByteBuffer() noexcept : zero(nullptr), end_(nullptr), cursor(nullptr) {}; template constexpr explicit ByteBuffer(uint8_t (&bytes)[N]) noexcept : zero(bytes), end_(&bytes[N]), cursor(zero) {}; ByteBuffer(uint8_t *bytes, size_t size) noexcept : zero(bytes), end_(&bytes[size]), cursor(zero) {}; ByteBuffer(uint8_t *bytes, size_t size, size_t position) : zero(bytes), end_(&bytes[size]), cursor(zero) { setCursor(position); }; template static const ByteBuffer wrapInitialized(const uint8_t (&bytes)[N], size_t cursor = 0) noexcept { return wrap(bytes, N, N); }; static const ByteBuffer wrap(const uint8_t *bytes, size_t size, size_t cursor = 0) noexcept; inline size_t getSize() const { return end_ - zero; } inline size_t getPosition() const { return cursor - zero; } inline size_t getBytesLeft() const { return end_ - cursor; } inline ByteBuffer &setCursor(size_t newCursor) { auto tmp = &zero[newCursor]; assertCanAccessPtr(tmp); cursor = tmp; return *this; } inline void skip(size_t length) { cursor += length; } inline const uint8_t *cbegin() const { return zero; } inline const uint8_t *cend() const { return end_; } inline uint8_t *underlying() { return const_cast(zero); } inline uint8_t *end() const { return const_cast(cend()); } ByteBuffer &write8(uint8_t value); ByteBuffer &write16le(uint16_t value); ByteBuffer &write32le(uint32_t value); /** * Appends the entire buffer. Make a view if you want to write a part of it. */ ByteBuffer &write(const ByteBuffer &value); ByteBuffer &write(const uint8_t *bytes, size_t len); ByteBuffer &writeFLOAT(double d); /** * Reads a uint8_t from the start of the buffer. */ uint8_t get8(size_t index) const; /** * Reads a uint8_t relative to the cursor. */ uint8_t peek8(size_t relative_index) const; uint8_t read8(); uint16_t read16le(); uint32_t read32le(); /** * IEEE-11073 32-bit FLOAT */ double readFLOAT(); void copyFromEntire(const ByteBuffer &other) const; void copyTo(uint8_t *bytes, size_t length) const; ByteBuffer viewCursorToEnd() const; ByteBuffer viewBeginningToCursor() const; /** * Creates a view from cursor to cursor + length. */ ByteBuffer viewForward(size_t length) const; /** * Creates a view from cursor to cursor + length and then moves the cursor length further. */ ByteBuffer viewForwardAndSkip(size_t length); std::string toString() const; void assertCanAccessPosition(size_t position) const; void assertCanAccessPtr(uint8_t* ptr) const; protected: uint8_t *zero, *end_, *cursor; }; template class StaticByteBuffer : public ByteBuffer { public: StaticByteBuffer() : ByteBuffer(raw) {} private: uint8_t raw[N] = {}; }; #endif