include/boost/capy/buffers/vector_dynamic_buffer.hpp

98.0% Lines (50/51) 100.0% Functions (9/9)
Line TLA Hits Source Code
1 //
2 // Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/cppalliance/capy
8 //
9
10 #ifndef BOOST_CAPY_BUFFERS_VECTOR_DYNAMIC_BUFFER_HPP
11 #define BOOST_CAPY_BUFFERS_VECTOR_DYNAMIC_BUFFER_HPP
12
13 #include <boost/capy/detail/config.hpp>
14 #include <boost/capy/buffers.hpp>
15 #include <boost/capy/detail/except.hpp>
16 #include <type_traits>
17 #include <vector>
18
19 namespace boost {
20 namespace capy {
21
22 /** A dynamic buffer using an underlying vector.
23
24 This class adapts a `std::vector` of byte-sized elements
25 to satisfy the DynamicBuffer concept. The vector provides
26 automatic memory management and growth.
27
28 @par Constraints
29
30 The element type `T` must be a fundamental type with
31 `sizeof( T ) == 1`. This includes `char`, `unsigned char`,
32 `signed char`, and similar byte-sized fundamental types.
33
34 @par Example
35 @code
36 std::vector<unsigned char> v;
37 vector_dynamic_buffer vb( &v );
38
39 // Write data
40 auto mb = vb.prepare( 100 );
41 std::memcpy( mb.data(), "hello", 5 );
42 vb.commit( 5 );
43
44 // Read data
45 auto data = vb.data();
46 // process data...
47 vb.consume( 5 );
48 @endcode
49
50 @par Thread Safety
51 Distinct objects: Safe.
52 Shared objects: Unsafe.
53
54 @tparam T The element type. Must be fundamental with sizeof 1.
55 @tparam Allocator The allocator type for the vector.
56
57 @see flat_dynamic_buffer, circular_dynamic_buffer, string_dynamic_buffer
58 */
59 template<
60 class T,
61 class Allocator = std::allocator<T>>
62 requires std::is_fundamental_v<T> && (sizeof(T) == 1)
63 class basic_vector_dynamic_buffer
64 {
65 std::vector<T, Allocator>* v_;
66 std::size_t max_size_;
67
68 std::size_t in_size_ = 0;
69 std::size_t out_size_ = 0;
70
71 public:
72 /// Indicates this is a DynamicBuffer adapter over external storage.
73 using is_dynamic_buffer_adapter = void;
74
75 /// The underlying vector type.
76 using vector_type = std::vector<T, Allocator>;
77
78 /// The ConstBufferSequence type for readable bytes.
79 using const_buffers_type = const_buffer;
80
81 /// The MutableBufferSequence type for writable bytes.
82 using mutable_buffers_type = mutable_buffer;
83
84 ~basic_vector_dynamic_buffer() = default;
85
86 /** Move constructor.
87 */
88 2x basic_vector_dynamic_buffer(
89 basic_vector_dynamic_buffer&& other) noexcept
90 2x : v_(other.v_)
91 2x , max_size_(other.max_size_)
92 2x , in_size_(other.in_size_)
93 2x , out_size_(other.out_size_)
94 {
95 2x other.v_ = nullptr;
96 2x }
97
98 /** Construct a dynamic buffer over a vector.
99
100 @param v Pointer to the vector to use as storage.
101 @param max_size Optional maximum size limit. Defaults
102 to the vector's `max_size()`.
103 */
104 explicit
105 213x basic_vector_dynamic_buffer(
106 vector_type* v,
107 std::size_t max_size =
108 std::size_t(-1)) noexcept
109 213x : v_(v)
110 213x , max_size_(
111 213x max_size > v_->max_size()
112 213x ? v_->max_size()
113 213x : max_size)
114 {
115 213x if(v_->size() > max_size_)
116 v_->resize(max_size_);
117 213x in_size_ = v_->size();
118 213x }
119
120 /// Copy assignment is deleted.
121 basic_vector_dynamic_buffer& operator=(
122 basic_vector_dynamic_buffer const&) = delete;
123
124 /// Return the number of readable bytes.
125 std::size_t
126 820x size() const noexcept
127 {
128 820x return in_size_;
129 }
130
131 /// Return the maximum number of bytes the buffer can hold.
132 std::size_t
133 2x max_size() const noexcept
134 {
135 2x return max_size_;
136 }
137
138 /// Return the number of writable bytes without reallocation.
139 std::size_t
140 2x capacity() const noexcept
141 {
142 2x if(v_->capacity() <= max_size_)
143 1x return v_->capacity() - in_size_;
144 1x return max_size_ - in_size_;
145 }
146
147 /// Return a buffer sequence representing the readable bytes.
148 const_buffers_type
149 147x data() const noexcept
150 {
151 147x return const_buffers_type(
152 294x v_->data(), in_size_);
153 }
154
155 /** Return a buffer sequence for writing.
156
157 Invalidates buffer sequences previously obtained
158 from @ref prepare.
159
160 @param n The desired number of writable bytes.
161
162 @return A mutable buffer sequence of size @p n.
163
164 @throws std::invalid_argument if `size() + n > max_size()`.
165 */
166 mutable_buffers_type
167 169x prepare(std::size_t n)
168 {
169 169x if(n > max_size_ - in_size_)
170 1x detail::throw_invalid_argument();
171
172 168x if(v_->size() < in_size_ + n)
173 167x v_->resize(in_size_ + n);
174 168x out_size_ = n;
175 504x return mutable_buffers_type(
176 168x v_->data() + in_size_, out_size_);
177 }
178
179 /** Move bytes from the output to the input sequence.
180
181 Invalidates buffer sequences previously obtained
182 from @ref prepare. Buffer sequences from @ref data
183 remain valid.
184
185 @param n The number of bytes to commit. If greater
186 than the prepared size, all prepared bytes
187 are committed.
188 */
189 void
190 147x commit(std::size_t n) noexcept
191 {
192 147x if(n < out_size_)
193 1x in_size_ += n;
194 else
195 146x in_size_ += out_size_;
196 147x out_size_ = 0;
197 147x v_->resize(in_size_);
198 147x }
199
200 /** Remove bytes from the beginning of the input sequence.
201
202 Invalidates buffer sequences previously obtained
203 from @ref data. Buffer sequences from @ref prepare
204 remain valid.
205
206 @param n The number of bytes to consume. If greater
207 than @ref size(), all readable bytes are consumed.
208 */
209 void
210 166x consume(std::size_t n) noexcept
211 {
212 166x if(n < in_size_)
213 {
214 1x v_->erase(v_->begin(), v_->begin() + n);
215 1x in_size_ -= n;
216 }
217 else
218 {
219 165x v_->clear();
220 165x in_size_ = 0;
221 }
222 166x out_size_ = 0;
223 166x }
224 };
225
226 /// A dynamic buffer using `std::vector<unsigned char>`.
227 using vector_dynamic_buffer =
228 basic_vector_dynamic_buffer<unsigned char>;
229
230 /** Create a dynamic buffer from a vector.
231
232 @param v The vector to wrap. Element type must be
233 a fundamental type with sizeof 1.
234 @param max_size Optional maximum size limit.
235 @return A vector_dynamic_buffer wrapping the vector.
236 */
237 template<class T, class Allocator>
238 requires std::is_fundamental_v<T> && (sizeof(T) == 1)
239 basic_vector_dynamic_buffer<T, Allocator>
240 dynamic_buffer(
241 std::vector<T, Allocator>& v,
242 std::size_t max_size = std::size_t(-1))
243 {
244 return basic_vector_dynamic_buffer<T, Allocator>(&v, max_size);
245 }
246
247 } // capy
248 } // boost
249
250 #endif
251