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/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 HIT 327 : circular_dynamic_buffer(
90 : void* base,
91 : std::size_t capacity) noexcept
92 327 : : base_(static_cast<
93 : unsigned char*>(base))
94 327 : , cap_(capacity)
95 : {
96 327 : }
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 2 : circular_dynamic_buffer(
108 : void* base,
109 : std::size_t capacity,
110 : std::size_t initial_size)
111 2 : : base_(static_cast<
112 : unsigned char*>(base))
113 2 : , cap_(capacity)
114 2 : , in_len_(initial_size)
115 : {
116 2 : if(in_len_ > capacity)
117 1 : detail::throw_invalid_argument();
118 1 : }
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 1520 : size() const noexcept
134 : {
135 1520 : return in_len_;
136 : }
137 :
138 : /// Return the maximum number of bytes the buffer can hold.
139 : std::size_t
140 7 : max_size() const noexcept
141 : {
142 7 : return cap_;
143 : }
144 :
145 : /// Return the number of writable bytes without reallocation.
146 : std::size_t
147 7 : capacity() const noexcept
148 : {
149 7 : 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
|