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