1  
//
1  
//
2  
// Copyright (c) 2022 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2022 Vinnie Falco (vinnie.falco@gmail.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/boostorg/url
7  
// Official repository: https://github.com/boostorg/url
8  
//
8  
//
9  

9  

10  

10  

11  
#include <boost/url/detail/config.hpp>
11  
#include <boost/url/detail/config.hpp>
12  
#include "path.hpp"
12  
#include "path.hpp"
13  
#include <boost/url/detail/url_impl.hpp>
13  
#include <boost/url/detail/url_impl.hpp>
14  
#include <boost/url/authority_view.hpp>
14  
#include <boost/url/authority_view.hpp>
15  
#include <boost/assert.hpp>
15  
#include <boost/assert.hpp>
16  
#include <cstring>
16  
#include <cstring>
17  

17  

18  
namespace boost {
18  
namespace boost {
19  
namespace urls {
19  
namespace urls {
20  
namespace detail {
20  
namespace detail {
21  

21  

22  
#if defined(__GNUC__) && ! defined(__clang__) && defined(__MINGW32__)
22  
#if defined(__GNUC__) && ! defined(__clang__) && defined(__MINGW32__)
23  
#pragma GCC diagnostic push
23  
#pragma GCC diagnostic push
24  
#pragma GCC diagnostic ignored "-Warray-bounds"
24  
#pragma GCC diagnostic ignored "-Warray-bounds"
25  
#endif
25  
#endif
26  

26  

27  
//------------------------------------------------
27  
//------------------------------------------------
28  
//
28  
//
29  
// url_impl
29  
// url_impl
30  
//
30  
//
31  
//------------------------------------------------
31  
//------------------------------------------------
32  

32  

33  
void
33  
void
34  
url_impl::
34  
url_impl::
35  
apply_scheme(
35  
apply_scheme(
36  
    core::string_view s) noexcept
36  
    core::string_view s) noexcept
37  
{
37  
{
38  
    scheme_ = string_to_scheme(s);
38  
    scheme_ = string_to_scheme(s);
39  
    set_size(id_scheme, s.size() + 1);
39  
    set_size(id_scheme, s.size() + 1);
40  
}
40  
}
41  

41  

42  
void
42  
void
43  
url_impl::
43  
url_impl::
44  
apply_userinfo(
44  
apply_userinfo(
45  
    pct_string_view const& user,
45  
    pct_string_view const& user,
46  
    pct_string_view const* pass) noexcept
46  
    pct_string_view const* pass) noexcept
47  
{
47  
{
48  
    // this function is for
48  
    // this function is for
49  
    // authority_view_rule only
49  
    // authority_view_rule only
50  
    BOOST_ASSERT(from_ == from::authority);
50  
    BOOST_ASSERT(from_ == from::authority);
51  

51  

52  
    // userinfo
52  
    // userinfo
53  
    set_size(id_user, user.size());
53  
    set_size(id_user, user.size());
54  
    decoded_[id_user] =
54  
    decoded_[id_user] =
55  
        user.decoded_size();
55  
        user.decoded_size();
56  
    if(pass)
56  
    if(pass)
57  
    {
57  
    {
58  
        set_size(id_pass,
58  
        set_size(id_pass,
59  
            pass->size() + 2);
59  
            pass->size() + 2);
60  
        decoded_[id_pass] =
60  
        decoded_[id_pass] =
61  
            pass->decoded_size();
61  
            pass->decoded_size();
62  
    }
62  
    }
63  
    else
63  
    else
64  
    {
64  
    {
65  
        // trailing '@'
65  
        // trailing '@'
66  
        set_size(id_pass, 1 );
66  
        set_size(id_pass, 1 );
67  
    }
67  
    }
68  
}
68  
}
69  

69  

70  
void
70  
void
71  
url_impl::
71  
url_impl::
72  
apply_host(
72  
apply_host(
73  
    host_type ht,
73  
    host_type ht,
74  
    pct_string_view s,
74  
    pct_string_view s,
75  
    unsigned char const* addr) noexcept
75  
    unsigned char const* addr) noexcept
76  
{
76  
{
77  
    // this function is for
77  
    // this function is for
78  
    // authority_view_rule only
78  
    // authority_view_rule only
79  
    BOOST_ASSERT(from_ == from::authority);
79  
    BOOST_ASSERT(from_ == from::authority);
80  

80  

81  
    // host, port
81  
    // host, port
82  
    host_type_ = ht;
82  
    host_type_ = ht;
83  
    set_size(id_host, s.size());
83  
    set_size(id_host, s.size());
84  
    decoded_[id_host] =
84  
    decoded_[id_host] =
85  
        s.decoded_size();
85  
        s.decoded_size();
86  
    std::memcpy(
86  
    std::memcpy(
87  
        ip_addr_,
87  
        ip_addr_,
88  
        addr,
88  
        addr,
89  
        sizeof(ip_addr_));
89  
        sizeof(ip_addr_));
90  
}
90  
}
91  

91  

92  
void
92  
void
93  
url_impl::
93  
url_impl::
94  
apply_port(
94  
apply_port(
95  
    core::string_view s,
95  
    core::string_view s,
96  
    unsigned short pn) noexcept
96  
    unsigned short pn) noexcept
97  
{
97  
{
98  
    // this function is for
98  
    // this function is for
99  
    // authority_view_rule only
99  
    // authority_view_rule only
100  
    BOOST_ASSERT(from_ == from::authority);
100  
    BOOST_ASSERT(from_ == from::authority);
101  

101  

102  
    port_number_ = pn;
102  
    port_number_ = pn;
103  
    set_size(id_port, 1 + s.size());
103  
    set_size(id_port, 1 + s.size());
104  
}
104  
}
105  

105  

106  
void
106  
void
107  
url_impl::
107  
url_impl::
108  
apply_authority(
108  
apply_authority(
109  
    authority_view const& a) noexcept
109  
    authority_view const& a) noexcept
110  
{
110  
{
111  
    BOOST_ASSERT(from_ != from::authority);
111  
    BOOST_ASSERT(from_ != from::authority);
112  

112  

113  
    // userinfo
113  
    // userinfo
114  
    set_size(id_user,
114  
    set_size(id_user,
115  
        a.u_.len(id_user) +
115  
        a.u_.len(id_user) +
116  
        (from_ == from::authority ? 0 : 2));
116  
        (from_ == from::authority ? 0 : 2));
117  
    set_size(id_pass, a.u_.len(id_pass));
117  
    set_size(id_pass, a.u_.len(id_pass));
118  
    decoded_[id_user] = a.u_.decoded_[id_user];
118  
    decoded_[id_user] = a.u_.decoded_[id_user];
119  
    decoded_[id_pass] = a.u_.decoded_[id_pass];
119  
    decoded_[id_pass] = a.u_.decoded_[id_pass];
120  

120  

121  
    // host, port
121  
    // host, port
122  
    host_type_ = a.u_.host_type_;
122  
    host_type_ = a.u_.host_type_;
123  
    port_number_ = a.u_.port_number_;
123  
    port_number_ = a.u_.port_number_;
124  
    set_size(id_host, a.u_.len(id_host));
124  
    set_size(id_host, a.u_.len(id_host));
125  
    set_size(id_port, a.u_.len(id_port));
125  
    set_size(id_port, a.u_.len(id_port));
126  
    std::memcpy(
126  
    std::memcpy(
127  
        ip_addr_,
127  
        ip_addr_,
128  
        a.u_.ip_addr_,
128  
        a.u_.ip_addr_,
129  
        sizeof(ip_addr_));
129  
        sizeof(ip_addr_));
130  
    decoded_[id_host] = a.u_.decoded_[id_host];
130  
    decoded_[id_host] = a.u_.decoded_[id_host];
131  
}
131  
}
132  

132  

133  
void
133  
void
134  
url_impl::
134  
url_impl::
135  
apply_path(
135  
apply_path(
136  
    pct_string_view s,
136  
    pct_string_view s,
137  
    std::size_t nseg) noexcept
137  
    std::size_t nseg) noexcept
138  
{
138  
{
139  
    set_size(id_path, s.size());
139  
    set_size(id_path, s.size());
140  
    decoded_[id_path] = s.decoded_size();
140  
    decoded_[id_path] = s.decoded_size();
141  
    nseg_ = detail::path_segments(s, nseg);
141  
    nseg_ = detail::path_segments(s, nseg);
142  
}
142  
}
143  

143  

144  
void
144  
void
145  
url_impl::
145  
url_impl::
146  
apply_query(
146  
apply_query(
147  
    pct_string_view s,
147  
    pct_string_view s,
148  
    std::size_t n) noexcept
148  
    std::size_t n) noexcept
149  
{
149  
{
150  
    nparam_ = n;
150  
    nparam_ = n;
151  
    set_size(id_query, 1 + s.size());
151  
    set_size(id_query, 1 + s.size());
152  
    decoded_[id_query] = s.decoded_size();
152  
    decoded_[id_query] = s.decoded_size();
153  
}
153  
}
154  

154  

155  
void
155  
void
156  
url_impl::
156  
url_impl::
157  
apply_frag(
157  
apply_frag(
158  
    pct_string_view s) noexcept
158  
    pct_string_view s) noexcept
159  
{
159  
{
160  
    set_size(id_frag, s.size() + 1);
160  
    set_size(id_frag, s.size() + 1);
161  
    decoded_[id_frag] = s.decoded_size();
161  
    decoded_[id_frag] = s.decoded_size();
162  
}
162  
}
163  

163  

164  
// return length of [first, last)
164  
// return length of [first, last)
165  
auto
165  
auto
166  
url_impl::
166  
url_impl::
167  
len(
167  
len(
168  
    int first,
168  
    int first,
169  
    int last) const noexcept ->
169  
    int last) const noexcept ->
170  
        std::size_t
170  
        std::size_t
171  
{
171  
{
172  
    BOOST_ASSERT(first <= last);
172  
    BOOST_ASSERT(first <= last);
173  
    BOOST_ASSERT(last <= id_end);
173  
    BOOST_ASSERT(last <= id_end);
174  
    return offset(last) - offset(first);
174  
    return offset(last) - offset(first);
175  
}
175  
}
176  

176  

177  
// return length of part
177  
// return length of part
178  
auto
178  
auto
179  
url_impl::
179  
url_impl::
180  
len(int id) const noexcept ->
180  
len(int id) const noexcept ->
181  
    std::size_t
181  
    std::size_t
182  
{
182  
{
183  
    return id == id_end
183  
    return id == id_end
184  
        ? zero_
184  
        ? zero_
185  
        : ( offset(id + 1) -
185  
        : ( offset(id + 1) -
186  
            offset(id) );
186  
            offset(id) );
187  
}
187  
}
188  

188  

189  
// return offset of id
189  
// return offset of id
190  
auto
190  
auto
191  
url_impl::
191  
url_impl::
192  
offset(int id) const noexcept ->
192  
offset(int id) const noexcept ->
193  
    std::size_t
193  
    std::size_t
194  
{
194  
{
195  
    return
195  
    return
196  
        id == id_scheme
196  
        id == id_scheme
197  
        ? zero_
197  
        ? zero_
198  
        : offset_[id];
198  
        : offset_[id];
199  
}
199  
}
200  

200  

201  
// return id as string
201  
// return id as string
202  
core::string_view
202  
core::string_view
203  
url_impl::
203  
url_impl::
204  
get(int id) const noexcept
204  
get(int id) const noexcept
205  
{
205  
{
206  
    return {
206  
    return {
207  
        cs_ + offset(id), len(id) };
207  
        cs_ + offset(id), len(id) };
208  
}
208  
}
209  

209  

210  
// return [first, last) as string
210  
// return [first, last) as string
211  
core::string_view
211  
core::string_view
212  
url_impl::
212  
url_impl::
213  
get(int first,
213  
get(int first,
214  
    int last) const noexcept
214  
    int last) const noexcept
215  
{
215  
{
216  
    return { cs_ + offset(first),
216  
    return { cs_ + offset(first),
217  
        offset(last) - offset(first) };
217  
        offset(last) - offset(first) };
218  
}
218  
}
219  

219  

220  
// return id as pct-string
220  
// return id as pct-string
221  
pct_string_view
221  
pct_string_view
222  
url_impl::
222  
url_impl::
223  
pct_get(
223  
pct_get(
224  
    int id) const noexcept
224  
    int id) const noexcept
225  
{
225  
{
226  
    return make_pct_string_view_unsafe(
226  
    return make_pct_string_view_unsafe(
227  
        cs_ + offset(id),
227  
        cs_ + offset(id),
228  
        len(id),
228  
        len(id),
229  
        decoded_[id]);
229  
        decoded_[id]);
230  
}
230  
}
231  

231  

232  
// return [first, last) as pct-string
232  
// return [first, last) as pct-string
233  
pct_string_view
233  
pct_string_view
234  
url_impl::
234  
url_impl::
235  
pct_get(
235  
pct_get(
236  
    int first,
236  
    int first,
237  
    int last) const noexcept
237  
    int last) const noexcept
238  
{
238  
{
239  
    auto const pos = offset(first);
239  
    auto const pos = offset(first);
240  
    std::size_t n = 0;
240  
    std::size_t n = 0;
241  
    for(auto i = first; i < last;)
241  
    for(auto i = first; i < last;)
242  
        n += decoded_[i++];
242  
        n += decoded_[i++];
243  
    return make_pct_string_view_unsafe(
243  
    return make_pct_string_view_unsafe(
244  
        cs_ + pos,
244  
        cs_ + pos,
245  
        offset(last) - pos,
245  
        offset(last) - pos,
246  
        n);
246  
        n);
247  
}
247  
}
248  

248  

249  
//------------------------------------------------
249  
//------------------------------------------------
250  

250  

251  
// change id to size n
251  
// change id to size n
252  
void
252  
void
253  
url_impl::
253  
url_impl::
254  
set_size(
254  
set_size(
255  
    int id,
255  
    int id,
256  
    std::size_t n) noexcept
256  
    std::size_t n) noexcept
257  
{
257  
{
258  
    auto d = n - len(id);
258  
    auto d = n - len(id);
259  
    for(auto i = id + 1;
259  
    for(auto i = id + 1;
260  
        i <= id_end; ++i)
260  
        i <= id_end; ++i)
261  
        offset_[i] += d;
261  
        offset_[i] += d;
262  
}
262  
}
263  

263  

264  
// trim id to size n,
264  
// trim id to size n,
265  
// moving excess into id+1
265  
// moving excess into id+1
266  
void
266  
void
267  
url_impl::
267  
url_impl::
268  
split(
268  
split(
269  
    int id,
269  
    int id,
270  
    std::size_t n) noexcept
270  
    std::size_t n) noexcept
271  
{
271  
{
272  
    BOOST_ASSERT(id < id_end - 1);
272  
    BOOST_ASSERT(id < id_end - 1);
273  
    //BOOST_ASSERT(n <= len(id));
273  
    //BOOST_ASSERT(n <= len(id));
274  
    offset_[id + 1] = offset(id) + n;
274  
    offset_[id + 1] = offset(id) + n;
275  
}
275  
}
276  

276  

277  
// add n to [first, last]
277  
// add n to [first, last]
278  
void
278  
void
279  
url_impl::
279  
url_impl::
280  
adjust_right(
280  
adjust_right(
281  
    int first,
281  
    int first,
282  
    int last,
282  
    int last,
283  
    std::size_t n) noexcept
283  
    std::size_t n) noexcept
284  
{
284  
{
285  
    for(int i = first;
285  
    for(int i = first;
286  
            i <= last; ++i)
286  
            i <= last; ++i)
287  
        offset_[i] += n;
287  
        offset_[i] += n;
288  
}
288  
}
289  

289  

290  
// remove n from [first, last]
290  
// remove n from [first, last]
291  
void
291  
void
292  
url_impl::
292  
url_impl::
293  
adjust_left(
293  
adjust_left(
294  
    int first,
294  
    int first,
295  
    int last,
295  
    int last,
296  
    std::size_t n) noexcept
296  
    std::size_t n) noexcept
297  
{
297  
{
298  
    for(int i = first;
298  
    for(int i = first;
299  
            i <= last; ++i)
299  
            i <= last; ++i)
300  
        offset_[i] -= n;
300  
        offset_[i] -= n;
301  
}
301  
}
302  

302  

303  
// set [first, last) offset
303  
// set [first, last) offset
304  
void
304  
void
305  
url_impl::
305  
url_impl::
306  
collapse(
306  
collapse(
307  
    int first,
307  
    int first,
308  
    int last,
308  
    int last,
309  
    std::size_t n) noexcept
309  
    std::size_t n) noexcept
310  
{
310  
{
311  
    for(int i = first + 1;
311  
    for(int i = first + 1;
312  
            i < last; ++i)
312  
            i < last; ++i)
313  
        offset_[i] = n;
313  
        offset_[i] = n;
314  
}
314  
}
315  

315  

316  

316  

317  
//------------------------------------------------
317  
//------------------------------------------------
318  
//
318  
//
319  
// path_ref
319  
// path_ref
320  
//
320  
//
321  
//------------------------------------------------
321  
//------------------------------------------------
322  

322  

323  
path_ref::
323  
path_ref::
324  
path_ref(
324  
path_ref(
325  
    url_impl const& impl) noexcept
325  
    url_impl const& impl) noexcept
326  
{
326  
{
327  
    if(impl.from_ == url_impl::from::url)
327  
    if(impl.from_ == url_impl::from::url)
328  
    {
328  
    {
329  
        impl_ = &impl;
329  
        impl_ = &impl;
330  
    }
330  
    }
331  
    else
331  
    else
332  
    {
332  
    {
333  
        core::string_view s = impl.get(id_path);
333  
        core::string_view s = impl.get(id_path);
334  
        data_ = s.data();
334  
        data_ = s.data();
335  
        size_ = s.size();
335  
        size_ = s.size();
336  
        nseg_ = impl.nseg_;
336  
        nseg_ = impl.nseg_;
337  
        dn_ = impl.decoded_[id_path];
337  
        dn_ = impl.decoded_[id_path];
338  
    }
338  
    }
339  
}
339  
}
340  

340  

341  
path_ref::
341  
path_ref::
342  
path_ref(
342  
path_ref(
343  
    core::string_view s,
343  
    core::string_view s,
344  
    std::size_t dn,
344  
    std::size_t dn,
345  
    std::size_t nseg) noexcept
345  
    std::size_t nseg) noexcept
346  
    : data_(s.data())
346  
    : data_(s.data())
347  
    , size_(s.size())
347  
    , size_(s.size())
348  
    , nseg_(nseg)
348  
    , nseg_(nseg)
349  
    , dn_(dn)
349  
    , dn_(dn)
350  
{
350  
{
351  
}
351  
}
352  

352  

353  
pct_string_view
353  
pct_string_view
354  
path_ref::
354  
path_ref::
355  
buffer() const noexcept
355  
buffer() const noexcept
356  
{
356  
{
357  
    if(impl_)
357  
    if(impl_)
358  
        return make_pct_string_view_unsafe(
358  
        return make_pct_string_view_unsafe(
359  
            impl_->cs_ +
359  
            impl_->cs_ +
360  
                impl_->offset(id_path),
360  
                impl_->offset(id_path),
361  
            impl_->len(id_path),
361  
            impl_->len(id_path),
362  
            impl_->decoded_[id_path]);
362  
            impl_->decoded_[id_path]);
363  
    return make_pct_string_view_unsafe(
363  
    return make_pct_string_view_unsafe(
364  
        data_, size_, dn_);
364  
        data_, size_, dn_);
365  
}
365  
}
366  

366  

367  
std::size_t
367  
std::size_t
368  
path_ref::
368  
path_ref::
369  
size() const noexcept
369  
size() const noexcept
370  
{
370  
{
371  
    if(impl_)
371  
    if(impl_)
372  
        return impl_->len(id_path);
372  
        return impl_->len(id_path);
373  
    return size_;
373  
    return size_;
374  
}
374  
}
375  

375  

376  
char const*
376  
char const*
377  
path_ref::
377  
path_ref::
378  
data() const noexcept
378  
data() const noexcept
379  
{
379  
{
380  
    if(impl_)
380  
    if(impl_)
381  
        return impl_->cs_ +
381  
        return impl_->cs_ +
382  
            impl_->offset(id_path);
382  
            impl_->offset(id_path);
383  
    return data_;
383  
    return data_;
384  
}
384  
}
385  

385  

386  
char const*
386  
char const*
387  
path_ref::
387  
path_ref::
388  
end() const noexcept
388  
end() const noexcept
389  
{
389  
{
390  
    if(impl_)
390  
    if(impl_)
391  
        return impl_->cs_ +
391  
        return impl_->cs_ +
392  
            impl_->offset(id_query);
392  
            impl_->offset(id_query);
393  
    return data_ + size_;
393  
    return data_ + size_;
394  
}
394  
}
395  

395  

396  
std::size_t
396  
std::size_t
397  
path_ref::
397  
path_ref::
398  
nseg() const noexcept
398  
nseg() const noexcept
399  
{
399  
{
400  
    if(impl_)
400  
    if(impl_)
401  
        return impl_->nseg_;
401  
        return impl_->nseg_;
402  
    return nseg_;
402  
    return nseg_;
403  
}
403  
}
404  

404  

405  
std::size_t
405  
std::size_t
406  
path_ref::
406  
path_ref::
407  
decoded_size() const noexcept
407  
decoded_size() const noexcept
408  
{
408  
{
409  
    if(impl_)
409  
    if(impl_)
410  
        return impl_->decoded_[id_path];
410  
        return impl_->decoded_[id_path];
411  
    return dn_;
411  
    return dn_;
412  
}
412  
}
413  

413  

414  
//------------------------------------------------
414  
//------------------------------------------------
415  
//
415  
//
416  
// query_ref
416  
// query_ref
417  
//
417  
//
418  
//------------------------------------------------
418  
//------------------------------------------------
419  

419  

420  
query_ref::
420  
query_ref::
421  
query_ref(
421  
query_ref(
422  
    core::string_view s,
422  
    core::string_view s,
423  
    std::size_t dn,
423  
    std::size_t dn,
424  
    std::size_t nparam) noexcept
424  
    std::size_t nparam) noexcept
425  
    : data_(s.data())
425  
    : data_(s.data())
426  
    , size_(s.size())
426  
    , size_(s.size())
427  
    , nparam_(nparam)
427  
    , nparam_(nparam)
428  
    , dn_(dn)
428  
    , dn_(dn)
429  
{
429  
{
430  
}
430  
}
431  

431  

432  
query_ref::
432  
query_ref::
433  
query_ref(
433  
query_ref(
434  
    url_impl const& impl) noexcept
434  
    url_impl const& impl) noexcept
435  
{
435  
{
436  
    if(impl.from_ == url_impl::from::url)
436  
    if(impl.from_ == url_impl::from::url)
437  
    {
437  
    {
438  
        impl_ = &impl;
438  
        impl_ = &impl;
439  
    }
439  
    }
440  
    else
440  
    else
441  
    {
441  
    {
442  
        core::string_view s = impl.get(id_query);
442  
        core::string_view s = impl.get(id_query);
443  
        if (!s.empty())
443  
        if (!s.empty())
444  
        {
444  
        {
445  
            s.remove_prefix(1);
445  
            s.remove_prefix(1);
446  
            question_mark_ = true;
446  
            question_mark_ = true;
447  
        }
447  
        }
448  
        data_ = s.data();
448  
        data_ = s.data();
449  
        size_ = s.size();
449  
        size_ = s.size();
450  
        nparam_ = impl.nparam_;
450  
        nparam_ = impl.nparam_;
451  
        dn_ = impl.decoded_[id_query];
451  
        dn_ = impl.decoded_[id_query];
452  
    }
452  
    }
453  
}
453  
}
454  

454  

455  
pct_string_view
455  
pct_string_view
456  
query_ref::
456  
query_ref::
457  
buffer() const noexcept
457  
buffer() const noexcept
458  
{
458  
{
459  
    if(impl_)
459  
    if(impl_)
460  
    {
460  
    {
461  
        auto pos = impl_->offset_[id_query];
461  
        auto pos = impl_->offset_[id_query];
462  
        auto pos1 = impl_->offset_[id_frag];
462  
        auto pos1 = impl_->offset_[id_frag];
463  
        if(pos < pos1)
463  
        if(pos < pos1)
464  
        {
464  
        {
465  
            ++pos; // no '?'
465  
            ++pos; // no '?'
466  
            return make_pct_string_view_unsafe(
466  
            return make_pct_string_view_unsafe(
467  
                impl_->cs_ + pos,
467  
                impl_->cs_ + pos,
468  
                pos1 - pos,
468  
                pos1 - pos,
469  
                impl_->decoded_[id_query]);
469  
                impl_->decoded_[id_query]);
470  
        }
470  
        }
471  
        // empty
471  
        // empty
472  
        return make_pct_string_view_unsafe(
472  
        return make_pct_string_view_unsafe(
473  
            impl_->cs_ + pos,
473  
            impl_->cs_ + pos,
474  
            0,
474  
            0,
475  
            0);
475  
            0);
476  
    }
476  
    }
477  
    // no '?'
477  
    // no '?'
478  
    return make_pct_string_view_unsafe(
478  
    return make_pct_string_view_unsafe(
479  
        data_, size_, dn_);
479  
        data_, size_, dn_);
480  
}
480  
}
481  

481  

482  
// with '?'
482  
// with '?'
483  
std::size_t
483  
std::size_t
484  
query_ref::
484  
query_ref::
485  
size() const noexcept
485  
size() const noexcept
486  
{
486  
{
487  
    if(impl_)
487  
    if(impl_)
488  
        return impl_->len(id_query);
488  
        return impl_->len(id_query);
489  
    if(size_ > 0)
489  
    if(size_ > 0)
490  
        return size_ + 1;
490  
        return size_ + 1;
491  
    return question_mark_;
491  
    return question_mark_;
492  
}
492  
}
493  

493  

494  
// no '?'
494  
// no '?'
495  
char const*
495  
char const*
496  
query_ref::
496  
query_ref::
497  
begin() const noexcept
497  
begin() const noexcept
498  
{
498  
{
499  
    if(impl_)
499  
    if(impl_)
500  
    {
500  
    {
501  
        // using the offset array here
501  
        // using the offset array here
502  
        auto pos = impl_->offset_[id_query];
502  
        auto pos = impl_->offset_[id_query];
503  
        auto pos1 = impl_->offset_[id_frag];
503  
        auto pos1 = impl_->offset_[id_frag];
504  
        if(pos < pos1)
504  
        if(pos < pos1)
505  
            return impl_->cs_ + pos + 1; // no '?'
505  
            return impl_->cs_ + pos + 1; // no '?'
506  
        // empty
506  
        // empty
507  
        return impl_->cs_ + pos;
507  
        return impl_->cs_ + pos;
508  
    }
508  
    }
509  
    return data_;
509  
    return data_;
510  

510  

511  
}
511  
}
512  

512  

513  
char const*
513  
char const*
514  
query_ref::
514  
query_ref::
515  
end() const noexcept
515  
end() const noexcept
516  
{
516  
{
517  
    if(impl_)
517  
    if(impl_)
518  
        return impl_->cs_ +
518  
        return impl_->cs_ +
519  
            impl_->offset(id_frag);
519  
            impl_->offset(id_frag);
520  
    return data_ + size_;
520  
    return data_ + size_;
521  
}
521  
}
522  

522  

523  
std::size_t
523  
std::size_t
524  
query_ref::
524  
query_ref::
525  
nparam() const noexcept
525  
nparam() const noexcept
526  
{
526  
{
527  
    if(impl_)
527  
    if(impl_)
528  
        return impl_->nparam_;
528  
        return impl_->nparam_;
529  
    return nparam_;
529  
    return nparam_;
530  
}
530  
}
531  

531  

532  
#if defined(__GNUC__) && ! defined(__clang__) && defined(__MINGW32__)
532  
#if defined(__GNUC__) && ! defined(__clang__) && defined(__MINGW32__)
533  
#pragma GCC diagnostic pop
533  
#pragma GCC diagnostic pop
534  
#endif
534  
#endif
535  

535  

536  
} // detail
536  
} // detail
537  
} // urls
537  
} // urls
538  
} // boost
538  
} // boost