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

48  

49  
/** A wrapper enabling a buffer sequence to be consumed
49  
/** A wrapper enabling a buffer sequence to be consumed
50  
*/
50  
*/
51  
template<ConstBufferSequence BufferSequence>
51  
template<ConstBufferSequence BufferSequence>
52  
class slice_of<BufferSequence>
52  
class slice_of<BufferSequence>
53  
{
53  
{
54  
    static_assert(!std::is_const_v<BufferSequence>,
54  
    static_assert(!std::is_const_v<BufferSequence>,
55  
        "BufferSequence can't be const");
55  
        "BufferSequence can't be const");
56  

56  

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

59  

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

62  

63  
    using difference_type =
63  
    using difference_type =
64  
        typename std::iterator_traits<iter_type>::difference_type;
64  
        typename std::iterator_traits<iter_type>::difference_type;
65  

65  

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

73  

74  
public:
74  
public:
75  
    /** The type of values returned by iterators
75  
    /** The type of values returned by iterators
76  
    */
76  
    */
77  
    using value_type = std::conditional_t<
77  
    using value_type = std::conditional_t<
78  
        MutableBufferSequence<BufferSequence>,
78  
        MutableBufferSequence<BufferSequence>,
79  
        mutable_buffer, const_buffer>;
79  
        mutable_buffer, const_buffer>;
80  

80  

81  
    /** The type of returned iterators
81  
    /** The type of returned iterators
82  
    */
82  
    */
83  
    class const_iterator
83  
    class const_iterator
84  
    {
84  
    {
85  
        iter_type it_;
85  
        iter_type it_;
86  
        // VFALCO we could just point back to
86  
        // VFALCO we could just point back to
87  
        // the original sequence to save size
87  
        // the original sequence to save size
88  
        std::size_t prefix_ = 0;
88  
        std::size_t prefix_ = 0;
89  
        std::size_t suffix_ = 0;
89  
        std::size_t suffix_ = 0;
90  
        std::size_t i_ = 0;
90  
        std::size_t i_ = 0;
91  
        std::size_t n_ = 0;
91  
        std::size_t n_ = 0;
92  

92  

93  
        friend class slice_of<BufferSequence>;
93  
        friend class slice_of<BufferSequence>;
94  

94  

95  
        const_iterator(
95  
        const_iterator(
96  
            iter_type it,
96  
            iter_type it,
97  
            std::size_t prefix__,
97  
            std::size_t prefix__,
98  
            std::size_t suffix__,
98  
            std::size_t suffix__,
99  
            std::size_t i,
99  
            std::size_t i,
100  
            std::size_t n) noexcept
100  
            std::size_t n) noexcept
101  
            : it_(it)
101  
            : it_(it)
102  
            , prefix_(prefix__)
102  
            , prefix_(prefix__)
103  
            , suffix_(suffix__)
103  
            , suffix_(suffix__)
104  
            , i_(i)
104  
            , i_(i)
105  
            , n_(n)
105  
            , n_(n)
106  
        {
106  
        {
107  
            // n_ is the index of the end iterator
107  
            // n_ is the index of the end iterator
108  
        }
108  
        }
109  

109  

110  
    public:
110  
    public:
111  
        using value_type = typename slice_of::value_type;
111  
        using value_type = typename slice_of::value_type;
112  
        using reference = value_type;
112  
        using reference = value_type;
113  
        using pointer = void;
113  
        using pointer = void;
114  
        using difference_type = std::ptrdiff_t;
114  
        using difference_type = std::ptrdiff_t;
115  
        using iterator_category =
115  
        using iterator_category =
116  
            std::bidirectional_iterator_tag;
116  
            std::bidirectional_iterator_tag;
117  
        using iterator_concept = std::bidirectional_iterator_tag;
117  
        using iterator_concept = std::bidirectional_iterator_tag;
118  

118  

119  
        const_iterator() = default;
119  
        const_iterator() = default;
120  

120  

121  
        bool
121  
        bool
122  
        operator==(
122  
        operator==(
123  
            const_iterator const& other) const noexcept
123  
            const_iterator const& other) const noexcept
124  
        {
124  
        {
125  
            return
125  
            return
126  
                it_     == other.it_ &&
126  
                it_     == other.it_ &&
127  
                prefix_ == other.prefix_ &&
127  
                prefix_ == other.prefix_ &&
128  
                suffix_ == other.suffix_ &&
128  
                suffix_ == other.suffix_ &&
129  
                i_      == other.i_ &&
129  
                i_      == other.i_ &&
130  
                n_      == other.n_;
130  
                n_      == other.n_;
131  
        }
131  
        }
132  

132  

133  
        bool
133  
        bool
134  
        operator!=(
134  
        operator!=(
135  
            const_iterator const& other) const noexcept
135  
            const_iterator const& other) const noexcept
136  
        {
136  
        {
137  
            return !(*this == other);
137  
            return !(*this == other);
138  
        }
138  
        }
139  

139  

140  
        reference
140  
        reference
141  
        operator*() const noexcept
141  
        operator*() const noexcept
142  
        {
142  
        {
143  
            value_type v = *it_;
143  
            value_type v = *it_;
144  
            using P = std::conditional_t<
144  
            using P = std::conditional_t<
145  
                MutableBufferSequence<BufferSequence>,
145  
                MutableBufferSequence<BufferSequence>,
146  
                char*, char const*>;
146  
                char*, char const*>;
147  
            auto p = reinterpret_cast<P>(v.data());
147  
            auto p = reinterpret_cast<P>(v.data());
148  
            auto n = v.size();
148  
            auto n = v.size();
149  
            if(i_ == 0)
149  
            if(i_ == 0)
150  
            {
150  
            {
151  
                p += prefix_;
151  
                p += prefix_;
152  
                n -= prefix_;
152  
                n -= prefix_;
153  
            }
153  
            }
154  
            if(i_ == n_ - 1)
154  
            if(i_ == n_ - 1)
155  
                n -= suffix_;
155  
                n -= suffix_;
156  
            return value_type(p, n);
156  
            return value_type(p, n);
157  
        }
157  
        }
158  

158  

159  
        const_iterator&
159  
        const_iterator&
160  
        operator++() noexcept
160  
        operator++() noexcept
161  
        {
161  
        {
162  
            BOOST_CAPY_ASSERT(i_ < n_);
162  
            BOOST_CAPY_ASSERT(i_ < n_);
163  
            ++it_;
163  
            ++it_;
164  
            ++i_;
164  
            ++i_;
165  
            return *this;
165  
            return *this;
166  
        }
166  
        }
167  

167  

168  
        const_iterator
168  
        const_iterator
169  
        operator++(int) noexcept
169  
        operator++(int) noexcept
170  
        {
170  
        {
171  
            auto temp = *this;
171  
            auto temp = *this;
172  
            ++(*this);
172  
            ++(*this);
173  
            return temp;
173  
            return temp;
174  
        }
174  
        }
175  

175  

176  
        const_iterator&
176  
        const_iterator&
177  
        operator--() noexcept
177  
        operator--() noexcept
178  
        {
178  
        {
179  
            BOOST_CAPY_ASSERT(i_ > 0);
179  
            BOOST_CAPY_ASSERT(i_ > 0);
180  
            --it_;
180  
            --it_;
181  
            --i_;
181  
            --i_;
182  
            return *this;
182  
            return *this;
183  
        }
183  
        }
184  

184  

185  
        const_iterator
185  
        const_iterator
186  
        operator--(int) noexcept
186  
        operator--(int) noexcept
187  
        {
187  
        {
188  
            auto temp = *this;
188  
            auto temp = *this;
189  
            --(*this);
189  
            --(*this);
190  
            return temp;
190  
            return temp;
191  
        }
191  
        }
192  
    };
192  
    };
193  

193  

194  
    /** Constructor
194  
    /** Constructor
195  
    */
195  
    */
196  
    slice_of() = default;
196  
    slice_of() = default;
197  

197  

198  
    /** Constructor
198  
    /** Constructor
199  
    */
199  
    */
200  
    slice_of(
200  
    slice_of(
201  
        BufferSequence const& bs)
201  
        BufferSequence const& bs)
202  
        : bs_(bs)
202  
        : bs_(bs)
203  
    {
203  
    {
204  
        iter_type it = capy::begin(bs_);
204  
        iter_type it = capy::begin(bs_);
205  
        iter_type eit = capy::end(bs_);
205  
        iter_type eit = capy::end(bs_);
206  
        begin_ = 0;
206  
        begin_ = 0;
207  
        end_ = std::distance(it, eit);
207  
        end_ = std::distance(it, eit);
208  
        while(it != eit)
208  
        while(it != eit)
209  
        {
209  
        {
210  
            value_type b(*it);
210  
            value_type b(*it);
211  
            size_ += b.size();
211  
            size_ += b.size();
212  
            ++len_;
212  
            ++len_;
213  
            ++it;
213  
            ++it;
214  
        }
214  
        }
215  
    }
215  
    }
216  

216  

217  
    /** Return an iterator to the beginning of the sequence
217  
    /** Return an iterator to the beginning of the sequence
218  
    */
218  
    */
219  
    const_iterator
219  
    const_iterator
220  
    begin() const noexcept
220  
    begin() const noexcept
221  
    {
221  
    {
222  
        return const_iterator(
222  
        return const_iterator(
223  
            begin_iter_impl(), prefix_, suffix_, 0, len_);
223  
            begin_iter_impl(), prefix_, suffix_, 0, len_);
224  
    }
224  
    }
225  

225  

226  
    /** Return an iterator to the end of the sequence
226  
    /** Return an iterator to the end of the sequence
227  
    */
227  
    */
228  
    const_iterator
228  
    const_iterator
229  
    end() const noexcept
229  
    end() const noexcept
230  
    {
230  
    {
231  
        return const_iterator(
231  
        return const_iterator(
232  
            end_iter_impl(), prefix_, suffix_, len_, len_);
232  
            end_iter_impl(), prefix_, suffix_, len_, len_);
233  
    }
233  
    }
234  

234  

235  
    friend
235  
    friend
236  
    void
236  
    void
237  
    tag_invoke(
237  
    tag_invoke(
238  
        slice_tag const&,
238  
        slice_tag const&,
239  
        slice_of<BufferSequence>& bs,
239  
        slice_of<BufferSequence>& bs,
240  
        slice_how how,
240  
        slice_how how,
241  
        std::size_t n)
241  
        std::size_t n)
242  
    {
242  
    {
243  
        bs.slice_impl(how, n);
243  
        bs.slice_impl(how, n);
244  
    }
244  
    }
245  

245  

246  
private:
246  
private:
247  
    iter_type
247  
    iter_type
248  
    begin_iter_impl() const noexcept
248  
    begin_iter_impl() const noexcept
249  
    {
249  
    {
250  
        iter_type it = capy::begin(bs_);
250  
        iter_type it = capy::begin(bs_);
251  
        std::advance(it, begin_);
251  
        std::advance(it, begin_);
252  
        return it;
252  
        return it;
253  
    }
253  
    }
254  

254  

255  
    iter_type
255  
    iter_type
256  
    end_iter_impl() const noexcept
256  
    end_iter_impl() const noexcept
257  
    {
257  
    {
258  
        iter_type it = capy::begin(bs_);
258  
        iter_type it = capy::begin(bs_);
259  
        std::advance(it, end_);
259  
        std::advance(it, end_);
260  
        return it;
260  
        return it;
261  
    }
261  
    }
262  

262  

263  
    void
263  
    void
264  
    remove_prefix_impl(
264  
    remove_prefix_impl(
265  
        std::size_t n)
265  
        std::size_t n)
266  
    {
266  
    {
267  
        if(n > size_)
267  
        if(n > size_)
268  
            n = size_;
268  
            n = size_;
269  

269  

270  
        // nice hack to simplify the loop (M. Nejati)
270  
        // nice hack to simplify the loop (M. Nejati)
271  
        n += prefix_;
271  
        n += prefix_;
272  
        size_ += prefix_;
272  
        size_ += prefix_;
273  
        prefix_ = 0;
273  
        prefix_ = 0;
274  

274  

275  
        iter_type it = begin_iter_impl();
275  
        iter_type it = begin_iter_impl();
276  

276  

277  
        while(n > 0 && begin_ != end_)
277  
        while(n > 0 && begin_ != end_)
278  
        {
278  
        {
279  
            value_type b = *it;
279  
            value_type b = *it;
280  
            if(n < b.size())
280  
            if(n < b.size())
281  
            {
281  
            {
282  
                prefix_ = n;
282  
                prefix_ = n;
283  
                size_ -= n;
283  
                size_ -= n;
284  
                break;
284  
                break;
285  
            }
285  
            }
286  
            n -= b.size();
286  
            n -= b.size();
287  
            size_ -= b.size();
287  
            size_ -= b.size();
288  
            ++begin_;
288  
            ++begin_;
289  
            ++it;
289  
            ++it;
290  
            --len_;
290  
            --len_;
291  
        }
291  
        }
292  
    }
292  
    }
293  

293  

294  
    void
294  
    void
295  
    remove_suffix_impl(
295  
    remove_suffix_impl(
296  
        std::size_t n)
296  
        std::size_t n)
297  
    {
297  
    {
298  
        if(size_ == 0)
298  
        if(size_ == 0)
299  
        {
299  
        {
300  
            BOOST_CAPY_ASSERT(begin_ == end_);
300  
            BOOST_CAPY_ASSERT(begin_ == end_);
301  
            return;
301  
            return;
302  
        }
302  
        }
303  
        BOOST_CAPY_ASSERT(begin_ != end_);
303  
        BOOST_CAPY_ASSERT(begin_ != end_);
304  

304  

305  
        if(n > size_)
305  
        if(n > size_)
306  
            n = size_;
306  
            n = size_;
307  

307  

308  
        n += suffix_;
308  
        n += suffix_;
309  
        size_ += suffix_;
309  
        size_ += suffix_;
310  
        suffix_ = 0;
310  
        suffix_ = 0;
311  

311  

312  
        iter_type bit = begin_iter_impl();
312  
        iter_type bit = begin_iter_impl();
313  
        iter_type it = end_iter_impl();
313  
        iter_type it = end_iter_impl();
314  
        it--;
314  
        it--;
315  

315  

316  
        while(it != bit)
316  
        while(it != bit)
317  
        {
317  
        {
318  
            value_type b = *it;
318  
            value_type b = *it;
319  
            if(n < b.size())
319  
            if(n < b.size())
320  
            {
320  
            {
321  
                suffix_ = n;
321  
                suffix_ = n;
322  
                size_ -= n;
322  
                size_ -= n;
323  
                return;
323  
                return;
324  
            }
324  
            }
325  
            n -= b.size();
325  
            n -= b.size();
326  
            size_ -= b.size();
326  
            size_ -= b.size();
327  
            --it;
327  
            --it;
328  
            --end_;
328  
            --end_;
329  
            --len_;
329  
            --len_;
330  
        }
330  
        }
331  
        value_type b = *it;
331  
        value_type b = *it;
332  
        auto m = b.size() - prefix_;
332  
        auto m = b.size() - prefix_;
333  
        if(n < m)
333  
        if(n < m)
334  
        {
334  
        {
335  
            suffix_ = n;
335  
            suffix_ = n;
336  
            size_ -= n;
336  
            size_ -= n;
337  
            return;
337  
            return;
338  
        }
338  
        }
339  
        end_ = begin_;
339  
        end_ = begin_;
340  
        len_ = 0;
340  
        len_ = 0;
341  
        size_ = 0;
341  
        size_ = 0;
342  
    }
342  
    }
343  

343  

344  
    void
344  
    void
345  
    keep_prefix_impl(
345  
    keep_prefix_impl(
346  
        std::size_t n)
346  
        std::size_t n)
347  
    {
347  
    {
348  
        if(n >= size_)
348  
        if(n >= size_)
349  
            return;
349  
            return;
350  
        if(n == 0)
350  
        if(n == 0)
351  
        {
351  
        {
352  
            end_ = begin_;
352  
            end_ = begin_;
353  
            len_ = 0;
353  
            len_ = 0;
354  
            size_ = 0;
354  
            size_ = 0;
355  
            return;
355  
            return;
356  
        }
356  
        }
357  
        remove_suffix_impl(size_ - n);
357  
        remove_suffix_impl(size_ - n);
358  
    }
358  
    }
359  

359  

360  
    void
360  
    void
361  
    keep_suffix_impl(
361  
    keep_suffix_impl(
362  
        std::size_t n)
362  
        std::size_t n)
363  
    {
363  
    {
364  
        if(n >= size_)
364  
        if(n >= size_)
365  
            return;
365  
            return;
366  
        if(n == 0)
366  
        if(n == 0)
367  
        {
367  
        {
368  
            begin_ = end_;
368  
            begin_ = end_;
369  
            len_ = 0;
369  
            len_ = 0;
370  
            size_ = 0;
370  
            size_ = 0;
371  
            return;
371  
            return;
372  
        }
372  
        }
373  
        remove_prefix_impl(size_ - n);
373  
        remove_prefix_impl(size_ - n);
374  
    }
374  
    }
375  

375  

376  
    void
376  
    void
377  
    slice_impl(
377  
    slice_impl(
378  
        slice_how how,
378  
        slice_how how,
379  
        std::size_t n)
379  
        std::size_t n)
380  
    {
380  
    {
381  
        switch(how)
381  
        switch(how)
382  
        {
382  
        {
383  
        case slice_how::remove_prefix:
383  
        case slice_how::remove_prefix:
384  
        {
384  
        {
385  
            remove_prefix_impl(n);
385  
            remove_prefix_impl(n);
386  
            break;
386  
            break;
387  
        }
387  
        }
388  
        case slice_how::keep_prefix:
388  
        case slice_how::keep_prefix:
389  
        {
389  
        {
390  
            keep_prefix_impl(n);
390  
            keep_prefix_impl(n);
391  
            break;
391  
            break;
392  
        }
392  
        }
393  
        }
393  
        }
394  
    }
394  
    }
395  
};
395  
};
396  

