98.04% Lines (50/51) 100.00% Functions (9/9)
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_VECTOR_DYNAMIC_BUFFER_HPP 10   #ifndef BOOST_CAPY_BUFFERS_VECTOR_DYNAMIC_BUFFER_HPP
11   #define BOOST_CAPY_BUFFERS_VECTOR_DYNAMIC_BUFFER_HPP 11   #define BOOST_CAPY_BUFFERS_VECTOR_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   #include <type_traits> 16   #include <type_traits>
17   #include <vector> 17   #include <vector>
18   18  
19   namespace boost { 19   namespace boost {
20   namespace capy { 20   namespace capy {
21   21  
22   /** A dynamic buffer using an underlying vector. 22   /** A dynamic buffer using an underlying vector.
23   23  
24   This class adapts a `std::vector` of byte-sized elements 24   This class adapts a `std::vector` of byte-sized elements
25   to satisfy the DynamicBuffer concept. The vector provides 25   to satisfy the DynamicBuffer concept. The vector provides
26   automatic memory management and growth. 26   automatic memory management and growth.
27   27  
28   @par Constraints 28   @par Constraints
29   29  
30   The element type `T` must be a fundamental type with 30   The element type `T` must be a fundamental type with
31   `sizeof( T ) == 1`. This includes `char`, `unsigned char`, 31   `sizeof( T ) == 1`. This includes `char`, `unsigned char`,
32   `signed char`, and similar byte-sized fundamental types. 32   `signed char`, and similar byte-sized fundamental types.
33   33  
34   @par Example 34   @par Example
35   @code 35   @code
36   std::vector<unsigned char> v; 36   std::vector<unsigned char> v;
37   vector_dynamic_buffer vb( &v ); 37   vector_dynamic_buffer vb( &v );
38   38  
39   // Write data 39   // Write data
40   auto mb = vb.prepare( 100 ); 40   auto mb = vb.prepare( 100 );
41   std::memcpy( mb.data(), "hello", 5 ); 41   std::memcpy( mb.data(), "hello", 5 );
42   vb.commit( 5 ); 42   vb.commit( 5 );
43   43  
44   // Read data 44   // Read data
45   auto data = vb.data(); 45   auto data = vb.data();
46   // process data... 46   // process data...
47   vb.consume( 5 ); 47   vb.consume( 5 );
48   @endcode 48   @endcode
49   49  
50   @par Thread Safety 50   @par Thread Safety
51   Distinct objects: Safe. 51   Distinct objects: Safe.
52   Shared objects: Unsafe. 52   Shared objects: Unsafe.
53   53  
54   @tparam T The element type. Must be fundamental with sizeof 1. 54   @tparam T The element type. Must be fundamental with sizeof 1.
55   @tparam Allocator The allocator type for the vector. 55   @tparam Allocator The allocator type for the vector.
56   56  
57   @see flat_dynamic_buffer, circular_dynamic_buffer, string_dynamic_buffer 57   @see flat_dynamic_buffer, circular_dynamic_buffer, string_dynamic_buffer
58   */ 58   */
59   template< 59   template<
60   class T, 60   class T,
61   class Allocator = std::allocator<T>> 61   class Allocator = std::allocator<T>>
62   requires std::is_fundamental_v<T> && (sizeof(T) == 1) 62   requires std::is_fundamental_v<T> && (sizeof(T) == 1)
63   class basic_vector_dynamic_buffer 63   class basic_vector_dynamic_buffer
64   { 64   {
65   std::vector<T, Allocator>* v_; 65   std::vector<T, Allocator>* v_;
66   std::size_t max_size_; 66   std::size_t max_size_;
67   67  
68   std::size_t in_size_ = 0; 68   std::size_t in_size_ = 0;
69   std::size_t out_size_ = 0; 69   std::size_t out_size_ = 0;
70   70  
71   public: 71   public:
72   /// Indicates this is a DynamicBuffer adapter over external storage. 72   /// Indicates this is a DynamicBuffer adapter over external storage.
73   using is_dynamic_buffer_adapter = void; 73   using is_dynamic_buffer_adapter = void;
74   74  
75   /// The underlying vector type. 75   /// The underlying vector type.
76   using vector_type = std::vector<T, Allocator>; 76   using vector_type = std::vector<T, Allocator>;
77   77  
78   /// The ConstBufferSequence type for readable bytes. 78   /// The ConstBufferSequence type for readable bytes.
79   using const_buffers_type = const_buffer; 79   using const_buffers_type = const_buffer;
80   80  
81   /// The MutableBufferSequence type for writable bytes. 81   /// The MutableBufferSequence type for writable bytes.
82   using mutable_buffers_type = mutable_buffer; 82   using mutable_buffers_type = mutable_buffer;
83   83  
  84 + /// Destroy the buffer.
84   ~basic_vector_dynamic_buffer() = default; 85   ~basic_vector_dynamic_buffer() = default;
85   86  
86 - /** Move constructor. 87 + /** Construct by moving.
87   */ 88   */
HITCBC 88   2 basic_vector_dynamic_buffer( 89   2 basic_vector_dynamic_buffer(
89   basic_vector_dynamic_buffer&& other) noexcept 90   basic_vector_dynamic_buffer&& other) noexcept
HITCBC 90   2 : v_(other.v_) 91   2 : v_(other.v_)
HITCBC 91   2 , max_size_(other.max_size_) 92   2 , max_size_(other.max_size_)
HITCBC 92   2 , in_size_(other.in_size_) 93   2 , in_size_(other.in_size_)
HITCBC 93   2 , out_size_(other.out_size_) 94   2 , out_size_(other.out_size_)
94   { 95   {
HITCBC 95   2 other.v_ = nullptr; 96   2 other.v_ = nullptr;
HITCBC 96   2 } 97   2 }
97   98  
98   /** Construct a dynamic buffer over a vector. 99   /** Construct a dynamic buffer over a vector.
99   100  
100   @param v Pointer to the vector to use as storage. 101   @param v Pointer to the vector to use as storage.
101   @param max_size Optional maximum size limit. Defaults 102   @param max_size Optional maximum size limit. Defaults
102   to the vector's `max_size()`. 103   to the vector's `max_size()`.
103   */ 104   */
104   explicit 105   explicit
HITCBC 105   213 basic_vector_dynamic_buffer( 106   213 basic_vector_dynamic_buffer(
106   vector_type* v, 107   vector_type* v,
107   std::size_t max_size = 108   std::size_t max_size =
108   std::size_t(-1)) noexcept 109   std::size_t(-1)) noexcept
HITCBC 109   213 : v_(v) 110   213 : v_(v)
HITCBC 110   213 , max_size_( 111   213 , max_size_(
HITCBC 111   213 max_size > v_->max_size() 112   213 max_size > v_->max_size()
HITCBC 112   213 ? v_->max_size() 113   213 ? v_->max_size()
HITCBC 113   213 : max_size) 114   213 : max_size)
114   { 115   {
HITCBC 115   213 if(v_->size() > max_size_) 116   213 if(v_->size() > max_size_)
MISUBC 116   v_->resize(max_size_); 117   v_->resize(max_size_);
HITCBC 117   213 in_size_ = v_->size(); 118   213 in_size_ = v_->size();
HITCBC 118   213 } 119   213 }
119   120  
120   /// Copy assignment is deleted. 121   /// Copy assignment is deleted.
121   basic_vector_dynamic_buffer& operator=( 122   basic_vector_dynamic_buffer& operator=(
122   basic_vector_dynamic_buffer const&) = delete; 123   basic_vector_dynamic_buffer const&) = delete;
123   124  
124   /// Return the number of readable bytes. 125   /// Return the number of readable bytes.
125   std::size_t 126   std::size_t
HITCBC 126   820 size() const noexcept 127   820 size() const noexcept
127   { 128   {
HITCBC 128   820 return in_size_; 129   820 return in_size_;
129   } 130   }
130   131  
131   /// Return the maximum number of bytes the buffer can hold. 132   /// Return the maximum number of bytes the buffer can hold.
132   std::size_t 133   std::size_t
HITCBC 133   2 max_size() const noexcept 134   2 max_size() const noexcept
134   { 135   {
HITCBC 135   2 return max_size_; 136   2 return max_size_;
136   } 137   }
137   138  
138   /// Return the number of writable bytes without reallocation. 139   /// Return the number of writable bytes without reallocation.
139   std::size_t 140   std::size_t
HITCBC 140   2 capacity() const noexcept 141   2 capacity() const noexcept
141   { 142   {
HITCBC 142   2 if(v_->capacity() <= max_size_) 143   2 if(v_->capacity() <= max_size_)
HITCBC 143   1 return v_->capacity() - in_size_; 144   1 return v_->capacity() - in_size_;
HITCBC 144   1 return max_size_ - in_size_; 145   1 return max_size_ - in_size_;
145   } 146   }
146   147  
147   /// Return a buffer sequence representing the readable bytes. 148   /// Return a buffer sequence representing the readable bytes.
148   const_buffers_type 149   const_buffers_type
HITCBC 149   147 data() const noexcept 150   147 data() const noexcept
150   { 151   {
HITCBC 151   147 return const_buffers_type( 152   147 return const_buffers_type(
HITCBC 152   294 v_->data(), in_size_); 153   294 v_->data(), in_size_);
153   } 154   }
154   155  
155   /** Return a buffer sequence for writing. 156   /** Return a buffer sequence for writing.
156   157  
157   Invalidates buffer sequences previously obtained 158   Invalidates buffer sequences previously obtained
158   from @ref prepare. 159   from @ref prepare.
159   160  
160   @param n The desired number of writable bytes. 161   @param n The desired number of writable bytes.
161   162  
162   @return A mutable buffer sequence of size @p n. 163   @return A mutable buffer sequence of size @p n.
163   164  
164   @throws std::invalid_argument if `size() + n > max_size()`. 165   @throws std::invalid_argument if `size() + n > max_size()`.
165   */ 166   */
166   mutable_buffers_type 167   mutable_buffers_type
HITCBC 167   169 prepare(std::size_t n) 168   169 prepare(std::size_t n)
168   { 169   {
HITCBC 169   169 if(n > max_size_ - in_size_) 170   169 if(n > max_size_ - in_size_)
HITCBC 170   1 detail::throw_invalid_argument(); 171   1 detail::throw_invalid_argument();
171   172  
HITCBC 172   168 if(v_->size() < in_size_ + n) 173   168 if(v_->size() < in_size_ + n)
HITCBC 173   167 v_->resize(in_size_ + n); 174   167 v_->resize(in_size_ + n);
HITCBC 174   168 out_size_ = n; 175   168 out_size_ = n;
HITCBC 175   504 return mutable_buffers_type( 176   504 return mutable_buffers_type(
HITCBC 176   168 v_->data() + in_size_, out_size_); 177   168 v_->data() + in_size_, out_size_);
177   } 178   }
178   179  
179   /** Move bytes from the output to the input sequence. 180   /** Move bytes from the output to the input sequence.
180   181  
181   Invalidates buffer sequences previously obtained 182   Invalidates buffer sequences previously obtained
182   from @ref prepare. Buffer sequences from @ref data 183   from @ref prepare. Buffer sequences from @ref data
183   remain valid. 184   remain valid.
184   185  
185   @param n The number of bytes to commit. If greater 186   @param n The number of bytes to commit. If greater
186   than the prepared size, all prepared bytes 187   than the prepared size, all prepared bytes
187   are committed. 188   are committed.
188   */ 189   */
189   void 190   void
HITCBC 190   147 commit(std::size_t n) noexcept 191   147 commit(std::size_t n) noexcept
191   { 192   {
HITCBC 192   147 if(n < out_size_) 193   147 if(n < out_size_)
HITCBC 193   1 in_size_ += n; 194   1 in_size_ += n;
194   else 195   else
HITCBC 195   146 in_size_ += out_size_; 196   146 in_size_ += out_size_;
HITCBC 196   147 out_size_ = 0; 197   147 out_size_ = 0;
HITCBC 197   147 v_->resize(in_size_); 198   147 v_->resize(in_size_);
HITCBC 198   147 } 199   147 }
199   200  
200   /** Remove bytes from the beginning of the input sequence. 201   /** Remove bytes from the beginning of the input sequence.
201   202  
202   Invalidates buffer sequences previously obtained 203   Invalidates buffer sequences previously obtained
203   from @ref data. Buffer sequences from @ref prepare 204   from @ref data. Buffer sequences from @ref prepare
204   remain valid. 205   remain valid.
205   206  
206   @param n The number of bytes to consume. If greater 207   @param n The number of bytes to consume. If greater
207   than @ref size(), all readable bytes are consumed. 208   than @ref size(), all readable bytes are consumed.
208   */ 209   */
209   void 210   void
HITCBC 210   166 consume(std::size_t n) noexcept 211   166 consume(std::size_t n) noexcept
211   { 212   {
HITCBC 212   166 if(n < in_size_) 213   166 if(n < in_size_)
213   { 214   {
HITCBC 214   1 v_->erase(v_->begin(), v_->begin() + n); 215   1 v_->erase(v_->begin(), v_->begin() + n);
HITCBC 215   1 in_size_ -= n; 216   1 in_size_ -= n;
216   } 217   }
217   else 218   else
218   { 219   {
HITCBC 219   165 v_->clear(); 220   165 v_->clear();
HITCBC 220   165 in_size_ = 0; 221   165 in_size_ = 0;
221   } 222   }
HITCBC 222   166 out_size_ = 0; 223   166 out_size_ = 0;
HITCBC 223   166 } 224   166 }
224   }; 225   };
225   226  
226   /// A dynamic buffer using `std::vector<unsigned char>`. 227   /// A dynamic buffer using `std::vector<unsigned char>`.
227   using vector_dynamic_buffer = 228   using vector_dynamic_buffer =
228   basic_vector_dynamic_buffer<unsigned char>; 229   basic_vector_dynamic_buffer<unsigned char>;
229   230  
230   /** Create a dynamic buffer from a vector. 231   /** Create a dynamic buffer from a vector.
231   232  
232   @param v The vector to wrap. Element type must be 233   @param v The vector to wrap. Element type must be
233   a fundamental type with sizeof 1. 234   a fundamental type with sizeof 1.
234   @param max_size Optional maximum size limit. 235   @param max_size Optional maximum size limit.
235   @return A vector_dynamic_buffer wrapping the vector. 236   @return A vector_dynamic_buffer wrapping the vector.
236   */ 237   */
237   template<class T, class Allocator> 238   template<class T, class Allocator>
238   requires std::is_fundamental_v<T> && (sizeof(T) == 1) 239   requires std::is_fundamental_v<T> && (sizeof(T) == 1)
239   basic_vector_dynamic_buffer<T, Allocator> 240   basic_vector_dynamic_buffer<T, Allocator>
240   dynamic_buffer( 241   dynamic_buffer(
241   std::vector<T, Allocator>& v, 242   std::vector<T, Allocator>& v,
242   std::size_t max_size = std::size_t(-1)) 243   std::size_t max_size = std::size_t(-1))
243   { 244   {
244   return basic_vector_dynamic_buffer<T, Allocator>(&v, max_size); 245   return basic_vector_dynamic_buffer<T, Allocator>(&v, max_size);
245   } 246   }
246   247  
247   } // capy 248   } // capy
248   } // boost 249   } // boost
249   250  
250   #endif 251   #endif