xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/balsa/simple_buffer.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 
5 #include "quiche/balsa/simple_buffer.h"
6 
7 #include <algorithm>
8 #include <cstring>
9 #include <memory>
10 
11 #include "quiche/common/platform/api/quiche_bug_tracker.h"
12 #include "quiche/common/platform/api/quiche_logging.h"
13 
14 namespace quiche {
15 
16 constexpr int kMinimumSimpleBufferSize = 10;
17 
SimpleBuffer(int size)18 SimpleBuffer::SimpleBuffer(int size) { Reserve(size); }
19 
20 ////////////////////////////////////////////////////////////////////////////////
21 
Write(const char * bytes,int size)22 int SimpleBuffer::Write(const char* bytes, int size) {
23   if (size <= 0) {
24     QUICHE_BUG_IF(simple_buffer_write_negative_size, size < 0)
25         << "size must not be negative: " << size;
26     return 0;
27   }
28 
29   Reserve(size);
30   memcpy(storage_ + write_idx_, bytes, size);
31   AdvanceWritablePtr(size);
32   return size;
33 }
34 
35 ////////////////////////////////////////////////////////////////////////////////
36 
Read(char * bytes,int size)37 int SimpleBuffer::Read(char* bytes, int size) {
38   if (size < 0) {
39     QUICHE_BUG(simple_buffer_read_negative_size)
40         << "size must not be negative: " << size;
41     return 0;
42   }
43 
44   char* read_ptr = nullptr;
45   int read_size = 0;
46   GetReadablePtr(&read_ptr, &read_size);
47   read_size = std::min(read_size, size);
48   if (read_size == 0) {
49     return 0;
50   }
51 
52   memcpy(bytes, read_ptr, read_size);
53   AdvanceReadablePtr(read_size);
54   return read_size;
55 }
56 
57 ////////////////////////////////////////////////////////////////////////////////
58 
59 // Attempts to reserve a contiguous block of buffer space either by reclaiming
60 // consumed data or by allocating a larger buffer.
Reserve(int size)61 void SimpleBuffer::Reserve(int size) {
62   if (size < 0) {
63     QUICHE_BUG(simple_buffer_reserve_negative_size)
64         << "size must not be negative: " << size;
65     return;
66   }
67 
68   if (size == 0 || storage_size_ - write_idx_ >= size) {
69     return;
70   }
71 
72   char* read_ptr = nullptr;
73   int read_size = 0;
74   GetReadablePtr(&read_ptr, &read_size);
75 
76   if (read_ptr == nullptr) {
77     QUICHE_DCHECK_EQ(0, read_size);
78 
79     size = std::max(size, kMinimumSimpleBufferSize);
80     storage_ = new char[size];
81     storage_size_ = size;
82     return;
83   }
84 
85   if (read_size + size <= storage_size_) {
86     // Can reclaim space from consumed bytes by shifting.
87     memmove(storage_, read_ptr, read_size);
88     read_idx_ = 0;
89     write_idx_ = read_size;
90     return;
91   }
92 
93   // The new buffer needs to be at least `read_size + size` bytes.
94   // At least double the buffer to amortize allocation costs.
95   storage_size_ = std::max(2 * storage_size_, size + read_size);
96 
97   char* new_storage = new char[storage_size_];
98   memcpy(new_storage, read_ptr, read_size);
99   delete[] storage_;
100 
101   read_idx_ = 0;
102   write_idx_ = read_size;
103   storage_ = new_storage;
104 }
105 
AdvanceReadablePtr(int amount_to_advance)106 void SimpleBuffer::AdvanceReadablePtr(int amount_to_advance) {
107   if (amount_to_advance < 0) {
108     QUICHE_BUG(simple_buffer_advance_read_negative_arg)
109         << "amount_to_advance must not be negative: " << amount_to_advance;
110     return;
111   }
112 
113   read_idx_ += amount_to_advance;
114   if (read_idx_ > write_idx_) {
115     QUICHE_BUG(simple_buffer_read_ptr_too_far)
116         << "error: readable pointer advanced beyond writable one";
117     read_idx_ = write_idx_;
118   }
119 
120   if (read_idx_ == write_idx_) {
121     // Buffer is empty, rewind `read_idx_` and `write_idx_` so that next write
122     // happens at the beginning of buffer instead of cutting free space in two.
123     Clear();
124   }
125 }
126 
AdvanceWritablePtr(int amount_to_advance)127 void SimpleBuffer::AdvanceWritablePtr(int amount_to_advance) {
128   if (amount_to_advance < 0) {
129     QUICHE_BUG(simple_buffer_advance_write_negative_arg)
130         << "amount_to_advance must not be negative: " << amount_to_advance;
131     return;
132   }
133 
134   write_idx_ += amount_to_advance;
135   if (write_idx_ > storage_size_) {
136     QUICHE_BUG(simple_buffer_write_ptr_too_far)
137         << "error: writable pointer advanced beyond end of storage";
138     write_idx_ = storage_size_;
139   }
140 }
141 
Release()142 SimpleBuffer::ReleasedBuffer SimpleBuffer::Release() {
143   if (write_idx_ == 0) {
144     return ReleasedBuffer{nullptr, 0};
145   }
146   ReleasedBuffer buffer{std::unique_ptr<char[]>(storage_),
147                         static_cast<size_t>(write_idx_)};
148   Clear();
149   storage_ = nullptr;
150   storage_size_ = 0;
151   return buffer;
152 }
153 }  // namespace quiche
154