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 +
//------------------------------------------------
48 -

 
49 -
    This class wraps a buffer sequence and presents a
 
50 -
    contiguous byte sub-range by adjusting the first and
 
51 -
    last buffers. The prefix and suffix can be removed or
 
52 -
    kept using the free functions @ref keep_prefix,
 
53 -
    @ref remove_prefix, etc.
 
54 -

 
55 -
    The wrapped sequence is stored by value. The underlying
 
56 -
    buffer memory must remain valid for the lifetime of the
 
57 -
    slice.
 
58 -

 
59 -
    @par Thread Safety
 
60 -
    Distinct objects: Safe.
 
61 -
    Shared objects: Unsafe.
 
62 -

 
63 -
    @par Example
 
64 -
    @code
 
65 -
    mutable_buffer buf(data, 100);
 
66 -
    auto s = prefix(buf, 50);   // first 50 bytes
 
67 -
    remove_prefix(s, 10);       // now bytes 10..49
 
68 -
    @endcode
 
69 -

 
70 -
    @tparam BufferSequence The buffer sequence type, stored
 
71 -
        by value. Must satisfy @ref ConstBufferSequence.
 
72  

48  

73 -
    @see keep_prefix, remove_prefix, prefix, sans_prefix
49 +
/** A wrapper enabling a buffer sequence to be consumed
74  
*/
50  
*/
75  
template<ConstBufferSequence BufferSequence>
51  
template<ConstBufferSequence BufferSequence>
76  
class slice_of<BufferSequence>
52  
class slice_of<BufferSequence>
77  
{
53  
{
78  
    static_assert(!std::is_const_v<BufferSequence>,
54  
    static_assert(!std::is_const_v<BufferSequence>,
79  
        "BufferSequence can't be const");
55  
        "BufferSequence can't be const");
80  

56  

81  
    static_assert(!std::is_reference_v<BufferSequence>,
57  
    static_assert(!std::is_reference_v<BufferSequence>,
82  
        "BufferSequence can't be a reference");
58  
        "BufferSequence can't be a reference");
83  

59  

84  
    using iter_type = decltype(
60  
    using iter_type = decltype(
85  
        std::declval<BufferSequence const&>().begin());
61  
        std::declval<BufferSequence const&>().begin());
86  

62  

87  
    using difference_type =
63  
    using difference_type =
88  
        typename std::iterator_traits<iter_type>::difference_type;
64  
        typename std::iterator_traits<iter_type>::difference_type;
89  

65  

90  
    BufferSequence bs_;
66  
    BufferSequence bs_;
91  
    difference_type begin_ = 0; // index of first buffer in sequence
67  
    difference_type begin_ = 0; // index of first buffer in sequence
92  
    difference_type end_ = 0;   // 1 + index of last buffer in sequence
68  
    difference_type end_ = 0;   // 1 + index of last buffer in sequence
93  
    std::size_t len_ = 0;       // length of bs_
69  
    std::size_t len_ = 0;       // length of bs_
94  
    std::size_t size_ = 0;      // total bytes
70  
    std::size_t size_ = 0;      // total bytes
95  
    std::size_t prefix_ = 0;    // used prefix bytes
71  
    std::size_t prefix_ = 0;    // used prefix bytes
96  
    std::size_t suffix_ = 0;    // used suffix bytes
72  
    std::size_t suffix_ = 0;    // used suffix bytes
97  

73  

98  
public:
74  
public:
99  
    /** The type of values returned by iterators
75  
    /** The type of values returned by iterators
100  
    */
76  
    */
101  
    using value_type = std::conditional_t<
77  
    using value_type = std::conditional_t<
102  
        MutableBufferSequence<BufferSequence>,
78  
        MutableBufferSequence<BufferSequence>,
103  
        mutable_buffer, const_buffer>;
79  
        mutable_buffer, const_buffer>;
104  

80  

105  
    /** The type of returned iterators
81  
    /** The type of returned iterators
106  
    */
82  
    */
107  
    class const_iterator
83  
    class const_iterator
108  
    {
84  
    {
109  
        iter_type it_;
85  
        iter_type it_;
110  
        // VFALCO we could just point back to
86  
        // VFALCO we could just point back to
111  
        // the original sequence to save size
87  
        // the original sequence to save size
112  
        std::size_t prefix_ = 0;
88  
        std::size_t prefix_ = 0;
113  
        std::size_t suffix_ = 0;
89  
        std::size_t suffix_ = 0;
114  
        std::size_t i_ = 0;
90  
        std::size_t i_ = 0;
115  
        std::size_t n_ = 0;
91  
        std::size_t n_ = 0;
116  

92  

117  
        friend class slice_of<BufferSequence>;
93  
        friend class slice_of<BufferSequence>;
118  

94  

119  
        const_iterator(
95  
        const_iterator(
120  
            iter_type it,
96  
            iter_type it,
121  
            std::size_t prefix__,
97  
            std::size_t prefix__,
122  
            std::size_t suffix__,
98  
            std::size_t suffix__,
123  
            std::size_t i,
99  
            std::size_t i,
124  
            std::size_t n) noexcept
100  
            std::size_t n) noexcept
125  
            : it_(it)
101  
            : it_(it)
126  
            , prefix_(prefix__)
102  
            , prefix_(prefix__)
127  
            , suffix_(suffix__)
103  
            , suffix_(suffix__)
128  
            , i_(i)
104  
            , i_(i)
129  
            , n_(n)
105  
            , n_(n)
130  
        {
106  
        {
131  
            // n_ is the index of the end iterator
107  
            // n_ is the index of the end iterator
132  
        }
108  
        }
133  

109  

134  
    public:
110  
    public:
135  
        using value_type = typename slice_of::value_type;
111  
        using value_type = typename slice_of::value_type;
136  
        using reference = value_type;
112  
        using reference = value_type;
137  
        using pointer = void;
113  
        using pointer = void;
138  
        using difference_type = std::ptrdiff_t;
114  
        using difference_type = std::ptrdiff_t;
139  
        using iterator_category =
115  
        using iterator_category =
140  
            std::bidirectional_iterator_tag;
116  
            std::bidirectional_iterator_tag;
141  
        using iterator_concept = std::bidirectional_iterator_tag;
117  
        using iterator_concept = std::bidirectional_iterator_tag;
142  

118  

143  
        const_iterator() = default;
119  
        const_iterator() = default;
144 -
        /// Test for equality.
 
145  

120  

146  
        bool
121  
        bool
147  
        operator==(
122  
        operator==(
148  
            const_iterator const& other) const noexcept
123  
            const_iterator const& other) const noexcept
149  
        {
124  
        {
150  
            return
125  
            return
151  
                it_     == other.it_ &&
126  
                it_     == other.it_ &&
152  
                prefix_ == other.prefix_ &&
127  
                prefix_ == other.prefix_ &&
153  
                suffix_ == other.suffix_ &&
128  
                suffix_ == other.suffix_ &&
154  
                i_      == other.i_ &&
129  
                i_      == other.i_ &&
155  
                n_      == other.n_;
130  
                n_      == other.n_;
156  
        }
131  
        }
157 -
        /// Test for inequality.
 
158  

132  

159  
        bool
133  
        bool
160  
        operator!=(
134  
        operator!=(
161  
            const_iterator const& other) const noexcept
135  
            const_iterator const& other) const noexcept
162  
        {
136  
        {
163  
            return !(*this == other);
137  
            return !(*this == other);
164  
        }
138  
        }
165 -
        /// Return the current buffer, adjusted for prefix/suffix.
 
166  

139  

167  
        reference
140  
        reference
168  
        operator*() const noexcept
141  
        operator*() const noexcept
169  
        {
142  
        {
170  
            value_type v = *it_;
143  
            value_type v = *it_;
171  
            using P = std::conditional_t<
144  
            using P = std::conditional_t<
172  
                MutableBufferSequence<BufferSequence>,
145  
                MutableBufferSequence<BufferSequence>,
173  
                char*, char const*>;
146  
                char*, char const*>;
174  
            auto p = reinterpret_cast<P>(v.data());
147  
            auto p = reinterpret_cast<P>(v.data());
175  
            auto n = v.size();
148  
            auto n = v.size();
176  
            if(i_ == 0)
149  
            if(i_ == 0)
177  
            {
150  
            {
178  
                p += prefix_;
151  
                p += prefix_;
179  
                n -= prefix_;
152  
                n -= prefix_;
180  
            }
153  
            }
181  
            if(i_ == n_ - 1)
154  
            if(i_ == n_ - 1)
182  
                n -= suffix_;
155  
                n -= suffix_;
183  
            return value_type(p, n);
156  
            return value_type(p, n);
184  
        }
157  
        }
185 -
        /// Advance to the next element.
 
186  

158  

187  
        const_iterator&
159  
        const_iterator&
188  
        operator++() noexcept
160  
        operator++() noexcept
189  
        {
161  
        {
190  
            BOOST_CAPY_ASSERT(i_ < n_);
162  
            BOOST_CAPY_ASSERT(i_ < n_);
191  
            ++it_;
163  
            ++it_;
192  
            ++i_;
164  
            ++i_;
193  
            return *this;
165  
            return *this;
194  
        }
166  
        }
195 -
        /// Advance to the next element (postfix).
 
196  

167  

197  
        const_iterator
168  
        const_iterator
198  
        operator++(int) noexcept
169  
        operator++(int) noexcept
199  
        {
170  
        {
200  
            auto temp = *this;
171  
            auto temp = *this;
201  
            ++(*this);
172  
            ++(*this);
202  
            return temp;
173  
            return temp;
203  
        }
174  
        }
204 -
        /// Move to the previous element.
 
205  

175  

206  
        const_iterator&
176  
        const_iterator&
207  
        operator--() noexcept
177  
        operator--() noexcept
208  
        {
178  
        {
209  
            BOOST_CAPY_ASSERT(i_ > 0);
179  
            BOOST_CAPY_ASSERT(i_ > 0);
210  
            --it_;
180  
            --it_;
211  
            --i_;
181  
            --i_;
212  
            return *this;
182  
            return *this;
213  
        }
183  
        }
214 -
        /// Move to the previous element (postfix).
 
215  

184  

216  
        const_iterator
185  
        const_iterator
217  
        operator--(int) noexcept
186  
        operator--(int) noexcept
218  
        {
187  
        {
219  
            auto temp = *this;
188  
            auto temp = *this;
220  
            --(*this);
189  
            --(*this);
221  
            return temp;
190  
            return temp;
222  
        }
191  
        }
223  
    };
192  
    };
224  

193  

225  
    /** Constructor
194  
    /** Constructor
226  
    */
195  
    */
227  
    slice_of() = default;
196  
    slice_of() = default;
228  

197  

229  
    /** Constructor
198  
    /** Constructor
230  
    */
199  
    */
231  
    slice_of(
200  
    slice_of(
232  
        BufferSequence const& bs)
201  
        BufferSequence const& bs)
233  
        : bs_(bs)
202  
        : bs_(bs)
234  
    {
203  
    {
235  
        iter_type it = capy::begin(bs_);
204  
        iter_type it = capy::begin(bs_);
236  
        iter_type eit = capy::end(bs_);
205  
        iter_type eit = capy::end(bs_);
237  
        begin_ = 0;
206  
        begin_ = 0;
238  
        end_ = std::distance(it, eit);
207  
        end_ = std::distance(it, eit);
239  
        while(it != eit)
208  
        while(it != eit)
240  
        {
209  
        {
241  
            value_type b(*it);
210  
            value_type b(*it);
242  
            size_ += b.size();
211  
            size_ += b.size();
243  
            ++len_;
212  
            ++len_;
244  
            ++it;
213  
            ++it;
245  
        }
214  
        }
246  
    }
215  
    }
247  

216  

248  
    /** Return an iterator to the beginning of the sequence
217  
    /** Return an iterator to the beginning of the sequence
249  
    */
218  
    */
250  
    const_iterator
219  
    const_iterator
251  
    begin() const noexcept
220  
    begin() const noexcept
252  
    {
221  
    {
253  
        return const_iterator(
222  
        return const_iterator(
254  
            begin_iter_impl(), prefix_, suffix_, 0, len_);
223  
            begin_iter_impl(), prefix_, suffix_, 0, len_);
255  
    }
224  
    }
256  

225  

257  
    /** Return an iterator to the end of the sequence
226  
    /** Return an iterator to the end of the sequence
258  
    */
227  
    */
259  
    const_iterator
228  
    const_iterator
260  
    end() const noexcept
229  
    end() const noexcept
261  
    {
230  
    {
262  
        return const_iterator(
231  
        return const_iterator(
263  
            end_iter_impl(), prefix_, suffix_, len_, len_);
232  
            end_iter_impl(), prefix_, suffix_, len_, len_);
264  
    }
233  
    }
265 -
    /// Slice customization point for this type.
 
266  

234  

267  
    friend
235  
    friend
268  
    void
236  
    void
269  
    tag_invoke(
237  
    tag_invoke(
270  
        slice_tag const&,
238  
        slice_tag const&,
271  
        slice_of<BufferSequence>& bs,
239  
        slice_of<BufferSequence>& bs,
272  
        slice_how how,
240  
        slice_how how,
273  
        std::size_t n)
241  
        std::size_t n)
274  
    {
242  
    {
275  
        bs.slice_impl(how, n);
243  
        bs.slice_impl(how, n);
276  
    }
244  
    }
277  

245  

278  
private:
246  
private:
279  
    iter_type
247  
    iter_type
280  
    begin_iter_impl() const noexcept
248  
    begin_iter_impl() const noexcept
281  
    {
249  
    {
282  
        iter_type it = capy::begin(bs_);
250  
        iter_type it = capy::begin(bs_);
283  
        std::advance(it, begin_);
251  
        std::advance(it, begin_);
284  
        return it;
252  
        return it;
285  
    }
253  
    }
286  

254  

287  
    iter_type
255  
    iter_type
288  
    end_iter_impl() const noexcept
256  
    end_iter_impl() const noexcept
289  
    {
257  
    {
290  
        iter_type it = capy::begin(bs_);
258  
        iter_type it = capy::begin(bs_);
291  
        std::advance(it, end_);
259  
        std::advance(it, end_);
292  
        return it;
260  
        return it;
293  
    }
261  
    }
294  

262  

295  
    void
263  
    void
296  
    remove_prefix_impl(
264  
    remove_prefix_impl(
297  
        std::size_t n)
265  
        std::size_t n)
298  
    {
266  
    {
299  
        if(n > size_)
267  
        if(n > size_)
300  
            n = size_;
268  
            n = size_;
301  

269  

302  
        // nice hack to simplify the loop (M. Nejati)
270  
        // nice hack to simplify the loop (M. Nejati)
303  
        n += prefix_;
271  
        n += prefix_;
304  
        size_ += prefix_;
272  
        size_ += prefix_;
305  
        prefix_ = 0;
273  
        prefix_ = 0;
306  

274  

307  
        iter_type it = begin_iter_impl();
275  
        iter_type it = begin_iter_impl();
308  

276  

309  
        while(n > 0 && begin_ != end_)
277  
        while(n > 0 && begin_ != end_)
310  
        {
278  
        {
311  
            value_type b = *it;
279  
            value_type b = *it;
312  
            if(n < b.size())
280  
            if(n < b.size())
313  
            {
281  
            {
314  
                prefix_ = n;
282  
                prefix_ = n;
315  
                size_ -= n;
283  
                size_ -= n;
316  
                break;
284  
                break;
317  
            }
285  
            }
318  
            n -= b.size();
286  
            n -= b.size();
319  
            size_ -= b.size();
287  
            size_ -= b.size();
320  
            ++begin_;
288  
            ++begin_;
321  
            ++it;
289  
            ++it;
322  
            --len_;
290  
            --len_;
323  
        }
291  
        }
324  
    }
292  
    }
325  

293  

326  
    void
294  
    void
327  
    remove_suffix_impl(
295  
    remove_suffix_impl(
328  
        std::size_t n)
296  
        std::size_t n)
329  
    {
297  
    {
330  
        if(size_ == 0)
298  
        if(size_ == 0)
331  
        {
299  
        {
332  
            BOOST_CAPY_ASSERT(begin_ == end_);
300  
            BOOST_CAPY_ASSERT(begin_ == end_);
333  
            return;
301  
            return;
334  
        }
302  
        }
335  
        BOOST_CAPY_ASSERT(begin_ != end_);
303  
        BOOST_CAPY_ASSERT(begin_ != end_);
336  

304  

337  
        if(n > size_)
305  
        if(n > size_)
338  
            n = size_;
306  
            n = size_;
339  

307  

340  
        n += suffix_;
308  
        n += suffix_;
341  
        size_ += suffix_;
309  
        size_ += suffix_;
342  
        suffix_ = 0;
310  
        suffix_ = 0;
343  

311  

344  
        iter_type bit = begin_iter_impl();
312  
        iter_type bit = begin_iter_impl();
345  
        iter_type it = end_iter_impl();
313  
        iter_type it = end_iter_impl();
346  
        it--;
314  
        it--;
347  

315  

348  
        while(it != bit)
316  
        while(it != bit)
349  
        {
317  
        {
350  
            value_type b = *it;
318  
            value_type b = *it;
351  
            if(n < b.size())
319  
            if(n < b.size())
352  
            {
320  
            {
353  
                suffix_ = n;
321  
                suffix_ = n;
354  
                size_ -= n;
322  
                size_ -= n;
355  
                return;
323  
                return;
356  
            }
324  
            }
357  
            n -= b.size();
325  
            n -= b.size();
358  
            size_ -= b.size();
326  
            size_ -= b.size();
359  
            --it;
327  
            --it;
360  
            --end_;
328  
            --end_;
361  
            --len_;
329  
            --len_;
362  
        }
330  
        }
363  
        value_type b = *it;
331  
        value_type b = *it;
364  
        auto m = b.size() - prefix_;
332  
        auto m = b.size() - prefix_;
365  
        if(n < m)
333  
        if(n < m)
366  
        {
334  
        {
367  
            suffix_ = n;
335  
            suffix_ = n;
368  
            size_ -= n;
336  
            size_ -= n;
369  
            return;
337  
            return;
370  
        }
338  
        }
371  
        end_ = begin_;
339  
        end_ = begin_;
372  
        len_ = 0;
340  
        len_ = 0;
373  
        size_ = 0;
341  
        size_ = 0;
374  
    }
342  
    }
375  

343  

376  
    void
344  
    void
377  
    keep_prefix_impl(
345  
    keep_prefix_impl(
378  
        std::size_t n)
346  
        std::size_t n)
379  
    {
347  
    {
380  
        if(n >= size_)
348  
        if(n >= size_)
381  
            return;
349  
            return;
382  
        if(n == 0)
350  
        if(n == 0)
383  
        {
351  
        {
384  
            end_ = begin_;
352  
            end_ = begin_;
385  
            len_ = 0;
353  
            len_ = 0;
386  
            size_ = 0;
354  
            size_ = 0;
387  
            return;
355  
            return;
388  
        }
356  
        }
389  
        remove_suffix_impl(size_ - n);
357  
        remove_suffix_impl(size_ - n);
390  
    }
358  
    }
391  

359  

392  
    void
360  
    void
393  
    keep_suffix_impl(
361  
    keep_suffix_impl(
394  
        std::size_t n)
362  
        std::size_t n)
395  
    {
363  
    {
396  
        if(n >= size_)
364  
        if(n >= size_)
397  
            return;
365  
            return;
398  
        if(n == 0)
366  
        if(n == 0)
399  
        {
367  
        {
400  
            begin_ = end_;
368  
            begin_ = end_;
401  
            len_ = 0;
369  
            len_ = 0;
402  
            size_ = 0;
370  
            size_ = 0;
403  
            return;
371  
            return;
404  
        }
372  
        }
405  
        remove_prefix_impl(size_ - n);
373  
        remove_prefix_impl(size_ - n);
406  
    }
374  
    }
407  

375  

408  
    void
376  
    void
409  
    slice_impl(
377  
    slice_impl(
410  
        slice_how how,
378  
        slice_how how,
411  
        std::size_t n)
379  
        std::size_t n)
412  
    {
380  
    {
413  
        switch(how)
381  
        switch(how)
414  
        {
382  
        {
415  
        case slice_how::remove_prefix:
383  
        case slice_how::remove_prefix:
416  
        {
384  
        {
417  
            remove_prefix_impl(n);
385  
            remove_prefix_impl(n);
418  
            break;
386  
            break;
419  
        }
387  
        }
420  
        case slice_how::keep_prefix:
388  
        case slice_how::keep_prefix:
421  
        {
389  
        {
422  
            keep_prefix_impl(n);
390  
            keep_prefix_impl(n);
423  
            break;
391  
            break;
424  
        }
392  
        }
425  
        }
393  
        }
426  
    }
394  
    }
427  
};
395  
};
428  

