blob: 8a15c2f3c5355b6b1ade062440f8d840a97e8af5 [file] [log] [blame]
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef QUICHE_BALSA_SIMPLE_BUFFER_H_
#define QUICHE_BALSA_SIMPLE_BUFFER_H_
#include <cstddef>
#include <memory>
#include "absl/strings/string_view.h"
#include "quiche/common/platform/api/quiche_export.h"
namespace quiche {
namespace test {
class SimpleBufferTest;
} // namespace test
// SimpleBuffer stores data in a contiguous region. It can grow on demand,
// which involves moving its data. It keeps track of a read and a write
// position. Reading consumes data.
class QUICHE_EXPORT SimpleBuffer {
public:
struct ReleasedBuffer {
std::unique_ptr<char[]> buffer;
size_t size;
};
SimpleBuffer() = default;
// Create SimpleBuffer with at least `size` reserved capacity.
explicit SimpleBuffer(int size);
SimpleBuffer(const SimpleBuffer&) = delete;
SimpleBuffer& operator=(const SimpleBuffer&) = delete;
virtual ~SimpleBuffer() { delete[] storage_; }
// Returns the number of bytes that can be read from the buffer.
int ReadableBytes() const { return write_idx_ - read_idx_; }
bool Empty() const { return read_idx_ == write_idx_; }
// Copies `size` bytes to the buffer. Returns size.
int Write(const char* bytes, int size);
int WriteString(absl::string_view piece) {
return Write(piece.data(), piece.size());
}
// Stores the pointer into the buffer that can be written to in `*ptr`, and
// the number of characters that are allowed to be written in `*size`. The
// pointer and size can be used in functions like recv() or read(). If
// `*size` is zero upon returning from this function, then it is unsafe to
// dereference `*ptr`. Writing to this region after calling any other
// non-const method results in undefined behavior.
void GetWritablePtr(char** ptr, int* size) const {
*ptr = storage_ + write_idx_;
*size = storage_size_ - write_idx_;
}
// Stores the pointer that can be read from in `*ptr`, and the number of bytes
// that are allowed to be read in `*size`. The pointer and size can be used
// in functions like send() or write(). If `*size` is zero upon returning
// from this function, then it is unsafe to dereference `*ptr`. Reading from
// this region after calling any other non-const method results in undefined
// behavior.
void GetReadablePtr(char** ptr, int* size) const {
*ptr = storage_ + read_idx_;
*size = write_idx_ - read_idx_;
}
// Returns the readable region as a string_view. Reading from this region
// after calling any other non-const method results in undefined behavior.
absl::string_view GetReadableRegion() const {
return absl::string_view(storage_ + read_idx_, write_idx_ - read_idx_);
}
// Reads bytes out of the buffer, and writes them into `bytes`. Returns the
// number of bytes read. Consumes bytes from the buffer.
int Read(char* bytes, int size);
// Marks all data consumed, making the entire reserved buffer available for
// write. Does not resize or free up any memory.
void Clear() { read_idx_ = write_idx_ = 0; }
// Makes sure at least `size` bytes can be written into the buffer. This can
// be an expensive operation: costing a new and a delete, and copying of all
// existing data. Even if the existing buffer does not need to be resized,
// unread data may need to be moved to consolidate fragmented free space.
void Reserve(int size);
// Marks the oldest `amount_to_advance` bytes as consumed.
// `amount_to_advance` must not be negative and it must not exceed
// ReadableBytes().
void AdvanceReadablePtr(int amount_to_advance);
// Marks the first `amount_to_advance` bytes of the writable area written.
// `amount_to_advance` must not be negative and it must not exceed the size of
// the writable area, returned as the `size` outparam of GetWritablePtr().
void AdvanceWritablePtr(int amount_to_advance);
// Releases the current contents of the SimpleBuffer and returns them as a
// unique_ptr<char[]>. Logically, has the same effect as calling Clear().
ReleasedBuffer Release();
private:
friend class test::SimpleBufferTest;
// The buffer owned by this class starts at `*storage_` and is `storage_size_`
// bytes long.
// If `storage_` is nullptr, then `storage_size_` must be zero.
// `0 <= read_idx_ <= write_idx_ <= storage_size_` must always hold.
// If `read_idx_ == write_idx_`, then they must be equal to zero.
// The first `read_idx_` bytes of the buffer are consumed,
// the next `write_idx_ - read_idx_` bytes are the readable region, and the
// remaining `storage_size_ - write_idx_` bytes are the writable region.
char* storage_ = nullptr;
int write_idx_ = 0;
int read_idx_ = 0;
int storage_size_ = 0;
};
} // namespace quiche
#endif // QUICHE_BALSA_SIMPLE_BUFFER_H_