1  
//
1  
//
2  
// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3  
//
3  
//
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
//
6  
//
7  
// Official repository: https://github.com/cppalliance/capy
7  
// Official repository: https://github.com/cppalliance/capy
8  
//
8  
//
9  

9  

10  
#ifndef BOOST_CAPY_BUFFERS_SLICE_HPP
10  
#ifndef BOOST_CAPY_BUFFERS_SLICE_HPP
11  
#define BOOST_CAPY_BUFFERS_SLICE_HPP
11  
#define BOOST_CAPY_BUFFERS_SLICE_HPP
12  

12  

13  
#include <boost/capy/detail/config.hpp>
13  
#include <boost/capy/detail/config.hpp>
14  
#include <boost/capy/buffers.hpp>
14  
#include <boost/capy/buffers.hpp>
15  
#include <array>
15  
#include <array>
16  
#include <cassert>
16  
#include <cassert>
17  
#include <iterator>
17  
#include <iterator>
18  
#include <type_traits>
18  
#include <type_traits>
19  

19  

20  
namespace boost {
20  
namespace boost {
21  
namespace capy {
21  
namespace capy {
22  

22  

23  
template<class T> class slice_of;
23  
template<class T> class slice_of;
24  

24  

25  
namespace detail {
25  
namespace detail {
26  

26  

27  
template<class T, class = void>
27  
template<class T, class = void>
28  
struct has_tag_invoke : std::false_type {};
28  
struct has_tag_invoke : std::false_type {};
29  

29  

30  
template<class T>
30  
template<class T>
31  
struct has_tag_invoke<T, decltype(tag_invoke(
31  
struct has_tag_invoke<T, decltype(tag_invoke(
32  
    std::declval<slice_tag const&>(),
32  
    std::declval<slice_tag const&>(),
33  
    std::declval<T&>(),
33  
    std::declval<T&>(),
34  
    std::declval<slice_how>(),
34  
    std::declval<slice_how>(),
35  
    std::declval<std::size_t>()))>
35  
    std::declval<std::size_t>()))>
36  
    : std::true_type {};
36  
    : std::true_type {};
37  

37  

38  
} // detail
38  
} // detail
39  

39  

40  
/** Alias for the type representing a slice of T
40  
/** Alias for the type representing a slice of T
41  
*/
41  
*/
42  
template<class T>
42  
template<class T>
43  
using slice_type = std::conditional_t<
43  
using slice_type = std::conditional_t<
44  
    detail::has_tag_invoke<T>::value,
44  
    detail::has_tag_invoke<T>::value,
45  
    T, slice_of<T>>;
45  
    T, slice_of<T>>;
46  

46  

47  
/** A view of a sub-range of a buffer sequence.
47  
/** A view of a sub-range of a buffer sequence.
48  

48  

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

54  

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

58  

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

62  

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

69  

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

72  

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

80  

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

83  

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

86  

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

89  

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

97  

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

104  

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

116  

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

118  

119  
        const_iterator(
119  
        const_iterator(
120  
            iter_type it,
120  
            iter_type it,
121  
            std::size_t prefix__,
121  
            std::size_t prefix__,
122  
            std::size_t suffix__,
122  
            std::size_t suffix__,
123  
            std::size_t i,
123  
            std::size_t i,
124  
            std::size_t n) noexcept
124  
            std::size_t n) noexcept
125  
            : it_(it)
125  
            : it_(it)
126  
            , prefix_(prefix__)
126  
            , prefix_(prefix__)
127  
            , suffix_(suffix__)
127  
            , suffix_(suffix__)
128  
            , i_(i)
128  
            , i_(i)
129  
            , n_(n)
129  
            , n_(n)
130  
        {
130  
        {
131  
            // n_ is the index of the end iterator
131  
            // n_ is the index of the end iterator
132  
        }
132  
        }
133  

133  

134  
    public:
134  
    public:
135  
        using value_type = typename slice_of::value_type;
135  
        using value_type = typename slice_of::value_type;
136  
        using reference = value_type;
136  
        using reference = value_type;
137  
        using pointer = void;
137  
        using pointer = void;
138  
        using difference_type = std::ptrdiff_t;
138  
        using difference_type = std::ptrdiff_t;
139  
        using iterator_category =
139  
        using iterator_category =
140  
            std::bidirectional_iterator_tag;
140  
            std::bidirectional_iterator_tag;
141  
        using iterator_concept = std::bidirectional_iterator_tag;
141  
        using iterator_concept = std::bidirectional_iterator_tag;
142  

142  

143  
        const_iterator() = default;
143  
        const_iterator() = default;
144  

144  

145  
        /// Test for equality.
145  
        /// Test for equality.
146  
        bool
146  
        bool
147  
        operator==(
147  
        operator==(
148  
            const_iterator const& other) const noexcept
148  
            const_iterator const& other) const noexcept
149  
        {
149  
        {
150  
            return
150  
            return
151  
                it_     == other.it_ &&
151  
                it_     == other.it_ &&
152  
                prefix_ == other.prefix_ &&
152  
                prefix_ == other.prefix_ &&
153  
                suffix_ == other.suffix_ &&
153  
                suffix_ == other.suffix_ &&
154  
                i_      == other.i_ &&
154  
                i_      == other.i_ &&
155  
                n_      == other.n_;
155  
                n_      == other.n_;
156  
        }
156  
        }
157  

157  

158  
        /// Test for inequality.
158  
        /// Test for inequality.
159  
        bool
159  
        bool
160  
        operator!=(
160  
        operator!=(
161  
            const_iterator const& other) const noexcept
161  
            const_iterator const& other) const noexcept
162  
        {
162  
        {
163  
            return !(*this == other);
163  
            return !(*this == other);
164  
        }
164  
        }
165  

165  

166  
        /// Return the current buffer, adjusted for prefix/suffix.
166  
        /// Return the current buffer, adjusted for prefix/suffix.
167  
        reference
167  
        reference
168  
        operator*() const noexcept
168  
        operator*() const noexcept
169  
        {
169  
        {
170  
            value_type v = *it_;
170  
            value_type v = *it_;
171  
            using P = std::conditional_t<
171  
            using P = std::conditional_t<
172  
                MutableBufferSequence<BufferSequence>,
172  
                MutableBufferSequence<BufferSequence>,
173  
                char*, char const*>;
173  
                char*, char const*>;
174  
            auto p = reinterpret_cast<P>(v.data());
174  
            auto p = reinterpret_cast<P>(v.data());
175  
            auto n = v.size();
175  
            auto n = v.size();
176  
            if(i_ == 0)
176  
            if(i_ == 0)
177  
            {
177  
            {
178  
                p += prefix_;
178  
                p += prefix_;
179  
                n -= prefix_;
179  
                n -= prefix_;
180  
            }
180  
            }
181  
            if(i_ == n_ - 1)
181  
            if(i_ == n_ - 1)
182  
                n -= suffix_;
182  
                n -= suffix_;
183  
            return value_type(p, n);
183  
            return value_type(p, n);
184  
        }
184  
        }
185  

185  

186  
        /// Advance to the next element.
186  
        /// Advance to the next element.
187  
        const_iterator&
187  
        const_iterator&
188  
        operator++() noexcept
188  
        operator++() noexcept
189  
        {
189  
        {
190  
            BOOST_CAPY_ASSERT(i_ < n_);
190  
            BOOST_CAPY_ASSERT(i_ < n_);
191  
            ++it_;
191  
            ++it_;
192  
            ++i_;
192  
            ++i_;
193  
            return *this;
193  
            return *this;
194  
        }
194  
        }
195  

195  

196  
        /// Advance to the next element (postfix).
196  
        /// Advance to the next element (postfix).
197  
        const_iterator
197  
        const_iterator
198  
        operator++(int) noexcept
198  
        operator++(int) noexcept
199  
        {
199  
        {
200  
            auto temp = *this;
200  
            auto temp = *this;
201  
            ++(*this);
201  
            ++(*this);
202  
            return temp;
202  
            return temp;
203  
        }
203  
        }
204  

204  

205  
        /// Move to the previous element.
205  
        /// Move to the previous element.
206  
        const_iterator&
206  
        const_iterator&
207  
        operator--() noexcept
207  
        operator--() noexcept
208  
        {
208  
        {
209  
            BOOST_CAPY_ASSERT(i_ > 0);
209  
            BOOST_CAPY_ASSERT(i_ > 0);
210  
            --it_;
210  
            --it_;
211  
            --i_;
211  
            --i_;
212  
            return *this;
212  
            return *this;
213  
        }
213  
        }
214  

214  

215  
        /// Move to the previous element (postfix).
215  
        /// Move to the previous element (postfix).
216  
        const_iterator
216  
        const_iterator
217  
        operator--(int) noexcept
217  
        operator--(int) noexcept
218  
        {
218  
        {
219  
            auto temp = *this;
219  
            auto temp = *this;
220  
            --(*this);
220  
            --(*this);
221  
            return temp;
221  
            return temp;
222  
        }
222  
        }
223  
    };
223  
    };
224  

224  

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

228  

229  
    /** Constructor
229  
    /** Constructor
230  
    */
230  
    */
231  
    slice_of(
231  
    slice_of(
232  
        BufferSequence const& bs)
232  
        BufferSequence const& bs)
233  
        : bs_(bs)
233  
        : bs_(bs)
234  
    {
234  
    {
235  
        iter_type it = capy::begin(bs_);
235  
        iter_type it = capy::begin(bs_);
236  
        iter_type eit = capy::end(bs_);
236  
        iter_type eit = capy::end(bs_);
237  
        begin_ = 0;
237  
        begin_ = 0;
238  
        end_ = std::distance(it, eit);
238  
        end_ = std::distance(it, eit);
239  
        while(it != eit)
239  
        while(it != eit)
240  
        {
240  
        {
241  
            value_type b(*it);
241  
            value_type b(*it);
242  
            size_ += b.size();
242  
            size_ += b.size();
243  
            ++len_;
243  
            ++len_;
244  
            ++it;
244  
            ++it;
245  
        }
245  
        }
246  
    }
246  
    }
247  

247  

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

256  

257  
    /** Return an iterator to the end of the sequence
257  
    /** Return an iterator to the end of the sequence
258  
    */
258  
    */
259  
    const_iterator
259  
    const_iterator
260  
    end() const noexcept
260  
    end() const noexcept
261  
    {
261  
    {
262  
        return const_iterator(
262  
        return const_iterator(
263  
            end_iter_impl(), prefix_, suffix_, len_, len_);
263  
            end_iter_impl(), prefix_, suffix_, len_, len_);
264  
    }
264  
    }
265  

265  

266  
    /// Slice customization point for this type.
266  
    /// Slice customization point for this type.
267  
    friend
267  
    friend
268  
    void
268  
    void
269  
    tag_invoke(
269  
    tag_invoke(
270  
        slice_tag const&,
270  
        slice_tag const&,
271  
        slice_of<BufferSequence>& bs,
271  
        slice_of<BufferSequence>& bs,
272  
        slice_how how,
272  
        slice_how how,
273  
        std::size_t n)
273  
        std::size_t n)
274  
    {
274  
    {
275  
        bs.slice_impl(how, n);
275  
        bs.slice_impl(how, n);
276  
    }
276  
    }
277  

277  

278  
private:
278  
private:
279  
    iter_type
279  
    iter_type
280  
    begin_iter_impl() const noexcept
280  
    begin_iter_impl() const noexcept
281  
    {
281  
    {
282  
        iter_type it = capy::begin(bs_);
282  
        iter_type it = capy::begin(bs_);
283  
        std::advance(it, begin_);
283  
        std::advance(it, begin_);
284  
        return it;
284  
        return it;
285  
    }
285  
    }
286  

286  

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

294  

295  
    void
295  
    void
296  
    remove_prefix_impl(
296  
    remove_prefix_impl(
297  
        std::size_t n)
297  
        std::size_t n)
298  
    {
298  
    {
299  
        if(n > size_)
299  
        if(n > size_)
300  
            n = size_;
300  
            n = size_;
301  

301  

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

306  

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

308  

309  
        while(n > 0 && begin_ != end_)
309  
        while(n > 0 && begin_ != end_)
310  
        {
310  
        {
311  
            value_type b = *it;
311  
            value_type b = *it;
312  
            if(n < b.size())
312  
            if(n < b.size())
313  
            {
313  
            {
314  
                prefix_ = n;
314  
                prefix_ = n;
315  
                size_ -= n;
315  
                size_ -= n;
316  
                break;
316  
                break;
317  
            }
317  
            }
318  
            n -= b.size();
318  
            n -= b.size();
319  
            size_ -= b.size();
319  
            size_ -= b.size();
320  
            ++begin_;
320  
            ++begin_;
321  
            ++it;
321  
            ++it;
322  
            --len_;
322  
            --len_;
323  
        }
323  
        }
324  
    }
324  
    }
325  

325  

326  
    void
326  
    void
327  
    remove_suffix_impl(
327  
    remove_suffix_impl(
328  
        std::size_t n)
328  
        std::size_t n)
329  
    {
329  
    {
330  
        if(size_ == 0)
330  
        if(size_ == 0)
331  
        {
331  
        {
332  
            BOOST_CAPY_ASSERT(begin_ == end_);
332  
            BOOST_CAPY_ASSERT(begin_ == end_);
333  
            return;
333  
            return;
334  
        }
334  
        }
335  
        BOOST_CAPY_ASSERT(begin_ != end_);
335  
        BOOST_CAPY_ASSERT(begin_ != end_);
336  

336  

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

339  

340  
        n += suffix_;
340  
        n += suffix_;
341  
        size_ += suffix_;
341  
        size_ += suffix_;
342  
        suffix_ = 0;
342  
        suffix_ = 0;
343  

343  

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

347  

348  
        while(it != bit)
348  
        while(it != bit)
349  
        {
349  
        {
350  
            value_type b = *it;
350  
            value_type b = *it;
351  
            if(n < b.size())
351  
            if(n < b.size())
352  
            {
352  
            {
353  
                suffix_ = n;
353  
                suffix_ = n;
354  
                size_ -= n;
354  
                size_ -= n;
355  
                return;
355  
                return;
356  
            }
356  
            }
357  
            n -= b.size();
357  
            n -= b.size();
358  
            size_ -= b.size();
358  
            size_ -= b.size();
359  
            --it;
359  
            --it;
360  
            --end_;
360  
            --end_;
361  
            --len_;
361  
            --len_;
362  
        }
362  
        }
363  
        value_type b = *it;
363  
        value_type b = *it;
364  
        auto m = b.size() - prefix_;
364  
        auto m = b.size() - prefix_;
365  
        if(n < m)
365  
        if(n < m)
366  
        {
366  
        {
367  
            suffix_ = n;
367  
            suffix_ = n;
368  
            size_ -= n;
368  
            size_ -= n;
369  
            return;
369  
            return;
370  
        }
370  
        }
371  
        end_ = begin_;
371  
        end_ = begin_;
372  
        len_ = 0;
372  
        len_ = 0;
373  
        size_ = 0;
373  
        size_ = 0;
374  
    }
374  
    }
375  

375  

376  
    void
376  
    void
377  
    keep_prefix_impl(
377  
    keep_prefix_impl(
378  
        std::size_t n)
378  
        std::size_t n)
379  
    {
379  
    {
380  
        if(n >= size_)
380  
        if(n >= size_)
381  
            return;
381  
            return;
382  
        if(n == 0)
382  
        if(n == 0)
383  
        {
383  
        {
384  
            end_ = begin_;
384  
            end_ = begin_;
385  
            len_ = 0;
385  
            len_ = 0;
386  
            size_ = 0;
386  
            size_ = 0;
387  
            return;
387  
            return;
388  
        }
388  
        }
389  
        remove_suffix_impl(size_ - n);
389  
        remove_suffix_impl(size_ - n);
390  
    }
390  
    }
391  

391  

392  
    void
392  
    void
393  
    keep_suffix_impl(
393  
    keep_suffix_impl(
394  
        std::size_t n)
394  
        std::size_t n)
395  
    {
395  
    {
396  
        if(n >= size_)
396  
        if(n >= size_)
397  
            return;
397  
            return;
398  
        if(n == 0)
398  
        if(n == 0)
399  
        {
399  
        {
400  
            begin_ = end_;
400  
            begin_ = end_;
401  
            len_ = 0;
401  
            len_ = 0;
402  
            size_ = 0;
402  
            size_ = 0;
403  
            return;
403  
            return;
404  
        }
404  
        }
405  
        remove_prefix_impl(size_ - n);
405  
        remove_prefix_impl(size_ - n);
406  
    }
406  
    }
407  

407  

408  
    void
408  
    void
409  
    slice_impl(
409  
    slice_impl(
410  
        slice_how how,
410  
        slice_how how,
411  
        std::size_t n)
411  
        std::size_t n)
412  
    {
412  
    {
413  
        switch(how)
413  
        switch(how)
414  
        {
414  
        {
415  
        case slice_how::remove_prefix:
415  
        case slice_how::remove_prefix:
416  
        {
416  
        {
417  
            remove_prefix_impl(n);
417  
            remove_prefix_impl(n);
418  
            break;
418  
            break;
419  
        }
419  
        }
420  
        case slice_how::keep_prefix:
420  
        case slice_how::keep_prefix:
421  
        {
421  
        {
422  
            keep_prefix_impl(n);
422  
            keep_prefix_impl(n);
423  
            break;
423  
            break;
424  
        }
424  
        }
425  
        }
425  
        }
426  
    }
426  
    }
427  
};
427  
};
428  

428  

429  
// in-place modify  return value
429  
// in-place modify  return value
430  
// -----------------------------
430  
// -----------------------------
431  
// keep_prefix*     prefix
431  
// keep_prefix*     prefix
432  
// keep_suffix      suffix
432  
// keep_suffix      suffix
433  
// remove_prefix*   sans_prefix
433  
// remove_prefix*   sans_prefix
434  
// remove_suffix    sans_suffix
434  
// remove_suffix    sans_suffix
435  

435  

436  
/** Remove all but the first `n` bytes from a buffer sequence
436  
/** Remove all but the first `n` bytes from a buffer sequence
437  
*/
437  
*/
438  
constexpr struct keep_prefix_mrdocs_workaround_t
438  
constexpr struct keep_prefix_mrdocs_workaround_t
439  
{
439  
{
440  
    template<ConstBufferSequence BufferSequence>
440  
    template<ConstBufferSequence BufferSequence>
441  
        requires detail::has_tag_invoke<BufferSequence>::value
441  
        requires detail::has_tag_invoke<BufferSequence>::value
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::keep_prefix, n);
446  
        tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n);
447  
    }
447  
    }
