96.99% Lines (161/166) 100.00% Functions (24/24)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com) 2   // Copyright (c) 2025 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_SLICE_HPP 10   #ifndef BOOST_CAPY_BUFFERS_SLICE_HPP
11   #define BOOST_CAPY_BUFFERS_SLICE_HPP 11   #define BOOST_CAPY_BUFFERS_SLICE_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 <array> 15   #include <array>
16   #include <cassert> 16   #include <cassert>
17   #include <iterator> 17   #include <iterator>
18   #include <type_traits> 18   #include <type_traits>
19   19  
20   namespace boost { 20   namespace boost {
21   namespace capy { 21   namespace capy {
22   22  
23   template<class T> class slice_of; 23   template<class T> class slice_of;
24   24  
25   namespace detail { 25   namespace detail {
26   26  
27   template<class T, class = void> 27   template<class T, class = void>
28   struct has_tag_invoke : std::false_type {}; 28   struct has_tag_invoke : std::false_type {};
29   29  
30   template<class T> 30   template<class T>
31   struct has_tag_invoke<T, decltype(tag_invoke( 31   struct has_tag_invoke<T, decltype(tag_invoke(
32   std::declval<slice_tag const&>(), 32   std::declval<slice_tag const&>(),
33   std::declval<T&>(), 33   std::declval<T&>(),
34   std::declval<slice_how>(), 34   std::declval<slice_how>(),
35   std::declval<std::size_t>()))> 35   std::declval<std::size_t>()))>
36   : std::true_type {}; 36   : std::true_type {};
37   37  
38   } // detail 38   } // detail
39   39  
40   /** Alias for the type representing a slice of T 40   /** Alias for the type representing a slice of T
41   */ 41   */
42   template<class T> 42   template<class T>
43   using slice_type = std::conditional_t< 43   using slice_type = std::conditional_t<
44   detail::has_tag_invoke<T>::value, 44   detail::has_tag_invoke<T>::value,
45   T, slice_of<T>>; 45   T, slice_of<T>>;
46   46  
47   /** A view of a sub-range of a buffer sequence. 47   /** A view of a sub-range of a buffer sequence.
48   48  
49   This class wraps a buffer sequence and presents a 49   This class wraps a buffer sequence and presents a
50   contiguous byte sub-range by adjusting the first and 50   contiguous byte sub-range by adjusting the first and
51   last buffers. The prefix and suffix can be removed or 51   last buffers. The prefix and suffix can be removed or
52   kept using the free functions @ref keep_prefix, 52   kept using the free functions @ref keep_prefix,
53   @ref remove_prefix, etc. 53   @ref remove_prefix, etc.
54   54  
55   The wrapped sequence is stored by value. The underlying 55   The wrapped sequence is stored by value. The underlying
56   buffer memory must remain valid for the lifetime of the 56   buffer memory must remain valid for the lifetime of the
57   slice. 57   slice.
58   58  
59   @par Thread Safety 59   @par Thread Safety
60   Distinct objects: Safe. 60   Distinct objects: Safe.
61   Shared objects: Unsafe. 61   Shared objects: Unsafe.
62   62  
63   @par Example 63   @par Example
64   @code 64   @code
65   mutable_buffer buf(data, 100); 65   mutable_buffer buf(data, 100);
66   auto s = prefix(buf, 50); // first 50 bytes 66   auto s = prefix(buf, 50); // first 50 bytes
67   remove_prefix(s, 10); // now bytes 10..49 67   remove_prefix(s, 10); // now bytes 10..49
68   @endcode 68   @endcode
69   69  
70   @tparam BufferSequence The buffer sequence type, stored 70   @tparam BufferSequence The buffer sequence type, stored
71   by value. Must satisfy @ref ConstBufferSequence. 71   by value. Must satisfy @ref ConstBufferSequence.
72   72  
73   @see keep_prefix, remove_prefix, prefix, sans_prefix 73   @see keep_prefix, remove_prefix, prefix, sans_prefix
74   */ 74   */
75   template<ConstBufferSequence BufferSequence> 75   template<ConstBufferSequence BufferSequence>
76   class slice_of<BufferSequence> 76   class slice_of<BufferSequence>
77   { 77   {
78   static_assert(!std::is_const_v<BufferSequence>, 78   static_assert(!std::is_const_v<BufferSequence>,
79   "BufferSequence can't be const"); 79   "BufferSequence can't be const");
80   80  
81   static_assert(!std::is_reference_v<BufferSequence>, 81   static_assert(!std::is_reference_v<BufferSequence>,
82   "BufferSequence can't be a reference"); 82   "BufferSequence can't be a reference");
83   83  
84   using iter_type = decltype( 84   using iter_type = decltype(
85   std::declval<BufferSequence const&>().begin()); 85   std::declval<BufferSequence const&>().begin());
86   86  
87   using difference_type = 87   using difference_type =
88   typename std::iterator_traits<iter_type>::difference_type; 88   typename std::iterator_traits<iter_type>::difference_type;
89   89  
90   BufferSequence bs_; 90   BufferSequence bs_;
91   difference_type begin_ = 0; // index of first buffer in sequence 91   difference_type begin_ = 0; // index of first buffer in sequence
92   difference_type end_ = 0; // 1 + index of last buffer in sequence 92   difference_type end_ = 0; // 1 + index of last buffer in sequence
93   std::size_t len_ = 0; // length of bs_ 93   std::size_t len_ = 0; // length of bs_
94   std::size_t size_ = 0; // total bytes 94   std::size_t size_ = 0; // total bytes
95   std::size_t prefix_ = 0; // used prefix bytes 95   std::size_t prefix_ = 0; // used prefix bytes
96   std::size_t suffix_ = 0; // used suffix bytes 96   std::size_t suffix_ = 0; // used suffix bytes
97   97  
98   public: 98   public:
99   /** The type of values returned by iterators 99   /** The type of values returned by iterators
100   */ 100   */
101   using value_type = std::conditional_t< 101   using value_type = std::conditional_t<
102   MutableBufferSequence<BufferSequence>, 102   MutableBufferSequence<BufferSequence>,
103   mutable_buffer, const_buffer>; 103   mutable_buffer, const_buffer>;
104   104  
105   /** The type of returned iterators 105   /** The type of returned iterators
106   */ 106   */
107   class const_iterator 107   class const_iterator
108   { 108   {
109   iter_type it_; 109   iter_type it_;
110   // VFALCO we could just point back to 110   // VFALCO we could just point back to
111   // the original sequence to save size 111   // the original sequence to save size
112   std::size_t prefix_ = 0; 112   std::size_t prefix_ = 0;
113   std::size_t suffix_ = 0; 113   std::size_t suffix_ = 0;
114   std::size_t i_ = 0; 114   std::size_t i_ = 0;
115   std::size_t n_ = 0; 115   std::size_t n_ = 0;
116   116  
117   friend class slice_of<BufferSequence>; 117   friend class slice_of<BufferSequence>;
118   118  
HITCBC 119   6652 const_iterator( 119   6652 const_iterator(
120   iter_type it, 120   iter_type it,
121   std::size_t prefix__, 121   std::size_t prefix__,
122   std::size_t suffix__, 122   std::size_t suffix__,
123   std::size_t i, 123   std::size_t i,
124   std::size_t n) noexcept 124   std::size_t n) noexcept
HITCBC 125   6652 : it_(it) 125   6652 : it_(it)
HITCBC 126   6652 , prefix_(prefix__) 126   6652 , prefix_(prefix__)
HITCBC 127   6652 , suffix_(suffix__) 127   6652 , suffix_(suffix__)
HITCBC 128   6652 , i_(i) 128   6652 , i_(i)
HITCBC 129   6652 , n_(n) 129   6652 , n_(n)
130   { 130   {
131   // n_ is the index of the end iterator 131   // n_ is the index of the end iterator
HITCBC 132   6652 } 132   6652 }
133   133  
134   public: 134   public:
135   using value_type = typename slice_of::value_type; 135   using value_type = typename slice_of::value_type;
136   using reference = value_type; 136   using reference = value_type;
137   using pointer = void; 137   using pointer = void;
138   using difference_type = std::ptrdiff_t; 138   using difference_type = std::ptrdiff_t;
139   using iterator_category = 139   using iterator_category =
140   std::bidirectional_iterator_tag; 140   std::bidirectional_iterator_tag;
141   using iterator_concept = std::bidirectional_iterator_tag; 141   using iterator_concept = std::bidirectional_iterator_tag;
142   142  
143   const_iterator() = default; 143   const_iterator() = default;
144   144  
145   /// Test for equality. 145   /// Test for equality.
146   bool 146   bool
HITCBC 147   9116 operator==( 147   9116 operator==(
148   const_iterator const& other) const noexcept 148   const_iterator const& other) const noexcept
149   { 149   {
150   return 150   return
HITCBC 151   9144 it_ == other.it_ && 151   9144 it_ == other.it_ &&
HITCBC 152   3326 prefix_ == other.prefix_ && 152   3326 prefix_ == other.prefix_ &&
HITCBC 153   3326 suffix_ == other.suffix_ && 153   3326 suffix_ == other.suffix_ &&
HITCBC 154   15768 i_ == other.i_ && 154   15768 i_ == other.i_ &&
HITCBC 155   12442 n_ == other.n_; 155   12442 n_ == other.n_;
156   } 156   }
157   157  
158   /// Test for inequality. 158   /// Test for inequality.
159   bool 159   bool
HITCBC 160   9116 operator!=( 160   9116 operator!=(
161   const_iterator const& other) const noexcept 161   const_iterator const& other) const noexcept
162   { 162   {
HITCBC 163   9116 return !(*this == other); 163   9116 return !(*this == other);
164   } 164   }
165   165  
166   /// Return the current buffer, adjusted for prefix/suffix. 166   /// Return the current buffer, adjusted for prefix/suffix.
167   reference 167   reference
HITCBC 168   5790 operator*() const noexcept 168   5790 operator*() const noexcept
169   { 169   {
HITCBC 170   5790 value_type v = *it_; 170   5790 value_type v = *it_;
171   using P = std::conditional_t< 171   using P = std::conditional_t<
172   MutableBufferSequence<BufferSequence>, 172   MutableBufferSequence<BufferSequence>,
173   char*, char const*>; 173   char*, char const*>;
HITCBC 174   5790 auto p = reinterpret_cast<P>(v.data()); 174   5790 auto p = reinterpret_cast<P>(v.data());
HITCBC 175   5790 auto n = v.size(); 175   5790 auto n = v.size();
HITCBC 176   5790 if(i_ == 0) 176   5790 if(i_ == 0)
177   { 177   {
HITCBC 178   2943 p += prefix_; 178   2943 p += prefix_;
HITCBC 179   2943 n -= prefix_; 179   2943 n -= prefix_;
180   } 180   }
HITCBC 181   5790 if(i_ == n_ - 1) 181   5790 if(i_ == n_ - 1)
HITCBC 182   2943 n -= suffix_; 182   2943 n -= suffix_;
HITCBC 183   5790 return value_type(p, n); 183   5790 return value_type(p, n);
184   } 184   }
185   185  
186   /// Advance to the next element. 186   /// Advance to the next element.
187   const_iterator& 187   const_iterator&
HITCBC 188   4502 operator++() noexcept 188   4502 operator++() noexcept
189   { 189   {
HITCBC 190   4502 BOOST_CAPY_ASSERT(i_ < n_); 190   4502 BOOST_CAPY_ASSERT(i_ < n_);
HITCBC 191   4502 ++it_; 191   4502 ++it_;
HITCBC 192   4502 ++i_; 192   4502 ++i_;
HITCBC 193   4502 return *this; 193   4502 return *this;
194   } 194   }
195   195  
196   /// Advance to the next element (postfix). 196   /// Advance to the next element (postfix).
197   const_iterator 197   const_iterator
HITCBC 198   644 operator++(int) noexcept 198   644 operator++(int) noexcept
199   { 199   {
HITCBC 200   644 auto temp = *this; 200   644 auto temp = *this;
HITCBC 201   644 ++(*this); 201   644 ++(*this);
HITCBC 202   644 return temp; 202   644 return temp;
203   } 203   }
204   204  
205   /// Move to the previous element. 205   /// Move to the previous element.
206   const_iterator& 206   const_iterator&
HITCBC 207   1288 operator--() noexcept 207   1288 operator--() noexcept
208   { 208   {
HITCBC 209   1288 BOOST_CAPY_ASSERT(i_ > 0); 209   1288 BOOST_CAPY_ASSERT(i_ > 0);
HITCBC 210   1288 --it_; 210   1288 --it_;
HITCBC 211   1288 --i_; 211   1288 --i_;
HITCBC 212   1288 return *this; 212   1288 return *this;
213   } 213   }
214   214  
215   /// Move to the previous element (postfix). 215   /// Move to the previous element (postfix).
216   const_iterator 216   const_iterator
HITCBC 217   644 operator--(int) noexcept 217   644 operator--(int) noexcept
218   { 218   {
HITCBC 219   644 auto temp = *this; 219   644 auto temp = *this;
HITCBC 220   644 --(*this); 220   644 --(*this);
HITCBC 221   644 return temp; 221   644 return temp;
222   } 222   }
223   }; 223   };
224   224  
225   /** Constructor 225   /** Constructor
226   */ 226   */
227   slice_of() = default; 227   slice_of() = default;
228   228  
229   /** Constructor 229   /** Constructor
230   */ 230   */
HITCBC 231   194 slice_of( 231   194 slice_of(
232   BufferSequence const& bs) 232   BufferSequence const& bs)
HITCBC 233   194 : bs_(bs) 233   194 : bs_(bs)
234   { 234   {
HITCBC 235   194 iter_type it = capy::begin(bs_); 235   194 iter_type it = capy::begin(bs_);
HITCBC 236   194 iter_type eit = capy::end(bs_); 236   194 iter_type eit = capy::end(bs_);
HITCBC 237   194 begin_ = 0; 237   194 begin_ = 0;
HITCBC 238   194 end_ = std::distance(it, eit); 238   194 end_ = std::distance(it, eit);
HITCBC 239   776 while(it != eit) 239   776 while(it != eit)
240   { 240   {
HITCBC 241   582 value_type b(*it); 241   582 value_type b(*it);
HITCBC 242   582 size_ += b.size(); 242   582 size_ += b.size();
HITCBC 243   582 ++len_; 243   582 ++len_;
HITCBC 244   582 ++it; 244   582 ++it;
245   } 245   }
HITCBC 246   194 } 246   194 }
247   247  
248   /** Return an iterator to the beginning of the sequence 248   /** Return an iterator to the beginning of the sequence
249   */ 249   */
250   const_iterator 250   const_iterator
HITCBC 251   3326 begin() const noexcept 251   3326 begin() const noexcept
252   { 252   {
253   return const_iterator( 253   return const_iterator(
HITCBC 254   3326 begin_iter_impl(), prefix_, suffix_, 0, len_); 254   3326 begin_iter_impl(), prefix_, suffix_, 0, len_);
255   } 255   }
256   256  
257   /** Return an iterator to the end of the sequence 257   /** Return an iterator to the end of the sequence
258   */ 258   */
259   const_iterator 259   const_iterator
HITCBC 260   3326 end() const noexcept 260   3326 end() const noexcept
261   { 261   {
262   return const_iterator( 262   return const_iterator(
HITCBC 263   3326 end_iter_impl(), prefix_, suffix_, len_, len_); 263   3326 end_iter_impl(), prefix_, suffix_, len_, len_);
264   } 264   }
265   265  
266   /// Slice customization point for this type. 266   /// Slice customization point for this type.
267   friend 267   friend
268   void 268   void
HITCBC 269   671 tag_invoke( 269   671 tag_invoke(
270   slice_tag const&, 270   slice_tag const&,
271   slice_of<BufferSequence>& bs, 271   slice_of<BufferSequence>& bs,
272   slice_how how, 272   slice_how how,
273   std::size_t n) 273   std::size_t n)
274   { 274   {
HITCBC 275   671 bs.slice_impl(how, n); 275   671 bs.slice_impl(how, n);
HITCBC 276   671 } 276   671 }
277   277  
278   private: 278   private:
279   iter_type 279   iter_type
HITCBC 280   3938 begin_iter_impl() const noexcept 280   3938 begin_iter_impl() const noexcept
281   { 281   {
HITCBC 282   3938 iter_type it = capy::begin(bs_); 282   3938 iter_type it = capy::begin(bs_);
HITCBC 283   3938 std::advance(it, begin_); 283   3938 std::advance(it, begin_);
HITCBC 284   3938 return it; 284   3938 return it;
285   } 285   }
286   286  
287   iter_type 287   iter_type
HITCBC 288   3591 end_iter_impl() const noexcept 288   3591 end_iter_impl() const noexcept
289   { 289   {
HITCBC 290   3591 iter_type it = capy::begin(bs_); 290   3591 iter_type it = capy::begin(bs_);
HITCBC 291   3591 std::advance(it, end_); 291   3591 std::advance(it, end_);
HITCBC 292   3591 return it; 292   3591 return it;
293   } 293   }
294   294  
295   void 295   void
HITCBC 296   347 remove_prefix_impl( 296   347 remove_prefix_impl(
297   std::size_t n) 297   std::size_t n)
298   { 298   {
HITCBC 299   347 if(n > size_) 299   347 if(n > size_)
HITCBC 300   25 n = size_; 300   25 n = size_;
301   301  
302   // nice hack to simplify the loop (M. Nejati) 302   // nice hack to simplify the loop (M. Nejati)
HITCBC 303   347 n += prefix_; 303   347 n += prefix_;
HITCBC 304   347 size_ += prefix_; 304   347 size_ += prefix_;
HITCBC 305   347 prefix_ = 0; 305   347 prefix_ = 0;
306   306  
HITCBC 307   347 iter_type it = begin_iter_impl(); 307   347 iter_type it = begin_iter_impl();
308   308  
HITCBC 309   709 while(n > 0 && begin_ != end_) 309   709 while(n > 0 && begin_ != end_)
310   { 310   {
HITCBC 311   612 value_type b = *it; 311   612 value_type b = *it;
HITCBC 312   612 if(n < b.size()) 312   612 if(n < b.size())
313   { 313   {
HITCBC 314   250 prefix_ = n; 314   250 prefix_ = n;
HITCBC 315   250 size_ -= n; 315   250 size_ -= n;
HITCBC 316   250 break; 316   250 break;
317   } 317   }
HITCBC 318   362 n -= b.size(); 318   362 n -= b.size();
HITCBC 319   362 size_ -= b.size(); 319   362 size_ -= b.size();
HITCBC 320   362 ++begin_; 320   362 ++begin_;
HITCBC 321   362 ++it; 321   362 ++it;
HITCBC 322   362 --len_; 322   362 --len_;
323   } 323   }
HITCBC 324   347 } 324   347 }
325   325  
326   void 326   void
HITCBC 327   265 remove_suffix_impl( 327   265 remove_suffix_impl(
328   std::size_t n) 328   std::size_t n)
329   { 329   {
HITCBC 330   265 if(size_ == 0) 330   265 if(size_ == 0)
331   { 331   {
MISUBC 332   BOOST_CAPY_ASSERT(begin_ == end_); 332   BOOST_CAPY_ASSERT(begin_ == end_);
HITCBC 333   265 return; 333   265 return;
334   } 334   }
HITCBC 335   265 BOOST_CAPY_ASSERT(begin_ != end_); 335   265 BOOST_CAPY_ASSERT(begin_ != end_);
336   336  
HITCBC 337   265 if(n > size_) 337   265 if(n > size_)
MISUBC 338   n = size_; 338   n = size_;
339   339  
HITCBC 340   265 n += suffix_; 340   265 n += suffix_;
HITCBC 341   265 size_ += suffix_; 341   265 size_ += suffix_;
HITCBC 342   265 suffix_ = 0; 342   265 suffix_ = 0;
343   343  
HITCBC 344   265 iter_type bit = begin_iter_impl(); 344   265 iter_type bit = begin_iter_impl();
HITCBC 345   265 iter_type it = end_iter_impl(); 345   265 iter_type it = end_iter_impl();
HITCBC 346   265 it--; 346   265 it--;
347   347  
HITCBC 348   517 while(it != bit) 348   517 while(it != bit)
349   { 349   {
HITCBC 350   391 value_type b = *it; 350   391 value_type b = *it;
HITCBC 351   391 if(n < b.size()) 351   391 if(n < b.size())
352   { 352   {
HITCBC 353   139 suffix_ = n; 353   139 suffix_ = n;
HITCBC 354   139 size_ -= n; 354   139 size_ -= n;
HITCBC 355   139 return; 355   139 return;
356   } 356   }
HITCBC 357   252 n -= b.size(); 357   252 n -= b.size();
HITCBC 358   252 size_ -= b.size(); 358   252 size_ -= b.size();
HITCBC 359   252 --it; 359   252 --it;
HITCBC 360   252 --end_; 360   252 --end_;
HITCBC 361   252 --len_; 361   252 --len_;
362   } 362   }
HITCBC 363   126 value_type b = *it; 363   126 value_type b = *it;
HITCBC 364   126 auto m = b.size() - prefix_; 364   126 auto m = b.size() - prefix_;
HITCBC 365   126 if(n < m) 365   126 if(n < m)
366   { 366   {
HITCBC 367   126 suffix_ = n; 367   126 suffix_ = n;
HITCBC 368   126 size_ -= n; 368   126 size_ -= n;
HITCBC 369   126 return; 369   126 return;
370   } 370   }
MISUBC 371   end_ = begin_; 371   end_ = begin_;
MISUBC 372   len_ = 0; 372   len_ = 0;
MISUBC 373   size_ = 0; 373   size_ = 0;
374   } 374   }
375   375  
376   void 376   void
HITCBC 377   324 keep_prefix_impl( 377   324 keep_prefix_impl(
378   std::size_t n) 378   std::size_t n)
379   { 379   {
HITCBC 380   324 if(n >= size_) 380   324 if(n >= size_)
HITCBC 381   9 return; 381   9 return;
HITCBC 382   315 if(n == 0) 382   315 if(n == 0)
383   { 383   {
HITCBC 384   50 end_ = begin_; 384   50 end_ = begin_;
HITCBC 385   50 len_ = 0; 385   50 len_ = 0;
HITCBC 386   50 size_ = 0; 386   50 size_ = 0;
HITCBC 387   50 return; 387   50 return;
388   } 388   }
HITCBC 389   265 remove_suffix_impl(size_ - n); 389   265 remove_suffix_impl(size_ - n);
390   } 390   }
391   391  
392   void 392   void
393   keep_suffix_impl( 393   keep_suffix_impl(
394   std::size_t n) 394   std::size_t n)
395   { 395   {
396   if(n >= size_) 396   if(n >= size_)
397   return; 397   return;
398   if(n == 0) 398   if(n == 0)
399   { 399   {
400   begin_ = end_; 400   begin_ = end_;
401   len_ = 0; 401   len_ = 0;
402   size_ = 0; 402   size_ = 0;
403   return; 403   return;
404   } 404   }
405   remove_prefix_impl(size_ - n); 405   remove_prefix_impl(size_ - n);
406   } 406   }
407   407  
408   void 408   void
HITCBC 409   671 slice_impl( 409   671 slice_impl(
410   slice_how how, 410   slice_how how,
411   std::size_t n) 411   std::size_t n)
412   { 412   {
HITCBC 413   671 switch(how) 413   671 switch(how)
414   { 414   {
HITCBC 415   347 case slice_how::remove_prefix: 415   347 case slice_how::remove_prefix:
416   { 416   {
HITCBC 417   347 remove_prefix_impl(n); 417   347 remove_prefix_impl(n);
HITCBC 418   347 break; 418   347 break;
419   } 419   }
HITCBC 420   324 case slice_how::keep_prefix: 420   324 case slice_how::keep_prefix:
421   { 421   {
HITCBC 422   324 keep_prefix_impl(n); 422   324 keep_prefix_impl(n);
HITCBC 423   324 break; 423   324 break;
424   } 424   }
425   } 425   }
HITCBC 426   671 } 426   671 }
427   }; 427   };
428   428  
429   // in-place modify return value 429   // in-place modify return value
430   // ----------------------------- 430   // -----------------------------
431   // keep_prefix* prefix 431   // keep_prefix* prefix
432   // keep_suffix suffix 432   // keep_suffix suffix
433   // remove_prefix* sans_prefix 433   // remove_prefix* sans_prefix
434   // remove_suffix sans_suffix 434   // remove_suffix sans_suffix
435   435  
436   /** Remove all but the first `n` bytes from a buffer sequence 436   /** Remove all but the first `n` bytes from a buffer sequence
437   */ 437   */
438   constexpr struct keep_prefix_mrdocs_workaround_t 438   constexpr struct keep_prefix_mrdocs_workaround_t
439   { 439   {
440   template<ConstBufferSequence BufferSequence> 440   template<ConstBufferSequence BufferSequence>
441   requires detail::has_tag_invoke<BufferSequence>::value 441   requires detail::has_tag_invoke<BufferSequence>::value
HITCBC 442   3142 void operator()( 442   3142 void operator()(
443   BufferSequence& bs, 443   BufferSequence& bs,
444   std::size_t n) const 444   std::size_t n) const
445   { 445   {
HITCBC 446   3142 tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n); 446   3142 tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n);
HITCBC 447   3142 } 447   3142 }
448   } const keep_prefix{}; 448   } const keep_prefix{};
449   449  
450   /** Remove all but the last `n` bytes from a buffer sequence 450   /** Remove all but the last `n` bytes from a buffer sequence
451   */ 451   */
452   constexpr struct keep_suffix_mrdocs_workaround_t 452   constexpr struct keep_suffix_mrdocs_workaround_t
453   { 453   {
454   template<ConstBufferSequence BufferSequence> 454   template<ConstBufferSequence BufferSequence>
455   requires detail::has_tag_invoke<BufferSequence>::value 455   requires detail::has_tag_invoke<BufferSequence>::value
HITCBC 456   1132 void operator()( 456   1132 void operator()(
457   BufferSequence& bs, 457   BufferSequence& bs,
458   std::size_t n) const 458   std::size_t n) const
459   { 459   {
HITCBC 460   1132 auto n0 = buffer_size(bs); 460   1132 auto n0 = buffer_size(bs);
HITCBC 461   1132 if(n < n0) 461   1132 if(n < n0)
HITCBC 462   998 tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n0 - n); 462   998 tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n0 - n);
HITCBC 463   1132 } 463   1132 }
464   } const keep_suffix{}; 464   } const keep_suffix{};
465   465  
466   /** Remove `n` bytes from the beginning of a buffer sequence 466   /** Remove `n` bytes from the beginning of a buffer sequence
467   */ 467   */
468   constexpr struct remove_prefix_mrdocs_workaround_t 468   constexpr struct remove_prefix_mrdocs_workaround_t
469   { 469   {
470   template<ConstBufferSequence BufferSequence> 470   template<ConstBufferSequence BufferSequence>
471   requires detail::has_tag_invoke<BufferSequence>::value 471   requires detail::has_tag_invoke<BufferSequence>::value
HITCBC 472   3369 void operator()( 472   3369 void operator()(
473   BufferSequence& bs, 473   BufferSequence& bs,
474   std::size_t n) const 474   std::size_t n) const
475   { 475   {
HITCBC 476   3369 tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n); 476   3369 tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n);
HITCBC 477   3369 } 477   3369 }
478   } const remove_prefix{}; 478   } const remove_prefix{};
479   479  
480   /** Remove `n` bytes from the end of a buffer sequence 480   /** Remove `n` bytes from the end of a buffer sequence
481   */ 481   */
482   constexpr struct remove_suffix_mrdocs_workaround_t 482   constexpr struct remove_suffix_mrdocs_workaround_t
483   { 483   {
484   template<ConstBufferSequence BufferSequence> 484   template<ConstBufferSequence BufferSequence>
485   requires detail::has_tag_invoke<BufferSequence>::value 485   requires detail::has_tag_invoke<BufferSequence>::value
HITCBC 486   1386 void operator()( 486   1386 void operator()(
487   BufferSequence& bs, 487   BufferSequence& bs,
488   std::size_t n) const 488   std::size_t n) const
489   { 489   {
HITCBC 490   1386 auto n0 = buffer_size(bs); 490   1386 auto n0 = buffer_size(bs);
HITCBC 491   1386 if(n > 0) 491   1386 if(n > 0)
492   { 492   {
HITCBC 493   1297 if( n > n0) 493   1297 if( n > n0)
HITCBC 494   89 n = n0; 494   89 n = n0;
HITCBC 495   1297 tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n0 - n); 495   1297 tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n0 - n);
496   } 496   }
HITCBC 497   1386 } 497   1386 }
498   } const remove_suffix{}; 498   } const remove_suffix{};
499   499  
500   /** Return a sequence representing the first `n` bytes of a buffer sequence 500   /** Return a sequence representing the first `n` bytes of a buffer sequence
501   */ 501   */
502   constexpr struct prefix_mrdocs_workaround_t 502   constexpr struct prefix_mrdocs_workaround_t
503   { 503   {
504   template<ConstBufferSequence BufferSequence> 504   template<ConstBufferSequence BufferSequence>
HITCBC 505   944 slice_type<BufferSequence> operator()( 505   944 slice_type<BufferSequence> operator()(
506   BufferSequence const& bs, 506   BufferSequence const& bs,
507   std::size_t n) const noexcept 507   std::size_t n) const noexcept
508   { 508   {
HITCBC 509   944 slice_type<BufferSequence> result(bs); 509   944 slice_type<BufferSequence> result(bs);
HITCBC 510   944 keep_prefix(result, n); 510   944 keep_prefix(result, n);
HITCBC 511   944 return result; 511   944 return result;
512   } 512   }
513   } prefix{}; 513   } prefix{};
514   514  
515   /** Return a sequence representing the last `n` bytes of a buffer sequence 515   /** Return a sequence representing the last `n` bytes of a buffer sequence
516   */ 516   */
517   constexpr struct suffix_mrdocs_workaround_t 517   constexpr struct suffix_mrdocs_workaround_t
518   { 518   {
519   template<ConstBufferSequence BufferSequence> 519   template<ConstBufferSequence BufferSequence>
520   slice_type<BufferSequence> operator()( 520   slice_type<BufferSequence> operator()(
521   BufferSequence const& bs, 521   BufferSequence const& bs,
522   std::size_t n) const noexcept 522   std::size_t n) const noexcept
523   { 523   {
524   slice_type<BufferSequence> result(bs); 524   slice_type<BufferSequence> result(bs);
525   keep_suffix(result, n); 525   keep_suffix(result, n);
526   return result; 526   return result;
527   } 527   }
528   } suffix{}; 528   } suffix{};
529   529  
530   /** Return a sequence representing all but the first `n` bytes of a buffer sequence 530   /** Return a sequence representing all but the first `n` bytes of a buffer sequence
531   */ 531   */
532   constexpr struct sans_prefix_mrdocs_workaround_t 532   constexpr struct sans_prefix_mrdocs_workaround_t
533   { 533   {
534   template<ConstBufferSequence BufferSequence> 534   template<ConstBufferSequence BufferSequence>
HITCBC 535   959 slice_type<BufferSequence> operator()( 535   959 slice_type<BufferSequence> operator()(
536   BufferSequence const& bs, 536   BufferSequence const& bs,
537   std::size_t n) const noexcept 537   std::size_t n) const noexcept
538   { 538   {
HITCBC 539   959 slice_type<BufferSequence> result(bs); 539   959 slice_type<BufferSequence> result(bs);
HITCBC 540   959 remove_prefix(result, n); 540   959 remove_prefix(result, n);
HITCBC 541   959 return result; 541   959 return result;
542   } 542   }
543   } sans_prefix{}; 543   } sans_prefix{};
544   544  
545   /** Return a sequence representing all but the last `n` bytes of a buffer sequence 545   /** Return a sequence representing all but the last `n` bytes of a buffer sequence
546   */ 546   */
547   constexpr struct sans_suffix_mrdocs_workaround_t 547   constexpr struct sans_suffix_mrdocs_workaround_t
548   { 548   {
549   template<ConstBufferSequence BufferSequence> 549   template<ConstBufferSequence BufferSequence>
550   slice_type<BufferSequence> operator()( 550   slice_type<BufferSequence> operator()(
551   BufferSequence const& bs, 551   BufferSequence const& bs,
552   std::size_t n) const noexcept 552   std::size_t n) const noexcept
553   { 553   {
554   slice_type<BufferSequence> result(bs); 554   slice_type<BufferSequence> result(bs);
555   remove_suffix(result, n); 555   remove_suffix(result, n);
556   return result; 556   return result;
557   } 557   }
558   } sans_suffix{}; 558   } sans_suffix{};
559   559  
560   } // capy 560   } // capy
561   } // boost 561   } // boost
562   562  
563   #endif 563   #endif