libs/capy/include/boost/capy/buffers/flat_dynamic_buffer.hpp

100.0% Lines (35/35) 100.0% Functions (8/8) 100.0% Branches (8/8)
libs/capy/include/boost/capy/buffers/flat_dynamic_buffer.hpp
Line Branch 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_FLAT_DYNAMIC_BUFFER_HPP
11 #define BOOST_CAPY_BUFFERS_FLAT_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
17 namespace boost {
18 namespace capy {
19
20 /** A fixed-capacity linear buffer satisfying DynamicBuffer.
21
22 This class provides a contiguous buffer with fixed capacity
23 determined at construction. Buffer sequences returned from
24 @ref data and @ref prepare always contain exactly one element,
25 making it suitable for APIs requiring contiguous memory.
26
27 @par Example
28 @code
29 char storage[1024];
30 flat_dynamic_buffer fb( storage, sizeof( storage ) );
31
32 // Write data
33 auto mb = fb.prepare( 100 );
34 std::memcpy( mb.data(), "hello", 5 );
35 fb.commit( 5 );
36
37 // Read data
38 auto data = fb.data();
39 // process data...
40 fb.consume( 5 );
41 @endcode
42
43 @par Thread Safety
44 Distinct objects: Safe.
45 Shared objects: Unsafe.
46
47 @see circular_dynamic_buffer, string_dynamic_buffer
48 */
49 class flat_dynamic_buffer
50 {
51 unsigned char* data_ = nullptr;
52 std::size_t cap_ = 0;
53 std::size_t in_pos_ = 0;
54 std::size_t in_size_ = 0;
55 std::size_t out_size_ = 0;
56
57 public:
58 /// Indicates this is a DynamicBuffer adapter over external storage.
59 using is_dynamic_buffer_adapter = void;
60
61 /// The ConstBufferSequence type for readable bytes.
62 using const_buffers_type = const_buffer;
63
64 /// The MutableBufferSequence type for writable bytes.
65 using mutable_buffers_type = mutable_buffer;
66
67 /// Construct an empty flat buffer with zero capacity.
68 flat_dynamic_buffer() = default;
69
70 /** Construct a flat buffer over existing storage.
71
72 @param data Pointer to the storage.
73 @param capacity Size of the storage in bytes.
74 @param initial_size Number of bytes already present as
75 readable. Must not exceed @p capacity.
76
77 @throws std::invalid_argument if initial_size > capacity.
78 */
79 223 flat_dynamic_buffer(
80 void* data,
81 std::size_t capacity,
82 std::size_t initial_size = 0)
83 223 : data_(static_cast<
84 unsigned char*>(data))
85 223 , cap_(capacity)
86 223 , in_size_(initial_size)
87 {
88
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 222 times.
223 if(in_size_ > cap_)
89 1 detail::throw_invalid_argument();
90 222 }
91
92 /// Copy constructor.
93 flat_dynamic_buffer(
94 flat_dynamic_buffer const&) = default;
95
96 /// Copy assignment.
97 flat_dynamic_buffer& operator=(
98 flat_dynamic_buffer const&) = default;
99
100 /// Return the number of readable bytes.
101 std::size_t
102 856 size() const noexcept
103 {
104 856 return in_size_;
105 }
106
107 /// Return the maximum number of bytes the buffer can hold.
108 std::size_t
109 10 max_size() const noexcept
110 {
111 10 return cap_;
112 }
113
114 /// Return the number of writable bytes without reallocation.
115 std::size_t
116 238 capacity() const noexcept
117 {
118 238 return cap_ - (in_pos_ + in_size_);
119 }
120
121 /// Return a buffer sequence representing the readable bytes.
122 const_buffers_type
123 161 data() const noexcept
124 {
125 322 return const_buffers_type(
126 161 data_ + in_pos_, in_size_);
127 }
128
129 /** Return a buffer sequence for writing.
130
131 Invalidates buffer sequences previously obtained
132 from @ref prepare.
133
134 @param n The desired number of writable bytes.
135
136 @return A mutable buffer sequence of size @p n.
137
138 @throws std::invalid_argument if `n > capacity()`.
139 */
140 mutable_buffers_type
141 197 prepare(std::size_t n)
142 {
143
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 194 times.
197 if( n > capacity() )
144 3 detail::throw_invalid_argument();
145
146 194 out_size_ = n;
147 388 return mutable_buffers_type(
148 194 data_ + in_pos_ + in_size_, n);
149 }
150
151 /** Move bytes from the output to the input sequence.
152
153 Invalidates buffer sequences previously obtained
154 from @ref prepare. Buffer sequences from @ref data
155 remain valid.
156
157 @param n The number of bytes to commit. If greater
158 than the prepared size, all prepared bytes
159 are committed.
160 */
161 void
162 160 commit(
163 std::size_t n) noexcept
164 {
165
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 145 times.
160 if(n < out_size_)
166 15 in_size_ += n;
167 else
168 145 in_size_ += out_size_;
169 160 out_size_ = 0;
170 160 }
171
172 /** Remove bytes from the beginning of the input sequence.
173
174 Invalidates buffer sequences previously obtained
175 from @ref data. Buffer sequences from @ref prepare
176 remain valid.
177
178 @param n The number of bytes to consume. If greater
179 than @ref size(), all readable bytes are consumed.
180 */
181 void
182 180 consume(
183 std::size_t n) noexcept
184 {
185
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 165 times.
180 if(n < in_size_)
186 {
187 15 in_pos_ += n;
188 15 in_size_ -= n;
189 }
190 else
191 {
192 165 in_pos_ = 0;
193 165 in_size_ = 0;
194 }
195 180 }
196 };
197
198 } // capy
199 } // boost
200
201 #endif
202