448  
} const keep_prefix{};
448  
} const keep_prefix{};
449  

449  

450  
/** Remove all but the last `n` bytes from a buffer sequence
450  
/** Remove all but the last `n` bytes from a buffer sequence
451  
*/
451  
*/
452  
constexpr struct keep_suffix_mrdocs_workaround_t
452  
constexpr struct keep_suffix_mrdocs_workaround_t
453  
{
453  
{
454  
    template<ConstBufferSequence BufferSequence>
454  
    template<ConstBufferSequence BufferSequence>
455  
        requires detail::has_tag_invoke<BufferSequence>::value
455  
        requires detail::has_tag_invoke<BufferSequence>::value
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 < n0)
461  
        if(n < n0)
462  
            tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n0 - n);
462  
            tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n0 - n);
463  
    }
463  
    }
464  
} const keep_suffix{};
464  
} const keep_suffix{};
465  

465  

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

479  

480  
/** Remove `n` bytes from the end of a buffer sequence
480  
/** Remove `n` bytes from the end of a buffer sequence
481  
*/
481  
*/
482  
constexpr struct remove_suffix_mrdocs_workaround_t
482  
constexpr struct remove_suffix_mrdocs_workaround_t
483  
{
483  
{
484  
    template<ConstBufferSequence BufferSequence>
484  
    template<ConstBufferSequence BufferSequence>
485  
        requires detail::has_tag_invoke<BufferSequence>::value
485  
        requires detail::has_tag_invoke<BufferSequence>::value
486  
    void operator()(
486  
    void operator()(
487  
        BufferSequence& bs,
487  
        BufferSequence& bs,
488  
        std::size_t n) const
488  
        std::size_t n) const
489  
    {
489  
    {
490  
        auto n0 = buffer_size(bs);
490  
        auto n0 = buffer_size(bs);
491  
        if(n > 0)
491  
        if(n > 0)
492  
        {
492  
        {
493  
            if( n > n0)
493  
            if( n > n0)
494  
                n = n0;
494  
                n = n0;
495  
            tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n0 - n);
495  
            tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n0 - n);
496  
        }
496  
        }
497  
    }
497  
    }