396  

 
397 +
//------------------------------------------------
 
398 +

429  
// in-place modify  return value
399  
// in-place modify  return value
430  
// -----------------------------
400  
// -----------------------------
431  
// keep_prefix*     prefix
401  
// keep_prefix*     prefix
432  
// keep_suffix      suffix
402  
// keep_suffix      suffix
433  
// remove_prefix*   sans_prefix
403  
// remove_prefix*   sans_prefix
434  
// remove_suffix    sans_suffix
404  
// remove_suffix    sans_suffix
435  

405  

436  
/** Remove all but the first `n` bytes from a buffer sequence
406  
/** Remove all but the first `n` bytes from a buffer sequence
437  
*/
407  
*/
438  
constexpr struct keep_prefix_mrdocs_workaround_t
408  
constexpr struct keep_prefix_mrdocs_workaround_t
439  
{
409  
{
440  
    template<ConstBufferSequence BufferSequence>
410  
    template<ConstBufferSequence BufferSequence>
441  
        requires detail::has_tag_invoke<BufferSequence>::value
411  
        requires detail::has_tag_invoke<BufferSequence>::value
442  
    void operator()(
412  
    void operator()(
443  
        BufferSequence& bs,
413  
        BufferSequence& bs,
444  
        std::size_t n) const
414  
        std::size_t n) const
445  
    {
415  
    {
446  
        tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n);
416  
        tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n);
447  
    }
417  
    }
