131 lines
4.0 KiB
C++
131 lines
4.0 KiB
C++
#ifndef SPONGE_LIBSPONGE_BUFFER_HH
|
|
#define SPONGE_LIBSPONGE_BUFFER_HH
|
|
|
|
#include <algorithm>
|
|
#include <deque>
|
|
#include <memory>
|
|
#include <numeric>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <sys/uio.h>
|
|
#include <vector>
|
|
|
|
//! \brief A reference-counted read-only string that can discard bytes from the front
|
|
class Buffer {
|
|
private:
|
|
std::shared_ptr<std::string> _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::string>(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<Buffer> _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<Buffer> &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<std::string_view> _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<char *>(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<iovec> as_iovecs() const;
|
|
};
|
|
|
|
#endif // SPONGE_LIBSPONGE_BUFFER_HH
|