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

13  

14  
#include <boost/url/params_view.hpp>
14  
#include <boost/url/params_view.hpp>
15  
#include <boost/url/url_base.hpp>
15  
#include <boost/url/url_base.hpp>
16  
#include <boost/url/detail/any_params_iter.hpp>
16  
#include <boost/url/detail/any_params_iter.hpp>
17  
#include <boost/url/detail/except.hpp>
17  
#include <boost/url/detail/except.hpp>
18  
#include <boost/url/grammar/ci_string.hpp>
18  
#include <boost/url/grammar/ci_string.hpp>
19  
#include <boost/url/grammar/recycled.hpp>
19  
#include <boost/url/grammar/recycled.hpp>
20  
#include <boost/assert.hpp>
20  
#include <boost/assert.hpp>
21  
#include <utility>
21  
#include <utility>
22  

22  

23  
namespace boost {
23  
namespace boost {
24  
namespace urls {
24  
namespace urls {
25  

25  

26  
template<class FwdIt>
26  
template<class FwdIt>
27  
void
27  
void
28  
params_ref::
28  
params_ref::
29  
assign(FwdIt first, FwdIt last)
29  
assign(FwdIt first, FwdIt last)
30  
{
30  
{
31  
/*  If you get a compile error here, it
31  
/*  If you get a compile error here, it
32  
    means that the iterators you passed
32  
    means that the iterators you passed
33  
    do not meet the requirements stated
33  
    do not meet the requirements stated
34  
    in the documentation.
34  
    in the documentation.
35  
*/
35  
*/
36  
    static_assert(
36  
    static_assert(
37  
        std::is_convertible<
37  
        std::is_convertible<
38  
            typename std::iterator_traits<
38  
            typename std::iterator_traits<
39  
                FwdIt>::reference,
39  
                FwdIt>::reference,
40  
            param_view>::value,
40  
            param_view>::value,
41  
        "Type requirements not met");
41  
        "Type requirements not met");
42  

42  

43  
    assign(first, last,
43  
    assign(first, last,
44  
        typename std::iterator_traits<
44  
        typename std::iterator_traits<
45  
            FwdIt>::iterator_category{});
45  
            FwdIt>::iterator_category{});
46  
}
46  
}
47  

47  

48  
template<class FwdIt>
48  
template<class FwdIt>
49  
auto
49  
auto
50  
params_ref::
50  
params_ref::
51  
append(FwdIt first, FwdIt last) ->
51  
append(FwdIt first, FwdIt last) ->
52  
    iterator
52  
    iterator
53  
{
53  
{
54  
/*  If you get a compile error here, it
54  
/*  If you get a compile error here, it
55  
    means that the iterators you passed
55  
    means that the iterators you passed
56  
    do not meet the requirements stated
56  
    do not meet the requirements stated
57  
    in the documentation.
57  
    in the documentation.
58  
*/
58  
*/
59  
    static_assert(
59  
    static_assert(
60  
        std::is_convertible<
60  
        std::is_convertible<
61  
            typename std::iterator_traits<
61  
            typename std::iterator_traits<
62  
                FwdIt>::reference,
62  
                FwdIt>::reference,
63  
            param_view>::value,
63  
            param_view>::value,
64  
        "Type requirements not met");
64  
        "Type requirements not met");
65  

65  

66  
    return insert(
66  
    return insert(
67  
        end(), first, last);
67  
        end(), first, last);
68  
}
68  
}
69  

69  

70  
template<class FwdIt>
70  
template<class FwdIt>
71  
auto
71  
auto
72  
params_ref::
72  
params_ref::
73  
insert(
73  
insert(
74  
    iterator before,
74  
    iterator before,
75  
    FwdIt first,
75  
    FwdIt first,
76  
    FwdIt last) ->
76  
    FwdIt last) ->
77  
        iterator
77  
        iterator
78  
{
78  
{
79  
/*  If you get a compile error here, it
79  
/*  If you get a compile error here, it
80  
    means that the iterators you passed
80  
    means that the iterators you passed
81  
    do not meet the requirements stated
81  
    do not meet the requirements stated
82  
    in the documentation.
82  
    in the documentation.
83  
*/
83  
*/
84  
    static_assert(
84  
    static_assert(
85  
        std::is_convertible<
85  
        std::is_convertible<
86  
            typename std::iterator_traits<
86  
            typename std::iterator_traits<
87  
                FwdIt>::reference,
87  
                FwdIt>::reference,
88  
            param_view>::value,
88  
            param_view>::value,
89  
        "Type requirements not met");
89  
        "Type requirements not met");
90  

90  

91  
    return insert(
91  
    return insert(
92  
        before,
92  
        before,
93  
        first,
93  
        first,
94  
        last,
94  
        last,
95  
        typename std::iterator_traits<
95  
        typename std::iterator_traits<
96  
            FwdIt>::iterator_category{});
96  
            FwdIt>::iterator_category{});
97  
}
97  
}
98  

98  

99  
template<class FwdIt>
99  
template<class FwdIt>
100  
auto
100  
auto
101  
params_ref::
101  
params_ref::
102  
replace(
102  
replace(
103  
    iterator from,
103  
    iterator from,
104  
    iterator to,
104  
    iterator to,
105  
    FwdIt first,
105  
    FwdIt first,
106  
    FwdIt last) ->
106  
    FwdIt last) ->
107  
        iterator
107  
        iterator
108  
{
108  
{
109  
/*  If you get a compile error here, it
109  
/*  If you get a compile error here, it
110  
    means that the iterators you passed
110  
    means that the iterators you passed
111  
    do not meet the requirements stated
111  
    do not meet the requirements stated
112  
    in the documentation.
112  
    in the documentation.
113  
*/
113  
*/
114  
    static_assert(
114  
    static_assert(
115  
        std::is_convertible<
115  
        std::is_convertible<
116  
            typename std::iterator_traits<
116  
            typename std::iterator_traits<
117  
                FwdIt>::reference,
117  
                FwdIt>::reference,
118  
            param_view>::value,
118  
            param_view>::value,
119  
        "Type requirements not met");
119  
        "Type requirements not met");
120  

120  

121  
    return iterator(
121  
    return iterator(
122  
        u_->edit_params(
122  
        u_->edit_params(
123  
            from.it_, to.it_,
123  
            from.it_, to.it_,
124  
            detail::make_params_iter(
124  
            detail::make_params_iter(
125  
                first, last, opt_.space_as_plus)),
125  
                first, last, opt_.space_as_plus)),
126  
        opt_);
126  
        opt_);
127  
}
127  
}
128  

128  

129  
//------------------------------------------------
129  
//------------------------------------------------
130  
//
130  
//
131  
// implementation
131  
// implementation
132  
//
132  
//
133  
//------------------------------------------------
133  
//------------------------------------------------
134  

134  

135  
template<class FwdIt>
135  
template<class FwdIt>
136  
void
136  
void
137  
params_ref::
137  
params_ref::
138  
assign(FwdIt first, FwdIt last,
138  
assign(FwdIt first, FwdIt last,
139  
    std::forward_iterator_tag)
139  
    std::forward_iterator_tag)
140  
{
140  
{
141  
    u_->edit_params(
141  
    u_->edit_params(
142  
        begin().it_,
142  
        begin().it_,
143  
        end().it_,
143  
        end().it_,
144  
        detail::make_params_iter(
144  
        detail::make_params_iter(
145  
            first, last, opt_.space_as_plus));
145  
            first, last, opt_.space_as_plus));
146  
}
146  
}
147  

147  

148  
template<class FwdIt>
148  
template<class FwdIt>
149  
auto
149  
auto
150  
params_ref::
150  
params_ref::
151  
insert(
151  
insert(
152  
    iterator before,
152  
    iterator before,
153  
    FwdIt first,
153  
    FwdIt first,
154  
    FwdIt last,
154  
    FwdIt last,
155  
    std::forward_iterator_tag) ->
155  
    std::forward_iterator_tag) ->
156  
        iterator
156  
        iterator
157  
{
157  
{
158  
    return iterator(
158  
    return iterator(
159  
        u_->edit_params(
159  
        u_->edit_params(
160  
            before.it_,
160  
            before.it_,
161  
            before.it_,
161  
            before.it_,
162  
            detail::make_params_iter(
162  
            detail::make_params_iter(
163  
                first, last, opt_.space_as_plus)),
163  
                first, last, opt_.space_as_plus)),
164  
        opt_);
164  
        opt_);
165  
}
165  
}
166  

166  

167  
//------------------------------------------------
167  
//------------------------------------------------
168  
//
168  
//
169  
// Special Members
169  
// Special Members
170  
//
170  
//
171  
//------------------------------------------------
171  
//------------------------------------------------
172  

172  

173  
inline
173  
inline
174  
params_ref::
174  
params_ref::
175  
params_ref(
175  
params_ref(
176  
    url_base& u,
176  
    url_base& u,
177  
    encoding_opts opt) noexcept
177  
    encoding_opts opt) noexcept
178  
    : params_base(u.impl_, opt)
178  
    : params_base(u.impl_, opt)
179  
    , u_(&u)
179  
    , u_(&u)
180  
{
180  
{
181  
}
181  
}
182  

182  

183  
inline
183  
inline
184  
params_ref::
184  
params_ref::
185  
params_ref(
185  
params_ref(
186  
    params_ref const& other,
186  
    params_ref const& other,
187  
    encoding_opts opt) noexcept
187  
    encoding_opts opt) noexcept
188  
    : params_base(other.u_->impl_, opt)
188  
    : params_base(other.u_->impl_, opt)
189  
    , u_(other.u_)
189  
    , u_(other.u_)
190  
{
190  
{
191  
}
191  
}
192  

192  

193  
inline
193  
inline
194  
auto
194  
auto
195  
params_ref::
195  
params_ref::
196  
operator=(params_ref const& other) ->
196  
operator=(params_ref const& other) ->
197  
    params_ref&
197  
    params_ref&
198  
{
198  
{
199  
    if (!ref_.alias_of(other.ref_))
199  
    if (!ref_.alias_of(other.ref_))
200  
        assign(other.begin(), other.end());
200  
        assign(other.begin(), other.end());
201  
    return *this;
201  
    return *this;
202  
}
202  
}
203  

203  

204  
inline
204  
inline
205  
auto
205  
auto
206  
params_ref::
206  
params_ref::
207  
operator=(std::initializer_list<
207  
operator=(std::initializer_list<
208  
    param_view> init) ->
208  
    param_view> init) ->
209  
        params_ref&
209  
        params_ref&
210  
{
210  
{
211  
    assign(init);
211  
    assign(init);
212  
    return *this;
212  
    return *this;
213  
}
213  
}
214  

214  

215  
inline
215  
inline
216  
params_ref::
216  
params_ref::
217  
operator
217  
operator
218  
params_view() const noexcept
218  
params_view() const noexcept
219  
{
219  
{
220  
    return { ref_, opt_ };
220  
    return { ref_, opt_ };
221  
}
221  
}
222  

222  

223  
//------------------------------------------------
223  
//------------------------------------------------
224  
//
224  
//
225  
// Modifiers
225  
// Modifiers
226  
//
226  
//
227  
//------------------------------------------------
227  
//------------------------------------------------
228  

228  

229  
inline
229  
inline
230  
void
230  
void
231  
params_ref::
231  
params_ref::
232  
clear() noexcept
232  
clear() noexcept
233  
{
233  
{
234  
    u_->remove_query();
234  
    u_->remove_query();
235  
}
235  
}
236  

236  

237  
inline
237  
inline
238  
void
238  
void
239  
params_ref::
239  
params_ref::
240  
assign(
240  
assign(
241  
    std::initializer_list<
241  
    std::initializer_list<
242  
        param_view> init)
242  
        param_view> init)
243  
{
243  
{
244  
    assign(init.begin(), init.end());
244  
    assign(init.begin(), init.end());
245  
}
245  
}
246  

246  

247  
inline
247  
inline
248  
auto
248  
auto
249  
params_ref::
249  
params_ref::
250  
insert(
250  
insert(
251  
    iterator before,
251  
    iterator before,
252  
    param_view const& p) ->
252  
    param_view const& p) ->
253  
        iterator
253  
        iterator
254  
{
254  
{
255  
    return {
255  
    return {
256  
        u_->edit_params(
256  
        u_->edit_params(
257  
            before.it_,
257  
            before.it_,
258  
            before.it_,
258  
            before.it_,
259  
            detail::single_param_iter(p, opt_.space_as_plus)),
259  
            detail::single_param_iter(p, opt_.space_as_plus)),
260  
        opt_};
260  
        opt_};
261  
}
261  
}
262  

262  

263  
inline
263  
inline
264  
auto
264  
auto
265  
params_ref::
265  
params_ref::
266  
insert(
266  
insert(
267  
    iterator before,
267  
    iterator before,
268  
    std::initializer_list<
268  
    std::initializer_list<
269  
        param_view> init) ->
269  
        param_view> init) ->
270  
    iterator
270  
    iterator
271  
{
271  
{
272  
    return insert(
272  
    return insert(
273  
        before,
273  
        before,
274  
        init.begin(),
274  
        init.begin(),
275  
        init.end());
275  
        init.end());
276  
}
276  
}
277  

277  

278  
inline
278  
inline
279  
auto
279  
auto
280  
params_ref::
280  
params_ref::
281  
append(
281  
append(
282  
    param_view const& p) ->
282  
    param_view const& p) ->
283  
        iterator
283  
        iterator
284  
{
284  
{
285  
    return insert(end(), p);
285  
    return insert(end(), p);
286  
}
286  
}
287  

287  

288  
inline
288  
inline
289  
auto
289  
auto
290  
params_ref::
290  
params_ref::
291  
append(
291  
append(
292  
    std::initializer_list<
292  
    std::initializer_list<
293  
        param_view> init) ->
293  
        param_view> init) ->
294  
    iterator
294  
    iterator
295  
{
295  
{
296  
    return insert(end(), init);
296  
    return insert(end(), init);
297  
}
297  
}
298  

298  

299  
inline
299  
inline
300  
std::size_t
300  
std::size_t
301  
params_ref::
301  
params_ref::
302  
erase(
302  
erase(
303  
    core::string_view key,
303  
    core::string_view key,
304  
    ignore_case_param ic) noexcept
304  
    ignore_case_param ic) noexcept
305  
{
305  
{
306  
    // end() can't be fully cached,
306  
    // end() can't be fully cached,
307  
    // since erase invalidates it.
307  
    // since erase invalidates it.
308  
    iterator it;
308  
    iterator it;
309  
    {
309  
    {
310  
        auto const end_ = end();
310  
        auto const end_ = end();
311  
        it = find_last(end_, key, ic);
311  
        it = find_last(end_, key, ic);
312  
        if(it == end_)
312  
        if(it == end_)
313  
            return 0;
313  
            return 0;
314  
    }
314  
    }
315  
    std::size_t n = 0;
315  
    std::size_t n = 0;
316  
    for(;;)
316  
    for(;;)
317  
    {
317  
    {
318  
        ++n;
318  
        ++n;
319  
        // Use it->key instead of key,
319  
        // Use it->key instead of key,
320  
        // to handle self-intersection
320  
        // to handle self-intersection
321  
        auto prev = find_last(it, (*it).key, ic);
321  
        auto prev = find_last(it, (*it).key, ic);
322  
        if(prev == end())
322  
        if(prev == end())
323  
            break;
323  
            break;
324  
        erase(it);
324  
        erase(it);
325  
        it = prev;
325  
        it = prev;
326  
    }
326  
    }
327  
    erase(it);
327  
    erase(it);
328  
    return n;
328  
    return n;
329  
}
329  
}
330  

330  

331  
inline
331  
inline
332  
auto
332  
auto
333  
params_ref::
333  
params_ref::
334  
replace(
334  
replace(
335  
    iterator pos,
335  
    iterator pos,
336  
    param_view const& p) ->
336  
    param_view const& p) ->
337  
        iterator
337  
        iterator
338  
{
338  
{
339  
    return iterator(
339  
    return iterator(
340  
        u_->edit_params(
340  
        u_->edit_params(
341  
            pos.it_,
341  
            pos.it_,
342  
            std::next(pos).it_,
342  
            std::next(pos).it_,
343  
            detail::single_param_iter(p, opt_.space_as_plus)),
343  
            detail::single_param_iter(p, opt_.space_as_plus)),
344  
        opt_);
344  
        opt_);
345  
}
345  
}
346  

346  

347  
inline
347  
inline
348  
auto
348  
auto
349  
params_ref::
349  
params_ref::
350  
replace(
350  
replace(
351  
    iterator from,
351  
    iterator from,
352  
    iterator to,
352  
    iterator to,
353  
    std::initializer_list<
353  
    std::initializer_list<
354  
        param_view> init) ->
354  
        param_view> init) ->
355  
    iterator
355  
    iterator
356  
{
356  
{
357  
    return replace(
357  
    return replace(
358  
        from,
358  
        from,
359  
        to,
359  
        to,
360  
        init.begin(),
360  
        init.begin(),
361  
        init.end());
361  
        init.end());
362  
}
362  
}
363  

363  

364  
inline
364  
inline
365  
auto
365  
auto
366  
params_ref::
366  
params_ref::
367  
unset(
367  
unset(
368  
    iterator pos) noexcept ->
368  
    iterator pos) noexcept ->
369  
        iterator
369  
        iterator
370  
{
370  
{
371  
    BOOST_ASSERT(pos.it_.nk > 0);
371  
    BOOST_ASSERT(pos.it_.nk > 0);
372  
    core::string_view s;
372  
    core::string_view s;
373  
    return iterator(
373  
    return iterator(
374  
        u_->edit_params(
374  
        u_->edit_params(
375  
            pos.it_,
375  
            pos.it_,
376  
            pos.it_.next(),
376  
            pos.it_.next(),
377  
            detail::param_value_iter(
377  
            detail::param_value_iter(
378  
                pos.it_.nk - 1, s, false)),
378  
                pos.it_.nk - 1, s, false)),
379  
        opt_);
379  
        opt_);
380  
}
380  
}
381  

381  

382  
inline
382  
inline
383  
auto
383  
auto
384  
params_ref::
384  
params_ref::
385  
set(
385  
set(
386  
    iterator pos,
386  
    iterator pos,
387  
    core::string_view value) ->
387  
    core::string_view value) ->
388  
        iterator
388  
        iterator
389  
{
389  
{
390  
    BOOST_ASSERT(pos.it_.nk > 0);
390  
    BOOST_ASSERT(pos.it_.nk > 0);
391  
    return iterator(
391  
    return iterator(
392  
        u_->edit_params(
392  
        u_->edit_params(
393  
            pos.it_,
393  
            pos.it_,
394  
            pos.it_.next(),
394  
            pos.it_.next(),
395  
            detail::param_value_iter(
395  
            detail::param_value_iter(
396  
                pos.it_.nk - 1, value, true)),
396  
                pos.it_.nk - 1, value, true)),
397  
        opt_);
397  
        opt_);
398  
}
398  
}
399  

399  

400  
inline
400  
inline
401  
auto
401  
auto
402  
params_ref::
402  
params_ref::
403  
set(
403  
set(
404  
    core::string_view key,
404  
    core::string_view key,
405  
    core::string_view value,
405  
    core::string_view value,
406  
    ignore_case_param ic) ->
406  
    ignore_case_param ic) ->
407  
        iterator
407  
        iterator
408  
{
408  
{
409  
    // VFALCO we can't cache end() here
409  
    // VFALCO we can't cache end() here
410  
    // because it is invalidated
410  
    // because it is invalidated
411  
    // every time we set or erase.
411  
    // every time we set or erase.
412  
    auto it0 = find(key, ic);
412  
    auto it0 = find(key, ic);
413  
    if(it0 == end())
413  
    if(it0 == end())
414  
        return append({key, value});
414  
        return append({key, value});
415  
    it0 = set(it0, value);
415  
    it0 = set(it0, value);
416  
    auto it = end();
416  
    auto it = end();
417  
    for(;;)
417  
    for(;;)
418  
    {
418  
    {
419  
        it = find_last(it, key, ic);
419  
        it = find_last(it, key, ic);
420  
        if(it == it0)
420  
        if(it == it0)
421  
            return it0;
421  
            return it0;
422  
        it = erase(it);
422  
        it = erase(it);
423  
    }
423  
    }
424  
}
424  
}
425  

425  

426  
inline
426  
inline
427  
auto
427  
auto
428  
params_ref::
428  
params_ref::
429  
erase(
429  
erase(
430  
    iterator pos) noexcept ->
430  
    iterator pos) noexcept ->
431  
    iterator
431  
    iterator
432  
{
432  
{
433  
    return erase(
433  
    return erase(
434  
        pos,
434  
        pos,
435  
        std::next(pos));
435  
        std::next(pos));
436  
}
436  
}
437  

437  

438  
inline
438  
inline
439  
auto
439  
auto
440  
params_ref::
440  
params_ref::
441  
erase(
441  
erase(
442  
    iterator first,
442  
    iterator first,
443  
    iterator last) noexcept ->
443  
    iterator last) noexcept ->
444  
        iterator
444  
        iterator
445  
{
445  
{
446  
    core::string_view s("", 0);
446  
    core::string_view s("", 0);
447  
    return iterator(
447  
    return iterator(
448  
        u_->edit_params(
448  
        u_->edit_params(
449  
            first.it_,
449  
            first.it_,
450  
            last.it_,
450  
            last.it_,
451  
            detail::query_string_iter(s)),
451  
            detail::query_string_iter(s)),
452  
        opt_);
452  
        opt_);
453  
}
453  
}
454  

454  

455  
} // urls
455  
} // urls
456  
} // boost
456  
} // boost
457  

457  

458  
#endif
458  
#endif