Line data Source code
1 : //
2 : // Copyright (c) 2025 Alan de Freitas (alandefreitas@gmail.com)
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/boostorg/url
8 : //
9 :
10 : #ifndef BOOST_URL_DETAIL_SEGMENTS_RANGE_HPP
11 : #define BOOST_URL_DETAIL_SEGMENTS_RANGE_HPP
12 :
13 : #include <boost/url/detail/config.hpp>
14 : #include <boost/url/detail/url_impl.hpp>
15 : #include <boost/url/segments_base.hpp>
16 : #include <boost/url/segments_encoded_base.hpp>
17 : #include <boost/core/detail/string_view.hpp>
18 : #include <boost/assert.hpp>
19 :
20 : namespace boost {
21 : namespace urls {
22 : namespace detail {
23 :
24 : struct segments_iter_access
25 : {
26 : static
27 : segments_iter_impl const&
28 36 : impl(segments_base::iterator const& it) noexcept
29 : {
30 36 : return it.it_;
31 : }
32 :
33 : static
34 : segments_iter_impl const&
35 2 : impl(segments_encoded_base::iterator const& it) noexcept
36 : {
37 2 : return it.it_;
38 : }
39 : };
40 :
41 : inline
42 : path_ref
43 19 : make_subref_from_impls(
44 : segments_iter_impl const& first,
45 : segments_iter_impl const& last) noexcept
46 : {
47 19 : BOOST_ASSERT(first.ref.alias_of(last.ref));
48 19 : path_ref const& ref = first.ref;
49 :
50 19 : std::size_t const i0 = first.index;
51 19 : std::size_t const i1 = last.index;
52 19 : BOOST_ASSERT(i0 <= i1);
53 19 : std::size_t const nseg = i1 - i0;
54 :
55 19 : bool const absolute = ref.buffer().starts_with('/');
56 :
57 : // Empty range
58 19 : if (nseg == 0)
59 : {
60 : std::size_t off0;
61 6 : if (i0 == 0)
62 : {
63 : // [begin, begin): don't include the leading '/'
64 : // for absolute, start right after the leading '/';
65 3 : if (absolute)
66 : {
67 2 : off0 = 1;
68 : }
69 : // for relative, start at the first segment character.
70 : else
71 : {
72 1 : off0 = first.pos;
73 : }
74 : }
75 : else
76 : {
77 : // [it, it) in the middle:
78 : // skip the separator before segment i0
79 3 : off0 = first.pos + 1;
80 : }
81 :
82 6 : core::string_view const sub(ref.data() + off0, 0);
83 6 : return {sub, 0, 0};
84 : }
85 :
86 : // General case: non-empty range
87 : // Start offset
88 : std::size_t off0;
89 13 : bool include_leading_slash = false;
90 13 : if (i0 == 0)
91 : {
92 8 : if (absolute)
93 : {
94 : // include leading '/'
95 5 : off0 = 0;
96 5 : include_leading_slash = true;
97 : }
98 : else
99 : {
100 : // relative: start at first segment
101 3 : off0 = first.pos;
102 : }
103 : }
104 : else
105 : {
106 : // skip slash before segment i0
107 5 : off0 = first.pos + 1;
108 : }
109 :
110 : // End offset
111 : std::size_t off1;
112 13 : if(i1 == ref.nseg())
113 : {
114 7 : off1 = ref.size();
115 : }
116 : else
117 : {
118 : // stop before the slash preceding i1
119 6 : off1 = last.pos;
120 : }
121 :
122 13 : BOOST_ASSERT(off1 >= off0);
123 13 : core::string_view const sub(ref.data() + off0, off1 - off0);
124 :
125 : // Decoded-length:
126 : // sum per-segment decoded lengths + internal '/' + the leading '/'.
127 13 : std::size_t dn_sum = 0;
128 : {
129 : // copy to iterate
130 13 : segments_iter_impl cur = first;
131 37 : for (std::size_t k = 0; k < nseg; ++k)
132 : {
133 : // per-segment decoded length
134 24 : dn_sum += cur.dn;
135 24 : cur.increment();
136 : }
137 : // internal '/'s
138 13 : dn_sum += (nseg - 1);
139 : // leading '/'
140 13 : if (include_leading_slash)
141 : {
142 5 : ++dn_sum;
143 : }
144 : }
145 :
146 13 : return {sub, dn_sum, nseg};
147 : }
148 :
149 : template<class Iter>
150 : inline
151 : path_ref
152 19 : make_subref(Iter const& first, Iter const& last) noexcept
153 : {
154 19 : auto const& f = segments_iter_access::impl(first);
155 19 : auto const& l = segments_iter_access::impl(last);
156 19 : return make_subref_from_impls(f, l);
157 : }
158 :
159 : } // detail
160 : } // urls
161 : } // boost
162 :
163 : #endif
|