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 +
/** A view of a sub-range of a buffer sequence.
48  

48  

49 -
/** A wrapper enabling a buffer sequence to be consumed
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 +

 
73 +
    @see keep_prefix, remove_prefix, prefix, sans_prefix
50  
*/
74  
*/
51  
template<ConstBufferSequence BufferSequence>
75  
template<ConstBufferSequence BufferSequence>
52  
class slice_of<BufferSequence>
76  
class slice_of<BufferSequence>
53  
{
77  
{
54  
    static_assert(!std::is_const_v<BufferSequence>,
78  
    static_assert(!std::is_const_v<BufferSequence>,
55  
        "BufferSequence can't be const");
79  
        "BufferSequence can't be const");
56  

80  

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

83  

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

86  

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

89  

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

97  

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

104  

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

116  

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

118  

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

133  

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

142  

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

144  

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

157  

 
158 +
        /// Test for inequality.
133  
        bool
159  
        bool
134  
        operator!=(
160  
        operator!=(
135  
            const_iterator const& other) const noexcept
161  
            const_iterator const& other) const noexcept
136  
        {
162  
        {
137  
            return !(*this == other);
163  
            return !(*this == other);
138  
        }
164  
        }
139  

165  

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

185  

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

195  

 
196 +
        /// Advance to the next element (postfix).
168  
        const_iterator
197  
        const_iterator
169  
        operator++(int) noexcept
198  
        operator++(int) noexcept
170  
        {
199  
        {
171  
            auto temp = *this;
200  
            auto temp = *this;
172  
            ++(*this);
201  
            ++(*this);
173  
            return temp;
202  
            return temp;
174  
        }
203  
        }
175  

204  

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

214  

 
215 +
        /// Move to the previous element (postfix).
185  
        const_iterator
216  
        const_iterator
186  
        operator--(int) noexcept
217  
        operator--(int) noexcept
187  
        {
218  
        {
188  
            auto temp = *this;
219  
            auto temp = *this;
189  
            --(*this);
220  
            --(*this);
190  
            return temp;
221  
            return temp;
191  
        }
222  
        }
192  
    };
223  
    };
193  

224  

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

228  

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

247  

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

256  

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

265  

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

277  

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

286  

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

294  

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

301  

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

306  

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

308  

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

325  

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

336  

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

339  

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

343  

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

347  

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

375  

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

391  

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

407  

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

 
398  

428  

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

435  

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

449  

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

465  

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

479  

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

 
469 -
//------------------------------------------------
 
470  
} const remove_suffix{};
498  
} const remove_suffix{};
471  

499  

472  
/** 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
473  
*/
501  
*/
474  
constexpr struct prefix_mrdocs_workaround_t
502  
constexpr struct prefix_mrdocs_workaround_t
475  
{
503  
{
476  
    template<ConstBufferSequence BufferSequence>
504  
    template<ConstBufferSequence BufferSequence>
477  
    slice_type<BufferSequence> operator()(
505  
    slice_type<BufferSequence> operator()(
478  
        BufferSequence const& bs,
506  
        BufferSequence const& bs,
479  
        std::size_t n) const noexcept
507  
        std::size_t n) const noexcept
480  
    {
508  
    {
481  
        slice_type<BufferSequence> result(bs);
509  
        slice_type<BufferSequence> result(bs);
482  
        keep_prefix(result, n);
510  
        keep_prefix(result, n);
483  
        return result;
511  
        return result;
484  
    }
512  
    }
485  
} prefix{};
513  
} prefix{};
486  

514  

487  
/** 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
488  
*/
516  
*/
489  
constexpr struct suffix_mrdocs_workaround_t
517  
constexpr struct suffix_mrdocs_workaround_t
490  
{
518  
{
491  
    template<ConstBufferSequence BufferSequence>
519  
    template<ConstBufferSequence BufferSequence>
492  
    slice_type<BufferSequence> operator()(
520  
    slice_type<BufferSequence> operator()(
493  
        BufferSequence const& bs,
521  
        BufferSequence const& bs,
494  
        std::size_t n) const noexcept
522  
        std::size_t n) const noexcept
495  
    {
523  
    {
496  
        slice_type<BufferSequence> result(bs);
524  
        slice_type<BufferSequence> result(bs);
497  
        keep_suffix(result, n);
525  
        keep_suffix(result, n);
498  
        return result;
526  
        return result;
499  
    }
527  
    }
500  
} suffix{};
528  
} suffix{};
501  

529  

502  
/** 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
503  
*/
531  
*/
504  
constexpr struct sans_prefix_mrdocs_workaround_t
532  
constexpr struct sans_prefix_mrdocs_workaround_t
505  
{
533  
{
506  
    template<ConstBufferSequence BufferSequence>
534  
    template<ConstBufferSequence BufferSequence>
507  
    slice_type<BufferSequence> operator()(
535  
    slice_type<BufferSequence> operator()(
508  
        BufferSequence const& bs,
536  
        BufferSequence const& bs,
509  
        std::size_t n) const noexcept
537  
        std::size_t n) const noexcept
510  
    {
538  
    {
511  
        slice_type<BufferSequence> result(bs);
539  
        slice_type<BufferSequence> result(bs);
512  
        remove_prefix(result, n);
540  
        remove_prefix(result, n);
513  
        return result;
541  
        return result;
514  
    }
542  
    }
515  
} sans_prefix{};
543  
} sans_prefix{};
516  

544  

517  
/** 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
518  
*/
546  
*/
519  
constexpr struct sans_suffix_mrdocs_workaround_t
547  
constexpr struct sans_suffix_mrdocs_workaround_t
520  
{
548  
{
521  
    template<ConstBufferSequence BufferSequence>
549  
    template<ConstBufferSequence BufferSequence>
522  
    slice_type<BufferSequence> operator()(
550  
    slice_type<BufferSequence> operator()(
523  
        BufferSequence const& bs,
551  
        BufferSequence const& bs,
524  
        std::size_t n) const noexcept
552  
        std::size_t n) const noexcept
525  
    {
553  
    {
526  
        slice_type<BufferSequence> result(bs);
554  
        slice_type<BufferSequence> result(bs);
527  
        remove_suffix(result, n);
555  
        remove_suffix(result, n);
528  
        return result;
556  
        return result;
529  
    }
557  
    }
530  
} sans_suffix{};
558  
} sans_suffix{};
531  

559  

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

562  

535  
#endif
563  
#endif