396  

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

398  

399  
// in-place modify  return value
399  
// in-place modify  return value
400  
// -----------------------------
400  
// -----------------------------
401  
// keep_prefix*     prefix
401  
// keep_prefix*     prefix
402  
// keep_suffix      suffix
402  
// keep_suffix      suffix
403  
// remove_prefix*   sans_prefix
403  
// remove_prefix*   sans_prefix
404  
// remove_suffix    sans_suffix
404  
// remove_suffix    sans_suffix
405  

405  

406  
/** Remove all but the first `n` bytes from a buffer sequence
406  
/** Remove all but the first `n` bytes from a buffer sequence
407  
*/
407  
*/
408  
constexpr struct keep_prefix_mrdocs_workaround_t
408  
constexpr struct keep_prefix_mrdocs_workaround_t
409  
{
409  
{
410  
    template<ConstBufferSequence BufferSequence>
410  
    template<ConstBufferSequence BufferSequence>
411  
        requires detail::has_tag_invoke<BufferSequence>::value
411  
        requires detail::has_tag_invoke<BufferSequence>::value
412  
    void operator()(
412  
    void operator()(
413  
        BufferSequence& bs,
413  
        BufferSequence& bs,
414  
        std::size_t n) const
414  
        std::size_t n) const
415  
    {
415  
    {
416  
        tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n);
416  
        tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n);
417  
    }
417  
    }