448  
} const keep_prefix{};
418  
} const keep_prefix{};
449  

419  

450  
/** Remove all but the last `n` bytes from a buffer sequence
420  
/** Remove all but the last `n` bytes from a buffer sequence
451  
*/
421  
*/
452  
constexpr struct keep_suffix_mrdocs_workaround_t
422  
constexpr struct keep_suffix_mrdocs_workaround_t
453  
{
423  
{
454  
    template<ConstBufferSequence BufferSequence>
424  
    template<ConstBufferSequence BufferSequence>
455  
        requires detail::has_tag_invoke<BufferSequence>::value
425  
        requires detail::has_tag_invoke<BufferSequence>::value
456  
    void operator()(
426  
    void operator()(
457  
        BufferSequence& bs,
427  
        BufferSequence& bs,
458  
        std::size_t n) const
428  
        std::size_t n) const
459  
    {
429  
    {
460  
        auto n0 = buffer_size(bs);
430  
        auto n0 = buffer_size(bs);
461  
        if(n < n0)
431  
        if(n < n0)
462  
            tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n0 - n);
432  
            tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n0 - n);
463  
    }
433  
    }
464  
} const keep_suffix{};
434  
} const keep_suffix{};
465  

435  

466  
/** Remove `n` bytes from the beginning of a buffer sequence
436  
/** Remove `n` bytes from the beginning of a buffer sequence
467  
*/
437  
*/
468  
constexpr struct remove_prefix_mrdocs_workaround_t
438  
constexpr struct remove_prefix_mrdocs_workaround_t
469  
{
439  
{
470  
    template<ConstBufferSequence BufferSequence>
440  
    template<ConstBufferSequence BufferSequence>
471  
        requires detail::has_tag_invoke<BufferSequence>::value
441  
        requires detail::has_tag_invoke<BufferSequence>::value
472  
    void operator()(
442  
    void operator()(
473  
        BufferSequence& bs,
443  
        BufferSequence& bs,
474  
        std::size_t n) const
444  
        std::size_t n) const
475  
    {
445  
    {
476  
        tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n);
446  
        tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n);
477  
    }
447  
    }
