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 : : #pragma once
16 : :
17 : : #include <cstddef>
18 : : #include <cstdint>
19 : : #include <initializer_list>
20 : : #include <type_traits>
21 : : #include <vector>
22 : :
23 : : namespace hpactor {
24 : : namespace adt {
25 : :
26 : : // StreamBuffer — contiguous byte buffer with O(1) consume and arena allocation.
27 : : //
28 : : // Combines ring-buffer semantics (read_pos_ offset tracks consumed prefix,
29 : : // consume() only advances a pointer) with pre-allocated arena backing
30 : : // (geometric growth from an initial capacity). Lazy compaction means
31 : : // memmove is amortized to near-zero: it only triggers when read_pos_ exceeds
32 : : // half the live data, or when capacity must grow.
33 : : //
34 : : // Provides a std::vector<uint8_t>-compatible API so it can serve as the
35 : : // concrete type behind the `bytes` typedef.
36 : : class StreamBuffer {
37 : : public:
38 : : using value_type = uint8_t;
39 : : using size_type = std::size_t;
40 : : using difference_type = std::ptrdiff_t;
41 : : using reference = uint8_t&;
42 : : using const_reference = const uint8_t&;
43 : : using pointer = uint8_t*;
44 : : using const_pointer = const uint8_t*;
45 : : using iterator = pointer;
46 : : using const_iterator = const_pointer;
47 : :
48 : : static constexpr size_t kDefaultInitialCapacity = 65536;
49 : : static constexpr size_t kCompactThreshold = 65536;
50 : :
51 : : // ---- Constructors ----
52 : :
53 : 988 : StreamBuffer() = default;
54 : :
55 : : // Create a buffer with count zero-initialized bytes (matches std::vector).
56 : : explicit StreamBuffer(size_t count);
57 : :
58 : : StreamBuffer(std::initializer_list<uint8_t> ilist);
59 : : StreamBuffer(size_t count, uint8_t value);
60 : :
61 : : template <typename InputIt, typename = std::enable_if_t<!std::is_integral_v<InputIt>>>
62 : : StreamBuffer(InputIt first, InputIt last);
63 : :
64 : 3248672 : ~StreamBuffer() = default;
65 : :
66 : : // Create a buffer with pre-allocated capacity but size() == 0.
67 : : static StreamBuffer with_capacity(size_t cap);
68 : :
69 : : // ---- Copy ----
70 : :
71 : : StreamBuffer(const StreamBuffer& other);
72 : : StreamBuffer& operator=(const StreamBuffer& other);
73 : :
74 : : // ---- Move ----
75 : :
76 : 2125619 : StreamBuffer(StreamBuffer&&) noexcept = default;
77 : 1001206 : StreamBuffer& operator=(StreamBuffer&&) noexcept = default;
78 : :
79 : : // ---- Capacity ----
80 : :
81 : 122320 : size_t size() const noexcept { return buf_.size() - read_pos_; }
82 : 21 : bool empty() const noexcept { return size() == 0; }
83 : : size_t capacity() const noexcept { return buf_.capacity(); }
84 : : void reserve(size_t n);
85 : : void resize(size_t n);
86 : : void resize(size_t n, uint8_t value);
87 : :
88 : : // ---- Iterators ----
89 : :
90 : 68 : iterator begin() noexcept {
91 : 68 : maybe_compact();
92 : 68 : return buf_.data() + read_pos_;
93 : : }
94 : 46 : const_iterator begin() const noexcept { return buf_.data() + read_pos_; }
95 : : const_iterator cbegin() const noexcept { return begin(); }
96 : 55 : iterator end() noexcept { return begin() + size(); }
97 : 18 : const_iterator end() const noexcept { return begin() + size(); }
98 : : const_iterator cend() const noexcept { return end(); }
99 : :
100 : : // ---- Element access ----
101 : :
102 : : uint8_t& front() { return operator[](0); }
103 : : const uint8_t& front() const { return operator[](0); }
104 : : uint8_t& back() { return operator[](size() - 1); }
105 : : const uint8_t& back() const { return operator[](size() - 1); }
106 : :
107 : 13 : uint8_t& operator[](size_t i) { return buf_[read_pos_ + i]; }
108 : 130 : const uint8_t& operator[](size_t i) const { return buf_[read_pos_ + i]; }
109 : :
110 : 65 : uint8_t* data() noexcept {
111 : 65 : maybe_compact();
112 : 65 : return buf_.data() + read_pos_;
113 : : }
114 : 187 : const uint8_t* data() const noexcept { return buf_.data() + read_pos_; }
115 : :
116 : : // ---- Reserve + Write (direct I/O) ----
117 : :
118 : : uint8_t* reserve_tail(size_t n);
119 : : void commit_tail(size_t n);
120 : :
121 : : // ---- Append (copy-in) ----
122 : :
123 : : void append(const uint8_t* data, size_t len);
124 : :
125 : : // ---- Modifiers ----
126 : :
127 : : void push_back(uint8_t value);
128 : :
129 : : void assign(size_t count, uint8_t value);
130 : : template <typename InputIt>
131 : : void assign(InputIt first, InputIt last);
132 : : void assign(std::initializer_list<uint8_t> ilist);
133 : :
134 : : template <typename InputIt>
135 : : iterator insert(const_iterator pos, InputIt first, InputIt last);
136 : :
137 : : iterator insert(const_iterator pos, std::initializer_list<uint8_t> ilist);
138 : :
139 : : iterator erase(const_iterator first, const_iterator last);
140 : :
141 : : void clear() noexcept;
142 : :
143 : : // ---- Consume (StreamBuffer-specific, not in std::vector) ----
144 : :
145 : : void consume(size_t n);
146 : : void compact();
147 : :
148 : : // ---- Comparison ----
149 : :
150 : : bool operator==(const StreamBuffer& other) const;
151 : : bool operator!=(const StreamBuffer& other) const { return !(*this == other); }
152 : :
153 : : private:
154 : : void ensure_capacity(size_t additional_bytes);
155 : : void maybe_compact();
156 : :
157 : : std::vector<uint8_t> buf_;
158 : : size_t read_pos_ = 0;
159 : : size_t reserve_tail_amount_ = 0;
160 : : };
161 : :
162 : : // ---- Template implementations ----
163 : :
164 : : template <typename InputIt, typename>
165 : 34 : StreamBuffer::StreamBuffer(InputIt first, InputIt last) {
166 : 34 : buf_.insert(buf_.end(), first, last);
167 : 34 : }
168 : :
169 : : template <typename InputIt>
170 : 0 : void StreamBuffer::assign(InputIt first, InputIt last) {
171 : 0 : clear();
172 : 0 : buf_.assign(first, last);
173 : 0 : }
174 : :
175 : : template <typename InputIt>
176 : 41 : auto StreamBuffer::insert(const_iterator pos, InputIt first, InputIt last) -> iterator {
177 : 41 : size_t offset = static_cast<size_t>(pos - (buf_.data() + read_pos_));
178 : 41 : compact();
179 : 41 : auto it = buf_.insert(buf_.begin() + static_cast<std::ptrdiff_t>(offset), first, last);
180 : 41 : return buf_.data() + static_cast<size_t>(it - buf_.begin());
181 : : }
182 : :
183 : : } // namespace adt
184 : : } // namespace hpactor
|