CS144Lab/libsponge/util/buffer.hh
2021-09-21 17:11:37 -07:00

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