blob: 86f3249e1b37579f73006d7f89c2656692131993 [file] [log] [blame]
#ifndef QUICHE_HTTP2_ADAPTER_CHUNKED_BUFFER_H_
#define QUICHE_HTTP2_ADAPTER_CHUNKED_BUFFER_H_
#include <memory>
#include <vector>
#include "absl/strings/string_view.h"
#include "quiche/common/platform/api/quiche_export.h"
#include "quiche/common/quiche_circular_deque.h"
namespace http2 {
namespace adapter {
// A simple buffer class that organizes its memory as a queue of contiguous
// regions. Data is written to the end, and read from the beginning.
class QUICHE_EXPORT ChunkedBuffer {
public:
ChunkedBuffer() = default;
// Appends data to the buffer.
void Append(absl::string_view data);
void Append(std::unique_ptr<char[]> data, size_t size);
// A region of memory into which data may be written by the caller.
class AppendRegion {
public:
// Data may be written here.
char* data;
// At most `size` bytes may be written at the address in `data`.
const size_t size;
// Once bytes are written to `data`, this member should be updated.
size_t written;
// Updates the state in `parent` once the write operation is complete.
~AppendRegion();
private:
friend class ChunkedBuffer;
AppendRegion(char* d, size_t s, size_t w, ChunkedBuffer* p)
: data(d), size(s), written(w), parent(p) {}
ChunkedBuffer* const parent;
};
AppendRegion GetAppendRegion();
// Reads data from the buffer non-destructively.
absl::string_view GetPrefix() const;
std::vector<absl::string_view> Read() const;
// Removes the first `n` bytes of the buffer. Invalidates any `string_view`s
// read from the buffer.
void RemovePrefix(size_t n);
// Returns true iff the buffer contains no data to read.
bool Empty() const;
size_t TotalSize() const { return total_size_; }
private:
static constexpr size_t kDefaultChunkSize = 1024;
// Describes a contiguous region of memory contained in the ChunkedBuffer. In
// the common case, data is appended to the buffer by copying it to the final
// chunk, or adding a unique_ptr to the list of chunks. Data is consumed from
// the beginning of the buffer, so the first chunk may have a nonzero offset
// from the start of the memory region to the first byte of readable data.
struct Chunk {
// A contiguous region of memory.
std::unique_ptr<char[]> data;
// The size of the contiguous memory.
const size_t size;
// The region occupied by live data that can be read from the buffer. A
// subset of `data`.
absl::string_view live;
void RemovePrefix(size_t n);
void AppendSuffix(absl::string_view to_append);
bool Empty() const { return live.empty(); }
// Returns the offset of the live data from the beginning of the chunk.
size_t LiveDataOffset() const { return live.data() - data.get(); }
// Returns the size of the free space at the end of the chunk.
size_t TailBytesFree() const {
return size - live.size() - LiveDataOffset();
}
};
// Returns the number of tail bytes free in the last chunk in the buffer, or
// zero.
size_t TailBytesFree() const;
// Ensures that the last chunk in the buffer has at least this many tail bytes
// free.
void EnsureTailBytesFree(size_t n);
// Removes the first chunk, unless it is the last chunk in the buffer and its
// size is kDefaultChunkSize.
void TrimFirstChunk();
quiche::QuicheCircularDeque<Chunk> chunks_;
size_t total_size_ = 0;
};
} // namespace adapter
} // namespace http2
#endif // QUICHE_HTTP2_ADAPTER_CHUNKED_BUFFER_H_