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   /// Destroy the buffer.
85   ~basic_vector_dynamic_buffer() = default; 85   ~basic_vector_dynamic_buffer() = default;
86   86  
87   /** Construct by moving. 87   /** Construct by moving.
88   */ 88   */
HITCBC 89   2 basic_vector_dynamic_buffer( 89   2 basic_vector_dynamic_buffer(
90   basic_vector_dynamic_buffer&& other) noexcept 90   basic_vector_dynamic_buffer&& other) noexcept
HITCBC 91   2 : v_(other.v_) 91   2 : v_(other.v_)
HITCBC 92   2 , max_size_(other.max_size_) 92   2 , max_size_(other.max_size_)
HITCBC 93   2 , in_size_(other.in_size_) 93   2 , in_size_(other.in_size_)
HITCBC 94   2 , out_size_(other.out_size_) 94   2 , out_size_(other.out_size_)
95   { 95   {
HITCBC 96   2 other.v_ = nullptr; 96   2 other.v_ = nullptr;
HITCBC 97   2 } 97   2 }
98   98  
99   /** Construct a dynamic buffer over a vector. 99   /** Construct a dynamic buffer over a vector.
100   100  
101   @param v Pointer to the vector to use as storage. 101   @param v Pointer to the vector to use as storage.
102   @param max_size Optional maximum size limit. Defaults 102   @param max_size Optional maximum size limit. Defaults
103   to the vector's `max_size()`. 103   to the vector's `max_size()`.
104   */ 104   */
105   explicit 105   explicit
HITCBC 106   213 basic_vector_dynamic_buffer( 106   213 basic_vector_dynamic_buffer(
107   vector_type* v, 107   vector_type* v,
108   std::size_t max_size = 108   std::size_t max_size =
109   std::size_t(-1)) noexcept 109   std::size_t(-1)) noexcept
HITCBC 110   213 : v_(v) 110   213 : v_(v)
HITCBC 111   213 , max_size_( 111   213 , max_size_(
HITCBC 112   213 max_size > v_->max_size() 112   213 max_size > v_->max_size()
HITCBC 113   213 ? v_->max_size() 113   213 ? v_->max_size()
HITCBC 114   213 : max_size) 114   213 : max_size)
115   { 115   {
HITCBC 116   213 if(v_->size() > max_size_) 116   213 if(v_->size() > max_size_)
MISUBC 117   v_->resize(max_size_); 117   v_->resize(max_size_);
HITCBC 118   213 in_size_ = v_->size(); 118   213 in_size_ = v_->size();
HITCBC 119   213 } 119   213 }
120   120  
121   /// Copy assignment is deleted. 121   /// Copy assignment is deleted.
122   basic_vector_dynamic_buffer& operator=( 122   basic_vector_dynamic_buffer& operator=(
123   basic_vector_dynamic_buffer const&) = delete; 123   basic_vector_dynamic_buffer const&) = delete;
124   124  
125   /// Return the number of readable bytes. 125   /// Return the number of readable bytes.
126   std::size_t 126   std::size_t
HITCBC 127   820 size() const noexcept 127   820 size() const noexcept
128   { 128   {
HITCBC 129   820 return in_size_; 129   820 return in_size_;
130   } 130   }
131   131  
132   /// Return the maximum number of bytes the buffer can hold. 132   /// Return the maximum number of bytes the buffer can hold.
133   std::size_t 133   std::size_t
HITCBC 134   2 max_size() const noexcept 134   2 max_size() const noexcept
135   { 135   {
HITCBC 136   2 return max_size_; 136   2 return max_size_;
137   } 137   }
138   138  
139   /// Return the number of writable bytes without reallocation. 139   /// Return the number of writable bytes without reallocation.
140   std::size_t 140   std::size_t
HITCBC 141   2 capacity() const noexcept 141   2 capacity() const noexcept
142   { 142   {
HITCBC 143   2 if(v_->capacity() <= max_size_) 143   2 if(v_->capacity() <= max_size_)
HITCBC 144   1 return v_->capacity() - in_size_; 144   1 return v_->capacity() - in_size_;
HITCBC 145   1 return max_size_ - in_size_; 145   1 return max_size_ - in_size_;
146   } 146   }
147   147  
148   /// Return a buffer sequence representing the readable bytes. 148   /// Return a buffer sequence representing the readable bytes.
149   const_buffers_type 149   const_buffers_type
HITCBC 150   147 data() const noexcept 150   147 data() const noexcept
151   { 151   {
HITCBC 152   147 return const_buffers_type( 152   147 return const_buffers_type(
HITCBC 153   294 v_->data(), in_size_); 153   294 v_->data(), in_size_);
154   } 154   }
155   155  
156   /** Return a buffer sequence for writing. 156   /** Return a buffer sequence for writing.
157   157  
158   Invalidates buffer sequences previously obtained 158   Invalidates buffer sequences previously obtained
159   from @ref prepare. 159   from @ref prepare.
160   160  
161   @param n The desired number of writable bytes. 161   @param n The desired number of writable bytes.
162   162  
163   @return A mutable buffer sequence of size @p n. 163   @return A mutable buffer sequence of size @p n.
164   164  
165   @throws std::invalid_argument if `size() + n > max_size()`. 165   @throws std::invalid_argument if `size() + n > max_size()`.
166   */ 166   */
167   mutable_buffers_type 167   mutable_buffers_type
HITCBC 168   169 prepare(std::size_t n) 168   169 prepare(std::size_t n)
169   { 169   {
HITCBC 170   169 if(n > max_size_ - in_size_) 170   169 if(n > max_size_ - in_size_)
HITCBC 171   1 detail::throw_invalid_argument(); 171   1 detail::throw_invalid_argument();
172   172  
HITCBC 173   168 if(v_->size() < in_size_ + n) 173   168 if(v_->size() < in_size_ + n)
HITCBC 174   167 v_->resize(in_size_ + n); 174   167 v_->resize(in_size_ + n);
HITCBC 175   168 out_size_ = n; 175   168 out_size_ = n;
HITCBC 176   504 return mutable_buffers_type( 176   504 return mutable_buffers_type(
HITCBC 177   168 v_->data() + in_size_, out_size_); 177   168 v_->data() + in_size_, out_size_);
178   } 178   }
179   179  
180   /** Move bytes from the output to the input sequence. 180   /** Move bytes from the output to the input sequence.
181   181  
182   Invalidates buffer sequences previously obtained 182   Invalidates buffer sequences previously obtained
183   from @ref prepare. Buffer sequences from @ref data 183   from @ref prepare. Buffer sequences from @ref data
184   remain valid. 184   remain valid.
185   185  
186   @param n The number of bytes to commit. If greater 186   @param n The number of bytes to commit. If greater
187   than the prepared size, all prepared bytes 187   than the prepared size, all prepared bytes
188   are committed. 188   are committed.
189   */ 189   */
190   void 190   void
HITCBC 191   147 commit(std::size_t n) noexcept 191   147 commit(std::size_t n) noexcept
192   { 192   {
HITCBC 193   147 if(n < out_size_) 193   147 if(n < out_size_)
HITCBC 194   1 in_size_ += n; 194   1 in_size_ += n;
195   else 195   else
HITCBC 196   146 in_size_ += out_size_; 196   146 in_size_ += out_size_;
HITCBC 197   147 out_size_ = 0; 197   147 out_size_ = 0;
HITCBC 198   147 v_->resize(in_size_); 198   147 v_->resize(in_size_);
HITCBC 199   147 } 199   147 }
200   200  
201   /** Remove bytes from the beginning of the input sequence. 201   /** Remove bytes from the beginning of the input sequence.
202   202  
203   Invalidates buffer sequences previously obtained 203   Invalidates buffer sequences previously obtained
204   from @ref data. Buffer sequences from @ref prepare 204   from @ref data. Buffer sequences from @ref prepare
205   remain valid. 205   remain valid.
206   206  
207   @param n The number of bytes to consume. If greater 207   @param n The number of bytes to consume. If greater
208   than @ref size(), all readable bytes are consumed. 208   than @ref size(), all readable bytes are consumed.
209   */ 209   */
210   void 210   void
HITCBC 211   166 consume(std::size_t n) noexcept 211   166 consume(std::size_t n) noexcept
212   { 212   {
HITCBC 213   166 if(n < in_size_) 213   166 if(n < in_size_)
214   { 214   {
HITCBC 215   1 v_->erase(v_->begin(), v_->begin() + n); 215   1 v_->erase(v_->begin(), v_->begin() + n);
HITCBC 216   1 in_size_ -= n; 216   1 in_size_ -= n;
217   } 217   }
218   else 218   else
219   { 219   {
HITCBC 220   165 v_->clear(); 220   165 v_->clear();
HITCBC 221   165 in_size_ = 0; 221   165 in_size_ = 0;
222   } 222   }
HITCBC 223   166 out_size_ = 0; 223   166 out_size_ = 0;
HITCBC 224   166 } 224   166 }
225   }; 225   };
226   226  
227   /// A dynamic buffer using `std::vector<unsigned char>`. 227   /// A dynamic buffer using `std::vector<unsigned char>`.
228   using vector_dynamic_buffer = 228   using vector_dynamic_buffer =
229   basic_vector_dynamic_buffer<unsigned char>; 229   basic_vector_dynamic_buffer<unsigned char>;
230   230  
231   /** Create a dynamic buffer from a vector. 231   /** Create a dynamic buffer from a vector.
232   232  
233   @param v The vector to wrap. Element type must be 233   @param v The vector to wrap. Element type must be
234   a fundamental type with sizeof 1. 234   a fundamental type with sizeof 1.
235   @param max_size Optional maximum size limit. 235   @param max_size Optional maximum size limit.
236   @return A vector_dynamic_buffer wrapping the vector. 236   @return A vector_dynamic_buffer wrapping the vector.
237   */ 237   */
238   template<class T, class Allocator> 238   template<class T, class Allocator>
239   requires std::is_fundamental_v<T> && (sizeof(T) == 1) 239   requires std::is_fundamental_v<T> && (sizeof(T) == 1)
240   basic_vector_dynamic_buffer<T, Allocator> 240   basic_vector_dynamic_buffer<T, Allocator>
241   dynamic_buffer( 241   dynamic_buffer(
242   std::vector<T, Allocator>& v, 242   std::vector<T, Allocator>& v,
243   std::size_t max_size = std::size_t(-1)) 243   std::size_t max_size = std::size_t(-1))
244   { 244   {
245   return basic_vector_dynamic_buffer<T, Allocator>(&v, max_size); 245   return basic_vector_dynamic_buffer<T, Allocator>(&v, max_size);
246   } 246   }
247   247  
248   } // capy 248   } // capy
249   } // boost 249   } // boost
250   250  
251   #endif 251   #endif