418  
} const keep_prefix{};
418  
} const keep_prefix{};
419  

419  

420  
/** Remove all but the last `n` bytes from a buffer sequence
420  
/** Remove all but the last `n` bytes from a buffer sequence
421  
*/
421  
*/
422  
constexpr struct keep_suffix_mrdocs_workaround_t
422  
constexpr struct keep_suffix_mrdocs_workaround_t
423  
{
423  
{
424  
    template<ConstBufferSequence BufferSequence>
424  
    template<ConstBufferSequence BufferSequence>
425  
        requires detail::has_tag_invoke<BufferSequence>::value
425  
        requires detail::has_tag_invoke<BufferSequence>::value
426  
    void operator()(
426  
    void operator()(
427  
        BufferSequence& bs,
427  
        BufferSequence& bs,
428  
        std::size_t n) const
428  
        std::size_t n) const
429  
    {
429  
    {
430  
        auto n0 = buffer_size(bs);
430  
        auto n0 = buffer_size(bs);
431  
        if(n < n0)
431  
        if(n < n0)
432  
            tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n0 - n);
432  
            tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n0 - n);
433  
    }
433  
    }
434  
} const keep_suffix{};
434  
} const keep_suffix{};
435  

435  

436  
/** Remove `n` bytes from the beginning of a buffer sequence
436  
/** Remove `n` bytes from the beginning of a buffer sequence
437  
*/
437  
*/
438  
constexpr struct remove_prefix_mrdocs_workaround_t
438  
constexpr struct remove_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
442  
    void operator()(
442  
    void operator()(
443  
        BufferSequence& bs,
443  
        BufferSequence& bs,
444  
        std::size_t n) const
444  
        std::size_t n) const
