include/boost/capy/buffers/circular_dynamic_buffer.hpp

100.0% Lines (17/17) 100.0% Functions (5/5)
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_CIRCULAR_DYNAMIC_BUFFER_HPP
11 #define BOOST_CAPY_BUFFERS_CIRCULAR_DYNAMIC_BUFFER_HPP
12
13 #include <boost/capy/detail/config.hpp>
14 #include <boost/capy/buffers/buffer_pair.hpp>
15 #include <boost/capy/detail/except.hpp>
16
17 namespace boost {
18 namespace capy {
19
20 /** A fixed-capacity circular buffer satisfying DynamicBuffer.
21
22 This class implements a circular ( ring ) buffer with
23 fixed capacity determined at construction. Unlike linear
24 buffers, data can wrap around from the end to the beginning,
25 enabling efficient FIFO operations without memory copies.
26
27 Buffer sequences returned from @ref data and @ref prepare
28 may contain up to two elements to represent wrapped regions.
29
30 @par Example
31 @code
32 char storage[1024];
33 circular_dynamic_buffer cb( storage, sizeof( storage ) );
34
35 // Write data
36 auto mb = cb.prepare( 100 );
37 std::memcpy( mb.data(), "hello", 5 );
38 cb.commit( 5 );
39
40 // Read data
41 auto cb_data = cb.data();
42 // process cb_data...
43 cb.consume( 5 );
44 @endcode
45
46 @par Thread Safety
47 Distinct objects: Safe.
48 Shared objects: Unsafe.
49
50 @see flat_dynamic_buffer, string_dynamic_buffer
51 */
52 class circular_dynamic_buffer
53 {
54 unsigned char* base_ = nullptr;
55 std::size_t cap_ = 0;
56 std::size_t in_pos_ = 0;
57 std::size_t in_len_ = 0;
58 std::size_t out_size_ = 0;
59
60 public:
61 /// Indicates this is a DynamicBuffer adapter over external storage.
62 using is_dynamic_buffer_adapter = void;
63
64 /// The ConstBufferSequence type for readable bytes.
65 using const_buffers_type = const_buffer_pair;
66
67 /// The MutableBufferSequence type for writable bytes.
68 using mutable_buffers_type = mutable_buffer_pair;
69
70 /// Construct an empty circular buffer with zero capacity.
71 circular_dynamic_buffer() = default;
72
73 /** Construct a copy.
74
75 Copies the adapter state (position and length) but does
76 not deep-copy the backing storage. Both objects alias the
77 same external buffer.
78
79 @note The underlying storage must outlive all copies.
80 */
81 circular_dynamic_buffer(
82 circular_dynamic_buffer const&) = default;
83
84 /** Construct a circular buffer over existing storage.
85
86 @param base Pointer to the storage.
87 @param capacity Size of the storage in bytes.
88 */
89 327x circular_dynamic_buffer(
90 void* base,
91 std::size_t capacity) noexcept
92 327x : base_(static_cast<
93 unsigned char*>(base))
94 327x , cap_(capacity)
95 {
96 327x }
97
98 /** Construct a circular buffer with initial readable bytes.
99
100 @param base Pointer to the storage.
101 @param capacity Size of the storage in bytes.
102 @param initial_size Number of bytes already present as
103 readable. Must not exceed @p capacity.
104
105 @throws std::invalid_argument if initial_size > capacity.
106 */
107 2x circular_dynamic_buffer(
108 void* base,
109 std::size_t capacity,
110 std::size_t initial_size)
111 2x : base_(static_cast<
112 unsigned char*>(base))
113 2x , cap_(capacity)
114 2x , in_len_(initial_size)
115 {
116 2x if(in_len_ > capacity)
117 1x detail::throw_invalid_argument();
118 1x }
119
120 /** Assign by copying.
121
122 Copies the adapter state but does not deep-copy the
123 backing storage. Both objects alias the same external
124 buffer afterward.
125
126 @note The underlying storage must outlive all copies.
127 */
128 circular_dynamic_buffer& operator=(
129 circular_dynamic_buffer const&) = default;
130
131 /// Return the number of readable bytes.
132 std::size_t
133 1520x size() const noexcept
134 {
135 1520x return in_len_;
136 }
137
138 /// Return the maximum number of bytes the buffer can hold.
139 std::size_t
140 7x max_size() const noexcept
141 {
142 7x return cap_;
143 }
144
145 /// Return the number of writable bytes without reallocation.
146 std::size_t
147 7x capacity() const noexcept
148 {
149 7x return cap_ - in_len_;
150 }
151
152 /// Return a buffer sequence representing the readable bytes.
153 BOOST_CAPY_DECL
154 const_buffers_type
155 data() const noexcept;
156
157 /** Return a buffer sequence for writing.
158
159 Invalidates buffer sequences previously obtained
160 from @ref prepare.
161
162 @param n The desired number of writable bytes.
163
164 @return A mutable buffer sequence of size @p n.
165
166 @throws std::length_error if `size() + n > max_size()`.
167 */
168 BOOST_CAPY_DECL
169 mutable_buffers_type
170 prepare(std::size_t n);
171
172 /** Move bytes from the output to the input sequence.
173
174 Invalidates buffer sequences previously obtained
175 from @ref prepare. Buffer sequences from @ref data
176 remain valid.
177
178 @param n The number of bytes to commit. If greater
179 than the prepared size, all prepared bytes
180 are committed.
181 */
182 BOOST_CAPY_DECL
183 void
184 commit(std::size_t n) noexcept;
185
186 /** Remove bytes from the beginning of the input sequence.
187
188 Invalidates buffer sequences previously obtained
189 from @ref data. Buffer sequences from @ref prepare
190 remain valid.
191
192 @param n The number of bytes to consume. If greater
193 than @ref size(), all readable bytes are consumed.
194 */
195 BOOST_CAPY_DECL
196 void
197 consume(std::size_t n) noexcept;
198 };
199
200 } // capy
201 } // boost
202
203 #endif
204