diff options
Diffstat (limited to 'extensions/openpower-pels/stream.hpp')
-rw-r--r-- | extensions/openpower-pels/stream.hpp | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/extensions/openpower-pels/stream.hpp b/extensions/openpower-pels/stream.hpp new file mode 100644 index 0000000..1a776f6 --- /dev/null +++ b/extensions/openpower-pels/stream.hpp @@ -0,0 +1,373 @@ +#pragma once + +#include <arpa/inet.h> +#include <byteswap.h> + +#include <cassert> +#include <cstring> +#include <memory> +#include <string> +#include <vector> + +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<uint8_t> + * 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<uint8_t>& data) : _data(data), _offset(0) + { + } + + /** + * @brief Constructor + * + * @param[in] data - the vector of data + * @param[in] offset - the starting offset + */ + Stream(std::vector<uint8_t>& 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<uint8_t> + * + * The vector's size is the amount extracted. + * + * @param[out] value - filled in with the value + * @return Stream& + */ + Stream& operator>>(std::vector<uint8_t>& value) + { + if (!value.empty()) + { + read(value.data(), value.size()); + } + return *this; + } + + /** + * @brief Extraction operator for a std::vector<char> + * + * The vector's size is the amount extracted. + * + * @param[out] value - filled in with the value + * @return Stream& + */ + Stream& operator>>(std::vector<char>& 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<uint8_t> + * + * 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<uint8_t>& value) + { + if (!value.empty()) + { + write(value.data(), value.size()); + } + return *this; + } + + /** + * @brief Insert operator for a std::vector<char> + * + * 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<char>& 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<uint8_t>& _data; + + /** + * @brief The current offset of the stream. + */ + std::size_t _offset; +}; + +} // namespace pels +} // namespace openpower |