QUICHE team | d7a507e | 2022-04-15 14:35:46 -0700 | [diff] [blame] | 1 | // Copyright 2022 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
bnc | 30bbde7 | 2022-05-12 06:41:23 -0700 | [diff] [blame] | 5 | #ifndef QUICHE_BALSA_SIMPLE_BUFFER_H_ |
| 6 | #define QUICHE_BALSA_SIMPLE_BUFFER_H_ |
QUICHE team | d7a507e | 2022-04-15 14:35:46 -0700 | [diff] [blame] | 7 | |
| 8 | #include "absl/strings/string_view.h" |
| 9 | #include "quiche/common/platform/api/quiche_export.h" |
| 10 | #include "quiche/common/platform/api/quiche_mem_slice.h" |
| 11 | |
| 12 | namespace quiche { |
| 13 | |
| 14 | namespace test { |
| 15 | class SimpleBufferTest; |
| 16 | } // namespace test |
| 17 | |
| 18 | // SimpleBuffer stores data in a contiguous region. It can grow on demand, |
| 19 | // which involves moving its data. It keeps track of a read and a write |
| 20 | // position. Reading consumes data. |
vasilvv | e124b7b | 2022-10-21 10:09:44 -0700 | [diff] [blame] | 21 | class QUICHE_EXPORT SimpleBuffer { |
QUICHE team | d7a507e | 2022-04-15 14:35:46 -0700 | [diff] [blame] | 22 | public: |
bnc | 53020a5 | 2022-05-16 12:35:34 -0700 | [diff] [blame] | 23 | SimpleBuffer() = default; |
| 24 | // Create SimpleBuffer with at least `size` reserved capacity. |
QUICHE team | d7a507e | 2022-04-15 14:35:46 -0700 | [diff] [blame] | 25 | explicit SimpleBuffer(int size); |
| 26 | |
| 27 | SimpleBuffer(const SimpleBuffer&) = delete; |
| 28 | SimpleBuffer& operator=(const SimpleBuffer&) = delete; |
| 29 | |
| 30 | virtual ~SimpleBuffer() { delete[] storage_; } |
| 31 | |
| 32 | // Returns the number of bytes that can be read from the buffer. |
| 33 | int ReadableBytes() const { return write_idx_ - read_idx_; } |
| 34 | |
| 35 | bool Empty() const { return read_idx_ == write_idx_; } |
| 36 | |
| 37 | // Copies `size` bytes to the buffer. Returns size. |
| 38 | int Write(const char* bytes, int size); |
| 39 | int WriteString(absl::string_view piece) { |
| 40 | return Write(piece.data(), piece.size()); |
| 41 | } |
| 42 | |
bnc | 53020a5 | 2022-05-16 12:35:34 -0700 | [diff] [blame] | 43 | // Stores the pointer into the buffer that can be written to in `*ptr`, and |
| 44 | // the number of characters that are allowed to be written in `*size`. The |
| 45 | // pointer and size can be used in functions like recv() or read(). If |
| 46 | // `*size` is zero upon returning from this function, then it is unsafe to |
| 47 | // dereference `*ptr`. Writing to this region after calling any other |
| 48 | // non-const method results in undefined behavior. |
QUICHE team | d7a507e | 2022-04-15 14:35:46 -0700 | [diff] [blame] | 49 | void GetWritablePtr(char** ptr, int* size) const { |
| 50 | *ptr = storage_ + write_idx_; |
| 51 | *size = storage_size_ - write_idx_; |
| 52 | } |
| 53 | |
bnc | 53020a5 | 2022-05-16 12:35:34 -0700 | [diff] [blame] | 54 | // Stores the pointer that can be read from in `*ptr`, and the number of bytes |
| 55 | // that are allowed to be read in `*size`. The pointer and size can be used |
QUICHE team | d7a507e | 2022-04-15 14:35:46 -0700 | [diff] [blame] | 56 | // in functions like send() or write(). If `*size` is zero upon returning |
| 57 | // from this function, then it is unsafe to dereference `*ptr`. Reading from |
| 58 | // this region after calling any other non-const method results in undefined |
| 59 | // behavior. |
| 60 | void GetReadablePtr(char** ptr, int* size) const { |
| 61 | *ptr = storage_ + read_idx_; |
| 62 | *size = write_idx_ - read_idx_; |
| 63 | } |
| 64 | |
| 65 | // Returns the readable region as a string_view. Reading from this region |
| 66 | // after calling any other non-const method results in undefined behavior. |
| 67 | absl::string_view GetReadableRegion() const { |
| 68 | return absl::string_view(storage_ + read_idx_, write_idx_ - read_idx_); |
| 69 | } |
| 70 | |
| 71 | // Reads bytes out of the buffer, and writes them into `bytes`. Returns the |
| 72 | // number of bytes read. Consumes bytes from the buffer. |
| 73 | int Read(char* bytes, int size); |
| 74 | |
| 75 | // Marks all data consumed, making the entire reserved buffer available for |
| 76 | // write. Does not resize or free up any memory. |
| 77 | void Clear() { read_idx_ = write_idx_ = 0; } |
| 78 | |
| 79 | // Makes sure at least `size` bytes can be written into the buffer. This can |
| 80 | // be an expensive operation: costing a new and a delete, and copying of all |
| 81 | // existing data. Even if the existing buffer does not need to be resized, |
| 82 | // unread data may need to be moved to consolidate fragmented free space. |
| 83 | void Reserve(int size); |
| 84 | |
| 85 | // Marks the oldest `amount_to_advance` bytes as consumed. |
| 86 | // `amount_to_advance` must not be negative and it must not exceed |
| 87 | // ReadableBytes(). |
| 88 | void AdvanceReadablePtr(int amount_to_advance); |
| 89 | |
| 90 | // Marks the first `amount_to_advance` bytes of the writable area written. |
| 91 | // `amount_to_advance` must not be negative and it must not exceed the size of |
| 92 | // the writable area, returned as the `size` outparam of GetWritablePtr(). |
| 93 | void AdvanceWritablePtr(int amount_to_advance); |
| 94 | |
| 95 | // Releases the current contents of the SimpleBuffer and returns them as a |
| 96 | // MemSlice. Logically, has the same effect as calling Clear(). |
| 97 | QuicheMemSlice ReleaseAsSlice(); |
| 98 | |
| 99 | private: |
| 100 | friend class test::SimpleBufferTest; |
| 101 | |
| 102 | // The buffer owned by this class starts at `*storage_` and is `storage_size_` |
| 103 | // bytes long. |
bnc | 53020a5 | 2022-05-16 12:35:34 -0700 | [diff] [blame] | 104 | // If `storage_` is nullptr, then `storage_size_` must be zero. |
QUICHE team | d7a507e | 2022-04-15 14:35:46 -0700 | [diff] [blame] | 105 | // `0 <= read_idx_ <= write_idx_ <= storage_size_` must always hold. |
| 106 | // If `read_idx_ == write_idx_`, then they must be equal to zero. |
| 107 | // The first `read_idx_` bytes of the buffer are consumed, |
| 108 | // the next `write_idx_ - read_idx_` bytes are the readable region, and the |
| 109 | // remaining `storage_size_ - write_idx_` bytes are the writable region. |
bnc | 53020a5 | 2022-05-16 12:35:34 -0700 | [diff] [blame] | 110 | char* storage_ = nullptr; |
| 111 | int write_idx_ = 0; |
| 112 | int read_idx_ = 0; |
| 113 | int storage_size_ = 0; |
QUICHE team | d7a507e | 2022-04-15 14:35:46 -0700 | [diff] [blame] | 114 | }; |
| 115 | |
| 116 | } // namespace quiche |
| 117 | |
bnc | 30bbde7 | 2022-05-12 06:41:23 -0700 | [diff] [blame] | 118 | #endif // QUICHE_BALSA_SIMPLE_BUFFER_H_ |