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