#ifndef SPONGE_LIBSPONGE_BUFFER_HH #define SPONGE_LIBSPONGE_BUFFER_HH #include #include #include #include #include #include #include #include #include //! \brief A reference-counted read-only string that can discard bytes from the front class Buffer { private: std::shared_ptr _storage{}; size_t _starting_offset{}; public: Buffer() = default; //! \brief Construct by taking ownership of a string Buffer(std::string &&str) noexcept : _storage(std::make_shared(std::move(str))) {} //! \name Expose contents as a std::string_view //!@{ std::string_view str() const { if (not _storage) { return {}; } return {_storage->data() + _starting_offset, _storage->size() - _starting_offset}; } operator std::string_view() const { return str(); } //!@} //! \brief Get character at location `n` uint8_t at(const size_t n) const { return str().at(n); } //! \brief Size of the string size_t size() const { return str().size(); } //! \brief Make a copy to a new std::string std::string copy() const { return std::string(str()); } //! \brief Discard the first `n` bytes of the string (does not require a copy or move) //! \note Doesn't free any memory until the whole string has been discarded in all copies of the Buffer. void remove_prefix(const size_t n); }; //! \brief A reference-counted discontiguous string that can discard bytes from the front //! \note Used to model packets that contain multiple sets of headers //! + a payload. This allows us to prepend headers (e.g., to //! encapsulate a TCP payload in a TCPSegment, and then encapsulate //! the TCPSegment in an IPv4Datagram) without copying the payload. class BufferList { private: std::deque _buffers{}; public: //! \name Constructors //!@{ BufferList() = default; //! \brief Construct from a Buffer BufferList(Buffer buffer) : _buffers{buffer} {} //! \brief Construct by taking ownership of a std::string BufferList(std::string &&str) noexcept { Buffer buf{std::move(str)}; append(buf); } //!@} //! \brief Access the underlying queue of Buffers const std::deque &buffers() const { return _buffers; } //! \brief Append a BufferList void append(const BufferList &other); //! \brief Transform to a Buffer //! \note Throws an exception unless BufferList is contiguous operator Buffer() const; //! \brief Discard the first `n` bytes of the string (does not require a copy or move) void remove_prefix(size_t n); //! \brief Size of the string size_t size() const; //! \brief Make a copy to a new std::string std::string concatenate() const; }; //! \brief A non-owning temporary view (similar to std::string_view) of a discontiguous string class BufferViewList { std::deque _views{}; public: //! \name Constructors //!@{ //! \brief Construct from a std::string BufferViewList(const std::string &str) : BufferViewList(std::string_view(str)) {} //! \brief Construct from a C string (must be NULL-terminated) BufferViewList(const char *s) : BufferViewList(std::string_view(s)) {} //! \brief Construct from a BufferList BufferViewList(const BufferList &buffers); //! \brief Construct from a std::string_view BufferViewList(std::string_view str) { _views.push_back({const_cast(str.data()), str.size()}); } //!@} //! \brief Discard the first `n` bytes of the string (does not require a copy or move) void remove_prefix(size_t n); //! \brief Size of the string size_t size() const; //! \brief Convert to a vector of `iovec` structures //! \note used for system calls that write discontiguous buffers, //! e.g. [writev(2)](\ref man2::writev) and [sendmsg(2)](\ref man2::sendmsg) std::vector as_iovecs() const; }; #endif // SPONGE_LIBSPONGE_BUFFER_HH