1  
//
1  
//
2  
// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
2  
// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot 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  
        const_iterator(
132  
        const_iterator(
133  
            iterator_type it,
133  
            iterator_type it,
134  
            end_iterator_type end,
134  
            end_iterator_type end,
135  
            std::size_t consumed) noexcept
135  
            std::size_t consumed) noexcept
136  
            : it_(it)
136  
            : it_(it)
137  
            , end_(end)
137  
            , end_(end)
138  
            , consumed_(consumed)
138  
            , consumed_(consumed)
139  
        {
139  
        {
140  
        }
140  
        }
141  

141  

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

146  

147  
        // != operator required for equality_comparable
147  
        // != operator required for equality_comparable
148  
        bool operator!=(const_iterator const& other) const noexcept
148  
        bool operator!=(const_iterator const& other) const noexcept
149  
        {
149  
        {
150  
            return !(*this == other);
150  
            return !(*this == other);
151  
        }
151  
        }
152  

152  

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

169  

170  
        const_iterator& operator++() noexcept
170  
        const_iterator& operator++() noexcept
171  
        {
171  
        {
172  
            consumed_ = 0;
172  
            consumed_ = 0;
173  
            ++it_;
173  
            ++it_;
174  
            return *this;
174  
            return *this;
175  
        }
175  
        }
176  

176  

177  
        const_iterator operator++(int) noexcept
177  
        const_iterator operator++(int) noexcept
178  
        {
178  
        {
179  
            const_iterator tmp = *this;
179  
            const_iterator tmp = *this;
180  
            ++*this;
180  
            ++*this;
181  
            return tmp;
181  
            return tmp;
182  
        }
182  
        }
183  

183  

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

203  

204  
        const_iterator operator--(int) noexcept
204  
        const_iterator operator--(int) noexcept
205  
        {
205  
        {
206  
            const_iterator tmp = *this;
206  
            const_iterator tmp = *this;
207  
            --*this;
207  
            --*this;
208  
            return tmp;
208  
            return tmp;
209  
        }
209  
        }
210  
    };
210  
    };
211  

211  

212  
    /** Return iterator to beginning of remaining buffers.
212  
    /** Return iterator to beginning of remaining buffers.
213  

213  

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

221  

222  
    /** Return iterator to end of buffer sequence.
222  
    /** Return iterator to end of buffer sequence.
223  

223  

224  
        @return End iterator.
224  
        @return End iterator.
225  
    */
225  
    */
226  
    const_iterator end() const noexcept
226  
    const_iterator end() const noexcept
227  
    {
227  
    {
228  
        return const_iterator(end_, end_, 0);
228  
        return const_iterator(end_, end_, 0);
229  
    }
229  
    }
230  
};
230  
};
231  

231  

232  
} // namespace capy
232  
} // namespace capy
233  
} // namespace boost
233  
} // namespace boost
234  

234  

235  
#endif
235  
#endif