1 //
2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot 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/boostorg/beast
8 //
9 
10 #ifndef BOOST_BEAST_FLAT_STATIC_BUFFER_HPP
11 #define BOOST_BEAST_FLAT_STATIC_BUFFER_HPP
12 
13 #include <boost/beast/core/detail/config.hpp>
14 #include <boost/asio/buffer.hpp>
15 #include <algorithm>
16 #include <cstddef>
17 #include <cstring>
18 
19 namespace boost {
20 namespace beast {
21 
22 /** A dynamic buffer using a fixed size internal buffer.
23 
24     A dynamic buffer encapsulates memory storage that may be
25     automatically resized as required, where the memory is
26     divided into two regions: readable bytes followed by
27     writable bytes. These memory regions are internal to
28     the dynamic buffer, but direct access to the elements
29     is provided to permit them to be efficiently used with
30     I/O operations.
31 
32     Objects of this type meet the requirements of <em>DynamicBuffer</em>
33     and have the following additional properties:
34 
35     @li A mutable buffer sequence representing the readable
36     bytes is returned by @ref data when `this` is non-const.
37 
38     @li Buffer sequences representing the readable and writable
39     bytes, returned by @ref data and @ref prepare, will have
40     length one.
41 
42     @li Ownership of the underlying storage belongs to the
43     derived class.
44 
45     @note Variables are usually declared using the template class
46     @ref flat_static_buffer; however, to reduce the number of template
47     instantiations, objects should be passed `flat_static_buffer_base&`.
48 
49     @see flat_static_buffer
50 */
51 class flat_static_buffer_base
52 {
53     char* begin_;
54     char* in_;
55     char* out_;
56     char* last_;
57     char* end_;
58 
59     flat_static_buffer_base(
60         flat_static_buffer_base const& other) = delete;
61     flat_static_buffer_base& operator=(
62         flat_static_buffer_base const&) = delete;
63 
64 public:
65     /** Constructor
66 
67         This creates a dynamic buffer using the provided storage area.
68 
69         @param p A pointer to valid storage of at least `n` bytes.
70 
71         @param n The number of valid bytes pointed to by `p`.
72     */
flat_static_buffer_base(void * p,std::size_t n)73     flat_static_buffer_base(
74         void* p, std::size_t n) noexcept
75     {
76         reset(p, n);
77     }
78 
79     /** Clear the readable and writable bytes to zero.
80 
81         This function causes the readable and writable bytes
82         to become empty. The capacity is not changed.
83 
84         Buffer sequences previously obtained using @ref data or
85         @ref prepare become invalid.
86 
87         @esafe
88 
89         No-throw guarantee.
90     */
91     BOOST_BEAST_DECL
92     void
93     clear() noexcept;
94 
95     //--------------------------------------------------------------------------
96 
97     /// The ConstBufferSequence used to represent the readable bytes.
98     using const_buffers_type = net::const_buffer;
99 
100     /// The MutableBufferSequence used to represent the writable bytes.
101     using mutable_buffers_type = net::mutable_buffer;
102 
103     /// Returns the number of readable bytes.
104     std::size_t
size() const105     size() const noexcept
106     {
107         return out_ - in_;
108     }
109 
110     /// Return the maximum number of bytes, both readable and writable, that can ever be held.
111     std::size_t
max_size() const112     max_size() const noexcept
113     {
114         return dist(begin_, end_);
115     }
116 
117     /// Return the maximum number of bytes, both readable and writable, that can be held without requiring an allocation.
118     std::size_t
capacity() const119     capacity() const noexcept
120     {
121         return max_size();
122     }
123 
124     /// Returns a constant buffer sequence representing the readable bytes
125     const_buffers_type
data() const126     data() const noexcept
127     {
128         return {in_, dist(in_, out_)};
129     }
130 
131     /// Returns a constant buffer sequence representing the readable bytes
132     const_buffers_type
cdata() const133     cdata() const noexcept
134     {
135         return data();
136     }
137 
138     /// Returns a mutable buffer sequence representing the readable bytes
139     mutable_buffers_type
data()140     data() noexcept
141     {
142         return {in_, dist(in_, out_)};
143     }
144 
145     /** Returns a mutable buffer sequence representing writable bytes.
146 
147         Returns a mutable buffer sequence representing the writable
148         bytes containing exactly `n` bytes of storage.
149 
150         All buffers sequences previously obtained using
151         @ref data or @ref prepare are invalidated.
152 
153         @param n The desired number of bytes in the returned buffer
154         sequence.
155 
156         @throws std::length_error if `size() + n` exceeds `max_size()`.
157 
158         @esafe
159 
160         Strong guarantee.
161     */
162     BOOST_BEAST_DECL
163     mutable_buffers_type
164     prepare(std::size_t n);
165 
166     /** Append writable bytes to the readable bytes.
167 
168         Appends n bytes from the start of the writable bytes to the
169         end of the readable bytes. The remainder of the writable bytes
170         are discarded. If n is greater than the number of writable
171         bytes, all writable bytes are appended to the readable bytes.
172 
173         All buffers sequences previously obtained using
174         @ref data or @ref prepare are invalidated.
175 
176         @param n The number of bytes to append. If this number
177         is greater than the number of writable bytes, all
178         writable bytes are appended.
179 
180         @esafe
181 
182         No-throw guarantee.
183     */
184     void
commit(std::size_t n)185     commit(std::size_t n) noexcept
186     {
187         out_ += (std::min<std::size_t>)(n, last_ - out_);
188     }
189 
190     /** Remove bytes from beginning of the readable bytes.
191 
192         Removes n bytes from the beginning of the readable bytes.
193 
194         All buffers sequences previously obtained using
195         @ref data or @ref prepare are invalidated.
196 
197         @param n The number of bytes to remove. If this number
198         is greater than the number of readable bytes, all
199         readable bytes are removed.
200 
201         @esafe
202 
203         No-throw guarantee.
204     */
205     BOOST_BEAST_DECL
206     void
207     consume(std::size_t n) noexcept;
208 
209 protected:
210     /** Constructor
211 
212         The buffer will be in an undefined state. It is necessary
213         for the derived class to call @ref reset with a pointer
214         and size in order to initialize the object.
215     */
216     flat_static_buffer_base() = default;
217 
218     /** Reset the pointed-to buffer.
219 
220         This function resets the internal state to the buffer provided.
221         All input and output sequences are invalidated. This function
222         allows the derived class to construct its members before
223         initializing the static buffer.
224 
225         @param p A pointer to valid storage of at least `n` bytes.
226 
227         @param n The number of valid bytes pointed to by `p`.
228 
229         @esafe
230 
231         No-throw guarantee.
232     */
233     BOOST_BEAST_DECL
234     void
235     reset(void* p, std::size_t n) noexcept;
236 
237 private:
238     static
239     std::size_t
dist(char const * first,char const * last)240     dist(char const* first, char const* last) noexcept
241     {
242         return static_cast<std::size_t>(last - first);
243     }
244 };
245 
246 //------------------------------------------------------------------------------
247 
248 /** A <em>DynamicBuffer</em> with a fixed size internal buffer.
249 
250     Buffer sequences returned by @ref data and @ref prepare
251     will always be of length one.
252     This implements a dynamic buffer using no memory allocations.
253 
254     @tparam N The number of bytes in the internal buffer.
255 
256     @note To reduce the number of template instantiations when passing
257     objects of this type in a deduced context, the signature of the
258     receiving function should use @ref flat_static_buffer_base instead.
259 
260     @see flat_static_buffer_base
261 */
262 template<std::size_t N>
263 class flat_static_buffer : public flat_static_buffer_base
264 {
265     char buf_[N];
266 
267 public:
268     /// Constructor
269     flat_static_buffer(flat_static_buffer const&);
270 
271     /// Constructor
flat_static_buffer()272     flat_static_buffer()
273         : flat_static_buffer_base(buf_, N)
274     {
275     }
276 
277     /// Assignment
278     flat_static_buffer& operator=(flat_static_buffer const&);
279 
280     /// Returns the @ref flat_static_buffer_base portion of this object
281     flat_static_buffer_base&
base()282     base()
283     {
284         return *this;
285     }
286 
287     /// Returns the @ref flat_static_buffer_base portion of this object
288     flat_static_buffer_base const&
base() const289     base() const
290     {
291         return *this;
292     }
293 
294     /// Return the maximum sum of the input and output sequence sizes.
295     std::size_t constexpr
max_size() const296     max_size() const
297     {
298         return N;
299     }
300 
301     /// Return the maximum sum of input and output sizes that can be held without an allocation.
302     std::size_t constexpr
capacity() const303     capacity() const
304     {
305         return N;
306     }
307 };
308 
309 } // beast
310 } // boost
311 
312 #include <boost/beast/core/impl/flat_static_buffer.hpp>
313 #ifdef BOOST_BEAST_HEADER_ONLY
314 #include <boost/beast/core/impl/flat_static_buffer.ipp>
315 #endif
316 
317 #endif