1 | // |
2 | // Copyright (c) 2019 Vinnie Falco (vinnie.falco@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_IMPL_PARAMS_ITER_IMPL_IPP |
11 | #define BOOST_URL_DETAIL_IMPL_PARAMS_ITER_IMPL_IPP |
12 | |
13 | #include <boost/url/detail/config.hpp> |
14 | #include <boost/url/detail/params_iter_impl.hpp> |
15 | #include <boost/assert.hpp> |
16 | |
17 | namespace boost { |
18 | namespace urls { |
19 | namespace detail { |
20 | |
21 | /* index zero-based index of param |
22 | pos offset from start 0 = '?' |
23 | nk size of key with '?' or '&' |
24 | nv size of value with '=' |
25 | dk decoded key size no '?' or '&' |
26 | dv decoded value size no '=' |
27 | */ |
28 | params_iter_impl:: |
29 | params_iter_impl( |
30 | query_ref const& ref_) noexcept |
31 | : ref(ref_) |
32 | , index(0) |
33 | , pos(0) |
34 | { |
35 | if(index < ref_.nparam()) |
36 | setup(); |
37 | } |
38 | |
39 | params_iter_impl:: |
40 | params_iter_impl( |
41 | query_ref const& ref_, |
42 | int) noexcept |
43 | : ref(ref_) |
44 | , index(ref_.nparam()) |
45 | , pos(ref_.size()) |
46 | { |
47 | } |
48 | |
49 | params_iter_impl:: |
50 | params_iter_impl( |
51 | query_ref const& ref_, |
52 | std::size_t pos_, |
53 | std::size_t index_) noexcept |
54 | : ref(ref_) |
55 | , index(index_) |
56 | , pos(pos_) |
57 | { |
58 | BOOST_ASSERT( |
59 | pos <= ref.size()); |
60 | if(index < ref_.nparam()) |
61 | setup(); |
62 | } |
63 | |
64 | // set up state for key/value at pos |
65 | void |
66 | params_iter_impl:: |
67 | setup() noexcept |
68 | { |
69 | dk = 1; |
70 | dv = 0; |
71 | auto const end = ref.end(); |
72 | BOOST_ASSERT(pos != ref.size()); |
73 | auto p0 = ref.begin() + pos; |
74 | auto p = p0; |
75 | // key |
76 | for(;;) |
77 | { |
78 | if( p == end || |
79 | *p == '&') |
80 | { |
81 | // no value |
82 | nk = 1 + p - p0; |
83 | dk = nk - dk; |
84 | nv = 0; |
85 | return; |
86 | } |
87 | if(*p == '=') |
88 | break; |
89 | if(*p == '%') |
90 | { |
91 | BOOST_ASSERT( |
92 | end - p >= 3); |
93 | dk += 2; |
94 | p += 2; |
95 | } |
96 | ++p; |
97 | } |
98 | nk = 1 + p - p0; |
99 | dk = nk - dk; |
100 | p0 = p; |
101 | |
102 | // value |
103 | for(;;) |
104 | { |
105 | ++p; |
106 | if( p == end || |
107 | *p == '&') |
108 | break; |
109 | if(*p == '%') |
110 | { |
111 | BOOST_ASSERT( |
112 | end - p >= 3); |
113 | dv += 2; |
114 | p += 2; |
115 | } |
116 | } |
117 | nv = p - p0; |
118 | dv = nv - dv - 1; |
119 | } |
120 | |
121 | void |
122 | params_iter_impl:: |
123 | increment() noexcept |
124 | { |
125 | BOOST_ASSERT( |
126 | index < ref.nparam()); |
127 | pos += nk + nv; |
128 | ++index; |
129 | if(index < ref.nparam()) |
130 | setup(); |
131 | } |
132 | |
133 | void |
134 | params_iter_impl:: |
135 | decrement() noexcept |
136 | { |
137 | BOOST_ASSERT(index > 0); |
138 | --index; |
139 | dk = 1; // for '&' or '?' |
140 | dv = 1; // for '=' |
141 | auto const begin = ref.begin(); |
142 | BOOST_ASSERT(pos > 0); |
143 | auto p1 = begin + (pos - 1); |
144 | auto p = p1; |
145 | // find key or '=' |
146 | for(;;) |
147 | { |
148 | if(p == begin) |
149 | { |
150 | // key |
151 | nk = 1 + p1 - p; // with '?' |
152 | dk = nk - dv; |
153 | nv = 0; |
154 | dv = 0; |
155 | pos -= nk; |
156 | return; |
157 | } |
158 | else if(*--p == '&') |
159 | { |
160 | // key |
161 | nk = p1 - p; // with '&' |
162 | dk = nk - dv; |
163 | nv = 0; |
164 | dv = 0; |
165 | pos -= nk; |
166 | return; |
167 | } |
168 | if(*p == '=') |
169 | { |
170 | // value |
171 | nv = p1 - p; // with '=' |
172 | break; |
173 | } |
174 | if(*p == '%') |
175 | dv += 2; |
176 | } |
177 | // find key and value |
178 | for(;;) |
179 | { |
180 | if(p == begin) |
181 | { |
182 | // key and value |
183 | nk = 1 + p1 - p - nv; // with '?' |
184 | dk = nk - dk; |
185 | dv = nv - dv; |
186 | pos -= nk + nv; |
187 | return; |
188 | } |
189 | if(*--p == '&') |
190 | { |
191 | // key and value |
192 | nk = p1 - p - nv; // with '&' |
193 | dk = nk - dk; |
194 | dv = nv - dv; |
195 | pos -= nk + nv; |
196 | return; |
197 | } |
198 | if(*p == '=') |
199 | { |
200 | // value |
201 | nv = p1 - p; // with '=' |
202 | dv += dk; |
203 | dk = 0; |
204 | } |
205 | else if(*p == '%') |
206 | { |
207 | dk += 2; |
208 | } |
209 | } |
210 | } |
211 | |
212 | param_pct_view |
213 | params_iter_impl:: |
214 | dereference() const noexcept |
215 | { |
216 | BOOST_ASSERT(index < ref.nparam()); |
217 | BOOST_ASSERT(pos < ref.size()); |
218 | auto const p = ref.begin() + pos; |
219 | if(nv) |
220 | return { |
221 | make_pct_string_view_unsafe( |
222 | data: p, size: nk - 1, decoded_size: dk), |
223 | make_pct_string_view_unsafe( |
224 | data: p + nk, size: nv - 1, decoded_size: dv)}; |
225 | return { |
226 | make_pct_string_view_unsafe( |
227 | data: p, size: nk - 1, decoded_size: dk), |
228 | no_value}; |
229 | } |
230 | |
231 | pct_string_view |
232 | params_iter_impl:: |
233 | key() const noexcept |
234 | { |
235 | BOOST_ASSERT(index < ref.nparam()); |
236 | BOOST_ASSERT(pos < ref.size()); |
237 | auto const p = ref.begin() + pos; |
238 | return make_pct_string_view_unsafe( |
239 | data: p, size: nk - 1, decoded_size: dk); |
240 | } |
241 | |
242 | } // detail |
243 | } // url |
244 | } // boost |
245 | |
246 | #endif |
247 | |