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