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_CONSUMING_BUFFERS_HPP
10  
#ifndef BOOST_CAPY_BUFFERS_CONSUMING_BUFFERS_HPP
11  
#define BOOST_CAPY_BUFFERS_CONSUMING_BUFFERS_HPP
11  
#define BOOST_CAPY_BUFFERS_CONSUMING_BUFFERS_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  

15  

16  
#include <cstddef>
16  
#include <cstddef>
17  
#include <iterator>
17  
#include <iterator>
18  
#include <ranges>
18  
#include <ranges>
19  
#include <type_traits>
19  
#include <type_traits>
20  

20  

21  
namespace boost {
21  
namespace boost {
22  
namespace capy {
22  
namespace capy {
23  

23  

24  
namespace detail {
24  
namespace detail {
25  

25  

26  
template<class T>
26  
template<class T>
27  
struct buffer_type_for;
27  
struct buffer_type_for;
28  

28  

29  
template<MutableBufferSequence T>
29  
template<MutableBufferSequence T>
30  
struct buffer_type_for<T>
30  
struct buffer_type_for<T>
31  
{
31  
{
32  
    using type = mutable_buffer;
32  
    using type = mutable_buffer;
33  
};
33  
};
34  

34  

35  
template<ConstBufferSequence T>
35  
template<ConstBufferSequence T>
36  
    requires (!MutableBufferSequence<T>)
36  
    requires (!MutableBufferSequence<T>)
37  
struct buffer_type_for<T>
37  
struct buffer_type_for<T>
38  
{
38  
{
39  
    using type = const_buffer;
39  
    using type = const_buffer;
40  
};
40  
};
41  

41  

42  
} // namespace detail
42  
} // namespace detail
43  

43  

44  
/** Wrapper for consuming a buffer sequence incrementally.
44  
/** Wrapper for consuming a buffer sequence incrementally.
45  

45  

46  
    This class wraps a buffer sequence and tracks the current
46  
    This class wraps a buffer sequence and tracks the current
47  
    position. It provides a `consume(n)` function that advances
47  
    position. It provides a `consume(n)` function that advances
48  
    through the sequence as bytes are processed.
48  
    through the sequence as bytes are processed.
49  

49  

50  
    Works with both mutable and const buffer sequences.
50  
    Works with both mutable and const buffer sequences.
51  

51  

52  
    @tparam BufferSequence The buffer sequence type.
52  
    @tparam BufferSequence The buffer sequence type.
53  
*/
53  
*/
54  
template<class BufferSequence>
54  
template<class BufferSequence>
55  
    requires MutableBufferSequence<BufferSequence> ||
55  
    requires MutableBufferSequence<BufferSequence> ||
56  
             ConstBufferSequence<BufferSequence>
56  
             ConstBufferSequence<BufferSequence>
57  
class consuming_buffers
57  
class consuming_buffers
58  
{
58  
{
59  
    using iterator_type = decltype(capy::begin(std::declval<BufferSequence const&>()));
59  
    using iterator_type = decltype(capy::begin(std::declval<BufferSequence const&>()));
60  
    using end_iterator_type = decltype(capy::end(std::declval<BufferSequence const&>()));
60  
    using end_iterator_type = decltype(capy::end(std::declval<BufferSequence const&>()));
61  
    using buffer_type = typename detail::buffer_type_for<BufferSequence>::type;
61  
    using buffer_type = typename detail::buffer_type_for<BufferSequence>::type;
62  

62  

63  
    BufferSequence const& bufs_;
63  
    BufferSequence const& bufs_;
64  
    iterator_type it_;
64  
    iterator_type it_;
65  
    end_iterator_type end_;
65  
    end_iterator_type end_;
66  
    std::size_t consumed_ = 0;  // Bytes consumed in current buffer
66  
    std::size_t consumed_ = 0;  // Bytes consumed in current buffer
67  

67  

68  
public:
68  
public:
69  
    /** Construct from a buffer sequence.
69  
    /** Construct from a buffer sequence.
70  

70  

71  
        @param bufs The buffer sequence to wrap.
71  
        @param bufs The buffer sequence to wrap.
72  
    */
72  
    */
73  
    explicit consuming_buffers(BufferSequence const& bufs) noexcept
73  
    explicit consuming_buffers(BufferSequence const& bufs) noexcept
74  
        : bufs_(bufs)
74  
        : bufs_(bufs)
75  
        , it_(capy::begin(bufs))
75  
        , it_(capy::begin(bufs))
76  
        , end_(capy::end(bufs))
76  
        , end_(capy::end(bufs))
77  
    {
77  
    {
78  
    }
78  
    }
79  

79  

80  
    /** Consume n bytes from the buffer sequence.
80  
    /** Consume n bytes from the buffer sequence.
81  

81  

82  
        Advances the current position by n bytes, moving to the
82  
        Advances the current position by n bytes, moving to the
83  
        next buffer when the current one is exhausted.
83  
        next buffer when the current one is exhausted.
84  

84  

85  
        @param n The number of bytes to consume.
85  
        @param n The number of bytes to consume.
86  
    */
86  
    */
87  
    void consume(std::size_t n) noexcept
87  
    void consume(std::size_t n) noexcept
88  
    {
88  
    {
89  
        while (n > 0 && it_ != end_)
89  
        while (n > 0 && it_ != end_)
90  
        {
90  
        {
91  
            auto const& buf = *it_;
91  
            auto const& buf = *it_;
92  
            std::size_t const buf_size = buf.size();
92  
            std::size_t const buf_size = buf.size();
93  
            std::size_t const remaining = buf_size - consumed_;
93  
            std::size_t const remaining = buf_size - consumed_;
94  

94  

95  
            if (n < remaining)
95  
            if (n < remaining)
96  
            {
96  
            {
97  
                // Consume part of current buffer
97  
                // Consume part of current buffer
98  
                consumed_ += n;
98  
                consumed_ += n;
99  
                n = 0;
99  
                n = 0;
100  
            }
100  
            }
101  
            else
101  
            else
102  
            {
102  
            {
103  
                // Consume rest of current buffer and move to next
103  
                // Consume rest of current buffer and move to next
104  
                n -= remaining;
104  
                n -= remaining;
105  
                consumed_ = 0;
105  
                consumed_ = 0;
106  
                ++it_;
106  
                ++it_;
107  
            }
107  
            }
108  
        }
108  
        }
109  
    }
109  
    }
110  

110  

111  
    /** Iterator for the consuming buffer sequence.
111  
    /** Iterator for the consuming buffer sequence.
112  

112  

113  
        Returns buffers starting from the current position,
113  
        Returns buffers starting from the current position,
114  
        with the first buffer adjusted for consumed bytes.
114  
        with the first buffer adjusted for consumed bytes.
115  
    */
115  
    */
116  
    class const_iterator
116  
    class const_iterator
117  
    {
117  
    {
118  
        iterator_type it_;
118  
        iterator_type it_;
119  
        end_iterator_type end_;
119  
        end_iterator_type end_;
120  
        std::size_t consumed_;
120  
        std::size_t consumed_;
121  

121  

122  
    public:
122  
    public:
123  
        using iterator_category = std::bidirectional_iterator_tag;
123  
        using iterator_category = std::bidirectional_iterator_tag;
124  
        using value_type = buffer_type;
124  
        using value_type = buffer_type;
125  
        using difference_type = std::ptrdiff_t;
125  
        using difference_type = std::ptrdiff_t;
126  
        using pointer = value_type*;
126  
        using pointer = value_type*;
127  
        using reference = value_type;
127  
        using reference = value_type;
128  

128  

129  
        // Default constructor required for forward_iterator
129  
        // Default constructor required for forward_iterator
130  
        const_iterator() noexcept = default;
130  
        const_iterator() noexcept = default;
131 -
        /// Construct from position and consumed byte count.
 
132  

131  

133  
        const_iterator(
132  
        const_iterator(
134  
            iterator_type it,
133  
            iterator_type it,
135  
            end_iterator_type end,
134  
            end_iterator_type end,
136  
            std::size_t consumed) noexcept
135  
            std::size_t consumed) noexcept
137  
            : it_(it)
136  
            : it_(it)
138  
            , end_(end)
137  
            , end_(end)
139  
            , consumed_(consumed)
138  
            , consumed_(consumed)
140  
        {
139  
        {
141  
        }
140  
        }
142 -
        /// Test for equality.
 
143  

141  

144  
        bool operator==(const_iterator const& other) const noexcept
142  
        bool operator==(const_iterator const& other) const noexcept
145  
        {
143  
        {
146  
            return it_ == other.it_ && consumed_ == other.consumed_;
144  
            return it_ == other.it_ && consumed_ == other.consumed_;
147  
        }
145  
        }
148  

146  

149 -
        /// Test for inequality.
147 +
        // != operator required for equality_comparable
150  
        bool operator!=(const_iterator const& other) const noexcept
148  
        bool operator!=(const_iterator const& other) const noexcept
151  
        {
149  
        {
152  
            return !(*this == other);
150  
            return !(*this == other);
153  
        }
151  
        }
154 -
        /// Return the current buffer, adjusted for consumed bytes.
 
155  

152  

156  
        value_type operator*() const noexcept
153  
        value_type operator*() const noexcept
157  
        {
154  
        {
158  
            auto const& buf = *it_;
155  
            auto const& buf = *it_;
159  
            if constexpr (std::is_same_v<buffer_type, mutable_buffer>)
156  
            if constexpr (std::is_same_v<buffer_type, mutable_buffer>)
160  
            {
157  
            {
161  
                return buffer_type(
158  
                return buffer_type(
162  
                    static_cast<char*>(buf.data()) + consumed_,
159  
                    static_cast<char*>(buf.data()) + consumed_,
163  
                    buf.size() - consumed_);
160  
                    buf.size() - consumed_);
164  
            }
161  
            }
165  
            else
162  
            else
166  
            {
163  
            {
167  
                return buffer_type(
164  
                return buffer_type(
168  
                    static_cast<char const*>(buf.data()) + consumed_,
165  
                    static_cast<char const*>(buf.data()) + consumed_,
169  
                    buf.size() - consumed_);
166  
                    buf.size() - consumed_);
170  
            }
167  
            }
171  
        }
168  
        }
172 -
        /// Advance to the next element.
 
173  

169  

174  
        const_iterator& operator++() noexcept
170  
        const_iterator& operator++() noexcept
175  
        {
171  
        {
176  
            consumed_ = 0;
172  
            consumed_ = 0;
177  
            ++it_;
173  
            ++it_;
178  
            return *this;
174  
            return *this;
179  
        }
175  
        }
180 -
        /// Advance to the next element (postfix).
 
181  

176  

182  
        const_iterator operator++(int) noexcept
177  
        const_iterator operator++(int) noexcept
183  
        {
178  
        {
184  
            const_iterator tmp = *this;
179  
            const_iterator tmp = *this;
185  
            ++*this;
180  
            ++*this;
186  
            return tmp;
181  
            return tmp;
187  
        }
182  
        }
188 -
        /// Move to the previous element.
 
189  

183  

190  
        const_iterator& operator--() noexcept
184  
        const_iterator& operator--() noexcept
191  
        {
185  
        {
192  
            if (consumed_ == 0)
186  
            if (consumed_ == 0)
193  
            {
187  
            {
194  
                --it_;
188  
                --it_;
195  
                // Set consumed_ to the size of the previous buffer
189  
                // Set consumed_ to the size of the previous buffer
196  
                // This is a simplified implementation for bidirectional requirement
190  
                // This is a simplified implementation for bidirectional requirement
197  
                if (it_ != end_)
191  
                if (it_ != end_)
198  
                {
192  
                {
199  
                    auto const& buf = *it_;
193  
                    auto const& buf = *it_;
200  
                    consumed_ = buf.size();
194  
                    consumed_ = buf.size();
201  
                }
195  
                }
202  
            }
196  
            }
203  
            else
197  
            else
204  
            {
198  
            {
205  
                consumed_ = 0;
199  
                consumed_ = 0;
206  
            }
200  
            }
207  
            return *this;
201  
            return *this;
208  
        }
202  
        }
209 -
        /// Move to the previous element (postfix).
 
210  

203  

211  
        const_iterator operator--(int) noexcept
204  
        const_iterator operator--(int) noexcept
212  
        {
205  
        {
213  
            const_iterator tmp = *this;
206  
            const_iterator tmp = *this;
214  
            --*this;
207  
            --*this;
215  
            return tmp;
208  
            return tmp;
216  
        }
209  
        }
217  
    };
210  
    };
218  

211  

219  
    /** Return iterator to beginning of remaining buffers.
212  
    /** Return iterator to beginning of remaining buffers.
220  

213  

221  
        @return Iterator pointing to the first remaining buffer,
214  
        @return Iterator pointing to the first remaining buffer,
222  
            adjusted for consumed bytes in the current buffer.
215  
            adjusted for consumed bytes in the current buffer.
223  
    */
216  
    */
224  
    const_iterator begin() const noexcept
217  
    const_iterator begin() const noexcept
225  
    {
218  
    {
226  
        return const_iterator(it_, end_, consumed_);
219  
        return const_iterator(it_, end_, consumed_);
227  
    }
220  
    }
228  

221  

229  
    /** Return iterator to end of buffer sequence.
222  
    /** Return iterator to end of buffer sequence.
230  

223  

231  
        @return End iterator.
224  
        @return End iterator.
232  
    */
225  
    */
233  
    const_iterator end() const noexcept
226  
    const_iterator end() const noexcept
234  
    {
227  
    {
235  
        return const_iterator(end_, end_, 0);
228  
        return const_iterator(end_, end_, 0);
236  
    }
229  
    }
237  
};
230  
};
238  

231  

239  
} // namespace capy
232  
} // namespace capy
240  
} // namespace boost
233  
} // namespace boost
241  

234  

242  
#endif
235  
#endif