478  
} const remove_prefix{};
448  
} const remove_prefix{};
479  

449  

480  
/** Remove `n` bytes from the end of a buffer sequence
450  
/** Remove `n` bytes from the end of a buffer sequence
481  
*/
451  
*/
482  
constexpr struct remove_suffix_mrdocs_workaround_t
452  
constexpr struct remove_suffix_mrdocs_workaround_t
483  
{
453  
{
484  
    template<ConstBufferSequence BufferSequence>
454  
    template<ConstBufferSequence BufferSequence>
485  
        requires detail::has_tag_invoke<BufferSequence>::value
455  
        requires detail::has_tag_invoke<BufferSequence>::value
486  
    void operator()(
456  
    void operator()(
487  
        BufferSequence& bs,
457  
        BufferSequence& bs,
488  
        std::size_t n) const
458  
        std::size_t n) const
489  
    {
459  
    {
490  
        auto n0 = buffer_size(bs);
460  
        auto n0 = buffer_size(bs);
491  
        if(n > 0)
461  
        if(n > 0)
492  
        {
462  
        {
493  
            if( n > n0)
463  
            if( n > n0)
494  
                n = n0;
464  
                n = n0;
495  
            tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n0 - n);
465  
            tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n0 - n);
496  
        }
466  
        }
497  
    }
467  
    }
