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  
#ifndef BOOST_URL_IMPL_PARAMS_BASE_HPP
11  
#ifndef BOOST_URL_IMPL_PARAMS_BASE_HPP
12  
#define BOOST_URL_IMPL_PARAMS_BASE_HPP
12  
#define BOOST_URL_IMPL_PARAMS_BASE_HPP
13  

13  

14  
#include <boost/url/detail/params_iter_impl.hpp>
14  
#include <boost/url/detail/params_iter_impl.hpp>
15  
#include <boost/url/decode_view.hpp>
15  
#include <boost/url/decode_view.hpp>
16  
#include <boost/url/grammar/ci_string.hpp>
16  
#include <boost/url/grammar/ci_string.hpp>
17  
#include <iterator>
17  
#include <iterator>
18  
#include <ostream>
18  
#include <ostream>
19  
#include <string>
19  
#include <string>
20  

20  

21  
namespace boost {
21  
namespace boost {
22  
namespace urls {
22  
namespace urls {
23  

23  

24  
//------------------------------------------------
24  
//------------------------------------------------
25  

25  

26  
class BOOST_SYMBOL_VISIBLE params_base::iterator
26  
class BOOST_SYMBOL_VISIBLE params_base::iterator
27  
{
27  
{
28  
    detail::params_iter_impl it_;
28  
    detail::params_iter_impl it_;
29  
    bool space_as_plus_ = true;
29  
    bool space_as_plus_ = true;
30  

30  

31  
    friend class params_base;
31  
    friend class params_base;
32  
    friend class params_ref;
32  
    friend class params_ref;
33  

33  

34  
    iterator(
34  
    iterator(
35  
        detail::query_ref const& ref,
35  
        detail::query_ref const& ref,
36  
        encoding_opts opt) noexcept;
36  
        encoding_opts opt) noexcept;
37  

37  

38  
    iterator(
38  
    iterator(
39  
        detail::query_ref const& impl,
39  
        detail::query_ref const& impl,
40  
        encoding_opts opt,
40  
        encoding_opts opt,
41  
        int) noexcept;
41  
        int) noexcept;
42  

42  

43  
    iterator(
43  
    iterator(
44  
        detail::params_iter_impl const& it,
44  
        detail::params_iter_impl const& it,
45  
        encoding_opts opt) noexcept
45  
        encoding_opts opt) noexcept
46  
        : it_(it)
46  
        : it_(it)
47  
        , space_as_plus_(opt.space_as_plus)
47  
        , space_as_plus_(opt.space_as_plus)
48  
    {
48  
    {
49  
    }
49  
    }
50  

50  

51  
public:
51  
public:
52  
    using value_type = params_base::value_type;
52  
    using value_type = params_base::value_type;
53  
    using reference = params_base::reference;
53  
    using reference = params_base::reference;
54  
    using pointer = reference;
54  
    using pointer = reference;
55  
    using difference_type =
55  
    using difference_type =
56  
        params_base::difference_type;
56  
        params_base::difference_type;
57  
    using iterator_category =
57  
    using iterator_category =
58  
        std::bidirectional_iterator_tag;
58  
        std::bidirectional_iterator_tag;
59  

59  

60  
    iterator() = default;
60  
    iterator() = default;
61  
    iterator(iterator const&) = default;
61  
    iterator(iterator const&) = default;
62  
    iterator& operator=(
62  
    iterator& operator=(
63  
        iterator const&) noexcept = default;
63  
        iterator const&) noexcept = default;
64  

64  

65  
    iterator&
65  
    iterator&
66  
    operator++() noexcept
66  
    operator++() noexcept
67  
    {
67  
    {
68  
        it_.increment();
68  
        it_.increment();
69  
        return *this;
69  
        return *this;
70  
    }
70  
    }
71  

71  

72  
    iterator
72  
    iterator
73  
    operator++(int) noexcept
73  
    operator++(int) noexcept
74  
    {
74  
    {
75  
        auto tmp = *this;
75  
        auto tmp = *this;
76  
        ++*this;
76  
        ++*this;
77  
        return tmp;
77  
        return tmp;
78  
    }
78  
    }
79  

79  

80  
    iterator&
80  
    iterator&
81  
    operator--() noexcept
81  
    operator--() noexcept
82  
    {
82  
    {
83  
        it_.decrement();
83  
        it_.decrement();
84  
        return *this;
84  
        return *this;
85  
    }
85  
    }
86  

86  

87  
    iterator
87  
    iterator
88  
    operator--(int) noexcept
88  
    operator--(int) noexcept
89  
    {
89  
    {
90  
        auto tmp = *this;
90  
        auto tmp = *this;
91  
        --*this;
91  
        --*this;
92  
        return tmp;
92  
        return tmp;
93  
    }
93  
    }
94  

94  

95  
    reference
95  
    reference
96  
    operator*() const;
96  
    operator*() const;
97  

97  

98  
    // the return value is too expensive
98  
    // the return value is too expensive
99  
    pointer operator->() const = delete;
99  
    pointer operator->() const = delete;
100  

100  

101  
    bool
101  
    bool
102  
    operator==(
102  
    operator==(
103  
        iterator const& other) const noexcept
103  
        iterator const& other) const noexcept
104  
    {
104  
    {
105  
        return it_.equal(other.it_);
105  
        return it_.equal(other.it_);
106  
    }
106  
    }
107  

107  

108  
    bool
108  
    bool
109  
    operator!=(
109  
    operator!=(
110  
        iterator const& other) const noexcept
110  
        iterator const& other) const noexcept
111  
    {
111  
    {
112  
        return ! it_.equal(other.it_);
112  
        return ! it_.equal(other.it_);
113  
    }
113  
    }
114  
};
114  
};
115  

115  

116  

116  

117  
//------------------------------------------------
117  
//------------------------------------------------
118  

118  

119  
inline
119  
inline
120  
params_base::
120  
params_base::
121  
iterator::
121  
iterator::
122  
iterator(
122  
iterator(
123  
    detail::query_ref const& ref,
123  
    detail::query_ref const& ref,
124  
    encoding_opts opt) noexcept
124  
    encoding_opts opt) noexcept
125  
    : it_(ref)
125  
    : it_(ref)
126  
    , space_as_plus_(opt.space_as_plus)
126  
    , space_as_plus_(opt.space_as_plus)
127  
{
127  
{
128  
}
128  
}
129  

129  

130  
inline
130  
inline
131  
params_base::
131  
params_base::
132  
iterator::
132  
iterator::
133  
iterator(
133  
iterator(
134  
    detail::query_ref const& ref,
134  
    detail::query_ref const& ref,
135  
    encoding_opts opt,
135  
    encoding_opts opt,
136  
    int) noexcept
136  
    int) noexcept
137  
    : it_(ref, 0)
137  
    : it_(ref, 0)
138  
    , space_as_plus_(opt.space_as_plus)
138  
    , space_as_plus_(opt.space_as_plus)
139  
{
139  
{
140  
}
140  
}
141  

141  

142  

142  

143  
inline
143  
inline
144  
auto
144  
auto
145  
params_base::
145  
params_base::
146  
iterator::
146  
iterator::
147  
operator*() const ->
147  
operator*() const ->
148  
    reference
148  
    reference
149  

149  

150  
{
150  
{
151  
    encoding_opts opt;
151  
    encoding_opts opt;
152  
    opt.space_as_plus =
152  
    opt.space_as_plus =
153  
        space_as_plus_;
153  
        space_as_plus_;
154  
    param_pct_view p =
154  
    param_pct_view p =
155  
        it_.dereference();
155  
        it_.dereference();
156  
    return reference(
156  
    return reference(
157  
        p.key.decode(opt),
157  
        p.key.decode(opt),
158  
        p.value.decode(opt),
158  
        p.value.decode(opt),
159  
        p.has_value);
159  
        p.has_value);
160  
}
160  
}
161  

161  

162  
//------------------------------------------------
162  
//------------------------------------------------
163  
//
163  
//
164  
// params_base
164  
// params_base
165  
//
165  
//
166  
//------------------------------------------------
166  
//------------------------------------------------
167  

167  

168  
inline
168  
inline
169  
params_base::
169  
params_base::
170  
params_base() noexcept
170  
params_base() noexcept
171  
    // space_as_plus = true
171  
    // space_as_plus = true
172  
    : opt_(true, false, false)
172  
    : opt_(true, false, false)
173  
{
173  
{
174  
}
174  
}
175  

175  

176  
inline
176  
inline
177  
bool
177  
bool
178  
params_base::
178  
params_base::
179  
contains(
179  
contains(
180  
    core::string_view key,
180  
    core::string_view key,
181  
    ignore_case_param ic) const noexcept
181  
    ignore_case_param ic) const noexcept
182  
{
182  
{
183  
    return find(
183  
    return find(
184  
        begin(),key, ic) != end();
184  
        begin(),key, ic) != end();
185  
}
185  
}
186  

186  

187  
inline
187  
inline
188  
auto
188  
auto
189  
params_base::
189  
params_base::
190  
find(
190  
find(
191  
    core::string_view key,
191  
    core::string_view key,
192  
    ignore_case_param ic) const noexcept ->
192  
    ignore_case_param ic) const noexcept ->
193  
        iterator
193  
        iterator
194  
{
194  
{
195  
    return iterator(
195  
    return iterator(
196  
        find_impl(
196  
        find_impl(
197  
            begin().it_, key, ic),
197  
            begin().it_, key, ic),
198  
        opt_);
198  
        opt_);
199  
}
199  
}
200  

200  

201  
inline
201  
inline
202  
auto
202  
auto
203  
params_base::
203  
params_base::
204  
find(
204  
find(
205  
    iterator it,
205  
    iterator it,
206  
    core::string_view key,
206  
    core::string_view key,
207  
    ignore_case_param ic) const noexcept ->
207  
    ignore_case_param ic) const noexcept ->
208  
        iterator
208  
        iterator
209  
{
209  
{
210  
    return iterator(
210  
    return iterator(
211  
        find_impl(
211  
        find_impl(
212  
            it.it_, key, ic),
212  
            it.it_, key, ic),
213  
        opt_);
213  
        opt_);
214  
}
214  
}
215  

215  

216  
inline
216  
inline
217  
auto
217  
auto
218  
params_base::
218  
params_base::
219  
find_last(
219  
find_last(
220  
    core::string_view key,
220  
    core::string_view key,
221  
    ignore_case_param ic) const noexcept ->
221  
    ignore_case_param ic) const noexcept ->
222  
        iterator
222  
        iterator
223  
{
223  
{
224  
    return iterator(
224  
    return iterator(
225  
        find_last_impl(
225  
        find_last_impl(
226  
            end().it_, key, ic),
226  
            end().it_, key, ic),
227  
        opt_);
227  
        opt_);
228  
}
228  
}
229  

229  

230  
inline
230  
inline
231  
auto
231  
auto
232  
params_base::
232  
params_base::
233  
find_last(
233  
find_last(
234  
    iterator it,
234  
    iterator it,
235  
    core::string_view key,
235  
    core::string_view key,
236  
    ignore_case_param ic) const noexcept ->
236  
    ignore_case_param ic) const noexcept ->
237  
        iterator
237  
        iterator
238  
{
238  
{
239  
    return iterator(
239  
    return iterator(
240  
        find_last_impl(
240  
        find_last_impl(
241  
            it.it_, key, ic),
241  
            it.it_, key, ic),
242  
        opt_);
242  
        opt_);
243  
}
243  
}
244  

244  

245  
inline
245  
inline
246  
params_base::
246  
params_base::
247  
params_base(
247  
params_base(
248  
    detail::query_ref const& ref,
248  
    detail::query_ref const& ref,
249  
    encoding_opts opt) noexcept
249  
    encoding_opts opt) noexcept
250  
    : ref_(ref)
250  
    : ref_(ref)
251  
    , opt_(opt)
251  
    , opt_(opt)
252  
{
252  
{
253  
}
253  
}
254  

254  

255  
inline
255  
inline
256  
pct_string_view
256  
pct_string_view
257  
params_base::
257  
params_base::
258  
buffer() const noexcept
258  
buffer() const noexcept
259  
{
259  
{
260  
    return ref_.buffer();
260  
    return ref_.buffer();
261  
}
261  
}
262  

262  

263  
inline
263  
inline
264  
bool
264  
bool
265  
params_base::
265  
params_base::
266  
empty() const noexcept
266  
empty() const noexcept
267  
{
267  
{
268  
    return ref_.nparam() == 0;
268  
    return ref_.nparam() == 0;
269  
}
269  
}
270  

270  

271  
inline
271  
inline
272  
std::size_t
272  
std::size_t
273  
params_base::
273  
params_base::
274  
size() const noexcept
274  
size() const noexcept
275  
{
275  
{
276  
    return ref_.nparam();
276  
    return ref_.nparam();
277  
}
277  
}
278  

278  

279  
inline
279  
inline
280  
auto
280  
auto
281  
params_base::
281  
params_base::
282  
begin() const noexcept ->
282  
begin() const noexcept ->
283  
    iterator
283  
    iterator
284  
{
284  
{
285  
    return iterator(ref_, opt_);
285  
    return iterator(ref_, opt_);
286  
}
286  
}
287  

287  

288  
inline
288  
inline
289  
auto
289  
auto
290  
params_base::
290  
params_base::
291  
end() const noexcept ->
291  
end() const noexcept ->
292  
    iterator
292  
    iterator
293  
{
293  
{
294  
    return {ref_, opt_, 0};
294  
    return {ref_, opt_, 0};
295  
}
295  
}
296  

296  

297  
//------------------------------------------------
297  
//------------------------------------------------
298  

298  

299  
inline
299  
inline
300  
std::size_t
300  
std::size_t
301  
params_base::
301  
params_base::
302  
count(
302  
count(
303  
    core::string_view key,
303  
    core::string_view key,
304  
    ignore_case_param ic) const noexcept
304  
    ignore_case_param ic) const noexcept
305  
{
305  
{
306  
    std::size_t n = 0;
306  
    std::size_t n = 0;
307  
    auto it = find(key, ic);
307  
    auto it = find(key, ic);
308  
    auto const end_ = end();
308  
    auto const end_ = end();
309  
    while(it != end_)
309  
    while(it != end_)
310  
    {
310  
    {
311  
        ++n;
311  
        ++n;
312  
        ++it;
312  
        ++it;
313  
        it = find(it, key, ic);
313  
        it = find(it, key, ic);
314  
    }
314  
    }
315  
    return n;
315  
    return n;
316  
}
316  
}
317  

317  

318  
inline
318  
inline
319  
std::string
319  
std::string
320  
params_base::
320  
params_base::
321  
get_or(
321  
get_or(
322  
    core::string_view key,
322  
    core::string_view key,
323  
    core::string_view value,
323  
    core::string_view value,
324  
    ignore_case_param ic) const
324  
    ignore_case_param ic) const
325  
{
325  
{
326  
    auto it = find_impl(
326  
    auto it = find_impl(
327  
        begin().it_, key, ic);
327  
        begin().it_, key, ic);
328  
    detail::params_iter_impl end_(ref_, 0);
328  
    detail::params_iter_impl end_(ref_, 0);
329  
    if(it.equal(end_))
329  
    if(it.equal(end_))
330  
        return std::string(value);
330  
        return std::string(value);
331  

331  

332  
    param_pct_view const p = it.dereference();
332  
    param_pct_view const p = it.dereference();
333  
    if(! p.has_value)
333  
    if(! p.has_value)
334  
        return std::string();
334  
        return std::string();
335  

335  

336  
    auto opt = opt_;
336  
    auto opt = opt_;
337  
    return p.value.decode(opt);
337  
    return p.value.decode(opt);
338  
}
338  
}
339  

339  

340  
//------------------------------------------------
340  
//------------------------------------------------
341  
//
341  
//
342  
// (implementation)
342  
// (implementation)
343  
//
343  
//
344  
//------------------------------------------------
344  
//------------------------------------------------
345  

345  

346  
inline
346  
inline
347  
detail::params_iter_impl
347  
detail::params_iter_impl
348  
params_base::
348  
params_base::
349  
find_impl(
349  
find_impl(
350  
    detail::params_iter_impl it,
350  
    detail::params_iter_impl it,
351  
    core::string_view key,
351  
    core::string_view key,
352  
    ignore_case_param ic) const noexcept
352  
    ignore_case_param ic) const noexcept
353  
{
353  
{
354  
    detail::params_iter_impl end_(ref_, 0);
354  
    detail::params_iter_impl end_(ref_, 0);
355  
    if(! ic)
355  
    if(! ic)
356  
    {
356  
    {
357  
        for(;;)
357  
        for(;;)
358  
        {
358  
        {
359  
            if(it.equal(end_))
359  
            if(it.equal(end_))
360  
                return it;
360  
                return it;
361  
            if(*it.key() == key)
361  
            if(*it.key() == key)
362  
                return it;
362  
                return it;
363  
            it.increment();
363  
            it.increment();
364  
        }
364  
        }
365  
    }
365  
    }
366  
    for(;;)
366  
    for(;;)
367  
    {
367  
    {
368  
        if(it.equal(end_))
368  
        if(it.equal(end_))
369  
            return it;
369  
            return it;
370  
        if( grammar::ci_is_equal(
370  
        if( grammar::ci_is_equal(
371  
                *it.key(), key))
371  
                *it.key(), key))
372  
            return it;
372  
            return it;
373  
        it.increment();
373  
        it.increment();
374  
    }
374  
    }
375  
}
375  
}
376  

376  

377  
inline
377  
inline
378  
detail::params_iter_impl
378  
detail::params_iter_impl
379  
params_base::
379  
params_base::
380  
find_last_impl(
380  
find_last_impl(
381  
    detail::params_iter_impl it,
381  
    detail::params_iter_impl it,
382  
    core::string_view key,
382  
    core::string_view key,
383  
    ignore_case_param ic) const noexcept
383  
    ignore_case_param ic) const noexcept
384  
{
384  
{
385  
    detail::params_iter_impl begin_(ref_);
385  
    detail::params_iter_impl begin_(ref_);
386  
    if(! ic)
386  
    if(! ic)
387  
    {
387  
    {
388  
        for(;;)
388  
        for(;;)
389  
        {
389  
        {
390  
            if(it.equal(begin_))
390  
            if(it.equal(begin_))
391  
                return { ref_, 0 };
391  
                return { ref_, 0 };
392  
            it.decrement();
392  
            it.decrement();
393  
            if(*it.key() == key)
393  
            if(*it.key() == key)
394  
                return it;
394  
                return it;
395  
        }
395  
        }
396  
    }
396  
    }
397  
    for(;;)
397  
    for(;;)
398  
    {
398  
    {
399  
        if(it.equal(begin_))
399  
        if(it.equal(begin_))
400  
            return { ref_, 0 };
400  
            return { ref_, 0 };
401  
        it.decrement();
401  
        it.decrement();
402  
        if(grammar::ci_is_equal(
402  
        if(grammar::ci_is_equal(
403  
                *it.key(), key))
403  
                *it.key(), key))
404  
            return it;
404  
            return it;
405  
    }
405  
    }
406  
}
406  
}
407  

407  

408  
//------------------------------------------------
408  
//------------------------------------------------
409  

409  

410  
inline
410  
inline
411  
std::ostream&
411  
std::ostream&
412  
operator<<(
412  
operator<<(
413  
    std::ostream& os,
413  
    std::ostream& os,
414  
    params_base const& qp)
414  
    params_base const& qp)
415  
{
415  
{
416  
    os << qp.buffer();
416  
    os << qp.buffer();
417  
    return os;
417  
    return os;
418  
}
418  
}
419  

419  

420  
} // urls
420  
} // urls
421  
} // boost
421  
} // boost
422  

422  

423  
#endif
423  
#endif