445  
    {
445  
    {
446  
        tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n);
446  
        tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n);
447  
    }
447  
    }
448  
} const remove_prefix{};
448  
} const remove_prefix{};
449  

449  

450  
/** Remove `n` bytes from the end of a buffer sequence
450  
/** Remove `n` bytes from the end of a buffer sequence
451  
*/
451  
*/
452  
constexpr struct remove_suffix_mrdocs_workaround_t
452  
constexpr struct remove_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
456  
    void operator()(
456  
    void operator()(
457  
        BufferSequence& bs,
457  
        BufferSequence& bs,
458  
        std::size_t n) const
458  
        std::size_t n) const
459  
    {
459  
    {
460  
        auto n0 = buffer_size(bs);
460  
        auto n0 = buffer_size(bs);
461  
        if(n > 0)
461  
        if(n > 0)
462  
        {
462  
        {
463  
            if( n > n0)
463  
            if( n > n0)
464  
                n = n0;
464  
                n = n0;
465  
            tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n0 - n);
465  
            tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n0 - n);
466  
        }
466  
        }
467  
    }
467  
    }
468  
} const remove_suffix{};
468  
} const remove_suffix{};
469  

469  

470  
//------------------------------------------------
470  
//------------------------------------------------
471  

471  

472  
/** 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
473  
*/
473  
*/
474  
constexpr struct prefix_mrdocs_workaround_t
474  
constexpr struct prefix_mrdocs_workaround_t
475  
{
475  
{
476  
    template<ConstBufferSequence BufferSequence>
476  
    template<ConstBufferSequence BufferSequence>
477  
    slice_type<BufferSequence> operator()(
477  
    slice_type<BufferSequence> operator()(
478  
        BufferSequence const& bs,
478  
        BufferSequence const& bs,
479  
        std::size_t n) const noexcept
479  
        std::size_t n) const noexcept
480  
    {
480  
    {
481  
        slice_type<BufferSequence> result(bs);
481  
        slice_type<BufferSequence> result(bs);
482  
        keep_prefix(result, n);
482  
        keep_prefix(result, n);
483  
        return result;
483  
        return result;
484  
    }
484  
    }
485  
} prefix{};
485  
} prefix{};
486  

