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