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  

131  

132  
        /// Construct from position and consumed byte count.
132  
        /// Construct from position and consumed byte count.
133  
        const_iterator(
133  
        const_iterator(
134  
            iterator_type it,
134  
            iterator_type it,
135  
            end_iterator_type end,
135  
            end_iterator_type end,
136  
            std::size_t consumed) noexcept
136  
            std::size_t consumed) noexcept
137  
            : it_(it)
137  
            : it_(it)
138  
            , end_(end)
138  
            , end_(end)
139  
            , consumed_(consumed)
139  
            , consumed_(consumed)
140  
        {
140  
        {
141  
        }
141  
        }
142  

142  

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

148  

149  
        /// Test for inequality.
149  
        /// Test for inequality.
150  
        bool operator!=(const_iterator const& other) const noexcept
150  
        bool operator!=(const_iterator const& other) const noexcept
151  
        {
151  
        {
152  
            return !(*this == other);
152  
            return !(*this == other);
153  
        }
153  
        }
154  

154  

155  
        /// Return the current buffer, adjusted for consumed bytes.
155  
        /// Return the current buffer, adjusted for consumed bytes.
156  
        value_type operator*() const noexcept
156  
        value_type operator*() const noexcept
157  
        {
157  
        {
158  
            auto const& buf = *it_;
158  
            auto const& buf = *it_;
159  
            if constexpr (std::is_same_v<buffer_type, mutable_buffer>)
159  
            if constexpr (std::is_same_v<buffer_type, mutable_buffer>)
160  
            {
160  
            {
161  
                return buffer_type(
161  
                return buffer_type(
162  
                    static_cast<char*>(buf.data()) + consumed_,
162  
                    static_cast<char*>(buf.data()) + consumed_,
163  
                    buf.size() - consumed_);
163  
                    buf.size() - consumed_);
164  
            }
164  
            }
165  
            else
165  
            else
166  
            {
166  
            {
167  
                return buffer_type(
167  
                return buffer_type(
168  
                    static_cast<char const*>(buf.data()) + consumed_,
168  
                    static_cast<char const*>(buf.data()) + consumed_,
169  
                    buf.size() - consumed_);
169  
                    buf.size() - consumed_);
170  
            }
170  
            }
171  
        }
171  
        }
172  

172  

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

180  

181  
        /// Advance to the next element (postfix).
181  
        /// Advance to the next element (postfix).
182  
        const_iterator operator++(int) noexcept
182  
        const_iterator operator++(int) noexcept
183  
        {
183  
        {
184  
            const_iterator tmp = *this;
184  
            const_iterator tmp = *this;
185  
            ++*this;
185  
            ++*this;
186  
            return tmp;
186  
            return tmp;
187  
        }
187  
        }
188  

188  

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

209  

210  
        /// Move to the previous element (postfix).
210  
        /// Move to the previous element (postfix).
211  
        const_iterator operator--(int) noexcept
211  
        const_iterator operator--(int) noexcept
212  
        {
212  
        {
213  
            const_iterator tmp = *this;
213  
            const_iterator tmp = *this;
214  
            --*this;
214  
            --*this;
215  
            return tmp;
215  
            return tmp;
216  
        }
216  
        }
217  
    };
217  
    };
218  

218  

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

220  

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

228  

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

230  

231  
        @return End iterator.
231  
        @return End iterator.
232  
    */
232  
    */
233  
    const_iterator end() const noexcept
233  
    const_iterator end() const noexcept
234  
    {
234  
    {
235  
        return const_iterator(end_, end_, 0);
235  
        return const_iterator(end_, end_, 0);
236  
    }
236  
    }
237  
};
237  
};
238  

238  

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

241  

242  
#endif
242  
#endif