blob: d669899d2ccd35a91c9abe33946a1c3222a9641b [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 "absl/strings/string_view.h"
#include "quiche/common/platform/api/quiche_export.h"
#include "quiche/common/platform/api/quiche_mem_slice.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_PRIVATE SimpleBuffer {
public:
SimpleBuffer();
// Create SimpleBuffer with `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());
}
// Gets a pointer into the buffer that can be written to. Stores the number
// of characters which 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_;
}
// Gets a pointer that can be read from. This 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
// MemSlice. Logically, has the same effect as calling Clear().
QuicheMemSlice ReleaseAsSlice();
private:
friend class test::SimpleBufferTest;
// The buffer owned by this class starts at `*storage_` and is `storage_size_`
// bytes long.
// `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_;
int write_idx_;
int read_idx_;
int storage_size_;
};
} // namespace quiche
#endif // QUICHE_BALSA_SIMPLE_BUFFER_H_