summaryrefslogtreecommitdiffstats
path: root/extensions/openpower-pels/stream.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/openpower-pels/stream.hpp')
-rw-r--r--extensions/openpower-pels/stream.hpp373
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
OpenPOWER on IntegriCloud