498  
} const remove_suffix{};
498  
} const remove_suffix{};
499  

499  

500  
/** Return a sequence representing the first `n` bytes of a buffer sequence
500  
/** Return a sequence representing the first `n` bytes of a buffer sequence
501  
*/
501  
*/
502  
constexpr struct prefix_mrdocs_workaround_t
502  
constexpr struct prefix_mrdocs_workaround_t
503  
{
503  
{
504  
    template<ConstBufferSequence BufferSequence>
504  
    template<ConstBufferSequence BufferSequence>
505  
    slice_type<BufferSequence> operator()(
505  
    slice_type<BufferSequence> operator()(
506  
        BufferSequence const& bs,
506  
        BufferSequence const& bs,
507  
        std::size_t n) const noexcept
507  
        std::size_t n) const noexcept
508  
    {
508  
    {
509  
        slice_type<BufferSequence> result(bs);
509  
        slice_type<BufferSequence> result(bs);
510  
        keep_prefix(result, n);
510  
        keep_prefix(result, n);
511  
        return result;
511  
        return result;
512  
    }
512  
    }
513  
} prefix{};
513  
} prefix{};
514  

514  

515  
/** Return a sequence representing the last `n` bytes of a buffer sequence
515  
/** Return a sequence representing the last `n` bytes of a buffer sequence
516  
*/
516  
*/
517  
constexpr struct suffix_mrdocs_workaround_t
517  
constexpr struct suffix_mrdocs_workaround_t
518  
{
518  
{
519  
    template<ConstBufferSequence BufferSequence>
519  
    template<ConstBufferSequence BufferSequence>
520  
    slice_type<BufferSequence> operator()(
520  
    slice_type<BufferSequence> operator()(
521  
        BufferSequence const& bs,
521  
        BufferSequence const& bs,
522  
        std::size_t n) const noexcept
522  
        std::size_t n) const noexcept
523  
    {
523  
    {
524  
        slice_type<BufferSequence> result(bs);
524  
        slice_type<BufferSequence> result(bs);
525  
        keep_suffix(result, n);
525  
        keep_suffix(result, n);
526  
        return result;
526  
        return result;
527  
    }
527  
    }
528  
} suffix{};
528  
} suffix{};
529  

529  

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

544  

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

559  

560  
} // capy
560  
} // capy
561  
} // boost
561  
} // boost
562  

562  

563  
#endif
563  
#endif