100.00% Lines (53/53) 100.00% Functions (10/10)
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_STRING_DYNAMIC_BUFFER_HPP 10   #ifndef BOOST_CAPY_BUFFERS_STRING_DYNAMIC_BUFFER_HPP
11   #define BOOST_CAPY_BUFFERS_STRING_DYNAMIC_BUFFER_HPP 11   #define BOOST_CAPY_BUFFERS_STRING_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 <string> 16   #include <string>
17   17  
18   namespace boost { 18   namespace boost {
19   namespace capy { 19   namespace capy {
20   20  
21   /** A dynamic buffer backed by a `std::basic_string`. 21   /** A dynamic buffer backed by a `std::basic_string`.
22   22  
23   This adapter wraps an externally-owned string and 23   This adapter wraps an externally-owned string and
24   exposes it through the @ref DynamicBuffer interface. 24   exposes it through the @ref DynamicBuffer interface.
25   Readable bytes occupy the front of the string; writable 25   Readable bytes occupy the front of the string; writable
26   bytes are appended by `prepare` and made readable by 26   bytes are appended by `prepare` and made readable by
27   `commit`. 27   `commit`.
28   28  
29   @note The wrapped string must outlive this adapter. 29   @note The wrapped string must outlive this adapter.
30   Calls to `prepare`, `commit`, and `consume` 30   Calls to `prepare`, `commit`, and `consume`
31   invalidate previously returned buffer views. 31   invalidate previously returned buffer views.
32   32  
33   @par Thread Safety 33   @par Thread Safety
34   Distinct objects: Safe. 34   Distinct objects: Safe.
35   Shared objects: Unsafe. 35   Shared objects: Unsafe.
36   36  
37   @par Example 37   @par Example
38   @code 38   @code
39   std::string s; 39   std::string s;
40   auto buf = dynamic_buffer( s, 4096 ); 40   auto buf = dynamic_buffer( s, 4096 );
41   auto mb = buf.prepare( 100 ); 41   auto mb = buf.prepare( 100 );
42   // fill mb with data... 42   // fill mb with data...
43   buf.commit( 100 ); 43   buf.commit( 100 );
44   // buf.data() now has 100 readable bytes 44   // buf.data() now has 100 readable bytes
45   buf.consume( 50 ); 45   buf.consume( 50 );
46   @endcode 46   @endcode
47   47  
48   @tparam CharT The character type. 48   @tparam CharT The character type.
49   @tparam Traits The character traits type. 49   @tparam Traits The character traits type.
50   @tparam Allocator The allocator type. 50   @tparam Allocator The allocator type.
51   51  
52   @see DynamicBuffer, string_dynamic_buffer, dynamic_buffer 52   @see DynamicBuffer, string_dynamic_buffer, dynamic_buffer
53   */ 53   */
54   template< 54   template<
55   class CharT, 55   class CharT,
56   class Traits = std::char_traits<CharT>, 56   class Traits = std::char_traits<CharT>,
57   class Allocator = std::allocator<CharT>> 57   class Allocator = std::allocator<CharT>>
58   class basic_string_dynamic_buffer 58   class basic_string_dynamic_buffer
59   { 59   {
60   std::basic_string< 60   std::basic_string<
61   CharT, Traits, Allocator>* s_; 61   CharT, Traits, Allocator>* s_;
62   std::size_t max_size_; 62   std::size_t max_size_;
63   63  
64   std::size_t in_size_ = 0; 64   std::size_t in_size_ = 0;
65   std::size_t out_size_ = 0; 65   std::size_t out_size_ = 0;
66   66  
67   public: 67   public:
68   /// Indicates this is a DynamicBuffer adapter over external storage. 68   /// Indicates this is a DynamicBuffer adapter over external storage.
69   using is_dynamic_buffer_adapter = void; 69   using is_dynamic_buffer_adapter = void;
70   70  
71   /// The underlying string type. 71   /// The underlying string type.
72   using string_type = std::basic_string< 72   using string_type = std::basic_string<
73   CharT, Traits, Allocator>; 73   CharT, Traits, Allocator>;
74   74  
75   /// The ConstBufferSequence type for readable bytes. 75   /// The ConstBufferSequence type for readable bytes.
76   using const_buffers_type = const_buffer; 76   using const_buffers_type = const_buffer;
77   77  
78   /// The MutableBufferSequence type for writable bytes. 78   /// The MutableBufferSequence type for writable bytes.
79   using mutable_buffers_type = mutable_buffer; 79   using mutable_buffers_type = mutable_buffer;
80   80  
81   /// Destroy the buffer. 81   /// Destroy the buffer.
82   ~basic_string_dynamic_buffer() = default; 82   ~basic_string_dynamic_buffer() = default;
83   83  
84   /// Construct by moving from another buffer. 84   /// Construct by moving from another buffer.
HITCBC 85   266 basic_string_dynamic_buffer( 85   266 basic_string_dynamic_buffer(
86   basic_string_dynamic_buffer&& other) noexcept 86   basic_string_dynamic_buffer&& other) noexcept
HITCBC 87   266 : s_(other.s_) 87   266 : s_(other.s_)
HITCBC 88   266 , max_size_(other.max_size_) 88   266 , max_size_(other.max_size_)
HITCBC 89   266 , in_size_(other.in_size_) 89   266 , in_size_(other.in_size_)
HITCBC 90   266 , out_size_(other.out_size_) 90   266 , out_size_(other.out_size_)
91   { 91   {
HITCBC 92   266 other.s_ = nullptr; 92   266 other.s_ = nullptr;
HITCBC 93   266 } 93   266 }
94   94  
95   /** Construct from an existing string. 95   /** Construct from an existing string.
96   96  
97   @param s Pointer to the string to wrap. Must 97   @param s Pointer to the string to wrap. Must
98   remain valid for the lifetime of this object. 98   remain valid for the lifetime of this object.
99   @param max_size Optional upper bound on the number 99   @param max_size Optional upper bound on the number
100   of bytes the buffer may hold. 100   of bytes the buffer may hold.
101   */ 101   */
102   explicit 102   explicit
HITCBC 103   427 basic_string_dynamic_buffer( 103   427 basic_string_dynamic_buffer(
104   string_type* s, 104   string_type* s,
105   std::size_t max_size = 105   std::size_t max_size =
106   std::size_t(-1)) noexcept 106   std::size_t(-1)) noexcept
HITCBC 107   427 : s_(s) 107   427 : s_(s)
HITCBC 108   427 , max_size_( 108   427 , max_size_(
HITCBC 109   427 max_size > s_->max_size() 109   427 max_size > s_->max_size()
HITCBC 110   427 ? s_->max_size() 110   427 ? s_->max_size()
HITCBC 111   427 : max_size) 111   427 : max_size)
112   { 112   {
HITCBC 113   427 if(s_->size() > max_size_) 113   427 if(s_->size() > max_size_)
HITCBC 114   1 s_->resize(max_size_); 114   1 s_->resize(max_size_);
HITCBC 115   427 in_size_ = s_->size(); 115   427 in_size_ = s_->size();
HITCBC 116   427 } 116   427 }
117   117  
118   /// Copy assignment is deleted. 118   /// Copy assignment is deleted.
119   basic_string_dynamic_buffer& operator=( 119   basic_string_dynamic_buffer& operator=(
120   basic_string_dynamic_buffer const&) = delete; 120   basic_string_dynamic_buffer const&) = delete;
121   121  
122   /// Return the number of readable bytes. 122   /// Return the number of readable bytes.
123   std::size_t 123   std::size_t
HITCBC 124   1280 size() const noexcept 124   1280 size() const noexcept
125   { 125   {
HITCBC 126   1280 return in_size_; 126   1280 return in_size_;
127   } 127   }
128   128  
129   /// Return the maximum number of bytes the buffer can hold. 129   /// Return the maximum number of bytes the buffer can hold.
130   std::size_t 130   std::size_t
HITCBC 131   410 max_size() const noexcept 131   410 max_size() const noexcept
132   { 132   {
HITCBC 133   410 return max_size_; 133   410 return max_size_;
134   } 134   }
135   135  
136   /// Return the number of writable bytes without reallocation. 136   /// Return the number of writable bytes without reallocation.
137   std::size_t 137   std::size_t
HITCBC 138   2 capacity() const noexcept 138   2 capacity() const noexcept
139   { 139   {
HITCBC 140   2 if(s_->capacity() <= max_size_) 140   2 if(s_->capacity() <= max_size_)
HITCBC 141   1 return s_->capacity() - in_size_; 141   1 return s_->capacity() - in_size_;
HITCBC 142   1 return max_size_ - in_size_; 142   1 return max_size_ - in_size_;
143   } 143   }
144   144  
145   /// Return a buffer sequence representing the readable bytes. 145   /// Return a buffer sequence representing the readable bytes.
146   const_buffers_type 146   const_buffers_type
HITCBC 147   387 data() const noexcept 147   387 data() const noexcept
148   { 148   {
HITCBC 149   387 return const_buffers_type( 149   387 return const_buffers_type(
HITCBC 150   774 s_->data(), in_size_); 150   774 s_->data(), in_size_);
151   } 151   }
152   152  
153   /** Prepare writable space of at least `n` bytes. 153   /** Prepare writable space of at least `n` bytes.
154   154  
155   Invalidates iterators and references returned by 155   Invalidates iterators and references returned by
156   previous calls to `data` and `prepare`. 156   previous calls to `data` and `prepare`.
157   157  
158   @throws std::invalid_argument if `n` exceeds 158   @throws std::invalid_argument if `n` exceeds
159   available space. 159   available space.
160   160  
161   @param n The number of bytes to prepare. 161   @param n The number of bytes to prepare.
162   162  
163   @return A mutable buffer of exactly `n` bytes. 163   @return A mutable buffer of exactly `n` bytes.
164   */ 164   */
165   mutable_buffers_type 165   mutable_buffers_type
HITCBC 166   533 prepare(std::size_t n) 166   533 prepare(std::size_t n)
167   { 167   {
168   // n exceeds available space 168   // n exceeds available space
HITCBC 169   533 if(n > max_size_ - in_size_) 169   533 if(n > max_size_ - in_size_)
HITCBC 170   1 detail::throw_invalid_argument(); 170   1 detail::throw_invalid_argument();
171   171  
HITCBC 172   532 if( s_->size() < in_size_ + n) 172   532 if( s_->size() < in_size_ + n)
HITCBC 173   531 s_->resize(in_size_ + n); 173   531 s_->resize(in_size_ + n);
HITCBC 174   532 out_size_ = n; 174   532 out_size_ = n;
HITCBC 175   532 return mutable_buffers_type( 175   532 return mutable_buffers_type(
HITCBC 176   1064 &(*s_)[in_size_], out_size_); 176   1064 &(*s_)[in_size_], out_size_);
177   } 177   }
178   178  
179   /** Move bytes from the writable to the readable area. 179   /** Move bytes from the writable to the readable area.
180   180  
181   Invalidates iterators and references returned by 181   Invalidates iterators and references returned by
182   previous calls to `data` and `prepare`. 182   previous calls to `data` and `prepare`.
183   183  
184   @param n The number of bytes to commit. Clamped 184   @param n The number of bytes to commit. Clamped
185   to the size of the writable area. 185   to the size of the writable area.
186   */ 186   */
HITCBC 187   434 void commit(std::size_t n) noexcept 187   434 void commit(std::size_t n) noexcept
188   { 188   {
HITCBC 189   434 if(n < out_size_) 189   434 if(n < out_size_)
HITCBC 190   242 in_size_ += n; 190   242 in_size_ += n;
191   else 191   else
HITCBC 192   192 in_size_ += out_size_; 192   192 in_size_ += out_size_;
HITCBC 193   434 out_size_ = 0; 193   434 out_size_ = 0;
HITCBC 194   434 s_->resize(in_size_); 194   434 s_->resize(in_size_);
HITCBC 195   434 } 195   434 }
196   196  
197   /** Remove bytes from the beginning of the readable area. 197   /** Remove bytes from the beginning of the readable area.
198   198  
199   Invalidates iterators and references returned by 199   Invalidates iterators and references returned by
200   previous calls to `data` and `prepare`. 200   previous calls to `data` and `prepare`.
201   201  
202   @param n The number of bytes to consume. Clamped 202   @param n The number of bytes to consume. Clamped
203   to the number of readable bytes. 203   to the number of readable bytes.
204   */ 204   */
HITCBC 205   168 void consume(std::size_t n) noexcept 205   168 void consume(std::size_t n) noexcept
206   { 206   {
HITCBC 207   168 if(n < in_size_) 207   168 if(n < in_size_)
208   { 208   {
HITCBC 209   3 s_->erase(0, n); 209   3 s_->erase(0, n);
HITCBC 210   3 in_size_ -= n; 210   3 in_size_ -= n;
211   } 211   }
212   else 212   else
213   { 213   {
HITCBC 214   165 s_->clear(); 214   165 s_->clear();
HITCBC 215   165 in_size_ = 0; 215   165 in_size_ = 0;
216   } 216   }
HITCBC 217   168 out_size_ = 0; 217   168 out_size_ = 0;
HITCBC 218   168 } 218   168 }
219   }; 219   };
220   220  
221   /// A dynamic buffer using `std::string`. 221   /// A dynamic buffer using `std::string`.
222   using string_dynamic_buffer = basic_string_dynamic_buffer<char>; 222   using string_dynamic_buffer = basic_string_dynamic_buffer<char>;
223   223  
224   /** Create a dynamic buffer from a string. 224   /** Create a dynamic buffer from a string.
225   225  
226   @param s The string to wrap. 226   @param s The string to wrap.
227   @param max_size Optional maximum size limit. 227   @param max_size Optional maximum size limit.
228   @return A string_dynamic_buffer wrapping the string. 228   @return A string_dynamic_buffer wrapping the string.
229   */ 229   */
230   template<class CharT, class Traits, class Allocator> 230   template<class CharT, class Traits, class Allocator>
231   basic_string_dynamic_buffer<CharT, Traits, Allocator> 231   basic_string_dynamic_buffer<CharT, Traits, Allocator>
HITCBC 232   132 dynamic_buffer( 232   132 dynamic_buffer(
233   std::basic_string<CharT, Traits, Allocator>& s, 233   std::basic_string<CharT, Traits, Allocator>& s,
234   std::size_t max_size = std::size_t(-1)) 234   std::size_t max_size = std::size_t(-1))
235   { 235   {
HITCBC 236   132 return basic_string_dynamic_buffer<CharT, Traits, Allocator>(&s, max_size); 236   132 return basic_string_dynamic_buffer<CharT, Traits, Allocator>(&s, max_size);
237   } 237   }
238   238  
239   } // capy 239   } // capy
240   } // boost 240   } // boost
241   241  
242   #endif 242   #endif