include/boost/capy/buffers/buffers_iterator.hpp
100.0% Lines (88 / 88)
96.3% Functions (79 / 82)
Functions (82)
Function
Calls
Lines
Blocks
boost::capy::buffers_iterator<boost::capy::const_buffer, char>::skip_forward()
:102
2x
85.7%
89.0%
boost::capy::buffers_iterator<boost::capy::mutable_buffer, char>::skip_forward()
:102
1x
71.4%
67.0%
boost::capy::buffers_iterator<std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> >, char>::skip_forward()
:102
17x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 2ul>, char>::skip_forward()
:102
5x
100.0%
89.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, char>::skip_forward()
:102
169x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, unsigned char>::skip_forward()
:102
2x
85.7%
78.0%
boost::capy::buffers_iterator<std::vector<boost::capy::mutable_buffer, std::allocator<boost::capy::mutable_buffer> >, char>::skip_forward()
:102
6x
100.0%
100.0%
boost::capy::buffers_iterator<boost::capy::mutable_buffer, char>::skip_backward()
:116
0
0.0%
0.0%
boost::capy::buffers_iterator<std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> >, char>::skip_backward()
:116
21x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, char>::skip_backward()
:116
134x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, unsigned char>::skip_backward()
:116
0
0.0%
0.0%
boost::capy::buffers_iterator<std::vector<boost::capy::mutable_buffer, std::allocator<boost::capy::mutable_buffer> >, char>::skip_backward()
:116
0
0.0%
0.0%
boost::capy::buffers_iterator<boost::capy::mutable_buffer, char>::advance(long)
:128
1x
41.7%
54.0%
boost::capy::buffers_iterator<std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> >, char>::advance(long)
:128
40x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, char>::advance(long)
:128
275x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, unsigned char>::advance(long)
:128
1x
50.0%
54.0%
boost::capy::buffers_iterator<std::vector<boost::capy::mutable_buffer, std::allocator<boost::capy::mutable_buffer> >, char>::advance(long)
:128
1x
62.5%
64.0%
boost::capy::buffers_iterator<std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> >, char>::buffers_iterator()
:185
14x
100.0%
100.0%
boost::capy::buffers_iterator<boost::capy::const_buffer, char>::begin(boost::capy::const_buffer const&)
:196
1x
100.0%
100.0%
boost::capy::buffers_iterator<boost::capy::mutable_buffer, char>::begin(boost::capy::mutable_buffer const&)
:196
1x
100.0%
100.0%
boost::capy::buffers_iterator<std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> >, char>::begin(std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> > const&)
:196
2x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 2ul>, char>::begin(std::array<boost::capy::const_buffer, 2ul> const&)
:196
4x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, char>::begin(std::array<boost::capy::const_buffer, 5ul> const&)
:196
6x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, unsigned char>::begin(std::array<boost::capy::const_buffer, 5ul> const&)
:196
1x
100.0%
100.0%
boost::capy::buffers_iterator<std::vector<boost::capy::mutable_buffer, std::allocator<boost::capy::mutable_buffer> >, char>::begin(std::vector<boost::capy::mutable_buffer, std::allocator<boost::capy::mutable_buffer> > const&)
:196
3x
100.0%
100.0%
boost::capy::buffers_iterator<boost::capy::const_buffer, char>::end(boost::capy::const_buffer const&)
:213
1x
100.0%
100.0%
boost::capy::buffers_iterator<boost::capy::mutable_buffer, char>::end(boost::capy::mutable_buffer const&)
:213
1x
100.0%
100.0%
boost::capy::buffers_iterator<std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> >, char>::end(std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> > const&)
:213
12x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 2ul>, char>::end(std::array<boost::capy::const_buffer, 2ul> const&)
:213
3x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, char>::end(std::array<boost::capy::const_buffer, 5ul> const&)
:213
6x
100.0%
100.0%
boost::capy::buffers_iterator<std::vector<boost::capy::mutable_buffer, std::allocator<boost::capy::mutable_buffer> >, char>::end(std::vector<boost::capy::mutable_buffer, std::allocator<boost::capy::mutable_buffer> > const&)
:213
1x
100.0%
100.0%
boost::capy::buffers_iterator<boost::capy::const_buffer, char>::operator*() const
:228
10x
100.0%
100.0%
boost::capy::buffers_iterator<boost::capy::mutable_buffer, char>::operator*() const
:228
2x
100.0%
100.0%
boost::capy::buffers_iterator<std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> >, char>::operator*() const
:228
40x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 2ul>, char>::operator*() const
:228
18x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, char>::operator*() const
:228
46x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, unsigned char>::operator*() const
:228
1x
100.0%
100.0%
boost::capy::buffers_iterator<std::vector<boost::capy::mutable_buffer, std::allocator<boost::capy::mutable_buffer> >, char>::operator*() const
:228
8x
100.0%
100.0%
boost::capy::buffers_iterator<boost::capy::mutable_buffer, char>::operator[](long) const
:253
1x
100.0%
100.0%
boost::capy::buffers_iterator<std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> >, char>::operator[](long) const
:253
20x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, char>::operator[](long) const
:253
10x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, unsigned char>::operator[](long) const
:253
1x
100.0%
100.0%
boost::capy::buffers_iterator<std::vector<boost::capy::mutable_buffer, std::allocator<boost::capy::mutable_buffer> >, char>::operator[](long) const
:253
1x
100.0%
100.0%
boost::capy::buffers_iterator<boost::capy::const_buffer, char>::operator++()
:260
10x
100.0%
100.0%
boost::capy::buffers_iterator<std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> >, char>::operator++()
:260
10x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 2ul>, char>::operator++()
:260
17x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, char>::operator++()
:260
15x
100.0%
100.0%
boost::capy::buffers_iterator<std::vector<boost::capy::mutable_buffer, std::allocator<boost::capy::mutable_buffer> >, char>::operator++()
:260
7x
100.0%
100.0%
boost::capy::buffers_iterator<std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> >, char>::operator--()
:282
10x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, char>::operator--()
:282
10x
100.0%
100.0%
boost::capy::buffers_iterator<boost::capy::mutable_buffer, char>::operator+=(long)
:307
1x
100.0%
100.0%
boost::capy::buffers_iterator<std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> >, char>::operator+=(long)
:307
20x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, char>::operator+=(long)
:307
143x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, unsigned char>::operator+=(long)
:307
1x
100.0%
100.0%
boost::capy::buffers_iterator<std::vector<boost::capy::mutable_buffer, std::allocator<boost::capy::mutable_buffer> >, char>::operator+=(long)
:307
1x
100.0%
100.0%
boost::capy::buffers_iterator<std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> >, char>::operator-=(long)
:323
10x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, char>::operator-=(long)
:323
122x
100.0%
100.0%
boost::capy::operator+(boost::capy::buffers_iterator<boost::capy::mutable_buffer, char>, long)
:332
1x
100.0%
100.0%
boost::capy::operator+(boost::capy::buffers_iterator<std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> >, char>, long)
:332
20x
100.0%
100.0%
boost::capy::operator+(boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, char>, long)
:332
143x
100.0%
100.0%
boost::capy::operator+(boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, unsigned char>, long)
:332
1x
100.0%
100.0%
boost::capy::operator+(boost::capy::buffers_iterator<std::vector<boost::capy::mutable_buffer, std::allocator<boost::capy::mutable_buffer> >, char>, long)
:332
1x
100.0%
100.0%
boost::capy::operator-(boost::capy::buffers_iterator<std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> >, char>, long)
:350
10x
100.0%
100.0%
boost::capy::operator-(boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, char>, long)
:350
1x
100.0%
100.0%
boost::capy::operator-(boost::capy::buffers_iterator<boost::capy::const_buffer, char> const&, boost::capy::buffers_iterator<boost::capy::const_buffer, char> const&)
:359
1x
100.0%
100.0%
boost::capy::operator-(boost::capy::buffers_iterator<boost::capy::mutable_buffer, char> const&, boost::capy::buffers_iterator<boost::capy::mutable_buffer, char> const&)
:359
1x
100.0%
100.0%
boost::capy::operator-(boost::capy::buffers_iterator<std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> >, char> const&, boost::capy::buffers_iterator<std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> >, char> const&)
:359
1x
100.0%
100.0%
boost::capy::operator-(boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 2ul>, char> const&, boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 2ul>, char> const&)
:359
3x
100.0%
100.0%
boost::capy::operator-(boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, char> const&, boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, char> const&)
:359
258x
100.0%
100.0%
boost::capy::operator==(boost::capy::buffers_iterator<boost::capy::const_buffer, char> const&, boost::capy::buffers_iterator<boost::capy::const_buffer, char> const&)
:370
11x
100.0%
100.0%
boost::capy::operator==(boost::capy::buffers_iterator<std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> >, char> const&, boost::capy::buffers_iterator<std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> >, char> const&)
:370
22x
100.0%
100.0%
boost::capy::operator==(boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 2ul>, char> const&, boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 2ul>, char> const&)
:370
6x
100.0%
100.0%
boost::capy::operator==(boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, char> const&, boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, char> const&)
:370
272x
100.0%
100.0%
boost::capy::operator==(boost::capy::buffers_iterator<std::vector<boost::capy::mutable_buffer, std::allocator<boost::capy::mutable_buffer> >, char> const&, boost::capy::buffers_iterator<std::vector<boost::capy::mutable_buffer, std::allocator<boost::capy::mutable_buffer> >, char> const&)
:370
1x
100.0%
100.0%
boost::capy::operator<=>(boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, char> const&, boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, char> const&)
:380
121x
100.0%
100.0%
boost::capy::buffers_iterator<boost::capy::const_buffer, char> boost::capy::buffers_begin<boost::capy::const_buffer>(boost::capy::const_buffer const&)
:398
1x
100.0%
100.0%
boost::capy::buffers_iterator<boost::capy::mutable_buffer, char> boost::capy::buffers_begin<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&)
:398
1x
100.0%
100.0%
boost::capy::buffers_iterator<std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> >, char> boost::capy::buffers_begin<std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> > >(std::__cxx11::list<boost::capy::const_buffer, std::allocator<boost::capy::const_buffer> > const&)
:398
2x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 2ul>, char> boost::capy::buffers_begin<std::array<boost::capy::const_buffer, 2ul> >(std::array<boost::capy::const_buffer, 2ul> const&)
:398
4x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 5ul>, char> boost::capy::buffers_begin<std::array<boost::capy::const_buffer, 5ul> >(std::array<boost::capy::const_buffer, 5ul> const&)
:398
6x
100.0%
100.0%
boost::capy::buffers_iterator<std::vector<boost::capy::mutable_buffer, std::allocator<boost::capy::mutable_buffer> >, char> boost::capy::buffers_begin<std::vector<boost::capy::mutable_buffer, std::allocator<boost::capy::mutable_buffer> > >(std::vector<boost::capy::mutable_buffer, std::allocator<boost::capy::mutable_buffer> > const&)
:398
3x
100.0%
100.0%
boost::capy::buffers_iterator<std::array<boost::capy::const_buffer, 2ul>, char> boost::capy::buffers_end<std::array<boost::capy::const_buffer, 2ul> >(std::array<boost::capy::const_buffer, 2ul> const&)
:418
1x
100.0%
100.0%
| Line | TLA | Hits | Source Code |
|---|---|---|---|
| 1 | // | ||
| 2 | // Copyright (c) 2026 Steve Gerbino | ||
| 3 | // | ||
| 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) | ||
| 6 | // | ||
| 7 | // Official repository: https://github.com/cppalliance/capy | ||
| 8 | // | ||
| 9 | |||
| 10 | #ifndef BOOST_CAPY_BUFFERS_BUFFERS_ITERATOR_HPP | ||
| 11 | #define BOOST_CAPY_BUFFERS_BUFFERS_ITERATOR_HPP | ||
| 12 | |||
| 13 | #include <boost/capy/detail/config.hpp> | ||
| 14 | #include <boost/capy/buffers.hpp> | ||
| 15 | |||
| 16 | #include <compare> | ||
| 17 | #include <cstddef> | ||
| 18 | #include <iterator> | ||
| 19 | #include <ranges> | ||
| 20 | #include <type_traits> | ||
| 21 | #include <utility> | ||
| 22 | |||
| 23 | namespace boost { | ||
| 24 | namespace capy { | ||
| 25 | |||
| 26 | namespace detail { | ||
| 27 | |||
| 28 | // Walking back from the end needs an end iterator, not a sentinel | ||
| 29 | template<class T> | ||
| 30 | concept common_buffer_sequence = | ||
| 31 | ConstBufferSequence<T> && | ||
| 32 | (ConstBuffer<T> || std::ranges::common_range<T const>); | ||
| 33 | |||
| 34 | } // detail | ||
| 35 | |||
| 36 | /** A random access iterator over the bytes in a buffer sequence. | ||
| 37 | |||
| 38 | A buffer sequence stores its bytes in several separate regions. | ||
| 39 | This iterator presents them as one run of bytes, so standard | ||
| 40 | algorithms such as `std::search` can scan across the boundaries | ||
| 41 | between buffers without first copying the data into contiguous | ||
| 42 | storage. Empty buffers in the sequence are skipped. | ||
| 43 | |||
| 44 | The iterator dereferences to `ByteType&` for a | ||
| 45 | @ref MutableBufferSequence and to `ByteType const&` otherwise. | ||
| 46 | |||
| 47 | Moving by `n` bytes walks the underlying buffers, so `operator+=`, | ||
| 48 | `operator-=`, `operator+`, `operator-` with an integer, and | ||
| 49 | `operator[]` are linear in the number of buffers crossed. Comparison | ||
| 50 | and the difference of two iterators are constant time. | ||
| 51 | |||
| 52 | @par Preconditions | ||
| 53 | The buffer sequence and the memory it refers to outlive every | ||
| 54 | iterator obtained from it. Iterators from different sequences are | ||
| 55 | not comparable. | ||
| 56 | |||
| 57 | @par Example | ||
| 58 | @code | ||
| 59 | std::array<capy::const_buffer, 2> bufs{ | ||
| 60 | capy::make_buffer(std::string_view("GET / HTTP/1.1\r")), | ||
| 61 | capy::make_buffer(std::string_view("\n\r\nbody")) }; | ||
| 62 | |||
| 63 | // Find the end of the header, which spans both buffers | ||
| 64 | char const crlfcrlf[] = "\r\n\r\n"; | ||
| 65 | auto it = std::search( | ||
| 66 | capy::buffers_begin(bufs), capy::buffers_end(bufs), | ||
| 67 | crlfcrlf, crlfcrlf + 4); | ||
| 68 | std::size_t header_size = it - capy::buffers_begin(bufs) + 4; | ||
| 69 | @endcode | ||
| 70 | |||
| 71 | @tparam BufferSequence The buffer sequence type. It must be a single | ||
| 72 | buffer, or a range of buffers whose begin and end have the same type. | ||
| 73 | |||
| 74 | @tparam ByteType The byte type presented by the iterator. Its size | ||
| 75 | must be 1. | ||
| 76 | |||
| 77 | @see @ref buffers_begin, @ref buffers_end, | ||
| 78 | @ref buffer_sequence_begin | ||
| 79 | */ | ||
| 80 | template<class BufferSequence, class ByteType = char> | ||
| 81 | requires detail::common_buffer_sequence<BufferSequence> | ||
| 82 | class buffers_iterator | ||
| 83 | { | ||
| 84 | static_assert(sizeof(ByteType) == 1, "ByteType must be a byte"); | ||
| 85 | |||
| 86 | using sequence_iterator = decltype( | ||
| 87 | buffer_sequence_begin(std::declval<BufferSequence const&>())); | ||
| 88 | using buffer_type = capy::buffer_type<BufferSequence>; | ||
| 89 | using byte_type = std::conditional_t< | ||
| 90 | MutableBufferSequence<BufferSequence>, | ||
| 91 | ByteType, | ||
| 92 | ByteType const>; | ||
| 93 | |||
| 94 | buffer_type current_buffer_{}; | ||
| 95 | std::size_t current_buffer_position_ = 0; | ||
| 96 | sequence_iterator current_{}; | ||
| 97 | sequence_iterator end_{}; | ||
| 98 | std::size_t position_ = 0; | ||
| 99 | |||
| 100 | // Move to the next non-empty buffer, or to the end of the sequence | ||
| 101 | void | ||
| 102 | 202x | skip_forward() noexcept | |
| 103 | { | ||
| 104 | 363x | while(current_ != end_) | |
| 105 | { | ||
| 106 | 334x | current_buffer_ = buffer_type(*current_); | |
| 107 | 334x | if(current_buffer_.size() > 0) | |
| 108 | 173x | return; | |
| 109 | 161x | ++current_; | |
| 110 | } | ||
| 111 | 29x | current_buffer_ = {}; | |
| 112 | } | ||
| 113 | |||
| 114 | // Move to the previous non-empty buffer, positioned past its last byte | ||
| 115 | void | ||
| 116 | 155x | skip_backward() noexcept | |
| 117 | { | ||
| 118 | do | ||
| 119 | { | ||
| 120 | 277x | --current_; | |
| 121 | 277x | current_buffer_ = buffer_type(*current_); | |
| 122 | } | ||
| 123 | 277x | while(current_buffer_.size() == 0); | |
| 124 | 155x | current_buffer_position_ = current_buffer_.size(); | |
| 125 | 155x | } | |
| 126 | |||
| 127 | void | ||
| 128 | 318x | advance(std::ptrdiff_t n) noexcept | |
| 129 | { | ||
| 130 | 318x | if(n >= 0) | |
| 131 | { | ||
| 132 | 177x | auto left = static_cast<std::size_t>(n); | |
| 133 | 349x | while(left > 0) | |
| 134 | { | ||
| 135 | 269x | std::size_t const avail = | |
| 136 | 269x | current_buffer_.size() - current_buffer_position_; | |
| 137 | 269x | if(left < avail) | |
| 138 | { | ||
| 139 | 97x | current_buffer_position_ += left; | |
| 140 | 97x | position_ += left; | |
| 141 | 97x | return; | |
| 142 | } | ||
| 143 | 172x | left -= avail; | |
| 144 | 172x | position_ += avail; | |
| 145 | 172x | ++current_; | |
| 146 | 172x | current_buffer_position_ = 0; | |
| 147 | 172x | skip_forward(); | |
| 148 | } | ||
| 149 | } | ||
| 150 | else | ||
| 151 | { | ||
| 152 | 141x | auto left = static_cast<std::size_t>(-n); | |
| 153 | 296x | while(left > 0) | |
| 154 | { | ||
| 155 | 296x | if(left <= current_buffer_position_) | |
| 156 | { | ||
| 157 | 141x | current_buffer_position_ -= left; | |
| 158 | 141x | position_ -= left; | |
| 159 | 141x | return; | |
| 160 | } | ||
| 161 | 155x | left -= current_buffer_position_; | |
| 162 | 155x | position_ -= current_buffer_position_; | |
| 163 | 155x | skip_backward(); | |
| 164 | } | ||
| 165 | } | ||
| 166 | } | ||
| 167 | |||
| 168 | public: | ||
| 169 | /// The signed type of the distance between two iterators. | ||
| 170 | using difference_type = std::ptrdiff_t; | ||
| 171 | |||
| 172 | /// The type of the bytes the iterator visits. | ||
| 173 | using value_type = ByteType; | ||
| 174 | |||
| 175 | /// The type returned by `operator->`. | ||
| 176 | using pointer = byte_type*; | ||
| 177 | |||
| 178 | /// The type returned by `operator*`. | ||
| 179 | using reference = byte_type&; | ||
| 180 | |||
| 181 | /// The iterator category. | ||
| 182 | using iterator_category = std::random_access_iterator_tag; | ||
| 183 | |||
| 184 | /// Construct a singular iterator. | ||
| 185 | 14x | buffers_iterator() = default; | |
| 186 | |||
| 187 | /** Return an iterator to the first byte of a buffer sequence. | ||
| 188 | |||
| 189 | @param bs The buffer sequence. It must outlive the iterator. | ||
| 190 | |||
| 191 | @return An iterator to the first byte, or the end iterator if | ||
| 192 | the sequence holds no bytes. | ||
| 193 | */ | ||
| 194 | static | ||
| 195 | buffers_iterator | ||
| 196 | 18x | begin(BufferSequence const& bs) noexcept | |
| 197 | { | ||
| 198 | 18x | buffers_iterator it; | |
| 199 | 18x | it.current_ = buffer_sequence_begin(bs); | |
| 200 | 18x | it.end_ = buffer_sequence_end(bs); | |
| 201 | 18x | it.skip_forward(); | |
| 202 | 18x | return it; | |
| 203 | } | ||
| 204 | |||
| 205 | /** Return an iterator past the last byte of a buffer sequence. | ||
| 206 | |||
| 207 | @param bs The buffer sequence. It must outlive the iterator. | ||
| 208 | |||
| 209 | @return The end iterator. | ||
| 210 | */ | ||
| 211 | static | ||
| 212 | buffers_iterator | ||
| 213 | 24x | end(BufferSequence const& bs) noexcept | |
| 214 | { | ||
| 215 | 24x | buffers_iterator it; | |
| 216 | 24x | it.current_ = buffer_sequence_end(bs); | |
| 217 | 24x | it.end_ = it.current_; | |
| 218 | 24x | it.position_ = buffer_size(bs); | |
| 219 | 24x | return it; | |
| 220 | } | ||
| 221 | |||
| 222 | /** Return a reference to the current byte. | ||
| 223 | |||
| 224 | @par Preconditions | ||
| 225 | The iterator is not the end iterator. | ||
| 226 | */ | ||
| 227 | reference | ||
| 228 | 125x | operator*() const noexcept | |
| 229 | { | ||
| 230 | return static_cast<pointer>( | ||
| 231 | 125x | current_buffer_.data())[current_buffer_position_]; | |
| 232 | } | ||
| 233 | |||
| 234 | /** Return a pointer to the current byte. | ||
| 235 | |||
| 236 | @par Preconditions | ||
| 237 | The iterator is not the end iterator. | ||
| 238 | */ | ||
| 239 | pointer | ||
| 240 | operator->() const noexcept | ||
| 241 | { | ||
| 242 | return &**this; | ||
| 243 | } | ||
| 244 | |||
| 245 | /** Return a reference to the byte `n` positions away. | ||
| 246 | |||
| 247 | @par Complexity | ||
| 248 | Linear in the number of buffers crossed. | ||
| 249 | |||
| 250 | @param n The offset from this iterator, in bytes. | ||
| 251 | */ | ||
| 252 | reference | ||
| 253 | 33x | operator[](difference_type n) const noexcept | |
| 254 | { | ||
| 255 | 33x | return *(*this + n); | |
| 256 | } | ||
| 257 | |||
| 258 | /// Advance to the next byte. | ||
| 259 | buffers_iterator& | ||
| 260 | 59x | operator++() noexcept | |
| 261 | { | ||
| 262 | 59x | ++position_; | |
| 263 | 59x | if(++current_buffer_position_ < current_buffer_.size()) | |
| 264 | 47x | return *this; | |
| 265 | 12x | ++current_; | |
| 266 | 12x | current_buffer_position_ = 0; | |
| 267 | 12x | skip_forward(); | |
| 268 | 12x | return *this; | |
| 269 | } | ||
| 270 | |||
| 271 | /// Advance to the next byte, returning the previous position. | ||
| 272 | buffers_iterator | ||
| 273 | operator++(int) noexcept | ||
| 274 | { | ||
| 275 | auto tmp = *this; | ||
| 276 | ++*this; | ||
| 277 | return tmp; | ||
| 278 | } | ||
| 279 | |||
| 280 | /// Move back to the previous byte. | ||
| 281 | buffers_iterator& | ||
| 282 | 20x | operator--() noexcept | |
| 283 | { | ||
| 284 | 20x | advance(-1); | |
| 285 | 20x | return *this; | |
| 286 | } | ||
| 287 | |||
| 288 | /// Move back to the previous byte, returning the previous position. | ||
| 289 | buffers_iterator | ||
| 290 | operator--(int) noexcept | ||
| 291 | { | ||
| 292 | auto tmp = *this; | ||
| 293 | --*this; | ||
| 294 | return tmp; | ||
| 295 | } | ||
| 296 | |||
| 297 | /** Move by `n` bytes. | ||
| 298 | |||
| 299 | @par Complexity | ||
| 300 | Linear in the number of buffers crossed. | ||
| 301 | |||
| 302 | @param n The number of bytes to move; negative moves backward. | ||
| 303 | |||
| 304 | @return A reference to `*this`. | ||
| 305 | */ | ||
| 306 | buffers_iterator& | ||
| 307 | 166x | operator+=(difference_type n) noexcept | |
| 308 | { | ||
| 309 | 166x | advance(n); | |
| 310 | 166x | return *this; | |
| 311 | } | ||
| 312 | |||
| 313 | /** Move back by `n` bytes. | ||
| 314 | |||
| 315 | @par Complexity | ||
| 316 | Linear in the number of buffers crossed. | ||
| 317 | |||
| 318 | @param n The number of bytes to move back. | ||
| 319 | |||
| 320 | @return A reference to `*this`. | ||
| 321 | */ | ||
| 322 | buffers_iterator& | ||
| 323 | 132x | operator-=(difference_type n) noexcept | |
| 324 | { | ||
| 325 | 132x | advance(-n); | |
| 326 | 132x | return *this; | |
| 327 | } | ||
| 328 | |||
| 329 | /// Return an iterator `n` bytes after `it`. | ||
| 330 | friend | ||
| 331 | buffers_iterator | ||
| 332 | 166x | operator+(buffers_iterator it, difference_type n) noexcept | |
| 333 | { | ||
| 334 | 166x | it += n; | |
| 335 | 166x | return it; | |
| 336 | } | ||
| 337 | |||
| 338 | /// Return an iterator `n` bytes after `it`. | ||
| 339 | friend | ||
| 340 | buffers_iterator | ||
| 341 | operator+(difference_type n, buffers_iterator it) noexcept | ||
| 342 | { | ||
| 343 | it += n; | ||
| 344 | return it; | ||
| 345 | } | ||
| 346 | |||
| 347 | /// Return an iterator `n` bytes before `it`. | ||
| 348 | friend | ||
| 349 | buffers_iterator | ||
| 350 | 11x | operator-(buffers_iterator it, difference_type n) noexcept | |
| 351 | { | ||
| 352 | 11x | it -= n; | |
| 353 | 11x | return it; | |
| 354 | } | ||
| 355 | |||
| 356 | /// Return the number of bytes from `b` to `a`. | ||
| 357 | friend | ||
| 358 | difference_type | ||
| 359 | 264x | operator-( | |
| 360 | buffers_iterator const& a, | ||
| 361 | buffers_iterator const& b) noexcept | ||
| 362 | { | ||
| 363 | 264x | return static_cast<difference_type>(a.position_) - | |
| 364 | 264x | static_cast<difference_type>(b.position_); | |
| 365 | } | ||
| 366 | |||
| 367 | /// Test whether two iterators refer to the same byte. | ||
| 368 | friend | ||
| 369 | bool | ||
| 370 | 312x | operator==( | |
| 371 | buffers_iterator const& a, | ||
| 372 | buffers_iterator const& b) noexcept | ||
| 373 | { | ||
| 374 | 312x | return a.position_ == b.position_; | |
| 375 | } | ||
| 376 | |||
| 377 | /// Order two iterators by byte position. | ||
| 378 | friend | ||
| 379 | std::strong_ordering | ||
| 380 | 121x | operator<=>( | |
| 381 | buffers_iterator const& a, | ||
| 382 | buffers_iterator const& b) noexcept | ||
| 383 | { | ||
| 384 | 121x | return a.position_ <=> b.position_; | |
| 385 | } | ||
| 386 | }; | ||
| 387 | |||
| 388 | /** Return an iterator to the first byte of a buffer sequence. | ||
| 389 | |||
| 390 | @param bs The buffer sequence. It must outlive the iterator. | ||
| 391 | |||
| 392 | @return `buffers_iterator<BufferSequence>::begin(bs)`. | ||
| 393 | |||
| 394 | @see @ref buffers_iterator, @ref buffers_end | ||
| 395 | */ | ||
| 396 | template<detail::common_buffer_sequence BufferSequence> | ||
| 397 | buffers_iterator<BufferSequence> | ||
| 398 | 17x | buffers_begin(BufferSequence const& bs) noexcept | |
| 399 | { | ||
| 400 | 17x | return buffers_iterator<BufferSequence>::begin(bs); | |
| 401 | } | ||
| 402 | |||
| 403 | /// Rejects a temporary sequence, since the iterator would dangle. | ||
| 404 | template<detail::common_buffer_sequence BufferSequence> | ||
| 405 | buffers_iterator<BufferSequence> | ||
| 406 | buffers_begin(BufferSequence const&& bs) = delete; | ||
| 407 | |||
| 408 | /** Return an iterator past the last byte of a buffer sequence. | ||
| 409 | |||
| 410 | @param bs The buffer sequence. It must outlive the iterator. | ||
| 411 | |||
| 412 | @return `buffers_iterator<BufferSequence>::end(bs)`. | ||
| 413 | |||
| 414 | @see @ref buffers_iterator, @ref buffers_begin | ||
| 415 | */ | ||
| 416 | template<detail::common_buffer_sequence BufferSequence> | ||
| 417 | buffers_iterator<BufferSequence> | ||
| 418 | 24x | buffers_end(BufferSequence const& bs) noexcept | |
| 419 | { | ||
| 420 | 24x | return buffers_iterator<BufferSequence>::end(bs); | |
| 421 | } | ||
| 422 | |||
| 423 | /// Rejects a temporary sequence, since the iterator would dangle. | ||
| 424 | template<detail::common_buffer_sequence BufferSequence> | ||
| 425 | buffers_iterator<BufferSequence> | ||
| 426 | buffers_end(BufferSequence const&& bs) = delete; | ||
| 427 | |||
| 428 | } // capy | ||
| 429 | } // boost | ||
| 430 | |||
| 431 | #endif | ||
| 432 |