Branch data Line data Source code
1 : : // Copyright 2026 HPActor Contributors
2 : : //
3 : : // Licensed under the Apache License, Version 2.0 (the "License");
4 : : // you may not use this file except in compliance with the License.
5 : : // You may obtain a copy of the License at
6 : : //
7 : : // http://www.apache.org/licenses/LICENSE-2.0
8 : : //
9 : : // Unless required by applicable law or agreed to in writing, software
10 : : // distributed under the License is distributed on an "AS IS" BASIS,
11 : : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : : // See the License for the specific language governing permissions and
13 : : // limitations under the License.
14 : :
15 : : #include <hpactor/adt/stream_buffer.hpp>
16 : :
17 : : #include <algorithm>
18 : : #include <cstring>
19 : :
20 : : namespace hpactor {
21 : : namespace adt {
22 : :
23 : : // ---- Constructors ----
24 : :
25 : 31 : StreamBuffer::StreamBuffer(size_t count)
26 : 62 : : buf_(count, uint8_t{0}), read_pos_(0) {}
27 : :
28 : 1121669 : StreamBuffer::StreamBuffer(std::initializer_list<uint8_t> ilist)
29 : 2243338 : : buf_(ilist), read_pos_(0) {}
30 : :
31 : 0 : StreamBuffer::StreamBuffer(size_t count, uint8_t value)
32 : 0 : : buf_(count, value), read_pos_(0) {}
33 : :
34 : 0 : StreamBuffer StreamBuffer::with_capacity(size_t cap) {
35 : 0 : StreamBuffer sb;
36 : 0 : sb.buf_.reserve(cap);
37 : 0 : return sb;
38 : : }
39 : :
40 : : // ---- Copy ----
41 : :
42 : 254 : StreamBuffer::StreamBuffer(const StreamBuffer& other)
43 : 254 : : buf_(other.buf_), read_pos_(other.read_pos_) {}
44 : :
45 : 42 : StreamBuffer& StreamBuffer::operator=(const StreamBuffer& other) {
46 : 42 : if (this != &other) {
47 : 42 : buf_ = other.buf_;
48 : 42 : read_pos_ = other.read_pos_;
49 : : }
50 : 42 : return *this;
51 : : }
52 : :
53 : : // ---- Capacity ----
54 : :
55 : 85 : void StreamBuffer::reserve(size_t n) {
56 : 85 : if (n > buf_.capacity()) {
57 : 85 : buf_.reserve(n);
58 : : }
59 : 85 : }
60 : :
61 : 3 : void StreamBuffer::resize(size_t n) {
62 : 3 : compact();
63 : 3 : buf_.resize(n);
64 : 3 : }
65 : :
66 : 0 : void StreamBuffer::resize(size_t n, uint8_t value) {
67 : 0 : compact();
68 : 0 : buf_.resize(n, value);
69 : 0 : }
70 : :
71 : : // ---- Reserve + Write (direct I/O) ----
72 : :
73 : 14 : uint8_t* StreamBuffer::reserve_tail(size_t n) {
74 : 14 : ensure_capacity(n);
75 : 14 : size_t old_size = buf_.size();
76 : 14 : buf_.resize(old_size + n);
77 : 14 : reserve_tail_amount_ = n;
78 : 14 : return buf_.data() + old_size;
79 : : }
80 : :
81 : 9 : void StreamBuffer::commit_tail(size_t n) {
82 : 9 : if (reserve_tail_amount_ > 0) {
83 : 9 : if (n < reserve_tail_amount_) {
84 : 9 : buf_.resize(buf_.size() - (reserve_tail_amount_ - n));
85 : : }
86 : 9 : reserve_tail_amount_ = 0;
87 : : } else {
88 : 0 : buf_.resize(buf_.size() + n);
89 : : }
90 : 9 : }
91 : :
92 : : // ---- Append (copy-in) ----
93 : :
94 : 153 : void StreamBuffer::append(const uint8_t* data, size_t len) {
95 : 153 : ensure_capacity(len);
96 : 153 : buf_.insert(buf_.end(), data, data + len);
97 : 153 : }
98 : :
99 : : // ---- Modifiers ----
100 : :
101 : 228 : void StreamBuffer::push_back(uint8_t value) {
102 : 228 : ensure_capacity(1);
103 : 228 : buf_.push_back(value);
104 : 228 : }
105 : :
106 : 0 : void StreamBuffer::assign(size_t count, uint8_t value) {
107 : 0 : clear();
108 : 0 : buf_.assign(count, value);
109 : 0 : }
110 : :
111 : 0 : void StreamBuffer::assign(std::initializer_list<uint8_t> ilist) {
112 : 0 : clear();
113 : 0 : buf_.assign(ilist);
114 : 0 : }
115 : :
116 : 1 : StreamBuffer::iterator StreamBuffer::insert(const_iterator pos,
117 : : std::initializer_list<uint8_t> ilist) {
118 : 1 : size_t offset = static_cast<size_t>(pos - (buf_.data() + read_pos_));
119 : 1 : compact();
120 : 1 : auto it = buf_.insert(buf_.begin() + static_cast<std::ptrdiff_t>(offset), ilist);
121 : 1 : return buf_.data() + static_cast<size_t>(it - buf_.begin());
122 : : }
123 : :
124 : 0 : StreamBuffer::iterator StreamBuffer::erase(const_iterator first, const_iterator last) {
125 : 0 : if (first >= last) return begin();
126 : :
127 : 0 : size_t old_read_pos = read_pos_;
128 : 0 : const uint8_t* logical_begin = buf_.data() + old_read_pos;
129 : 0 : size_t offset_first = static_cast<size_t>(first - logical_begin);
130 : 0 : size_t offset_last = static_cast<size_t>(last - logical_begin);
131 : :
132 : 0 : if (offset_first == 0) {
133 : 0 : consume(offset_last - offset_first);
134 : 0 : return begin();
135 : : }
136 : :
137 : 0 : compact();
138 : 0 : auto it = buf_.erase(buf_.begin() + static_cast<std::ptrdiff_t>(offset_first),
139 : 0 : buf_.begin() + static_cast<std::ptrdiff_t>(offset_last));
140 : 0 : return buf_.data() + static_cast<size_t>(it - buf_.begin());
141 : : }
142 : :
143 : 23 : void StreamBuffer::clear() noexcept {
144 : 23 : buf_.clear();
145 : 23 : read_pos_ = 0;
146 : 23 : }
147 : :
148 : : // ---- Consume ----
149 : :
150 : 8 : void StreamBuffer::consume(size_t n) {
151 : 8 : read_pos_ += n;
152 : 8 : }
153 : :
154 : 45 : void StreamBuffer::compact() {
155 : 45 : if (read_pos_ == 0)
156 : 45 : return;
157 : 0 : size_t readable = buf_.size() - read_pos_;
158 : 0 : if (readable == 0) {
159 : 0 : buf_.clear();
160 : 0 : read_pos_ = 0;
161 : 0 : return;
162 : : }
163 : 0 : std::memmove(buf_.data(), buf_.data() + read_pos_, readable);
164 : 0 : buf_.resize(readable);
165 : 0 : read_pos_ = 0;
166 : : }
167 : :
168 : : // ---- Comparison ----
169 : :
170 : 1 : bool StreamBuffer::operator==(const StreamBuffer& other) const {
171 : 1 : if (size() != other.size()) return false;
172 : 1 : if (size() == 0) return true;
173 : 1 : return std::memcmp(data(), other.data(), size()) == 0;
174 : : }
175 : :
176 : : // ---- Private ----
177 : :
178 : 133 : void StreamBuffer::maybe_compact() {
179 : 133 : if (read_pos_ == 0)
180 : 133 : return;
181 : 0 : size_t readable = buf_.size() - read_pos_;
182 : 0 : if (read_pos_ > readable || read_pos_ > kCompactThreshold) {
183 : 0 : compact();
184 : : }
185 : : }
186 : :
187 : 395 : void StreamBuffer::ensure_capacity(size_t additional_bytes) {
188 : 395 : if (read_pos_ > 0) {
189 : 1 : size_t usable = buf_.capacity() - buf_.size();
190 : 1 : if (usable < additional_bytes) {
191 : 0 : compact();
192 : : }
193 : : }
194 : 395 : size_t usable = buf_.capacity() - buf_.size();
195 : 395 : if (usable < additional_bytes) {
196 : 75 : size_t new_cap = std::max(buf_.capacity() * 2,
197 : 75 : buf_.size() + additional_bytes);
198 : 75 : new_cap = std::max(new_cap, kDefaultInitialCapacity);
199 : 75 : buf_.reserve(new_cap);
200 : : }
201 : 395 : }
202 : :
203 : : } // namespace adt
204 : : } // namespace hpactor
|