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