1  
//
1  
//
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3  
// Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
3  
// Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
4  
//
4  
//
5  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
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)
6  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7  
//
7  
//
8  
// Official repository: https://github.com/boostorg/url
8  
// Official repository: https://github.com/boostorg/url
9  
//
9  
//
10  

10  

11  

11  

12  
#include <boost/url/detail/config.hpp>
12  
#include <boost/url/detail/config.hpp>
13  
#include <boost/url/decode_view.hpp>
13  
#include <boost/url/decode_view.hpp>
14  
#include <boost/url/params_base.hpp>
14  
#include <boost/url/params_base.hpp>
15  
#include <boost/url/grammar/ci_string.hpp>
15  
#include <boost/url/grammar/ci_string.hpp>
16  
#include <ostream>
16  
#include <ostream>
17  
#include <string>
17  
#include <string>
18  

18  

19  
namespace boost {
19  
namespace boost {
20  
namespace urls {
20  
namespace urls {
21  

21  

22  
//------------------------------------------------
22  
//------------------------------------------------
23  

23  

24  
params_base::
24  
params_base::
25  
iterator::
25  
iterator::
26  
iterator(
26  
iterator(
27  
    detail::query_ref const& ref,
27  
    detail::query_ref const& ref,
28  
    encoding_opts opt) noexcept
28  
    encoding_opts opt) noexcept
29  
    : it_(ref)
29  
    : it_(ref)
30  
    , space_as_plus_(opt.space_as_plus)
30  
    , space_as_plus_(opt.space_as_plus)
31  
{
31  
{
32  
}
32  
}
33  

33  

34  
params_base::
34  
params_base::
35  
iterator::
35  
iterator::
36  
iterator(
36  
iterator(
37  
    detail::query_ref const& ref,
37  
    detail::query_ref const& ref,
38  
    encoding_opts opt,
38  
    encoding_opts opt,
39  
    int) noexcept
39  
    int) noexcept
40  
    : it_(ref, 0)
40  
    : it_(ref, 0)
41  
    , space_as_plus_(opt.space_as_plus)
41  
    , space_as_plus_(opt.space_as_plus)
42  
{
42  
{
43  
}
43  
}
44  

44  

45  

45  

46  
auto
46  
auto
47  
params_base::
47  
params_base::
48  
iterator::
48  
iterator::
49  
operator*() const ->
49  
operator*() const ->
50  
    reference
50  
    reference
51  

51  

52  
{
52  
{
53  
    encoding_opts opt;
53  
    encoding_opts opt;
54  
    opt.space_as_plus =
54  
    opt.space_as_plus =
55  
        space_as_plus_;
55  
        space_as_plus_;
56  
    param_pct_view p =
56  
    param_pct_view p =
57  
        it_.dereference();
57  
        it_.dereference();
58  
    return reference(
58  
    return reference(
59  
        p.key.decode(opt),
59  
        p.key.decode(opt),
60  
        p.value.decode(opt),
60  
        p.value.decode(opt),
61  
        p.has_value);
61  
        p.has_value);
62  
}
62  
}
63  

63  

64  
//------------------------------------------------
64  
//------------------------------------------------
65  
//
65  
//
66  
// params_base
66  
// params_base
67  
//
67  
//
68  
//------------------------------------------------
68  
//------------------------------------------------
69  

69  

70  
params_base::
70  
params_base::
71  
params_base() noexcept
71  
params_base() noexcept
72  
    // space_as_plus = true
72  
    // space_as_plus = true
73  
    : opt_(true, false, false)
73  
    : opt_(true, false, false)
74  
{
74  
{
75  
}
75  
}
76  

76  

77  
bool
77  
bool
78  
params_base::
78  
params_base::
79  
contains(
79  
contains(
80  
    core::string_view key,
80  
    core::string_view key,
81  
    ignore_case_param ic) const noexcept
81  
    ignore_case_param ic) const noexcept
82  
{
82  
{
83  
    return find(
83  
    return find(
84  
        begin(),key, ic) != end();
84  
        begin(),key, ic) != end();
85  
}
85  
}
86  

86  

87  
auto
87  
auto
88  
params_base::
88  
params_base::
89  
find(
89  
find(
90  
    core::string_view key,
90  
    core::string_view key,
91  
    ignore_case_param ic) const noexcept ->
91  
    ignore_case_param ic) const noexcept ->
92  
        iterator
92  
        iterator
93  
{
93  
{
94  
    return iterator(
94  
    return iterator(
95  
        find_impl(
95  
        find_impl(
96  
            begin().it_, key, ic),
96  
            begin().it_, key, ic),
97  
        opt_);
97  
        opt_);
98  
}
98  
}
99  

99  

100  
auto
100  
auto
101  
params_base::
101  
params_base::
102  
find(
102  
find(
103  
    iterator it,
103  
    iterator it,
104  
    core::string_view key,
104  
    core::string_view key,
105  
    ignore_case_param ic) const noexcept ->
105  
    ignore_case_param ic) const noexcept ->
106  
        iterator
106  
        iterator
107  
{
107  
{
108  
    return iterator(
108  
    return iterator(
109  
        find_impl(
109  
        find_impl(
110  
            it.it_, key, ic),
110  
            it.it_, key, ic),
111  
        opt_);
111  
        opt_);
112  
}
112  
}
113  

113  

114  
auto
114  
auto
115  
params_base::
115  
params_base::
116  
find_last(
116  
find_last(
117  
    core::string_view key,
117  
    core::string_view key,
118  
    ignore_case_param ic) const noexcept ->
118  
    ignore_case_param ic) const noexcept ->
119  
        iterator
119  
        iterator
120  
{
120  
{
121  
    return iterator(
121  
    return iterator(
122  
        find_last_impl(
122  
        find_last_impl(
123  
            end().it_, key, ic),
123  
            end().it_, key, ic),
124  
        opt_);
124  
        opt_);
125  
}
125  
}
126  

126  

127  
auto
127  
auto
128  
params_base::
128  
params_base::
129  
find_last(
129  
find_last(
130  
    iterator it,
130  
    iterator it,
131  
    core::string_view key,
131  
    core::string_view key,
132  
    ignore_case_param ic) const noexcept ->
132  
    ignore_case_param ic) const noexcept ->
133  
        iterator
133  
        iterator
134  
{
134  
{
135  
    return iterator(
135  
    return iterator(
136  
        find_last_impl(
136  
        find_last_impl(
137  
            it.it_, key, ic),
137  
            it.it_, key, ic),
138  
        opt_);
138  
        opt_);
139  
}
139  
}
140  

140  

141  
params_base::
141  
params_base::
142  
params_base(
142  
params_base(
143  
    detail::query_ref const& ref,
143  
    detail::query_ref const& ref,
144  
    encoding_opts opt) noexcept
144  
    encoding_opts opt) noexcept
145  
    : ref_(ref)
145  
    : ref_(ref)
146  
    , opt_(opt)
146  
    , opt_(opt)
147  
{
147  
{
148  
}
148  
}
149  

149  

150  
pct_string_view
150  
pct_string_view
151  
params_base::
151  
params_base::
152  
buffer() const noexcept
152  
buffer() const noexcept
153  
{
153  
{
154  
    return ref_.buffer();
154  
    return ref_.buffer();
155  
}
155  
}
156  

156  

157  
bool
157  
bool
158  
params_base::
158  
params_base::
159  
empty() const noexcept
159  
empty() const noexcept
160  
{
160  
{
161  
    return ref_.nparam() == 0;
161  
    return ref_.nparam() == 0;
162  
}
162  
}
163  

163  

164  
std::size_t
164  
std::size_t
165  
params_base::
165  
params_base::
166  
size() const noexcept
166  
size() const noexcept
167  
{
167  
{
168  
    return ref_.nparam();
168  
    return ref_.nparam();
169  
}
169  
}
170  

170  

171  
auto
171  
auto
172  
params_base::
172  
params_base::
173  
begin() const noexcept ->
173  
begin() const noexcept ->
174  
    iterator
174  
    iterator
175  
{
175  
{
176  
    return iterator(ref_, opt_);
176  
    return iterator(ref_, opt_);
177  
}
177  
}
178  

178  

179  
auto
179  
auto
180  
params_base::
180  
params_base::
181  
end() const noexcept ->
181  
end() const noexcept ->
182  
    iterator
182  
    iterator
183  
{
183  
{
184  
    return {ref_, opt_, 0};
184  
    return {ref_, opt_, 0};
185  
}
185  
}
186  

186  

187  
//------------------------------------------------
187  
//------------------------------------------------
188  

188  

189  
std::size_t
189  
std::size_t
190  
params_base::
190  
params_base::
191  
count(
191  
count(
192  
    core::string_view key,
192  
    core::string_view key,
193  
    ignore_case_param ic) const noexcept
193  
    ignore_case_param ic) const noexcept
194  
{
194  
{
195  
    std::size_t n = 0;
195  
    std::size_t n = 0;
196  
    auto it = find(key, ic);
196  
    auto it = find(key, ic);
197  
    auto const end_ = end();
197  
    auto const end_ = end();
198  
    while(it != end_)
198  
    while(it != end_)
199  
    {
199  
    {
200  
        ++n;
200  
        ++n;
201  
        ++it;
201  
        ++it;
202  
        it = find(it, key, ic);
202  
        it = find(it, key, ic);
203  
    }
203  
    }
204  
    return n;
204  
    return n;
205  
}
205  
}
206  

206  

207  
std::string
207  
std::string
208  
params_base::
208  
params_base::
209  
get_or(
209  
get_or(
210  
    core::string_view key,
210  
    core::string_view key,
211  
    core::string_view value,
211  
    core::string_view value,
212  
    ignore_case_param ic) const
212  
    ignore_case_param ic) const
213  
{
213  
{
214  
    auto it = find_impl(
214  
    auto it = find_impl(
215  
        begin().it_, key, ic);
215  
        begin().it_, key, ic);
216  
    detail::params_iter_impl end_(ref_, 0);
216  
    detail::params_iter_impl end_(ref_, 0);
217  
    if(it.equal(end_))
217  
    if(it.equal(end_))
218  
        return std::string(value);
218  
        return std::string(value);
219  

219  

220  
    param_pct_view const p = it.dereference();
220  
    param_pct_view const p = it.dereference();
221  
    if(! p.has_value)
221  
    if(! p.has_value)
222  
        return std::string();
222  
        return std::string();
223  

223  

224  
    auto opt = opt_;
224  
    auto opt = opt_;
225  
    return p.value.decode(opt);
225  
    return p.value.decode(opt);
226  
}
226  
}
227  

227  

228  
//------------------------------------------------
228  
//------------------------------------------------
229  
//
229  
//
230  
// (implementation)
230  
// (implementation)
231  
//
231  
//
232  
//------------------------------------------------
232  
//------------------------------------------------
233  

233  

234  
detail::params_iter_impl
234  
detail::params_iter_impl
235  
params_base::
235  
params_base::
236  
find_impl(
236  
find_impl(
237  
    detail::params_iter_impl it,
237  
    detail::params_iter_impl it,
238  
    core::string_view key,
238  
    core::string_view key,
239  
    ignore_case_param ic) const noexcept
239  
    ignore_case_param ic) const noexcept
240  
{
240  
{
241  
    detail::params_iter_impl end_(ref_, 0);
241  
    detail::params_iter_impl end_(ref_, 0);
242  
    if(! ic)
242  
    if(! ic)
243  
    {
243  
    {
244  
        for(;;)
244  
        for(;;)
245  
        {
245  
        {
246  
            if(it.equal(end_))
246  
            if(it.equal(end_))
247  
                return it;
247  
                return it;
248  
            if(*it.key() == key)
248  
            if(*it.key() == key)
249  
                return it;
249  
                return it;
250  
            it.increment();
250  
            it.increment();
251  
        }
251  
        }
252  
    }
252  
    }
253  
    for(;;)
253  
    for(;;)
254  
    {
254  
    {
255  
        if(it.equal(end_))
255  
        if(it.equal(end_))
256  
            return it;
256  
            return it;
257  
        if( grammar::ci_is_equal(
257  
        if( grammar::ci_is_equal(
258  
                *it.key(), key))
258  
                *it.key(), key))
259  
            return it;
259  
            return it;
260  
        it.increment();
260  
        it.increment();
261  
    }
261  
    }
262  
}
262  
}
263  

263  

264  
detail::params_iter_impl
264  
detail::params_iter_impl
265  
params_base::
265  
params_base::
266  
find_last_impl(
266  
find_last_impl(
267  
    detail::params_iter_impl it,
267  
    detail::params_iter_impl it,
268  
    core::string_view key,
268  
    core::string_view key,
269  
    ignore_case_param ic) const noexcept
269  
    ignore_case_param ic) const noexcept
270  
{
270  
{
271  
    detail::params_iter_impl begin_(ref_);
271  
    detail::params_iter_impl begin_(ref_);
272  
    if(! ic)
272  
    if(! ic)
273  
    {
273  
    {
274  
        for(;;)
274  
        for(;;)
275  
        {
275  
        {
276  
            if(it.equal(begin_))
276  
            if(it.equal(begin_))
277  
                return { ref_, 0 };
277  
                return { ref_, 0 };
278  
            it.decrement();
278  
            it.decrement();
279  
            if(*it.key() == key)
279  
            if(*it.key() == key)
280  
                return it;
280  
                return it;
281  
        }
281  
        }
282  
    }
282  
    }
283  
    for(;;)
283  
    for(;;)
284  
    {
284  
    {
285  
        if(it.equal(begin_))
285  
        if(it.equal(begin_))
286  
            return { ref_, 0 };
286  
            return { ref_, 0 };
287  
        it.decrement();
287  
        it.decrement();
288  
        if(grammar::ci_is_equal(
288  
        if(grammar::ci_is_equal(
289  
                *it.key(), key))
289  
                *it.key(), key))
290  
            return it;
290  
            return it;
291  
    }
291  
    }
292  
}
292  
}
293  

293  

294  
//------------------------------------------------
294  
//------------------------------------------------
295  

295  

296  
std::ostream&
296  
std::ostream&
297  
operator<<(
297  
operator<<(
298  
    std::ostream& os,
298  
    std::ostream& os,
299  
    params_base const& qp)
299  
    params_base const& qp)
300  
{
300  
{
301  
    os << qp.buffer();
301  
    os << qp.buffer();
302  
    return os;
302  
    return os;
303  
}
303  
}
304  

304  

305  
} // urls
305  
} // urls
306  
} // boost
306  
} // boost