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 : /// Copy constructor.
74 : circular_dynamic_buffer(
75 : circular_dynamic_buffer const&) = default;
76 :
77 : /** Construct a circular buffer over existing storage.
78 :
79 : @param base Pointer to the storage.
80 : @param capacity Size of the storage in bytes.
81 : */
82 323 : circular_dynamic_buffer(
83 : void* base,
84 : std::size_t capacity) noexcept
85 323 : : base_(static_cast<
86 : unsigned char*>(base))
87 323 : , cap_(capacity)
88 : {
89 323 : }
90 :
91 : /** Construct a circular buffer with initial readable bytes.
92 :
93 : @param base Pointer to the storage.
94 : @param capacity Size of the storage in bytes.
95 : @param initial_size Number of bytes already present as
96 : readable. Must not exceed @p capacity.
97 :
98 : @throws std::invalid_argument if initial_size > capacity.
99 : */
100 2 : circular_dynamic_buffer(
101 : void* base,
102 : std::size_t capacity,
103 : std::size_t initial_size)
104 2 : : base_(static_cast<
105 : unsigned char*>(base))
106 2 : , cap_(capacity)
107 2 : , in_len_(initial_size)
108 : {
109 2 : if(in_len_ > capacity)
110 1 : detail::throw_invalid_argument();
111 1 : }
112 :
113 : /// Copy assignment.
114 : circular_dynamic_buffer& operator=(
115 : circular_dynamic_buffer const&) = default;
116 :
117 : /// Return the number of readable bytes.
118 : std::size_t
119 823 : size() const noexcept
120 : {
121 823 : return in_len_;
122 : }
123 :
124 : /// Return the maximum number of bytes the buffer can hold.
125 : std::size_t
126 6 : max_size() const noexcept
127 : {
128 6 : return cap_;
129 : }
130 :
131 : /// Return the number of writable bytes without reallocation.
132 : std::size_t
133 7 : capacity() const noexcept
134 : {
135 7 : return cap_ - in_len_;
136 : }
137 :
138 : /// Return a buffer sequence representing the readable bytes.
139 : BOOST_CAPY_DECL
140 : const_buffers_type
141 : data() const noexcept;
142 :
143 : /** Return a buffer sequence for writing.
144 :
145 : Invalidates buffer sequences previously obtained
146 : from @ref prepare.
147 :
148 : @param n The desired number of writable bytes.
149 :
150 : @return A mutable buffer sequence of size @p n.
151 :
152 : @throws std::length_error if `size() + n > max_size()`.
153 : */
154 : BOOST_CAPY_DECL
155 : mutable_buffers_type
156 : prepare(std::size_t n);
157 :
158 : /** Move bytes from the output to the input sequence.
159 :
160 : Invalidates buffer sequences previously obtained
161 : from @ref prepare. Buffer sequences from @ref data
162 : remain valid.
163 :
164 : @param n The number of bytes to commit. If greater
165 : than the prepared size, all prepared bytes
166 : are committed.
167 : */
168 : BOOST_CAPY_DECL
169 : void
170 : commit(std::size_t n) noexcept;
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 : BOOST_CAPY_DECL
182 : void
183 : consume(std::size_t n) noexcept;
184 : };
185 :
186 : } // capy
187 : } // boost
188 :
189 : #endif
|