498  
} const remove_suffix{};
468  
} const remove_suffix{};
 
469 +

 
470 +
//------------------------------------------------
499  

471  

500  
/** Return a sequence representing the first `n` bytes of a buffer sequence
472  
/** Return a sequence representing the first `n` bytes of a buffer sequence
501  
*/
473  
*/
502  
constexpr struct prefix_mrdocs_workaround_t
474  
constexpr struct prefix_mrdocs_workaround_t
503  
{
475  
{
504  
    template<ConstBufferSequence BufferSequence>
476  
    template<ConstBufferSequence BufferSequence>
505  
    slice_type<BufferSequence> operator()(
477  
    slice_type<BufferSequence> operator()(
506  
        BufferSequence const& bs,
478  
        BufferSequence const& bs,
507  
        std::size_t n) const noexcept
479  
        std::size_t n) const noexcept
508  
    {
480  
    {
509  
        slice_type<BufferSequence> result(bs);
481  
        slice_type<BufferSequence> result(bs);
510  
        keep_prefix(result, n);
482  
        keep_prefix(result, n);
511  
        return result;
483  
        return result;
512  
    }
484  
    }
513  
} prefix{};
485  
} prefix{};
514  

486  

515  
/** Return a sequence representing the last `n` bytes of a buffer sequence
487  
/** Return a sequence representing the last `n` bytes of a buffer sequence
516  
*/
488  
*/
517  
constexpr struct suffix_mrdocs_workaround_t
489  
constexpr struct suffix_mrdocs_workaround_t
518  
{
490  
{
519  
    template<ConstBufferSequence BufferSequence>
491  
    template<ConstBufferSequence BufferSequence>
520  
    slice_type<BufferSequence> operator()(
492  
    slice_type<BufferSequence> operator()(
521  
        BufferSequence const& bs,
493  
        BufferSequence const& bs,
522  
        std::size_t n) const noexcept
494  
        std::size_t n) const noexcept
523  
    {
495  
    {
524  
        slice_type<BufferSequence> result(bs);
496  
        slice_type<BufferSequence> result(bs);
525  
        keep_suffix(result, n);
497  
        keep_suffix(result, n);
526  
        return result;
498  
        return result;
527  
    }
499  
    }
528  
} suffix{};
500  
} suffix{};
529  