486  

487  
/** 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
488  
*/
488  
*/
489  
constexpr struct suffix_mrdocs_workaround_t
489  
constexpr struct suffix_mrdocs_workaround_t
490  
{
490  
{
491  
    template<ConstBufferSequence BufferSequence>
491  
    template<ConstBufferSequence BufferSequence>
492  
    slice_type<BufferSequence> operator()(
492  
    slice_type<BufferSequence> operator()(
493  
        BufferSequence const& bs,
493  
        BufferSequence const& bs,
494  
        std::size_t n) const noexcept
494  
        std::size_t n) const noexcept
495  
    {
495  
    {
496  
        slice_type<BufferSequence> result(bs);
496  
        slice_type<BufferSequence> result(bs);
497  
        keep_suffix(result, n);
497  
        keep_suffix(result, n);
498  
        return result;
498  
        return result;
499  
    }
499  
    }
500  
} suffix{};
500  
} suffix{};
501  

501  

502  
/** 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
503  
*/
503  
*/
504  
constexpr struct sans_prefix_mrdocs_workaround_t
504  
constexpr struct sans_prefix_mrdocs_workaround_t
505  
{
505  
{
506  
    template<ConstBufferSequence BufferSequence>
506  
    template<ConstBufferSequence BufferSequence>
507  
    slice_type<BufferSequence> operator()(
507  
    slice_type<BufferSequence> operator()(
508  
        BufferSequence const& bs,
508  
        BufferSequence const& bs,
509  
        std::size_t n) const noexcept
509  
        std::size_t n) const noexcept
510  
    {
510  
    {
511  
        slice_type<BufferSequence> result(bs);
511  
        slice_type<BufferSequence> result(bs);
512  
        remove_prefix(result, n);
512  
        remove_prefix(result, n);
513  
        return result;
513  
        return result;
514  
    }
514  
    }
515  
} sans_prefix{};
515  
} sans_prefix{};
516  

516  

517  
/** 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
518  
*/
518  
*/
519  
constexpr struct sans_suffix_mrdocs_workaround_t
519  
constexpr struct sans_suffix_mrdocs_workaround_t
520  
{
520  
{
521  
    template<ConstBufferSequence BufferSequence>
521  
    template<ConstBufferSequence BufferSequence>
522  
    slice_type<BufferSequence> operator()(
522  
    slice_type<BufferSequence> operator()(
523  
        BufferSequence const& bs,
523  
        BufferSequence const& bs,
524  
        std::size_t n) const noexcept
524  
        std::size_t n) const noexcept
525  
    {
525  
    {
526  
        slice_type<BufferSequence> result(bs);
526  
        slice_type<BufferSequence> result(bs);
527  
        remove_suffix(result, n);
527  
        remove_suffix(result, n);
528  
        return result;
528  
        return result;
529  
    }
529  
    }
530  
} sans_suffix{};
530  
} sans_suffix{};
531  

531  

532  
} // capy
532  
} // capy
533  
} // boost
533  
} // boost
534  

534  

535  
#endif
535  
#endif