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 /// Destroy the buffer.
85 ~basic_vector_dynamic_buffer() = default;
86
87 /** Construct by moving.
88 */
89 2x basic_vector_dynamic_buffer(
90 basic_vector_dynamic_buffer&& other) noexcept
91 2x : v_(other.v_)
92 2x , max_size_(other.max_size_)
93 2x , in_size_(other.in_size_)
94 2x , out_size_(other.out_size_)
95 {
96 2x other.v_ = nullptr;
97 2x }
98
99 /** Construct a dynamic buffer over a vector.
100
101 @param v Pointer to the vector to use as storage.
102 @param max_size Optional maximum size limit. Defaults
103 to the vector's `max_size()`.
104 */
105 explicit
106 213x basic_vector_dynamic_buffer(
107 vector_type* v,
108 std::size_t max_size =
109 std::size_t(-1)) noexcept
110 213x : v_(v)
111 213x , max_size_(
112 213x max_size > v_->max_size()
113 213x ? v_->max_size()
114 213x : max_size)
115 {
116 213x if(v_->size() > max_size_)
117 v_->resize(max_size_);
118 213x in_size_ = v_->size();
119 213x }
120
121 /// Copy assignment is deleted.
122 basic_vector_dynamic_buffer& operator=(
123 basic_vector_dynamic_buffer const&) = delete;
124
125 /// Return the number of readable bytes.
126 std::size_t
127 820x size() const noexcept
128 {
129 820x return in_size_;
130 }
131
132 /// Return the maximum number of bytes the buffer can hold.
133 std::size_t
134 2x max_size() const noexcept
135 {
136 2x return max_size_;
137 }
138
139 /// Return the number of writable bytes without reallocation.
140 std::size_t
141 2x capacity() const noexcept
142 {
143 2x if(v_->capacity() <= max_size_)
144 1x return v_->capacity() - in_size_;
145 1x return max_size_ - in_size_;
146 }
147
148 /// Return a buffer sequence representing the readable bytes.
149 const_buffers_type
150 147x data() const noexcept
151 {
152 147x return const_buffers_type(
153 294x v_->data(), in_size_);
154 }
155
156 /** Return a buffer sequence for writing.
157
158 Invalidates buffer sequences previously obtained
159 from @ref prepare.
160
161 @param n The desired number of writable bytes.
162
163 @return A mutable buffer sequence of size @p n.
164
165 @throws std::invalid_argument if `size() + n > max_size()`.
166 */
167 mutable_buffers_type
168 169x prepare(std::size_t n)
169 {
170 169x if(n > max_size_ - in_size_)
171 1x detail::throw_invalid_argument();
172
173 168x if(v_->size() < in_size_ + n)
174 167x v_->resize(in_size_ + n);
175 168x out_size_ = n;
176 504x return mutable_buffers_type(
177 168x v_->data() + in_size_, out_size_);
178 }
179
180 /** Move bytes from the output to the input sequence.
181
182 Invalidates buffer sequences previously obtained
183 from @ref prepare. Buffer sequences from @ref data
184 remain valid.
185
186 @param n The number of bytes to commit. If greater
187 than the prepared size, all prepared bytes
188 are committed.
189 */
190 void
191 147x commit(std::size_t n) noexcept
192 {
193 147x if(n < out_size_)
194 1x in_size_ += n;
195 else
196 146x in_size_ += out_size_;
197 147x out_size_ = 0;
198 147x v_->resize(in_size_);
199 147x }
200
201 /** Remove bytes from the beginning of the input sequence.
202
203 Invalidates buffer sequences previously obtained
204 from @ref data. Buffer sequences from @ref prepare
205 remain valid.
206
207 @param n The number of bytes to consume. If greater
208 than @ref size(), all readable bytes are consumed.
209 */
210 void
211 166x consume(std::size_t n) noexcept
212 {
213 166x if(n < in_size_)
214 {
215 1x v_->erase(v_->begin(), v_->begin() + n);
216 1x in_size_ -= n;
217 }
218 else
219 {
220 165x v_->clear();
221 165x in_size_ = 0;
222 }
223 166x out_size_ = 0;
224 166x }
225 };
226
227 /// A dynamic buffer using `std::vector<unsigned char>`.
228 using vector_dynamic_buffer =
229 basic_vector_dynamic_buffer<unsigned char>;
230
231 /** Create a dynamic buffer from a vector.
232
233 @param v The vector to wrap. Element type must be
234 a fundamental type with sizeof 1.
235 @param max_size Optional maximum size limit.
236 @return A vector_dynamic_buffer wrapping the vector.
237 */
238 template<class T, class Allocator>
239 requires std::is_fundamental_v<T> && (sizeof(T) == 1)
240 basic_vector_dynamic_buffer<T, Allocator>
241 dynamic_buffer(
242 std::vector<T, Allocator>& v,
243 std::size_t max_size = std::size_t(-1))
244 {
245 return basic_vector_dynamic_buffer<T, Allocator>(&v, max_size);
246 }
247
248 } // capy
249 } // boost
250
251 #endif
252