include/boost/url/detail/impl/segments_iter_impl.hpp
99.1% Lines (114/115)
100.0% List of functions (6/6)
Functions (6)
Function
Calls
Lines
Blocks
boost::urls::detail::segments_iter_impl::segments_iter_impl(boost::urls::detail::path_ref const&)
:24
9364x
100.0%
100.0%
boost::urls::detail::segments_iter_impl::segments_iter_impl(boost::urls::detail::path_ref const&, int)
:37
16416x
100.0%
100.0%
boost::urls::detail::segments_iter_impl::segments_iter_impl(boost::urls::detail::url_impl const&, unsigned long, unsigned long)
:51
2313x
96.2%
90.0%
boost::urls::detail::segments_iter_impl::update()
:99
12695x
100.0%
94.0%
boost::urls::detail::segments_iter_impl::increment()
:130
10857x
100.0%
88.0%
boost::urls::detail::segments_iter_impl::decrement()
:174
1979x
100.0%
90.0%
| Line | TLA | Hits | Source Code |
|---|---|---|---|
| 1 | // | ||
| 2 | // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) | ||
| 3 | // Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com) | ||
| 4 | // | ||
| 5 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
| 6 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
| 7 | // | ||
| 8 | // Official repository: https://github.com/boostorg/url | ||
| 9 | // | ||
| 10 | |||
| 11 | #ifndef BOOST_URL_DETAIL_IMPL_SEGMENTS_ITER_IMPL_HPP | ||
| 12 | #define BOOST_URL_DETAIL_IMPL_SEGMENTS_ITER_IMPL_HPP | ||
| 13 | |||
| 14 | #include <boost/url/detail/decode.hpp> | ||
| 15 | #include <boost/url/detail/path.hpp> | ||
| 16 | #include <boost/assert.hpp> | ||
| 17 | |||
| 18 | namespace boost { | ||
| 19 | namespace urls { | ||
| 20 | namespace detail { | ||
| 21 | |||
| 22 | // begin | ||
| 23 | inline | ||
| 24 | 9364x | segments_iter_impl:: | |
| 25 | segments_iter_impl( | ||
| 26 | 9364x | detail::path_ref const& ref_) noexcept | |
| 27 | 9364x | : ref(ref_) | |
| 28 | { | ||
| 29 | 9364x | pos = path_prefix(ref.buffer()); | |
| 30 | // begin() starts after any malleable prefix but remembers decoded chars skipped | ||
| 31 | 9364x | decoded_prefix = pos; | |
| 32 | 9364x | update(); | |
| 33 | 9364x | } | |
| 34 | |||
| 35 | // end | ||
| 36 | inline | ||
| 37 | 16416x | segments_iter_impl:: | |
| 38 | segments_iter_impl( | ||
| 39 | detail::path_ref const& ref_, | ||
| 40 | 16416x | int) noexcept | |
| 41 | 16416x | : ref(ref_) | |
| 42 | 16416x | , pos(ref.size()) | |
| 43 | 16416x | , next(ref.size()) | |
| 44 | 16416x | , index(ref.nseg()) | |
| 45 | { | ||
| 46 | // end() carries the total decoded length for O(1) range math | ||
| 47 | 16416x | decoded_prefix = ref.decoded_size(); | |
| 48 | 16416x | } | |
| 49 | |||
| 50 | inline | ||
| 51 | 2313x | segments_iter_impl:: | |
| 52 | segments_iter_impl( | ||
| 53 | url_impl const& u_, | ||
| 54 | std::size_t pos_, | ||
| 55 | 2313x | std::size_t index_) noexcept | |
| 56 | 2313x | : ref(u_) | |
| 57 | 2313x | , pos(pos_) | |
| 58 | 2313x | , index(index_) | |
| 59 | { | ||
| 60 | 2313x | auto const total = ref.nseg(); | |
| 61 | 2313x | if(index >= total) | |
| 62 | { | ||
| 63 | 961x | pos = ref.size(); | |
| 64 | 961x | next = ref.size(); | |
| 65 | 961x | decoded_prefix = ref.decoded_size(); | |
| 66 | // iterator equal to end: nothing to decode | ||
| 67 | 961x | dn = 0; | |
| 68 | 961x | return; | |
| 69 | } | ||
| 70 | |||
| 71 | 1352x | if(index == 0) | |
| 72 | { | ||
| 73 | 763x | pos = path_prefix(ref.buffer()); | |
| 74 | // first segment inherits the prefix size (including leading '/') | ||
| 75 | 763x | decoded_prefix = pos; | |
| 76 | 763x | update(); | |
| 77 | 763x | return; | |
| 78 | } | ||
| 79 | |||
| 80 | 589x | BOOST_ASSERT(pos <= ref.size()); | |
| 81 | // compute decoded prefix by scanning once up to the encoded offset | ||
| 82 | 589x | decoded_prefix = detail::decode_bytes_unsafe( | |
| 83 | core::string_view(ref.data(), pos)); | ||
| 84 | 589x | if(pos != ref.size()) | |
| 85 | { | ||
| 86 | 589x | BOOST_ASSERT( | |
| 87 | ref.data()[pos] == '/'); | ||
| 88 | 589x | ++pos; // skip '/' | |
| 89 | 589x | update(); | |
| 90 | 589x | --pos; | |
| 91 | 589x | return; | |
| 92 | } | ||
| 93 | |||
| 94 | ✗ | update(); | |
| 95 | } | ||
| 96 | |||
| 97 | inline | ||
| 98 | void | ||
| 99 | 12695x | segments_iter_impl:: | |
| 100 | update() noexcept | ||
| 101 | { | ||
| 102 | 12695x | BOOST_ASSERT( | |
| 103 | pos == 0 || | ||
| 104 | ref.data()[pos - 1] == '/'); | ||
| 105 | 12695x | auto const end = ref.end(); | |
| 106 | char const* const p0 = | ||
| 107 | 12695x | ref.data() + pos; | |
| 108 | 12695x | dn = 0; | |
| 109 | 12695x | auto p = p0; | |
| 110 | 56663x | while(p != end) | |
| 111 | { | ||
| 112 | 49262x | if(*p == '/') | |
| 113 | 5294x | break; | |
| 114 | 43968x | if(*p != '%') | |
| 115 | { | ||
| 116 | 39695x | ++p; | |
| 117 | 39695x | continue; | |
| 118 | } | ||
| 119 | 4273x | p += 3; | |
| 120 | 4273x | dn += 2; | |
| 121 | } | ||
| 122 | 12695x | next = p - ref.data(); | |
| 123 | 12695x | dn = p - p0 - dn; | |
| 124 | 12695x | s_ = make_pct_string_view_unsafe( | |
| 125 | 12695x | p0, p - p0, dn); | |
| 126 | 12695x | } | |
| 127 | |||
| 128 | inline | ||
| 129 | void | ||
| 130 | 10857x | segments_iter_impl:: | |
| 131 | increment() noexcept | ||
| 132 | { | ||
| 133 | 10857x | BOOST_ASSERT( | |
| 134 | index != ref.nseg()); | ||
| 135 | 10857x | auto const old_index = index; | |
| 136 | 10857x | auto const old_dn = dn; | |
| 137 | // add decoded length of previous segment | ||
| 138 | 10857x | decoded_prefix += old_dn; | |
| 139 | 10857x | if(old_index > 0) | |
| 140 | // account for the '/' separator we just crossed | ||
| 141 | 6005x | ++decoded_prefix; | |
| 142 | 10857x | ++index; | |
| 143 | 10857x | pos = next; | |
| 144 | 10857x | if(index == ref.nseg()) | |
| 145 | 4765x | return; | |
| 146 | // "/" segment | ||
| 147 | 6092x | auto const end = ref.end(); | |
| 148 | 6092x | auto p = ref.data() + pos; | |
| 149 | 6092x | BOOST_ASSERT(p != end); | |
| 150 | 6092x | BOOST_ASSERT(*p == '/'); | |
| 151 | 6092x | dn = 0; | |
| 152 | 6092x | ++p; // skip '/' | |
| 153 | 6092x | auto const p0 = p; | |
| 154 | 31779x | while(p != end) | |
| 155 | { | ||
| 156 | 28672x | if(*p == '/') | |
| 157 | 2985x | break; | |
| 158 | 25687x | if(*p != '%') | |
| 159 | { | ||
| 160 | 24649x | ++p; | |
| 161 | 24649x | continue; | |
| 162 | } | ||
| 163 | 1038x | p += 3; | |
| 164 | 1038x | dn += 2; | |
| 165 | } | ||
| 166 | 6092x | next = p - ref.data(); | |
| 167 | 6092x | dn = p - p0 - dn; | |
| 168 | 6092x | s_ = make_pct_string_view_unsafe( | |
| 169 | 6092x | p0, p - p0, dn); | |
| 170 | } | ||
| 171 | |||
| 172 | inline | ||
| 173 | void | ||
| 174 | 1979x | segments_iter_impl:: | |
| 175 | decrement() noexcept | ||
| 176 | { | ||
| 177 | 1979x | BOOST_ASSERT(index != 0); | |
| 178 | 1979x | auto const current_dn = dn; | |
| 179 | 1979x | auto const current_index = index; | |
| 180 | // remove the decoded length of the segment we're leaving | ||
| 181 | 1979x | decoded_prefix -= current_dn; | |
| 182 | 1979x | if(current_index > 0 && decoded_prefix > 0) | |
| 183 | // drop the '/' separator when stepping left of it | ||
| 184 | 1979x | --decoded_prefix; | |
| 185 | 1979x | --index; | |
| 186 | 1979x | if(index == 0) | |
| 187 | { | ||
| 188 | 794x | pos = path_prefix(ref.buffer()); | |
| 189 | 794x | decoded_prefix = pos; | |
| 190 | 794x | update(); | |
| 191 | 794x | BOOST_ASSERT(! s_.ends_with('/')); | |
| 192 | 794x | return; | |
| 193 | } | ||
| 194 | // scan backwards to find the '/' before | ||
| 195 | // the previous segment | ||
| 196 | 1185x | auto const begin = ref.data() + | |
| 197 | 1185x | path_prefix(ref.buffer()); | |
| 198 | 1185x | auto p = ref.data() + pos; | |
| 199 | 1185x | BOOST_ASSERT(p != begin); | |
| 200 | 4738x | while(p != begin) | |
| 201 | { | ||
| 202 | 4738x | --p; | |
| 203 | 4738x | if(*p == '/') | |
| 204 | 1185x | break; | |
| 205 | } | ||
| 206 | 1185x | pos = p - ref.data() + 1; | |
| 207 | 1185x | update(); | |
| 208 | 1185x | --pos; | |
| 209 | } | ||
| 210 | |||
| 211 | } // detail | ||
| 212 | } // urls | ||
| 213 | } // boost | ||
| 214 | |||
| 215 | #endif | ||
| 216 |