501  

530  
/** Return a sequence representing all but the first `n` bytes of a buffer sequence
502  
/** Return a sequence representing all but the first `n` bytes of a buffer sequence
531  
*/
503  
*/
532  
constexpr struct sans_prefix_mrdocs_workaround_t
504  
constexpr struct sans_prefix_mrdocs_workaround_t
533  
{
505  
{
534  
    template<ConstBufferSequence BufferSequence>
506  
    template<ConstBufferSequence BufferSequence>
535  
    slice_type<BufferSequence> operator()(
507  
    slice_type<BufferSequence> operator()(
536  
        BufferSequence const& bs,
508  
        BufferSequence const& bs,
537  
        std::size_t n) const noexcept
509  
        std::size_t n) const noexcept
538  
    {
510  
    {
539  
        slice_type<BufferSequence> result(bs);
511  
        slice_type<BufferSequence> result(bs);
540  
        remove_prefix(result, n);
512  
        remove_prefix(result, n);
541  
        return result;
513  
        return result;
542  
    }
514  
    }
543  
} sans_prefix{};
515  
} sans_prefix{};
544  

516  

545  
/** Return a sequence representing all but the last `n` bytes of a buffer sequence
517  
/** Return a sequence representing all but the last `n` bytes of a buffer sequence
546  
*/
518  
*/
547  
constexpr struct sans_suffix_mrdocs_workaround_t
519  
constexpr struct sans_suffix_mrdocs_workaround_t
548  
{
520  
{
549  
    template<ConstBufferSequence BufferSequence>
521  
    template<ConstBufferSequence BufferSequence>
550  
    slice_type<BufferSequence> operator()(
522  
    slice_type<BufferSequence> operator()(
551  
        BufferSequence const& bs,
523  
        BufferSequence const& bs,
552  
        std::size_t n) const noexcept
524  
        std::size_t n) const noexcept
553  
    {
525  
    {
554  
        slice_type<BufferSequence> result(bs);
526  
        slice_type<BufferSequence> result(bs);
555  
        remove_suffix(result, n);
527  
        remove_suffix(result, n);
556  
        return result;
528  
        return result;
557  
    }
529  
    }
558  
} sans_suffix{};
530  
} sans_suffix{};
559  

531  

560  
} // capy
532  
} // capy
561  
} // boost
533  
} // boost
562  

534  

563  
#endif
535  
#endif