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