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_FLAT_BUFFER_HPP
11 : #define BOOST_HTTP_DETAIL_FLAT_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 <cstddef>
19 :
20 : namespace boost {
21 : namespace http {
22 : namespace detail {
23 :
24 : /** A fixed-capacity linear buffer satisfying DynamicBuffer.
25 :
26 : This class provides a contiguous buffer with fixed capacity
27 : determined at construction. Buffer sequences returned from
28 : @ref data and @ref prepare always contain exactly one element,
29 : making it suitable for APIs requiring contiguous memory.
30 :
31 : @par Example
32 : @code
33 : char storage[1024];
34 : flat_buffer fb( storage, sizeof( storage ) );
35 :
36 : // Write data
37 : auto mb = fb.prepare( 100 );
38 : std::memcpy( mb.data(), "hello", 5 );
39 : fb.commit( 5 );
40 :
41 : // Read data
42 : auto data = fb.data();
43 : // process data...
44 : fb.consume( 5 );
45 : @endcode
46 :
47 : @par Thread Safety
48 : Distinct objects: Safe.
49 : Shared objects: Unsafe.
50 :
51 : @see circular_buffer
52 : */
53 : class flat_buffer
54 : {
55 : unsigned char* data_ = nullptr;
56 : std::size_t cap_ = 0;
57 : std::size_t in_pos_ = 0;
58 : std::size_t in_size_ = 0;
59 : std::size_t out_size_ = 0;
60 :
61 : public:
62 : /// Indicates this is a DynamicBuffer adapter over external storage.
63 : using is_circular_buffer_adapter = void;
64 :
65 : /// The ConstBufferSequence type for readable bytes.
66 : using const_buffers_type = capy::const_buffer;
67 :
68 : /// The MutableBufferSequence type for writable bytes.
69 : using mutable_buffers_type = capy::mutable_buffer;
70 :
71 : /// Construct an empty flat buffer with zero capacity.
72 HIT 2175 : flat_buffer() = default;
73 :
74 : /** Construct a flat buffer over existing storage.
75 :
76 : @param data Pointer to the storage.
77 : @param capacity Size of the storage in bytes.
78 : @param initial_size Number of bytes already present as
79 : readable. Must not exceed @p capacity.
80 :
81 : @throws std::invalid_argument if initial_size > capacity.
82 : */
83 10647 : flat_buffer(
84 : void* data,
85 : std::size_t capacity,
86 : std::size_t initial_size = 0)
87 10647 : : data_(static_cast<
88 : unsigned char*>(data))
89 10647 : , cap_(capacity)
90 10647 : , in_size_(initial_size)
91 : {
92 10647 : if(in_size_ > cap_)
93 MIS 0 : detail::throw_invalid_argument();
94 HIT 10647 : }
95 :
96 : /// Construct a copy.
97 : flat_buffer(
98 : flat_buffer const&) = default;
99 :
100 : /// Assign by copying.
101 : flat_buffer& operator=(
102 : flat_buffer const&) = default;
103 :
104 : /// Return the number of readable bytes.
105 : std::size_t
106 54566 : size() const noexcept
107 : {
108 54566 : return in_size_;
109 : }
110 :
111 : /// Return the maximum number of bytes the buffer can hold.
112 : std::size_t
113 : max_size() const noexcept
114 : {
115 : return cap_;
116 : }
117 :
118 : /// Return the number of writable bytes without reallocation.
119 : std::size_t
120 99018 : capacity() const noexcept
121 : {
122 99018 : return cap_ - (in_pos_ + in_size_);
123 : }
124 :
125 : /// Return a buffer sequence representing the readable bytes.
126 : const_buffers_type
127 : data() const noexcept
128 : {
129 : return const_buffers_type(
130 : data_ + in_pos_, in_size_);
131 : }
132 :
133 : /** Return a buffer sequence for writing.
134 :
135 : Invalidates buffer sequences previously obtained
136 : from @ref prepare.
137 :
138 : @param n The desired number of writable bytes.
139 :
140 : @return A mutable buffer sequence of size @p n.
141 :
142 : @throws std::invalid_argument if `n > capacity()`.
143 : */
144 : mutable_buffers_type
145 39830 : prepare(std::size_t n)
146 : {
147 39830 : if( n > capacity() )
148 MIS 0 : detail::throw_invalid_argument();
149 :
150 HIT 39830 : out_size_ = n;
151 79660 : return mutable_buffers_type(
152 39830 : data_ + in_pos_ + in_size_, n);
153 : }
154 :
155 : /** Move bytes from the output to the input sequence.
156 :
157 : Invalidates buffer sequences previously obtained
158 : from @ref prepare. Buffer sequences from @ref data
159 : remain valid.
160 :
161 : @param n The number of bytes to commit. If greater
162 : than the prepared size, all prepared bytes
163 : are committed.
164 : */
165 : void
166 39046 : commit(
167 : std::size_t n) noexcept
168 : {
169 39046 : if(n < out_size_)
170 39030 : in_size_ += n;
171 : else
172 16 : in_size_ += out_size_;
173 39046 : out_size_ = 0;
174 39046 : }
175 :
176 : /** Remove bytes from the beginning of the input sequence.
177 :
178 : Invalidates buffer sequences previously obtained
179 : from @ref data. Buffer sequences from @ref prepare
180 : remain valid.
181 :
182 : @param n The number of bytes to consume. If greater
183 : than @ref size(), all readable bytes are consumed.
184 : */
185 : void
186 : consume(
187 : std::size_t n) noexcept
188 : {
189 : if(n < in_size_)
190 : {
191 : in_pos_ += n;
192 : in_size_ -= n;
193 : }
194 : else
195 : {
196 : in_pos_ = 0;
197 : in_size_ = 0;
198 : }
199 : }
200 : };
201 :
202 : } // detail
203 : } // http
204 : } // boost
205 :
206 : #endif
|