#pragma once #include #include #include #include #include #include #include #include namespace openpower { namespace pels { namespace detail { /** * @brief A host-to-network implementation for uint64_t * * @param[in] value - the value to convert to * @return uint64_t - the byteswapped value */ inline uint64_t htonll(uint64_t value) { return bswap_64(value); } /** * @brief A network-to-host implementation for uint64_t * * @param[in] value - the value to convert to * @return uint64_t - the byteswapped value */ inline uint64_t ntohll(uint64_t value) { return bswap_64(value); } } // namespace detail /** * @class Stream * * This class is used for getting data types into and out of a vector * that contains data in network byte (big endian) ordering. */ class Stream { public: Stream() = delete; ~Stream() = default; Stream(const Stream&) = default; Stream& operator=(const Stream&) = default; Stream(Stream&&) = default; Stream& operator=(Stream&&) = default; /** * @brief Constructor * * @param[in] data - the vector of data */ explicit Stream(std::vector& data) : _data(data), _offset(0) {} /** * @brief Constructor * * @param[in] data - the vector of data * @param[in] offset - the starting offset */ Stream(std::vector& data, std::size_t offset) : _data(data), _offset(offset) { if (_offset >= _data.size()) { throw std::out_of_range("Offset out of range"); } } /** * @brief Extraction operator for a uint8_t * * @param[out] value - filled in with the value * @return Stream& */ Stream& operator>>(uint8_t& value) { read(&value, 1); return *this; } /** * @brief Extraction operator for a char * * @param[out] value -filled in with the value * @return Stream& */ Stream& operator>>(char& value) { read(&value, 1); return *this; } /** * @brief Extraction operator for a uint16_t * * @param[out] value -filled in with the value * @return Stream& */ Stream& operator>>(uint16_t& value) { read(&value, 2); value = htons(value); return *this; } /** * @brief Extraction operator for a uint32_t * * @param[out] value -filled in with the value * @return Stream& */ Stream& operator>>(uint32_t& value) { read(&value, 4); value = htonl(value); return *this; } /** * @brief Extraction operator for a uint64_t * * @param[out] value -filled in with the value * @return Stream& */ Stream& operator>>(uint64_t& value) { read(&value, 8); value = detail::htonll(value); return *this; } /** * @brief Extraction operator for a std::vector * * The vector's size is the amount extracted. * * @param[out] value - filled in with the value * @return Stream& */ Stream& operator>>(std::vector& value) { if (!value.empty()) { read(value.data(), value.size()); } return *this; } /** * @brief Extraction operator for a std::vector * * The vector's size is the amount extracted. * * @param[out] value - filled in with the value * @return Stream& */ Stream& operator>>(std::vector& value) { if (!value.empty()) { read(value.data(), value.size()); } return *this; } /** * @brief Insert operator for a uint8_t * * @param[in] value - the value to write to the stream * @return Stream& */ Stream& operator<<(uint8_t value) { write(&value, 1); return *this; } /** * @brief Insert operator for a char * * @param[in] value - the value to write to the stream * @return Stream& */ Stream& operator<<(char value) { write(&value, 1); return *this; } /** * @brief Insert operator for a uint16_t * * @param[in] value - the value to write to the stream * @return Stream& */ Stream& operator<<(uint16_t value) { uint16_t data = ntohs(value); write(&data, 2); return *this; } /** * @brief Insert operator for a uint32_t * * @param[in] value - the value to write to the stream * @return Stream& */ Stream& operator<<(uint32_t value) { uint32_t data = ntohl(value); write(&data, 4); return *this; } /** * @brief Insert operator for a uint64_t * * @param[in] value - the value to write to the stream * @return Stream& */ Stream& operator<<(uint64_t value) { uint64_t data = detail::ntohll(value); write(&data, 8); return *this; } /** * @brief Insert operator for a std::vector * * The full vector is written to the stream. * * @param[in] value - the value to write to the stream * @return Stream& */ Stream& operator<<(const std::vector& value) { if (!value.empty()) { write(value.data(), value.size()); } return *this; } /** * @brief Insert operator for a std::vector * * The full vector is written to the stream. * * @param[in] value - the value to write to the stream * @return Stream& */ Stream& operator<<(const std::vector& value) { if (!value.empty()) { write(value.data(), value.size()); } return *this; } /** * @brief Sets the offset of the stream * * @param[in] newOffset - the new offset */ void offset(std::size_t newOffset) { if (newOffset >= _data.size()) { throw std::out_of_range("new offset out of range"); } _offset = newOffset; } /** * @brief Returns the current offset of the stream * * @return size_t - the offset */ std::size_t offset() const { return _offset; } /** * @brief Returns the remaining bytes left between the current offset * and the data size. * * @return size_t - the remaining size */ std::size_t remaining() const { assert(_data.size() >= _offset); return _data.size() - _offset; } /** * @brief Reads a specified number of bytes out of a stream * * @param[out] out - filled in with the data * @param[in] size - the size to read */ void read(void* out, std::size_t size) { rangeCheck(size); memcpy(out, &_data[_offset], size); _offset += size; } /** * @brief Writes a specified number of bytes into the stream * * @param[in] in - the data to write * @param[in] size - the size to write */ void write(const void* in, std::size_t size) { size_t newSize = _offset + size; if (newSize > _data.size()) { _data.resize(newSize, 0); } memcpy(&_data[_offset], in, size); _offset += size; } private: /** * @brief Throws an exception if the size passed in plus the current * offset is bigger than the current data size. * @param[in] size - the size to check */ void rangeCheck(std::size_t size) { if (_offset + size > _data.size()) { std::string msg{"Attempted stream overflow: offset "}; msg += std::to_string(_offset) + " buffer size " + std::to_string(_data.size()) + " op size " + std::to_string(size); throw std::out_of_range(msg.c_str()); } } /** * @brief The data that the stream accesses. */ std::vector& _data; /** * @brief The current offset of the stream. */ std::size_t _offset; }; } // namespace pels } // namespace openpower