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

13  

14  
#include <boost/url/params_encoded_view.hpp>
14  
#include <boost/url/params_encoded_view.hpp>
15  
#include <boost/url/url_base.hpp>
15  
#include <boost/url/url_base.hpp>
16  
#include <boost/url/detail/except.hpp>
16  
#include <boost/url/detail/except.hpp>
17  
#include <boost/url/grammar/ci_string.hpp>
17  
#include <boost/url/grammar/ci_string.hpp>
18  
#include <boost/assert.hpp>
18  
#include <boost/assert.hpp>
19  
#include <utility>
19  
#include <utility>
20  

20  

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

23  

24  
//------------------------------------------------
24  
//------------------------------------------------
25  
//
25  
//
26  
// Special Members
26  
// Special Members
27  
//
27  
//
28  
//------------------------------------------------
28  
//------------------------------------------------
29  

29  

30  
inline
30  
inline
31  
params_encoded_ref::
31  
params_encoded_ref::
32  
params_encoded_ref(
32  
params_encoded_ref(
33  
    url_base& u) noexcept
33  
    url_base& u) noexcept
34  
    : params_encoded_base(u.impl_)
34  
    : params_encoded_base(u.impl_)
35  
    , u_(&u)
35  
    , u_(&u)
36  
{
36  
{
37  
}
37  
}
38  

38  

39  
inline
39  
inline
40  
params_encoded_ref&
40  
params_encoded_ref&
41  
params_encoded_ref::
41  
params_encoded_ref::
42  
operator=(
42  
operator=(
43  
    params_encoded_ref const& other)
43  
    params_encoded_ref const& other)
44  
{
44  
{
45  
    if (!ref_.alias_of( other.ref_ ))
45  
    if (!ref_.alias_of( other.ref_ ))
46  
        assign(other.begin(), other.end());
46  
        assign(other.begin(), other.end());
47  
    return *this;
47  
    return *this;
48  
}
48  
}
49  

49  

50  
inline
50  
inline
51  
params_encoded_ref&
51  
params_encoded_ref&
52  
params_encoded_ref::
52  
params_encoded_ref::
53  
operator=(std::initializer_list<
53  
operator=(std::initializer_list<
54  
    param_pct_view> init)
54  
    param_pct_view> init)
55  
{
55  
{
56  
    assign(init.begin(), init.end());
56  
    assign(init.begin(), init.end());
57  
    return *this;
57  
    return *this;
58  
}
58  
}
59  

59  

60  
inline
60  
inline
61  
params_encoded_ref::
61  
params_encoded_ref::
62  
operator
62  
operator
63  
params_encoded_view() const noexcept
63  
params_encoded_view() const noexcept
64  
{
64  
{
65  
    return {ref_};
65  
    return {ref_};
66  
}
66  
}
67  

67  

68  
//------------------------------------------------
68  
//------------------------------------------------
69  
//
69  
//
70  
// Modifiers
70  
// Modifiers
71  
//
71  
//
72  
//------------------------------------------------
72  
//------------------------------------------------
73  

73  

74  
inline
74  
inline
75  
void
75  
void
76  
params_encoded_ref::
76  
params_encoded_ref::
77  
assign(
77  
assign(
78  
    std::initializer_list<
78  
    std::initializer_list<
79  
        param_pct_view> init)
79  
        param_pct_view> init)
80  
{
80  
{
81  
    assign(init.begin(), init.end());
81  
    assign(init.begin(), init.end());
82  
}
82  
}
83  

83  

84  
inline
84  
inline
85  
void
85  
void
86  
params_encoded_ref::
86  
params_encoded_ref::
87  
clear() noexcept
87  
clear() noexcept
88  
{
88  
{
89  
    u_->remove_query();
89  
    u_->remove_query();
90  
}
90  
}
91  

91  

92  
template<class FwdIt>
92  
template<class FwdIt>
93  
void
93  
void
94  
params_encoded_ref::
94  
params_encoded_ref::
95  
assign(FwdIt first, FwdIt last)
95  
assign(FwdIt first, FwdIt last)
96  
{
96  
{
97  
/*  If you get a compile error here, it
97  
/*  If you get a compile error here, it
98  
    means that the iterators you passed
98  
    means that the iterators you passed
99  
    do not meet the requirements stated
99  
    do not meet the requirements stated
100  
    in the documentation.
100  
    in the documentation.
101  
*/
101  
*/
102  
    static_assert(
102  
    static_assert(
103  
        std::is_convertible<
103  
        std::is_convertible<
104  
            typename std::iterator_traits<
104  
            typename std::iterator_traits<
105  
                FwdIt>::reference,
105  
                FwdIt>::reference,
106  
            param_view>::value,
106  
            param_view>::value,
107  
        "Type requirements not met");
107  
        "Type requirements not met");
108  

108  

109  
    assign(first, last,
109  
    assign(first, last,
110  
        typename std::iterator_traits<
110  
        typename std::iterator_traits<
111  
            FwdIt>::iterator_category{});
111  
            FwdIt>::iterator_category{});
112  
}
112  
}
113  

113  

114  
inline
114  
inline
115  
auto
115  
auto
116  
params_encoded_ref::
116  
params_encoded_ref::
117  
append(
117  
append(
118  
    param_pct_view const& p) ->
118  
    param_pct_view const& p) ->
119  
        iterator
119  
        iterator
120  
{
120  
{
121  
    return insert(end(), p);
121  
    return insert(end(), p);
122  
}
122  
}
123  

123  

124  
inline
124  
inline
125  
auto
125  
auto
126  
params_encoded_ref::
126  
params_encoded_ref::
127  
append(
127  
append(
128  
    std::initializer_list<
128  
    std::initializer_list<
129  
        param_pct_view> init) ->
129  
        param_pct_view> init) ->
130  
    iterator
130  
    iterator
131  
{
131  
{
132  
    return insert(end(), init);
132  
    return insert(end(), init);
133  
}
133  
}
134  

134  

135  
template<class FwdIt>
135  
template<class FwdIt>
136  
auto
136  
auto
137  
params_encoded_ref::
137  
params_encoded_ref::
138  
append(
138  
append(
139  
    FwdIt first, FwdIt last) ->
139  
    FwdIt first, FwdIt last) ->
140  
    iterator
140  
    iterator
141  
{
141  
{
142  
/*  If you get a compile error here, it
142  
/*  If you get a compile error here, it
143  
    means that the iterators you passed
143  
    means that the iterators you passed
144  
    do not meet the requirements stated
144  
    do not meet the requirements stated
145  
    in the documentation.
145  
    in the documentation.
146  
*/
146  
*/
147  
    static_assert(
147  
    static_assert(
148  
        std::is_convertible<
148  
        std::is_convertible<
149  
            typename std::iterator_traits<
149  
            typename std::iterator_traits<
150  
                FwdIt>::reference,
150  
                FwdIt>::reference,
151  
            param_view>::value,
151  
            param_view>::value,
152  
        "Type requirements not met");
152  
        "Type requirements not met");
153  

153  

154  
    return insert(
154  
    return insert(
155  
        end(), first, last);
155  
        end(), first, last);
156  
}
156  
}
157  

157  

158  
template<class FwdIt>
158  
template<class FwdIt>
159  
auto
159  
auto
160  
params_encoded_ref::
160  
params_encoded_ref::
161  
insert(
161  
insert(
162  
    iterator before,
162  
    iterator before,
163  
    FwdIt first,
163  
    FwdIt first,
164  
    FwdIt last) ->
164  
    FwdIt last) ->
165  
        iterator
165  
        iterator
166  
{
166  
{
167  
/*  If you get a compile error here, it
167  
/*  If you get a compile error here, it
168  
    means that the iterators you passed
168  
    means that the iterators you passed
169  
    do not meet the requirements stated
169  
    do not meet the requirements stated
170  
    in the documentation.
170  
    in the documentation.
171  
*/
171  
*/
172  
    static_assert(
172  
    static_assert(
173  
        std::is_convertible<
173  
        std::is_convertible<
174  
            typename std::iterator_traits<
174  
            typename std::iterator_traits<
175  
                FwdIt>::reference,
175  
                FwdIt>::reference,
176  
            param_view>::value,
176  
            param_view>::value,
177  
        "Type requirements not met");
177  
        "Type requirements not met");
178  

178  

179  
    return insert(
179  
    return insert(
180  
        before,
180  
        before,
181  
        first,
181  
        first,
182  
        last,
182  
        last,
183  
        typename std::iterator_traits<
183  
        typename std::iterator_traits<
184  
            FwdIt>::iterator_category{});
184  
            FwdIt>::iterator_category{});
185  
}
185  
}
186  

186  

187  
template<class FwdIt>
187  
template<class FwdIt>
188  
auto
188  
auto
189  
params_encoded_ref::
189  
params_encoded_ref::
190  
replace(
190  
replace(
191  
    iterator from,
191  
    iterator from,
192  
    iterator to,
192  
    iterator to,
193  
    FwdIt first,
193  
    FwdIt first,
194  
    FwdIt last) ->
194  
    FwdIt last) ->
195  
        iterator
195  
        iterator
196  
{
196  
{
197  
/*  If you get a compile error here, it
197  
/*  If you get a compile error here, it
198  
    means that the iterators you passed
198  
    means that the iterators you passed
199  
    do not meet the requirements stated
199  
    do not meet the requirements stated
200  
    in the documentation.
200  
    in the documentation.
201  
*/
201  
*/
202  
    static_assert(
202  
    static_assert(
203  
        std::is_convertible<
203  
        std::is_convertible<
204  
            typename std::iterator_traits<
204  
            typename std::iterator_traits<
205  
                FwdIt>::reference,
205  
                FwdIt>::reference,
206  
            param_view>::value,
206  
            param_view>::value,
207  
        "Type requirements not met");
207  
        "Type requirements not met");
208  

208  

209  
    return u_->edit_params(
209  
    return u_->edit_params(
210  
        from.it_, to.it_,
210  
        from.it_, to.it_,
211  
        detail::make_params_encoded_iter(
211  
        detail::make_params_encoded_iter(
212  
            first, last));
212  
            first, last));
213  
}
213  
}
214  

214  

215  
//------------------------------------------------
215  
//------------------------------------------------
216  
//
216  
//
217  
// implementation
217  
// implementation
218  
//
218  
//
219  
//------------------------------------------------
219  
//------------------------------------------------
220  

220  

221  
template<class FwdIt>
221  
template<class FwdIt>
222  
void
222  
void
223  
params_encoded_ref::
223  
params_encoded_ref::
224  
assign(FwdIt first, FwdIt last,
224  
assign(FwdIt first, FwdIt last,
225  
    std::forward_iterator_tag)
225  
    std::forward_iterator_tag)
226  
{
226  
{
227  
    u_->edit_params(
227  
    u_->edit_params(
228  
        begin().it_,
228  
        begin().it_,
229  
        end().it_,
229  
        end().it_,
230  
        detail::make_params_encoded_iter(
230  
        detail::make_params_encoded_iter(
231  
            first, last));
231  
            first, last));
232  
}
232  
}
233  

233  

234  
template<class FwdIt>
234  
template<class FwdIt>
235  
auto
235  
auto
236  
params_encoded_ref::
236  
params_encoded_ref::
237  
insert(
237  
insert(
238  
    iterator before,
238  
    iterator before,
239  
    FwdIt first,
239  
    FwdIt first,
240  
    FwdIt last,
240  
    FwdIt last,
241  
    std::forward_iterator_tag) ->
241  
    std::forward_iterator_tag) ->
242  
        iterator
242  
        iterator
243  
{
243  
{
244  
    return u_->edit_params(
244  
    return u_->edit_params(
245  
        before.it_,
245  
        before.it_,
246  
        before.it_,
246  
        before.it_,
247  
        detail::make_params_encoded_iter(
247  
        detail::make_params_encoded_iter(
248  
            first, last));
248  
            first, last));
249  
}
249  
}
250  

250  

251  
inline
251  
inline
252  
auto
252  
auto
253  
params_encoded_ref::
253  
params_encoded_ref::
254  
insert(
254  
insert(
255  
    iterator before,
255  
    iterator before,
256  
    param_pct_view const& p) ->
256  
    param_pct_view const& p) ->
257  
        iterator
257  
        iterator
258  
{
258  
{
259  
    return u_->edit_params(
259  
    return u_->edit_params(
260  
        before.it_,
260  
        before.it_,
261  
        before.it_,
261  
        before.it_,
262  
        detail::param_encoded_iter(p));
262  
        detail::param_encoded_iter(p));
263  
}
263  
}
264  

264  

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

279  

280  
inline
280  
inline
281  
std::size_t
281  
std::size_t
282  
params_encoded_ref::
282  
params_encoded_ref::
283  
erase(
283  
erase(
284  
    pct_string_view key,
284  
    pct_string_view key,
285  
    ignore_case_param ic) noexcept
285  
    ignore_case_param ic) noexcept
286  
{
286  
{
287  
    // end() can't be fully cached,
287  
    // end() can't be fully cached,
288  
    // since erase invalidates it.
288  
    // since erase invalidates it.
289  
    iterator it;
289  
    iterator it;
290  
    {
290  
    {
291  
        auto const end_ = end();
291  
        auto const end_ = end();
292  
        it = find_last(end_, key, ic);
292  
        it = find_last(end_, key, ic);
293  
        if(it == end_)
293  
        if(it == end_)
294  
            return 0;
294  
            return 0;
295  
    }
295  
    }
296  
    std::size_t n = 0;
296  
    std::size_t n = 0;
297  
    for(;;)
297  
    for(;;)
298  
    {
298  
    {
299  
        ++n;
299  
        ++n;
300  
        // Use it->key instead of key,
300  
        // Use it->key instead of key,
301  
        // to handle self-intersection
301  
        // to handle self-intersection
302  
        auto prev = find_last(it, it->key, ic);
302  
        auto prev = find_last(it, it->key, ic);
303  
        if(prev == end())
303  
        if(prev == end())
304  
            break;
304  
            break;
305  
        erase(it);
305  
        erase(it);
306  
        it = prev;
306  
        it = prev;
307  
    }
307  
    }
308  
    erase(it);
308  
    erase(it);
309  
    return n;
309  
    return n;
310  
}
310  
}
311  

311  

312  
inline
312  
inline
313  
auto
313  
auto
314  
params_encoded_ref::
314  
params_encoded_ref::
315  
replace(
315  
replace(
316  
    iterator pos,
316  
    iterator pos,
317  
    param_pct_view const& p) ->
317  
    param_pct_view const& p) ->
318  
        iterator
318  
        iterator
319  
{
319  
{
320  
    return u_->edit_params(
320  
    return u_->edit_params(
321  
        pos.it_,
321  
        pos.it_,
322  
        std::next(pos).it_,
322  
        std::next(pos).it_,
323  
        detail::param_encoded_iter(p));
323  
        detail::param_encoded_iter(p));
324  
}
324  
}
325  

325  

326  
inline
326  
inline
327  
auto
327  
auto
328  
params_encoded_ref::
328  
params_encoded_ref::
329  
replace(
329  
replace(
330  
    iterator from,
330  
    iterator from,
331  
    iterator to,
331  
    iterator to,
332  
    std::initializer_list<
332  
    std::initializer_list<
333  
        param_pct_view> init) ->
333  
        param_pct_view> init) ->
334  
    iterator
334  
    iterator
335  
{
335  
{
336  
    return replace(
336  
    return replace(
337  
        from,
337  
        from,
338  
        to,
338  
        to,
339  
        init.begin(),
339  
        init.begin(),
340  
        init.end());
340  
        init.end());
341  
}
341  
}
342  

342  

343  
inline
343  
inline
344  
auto
344  
auto
345  
params_encoded_ref::
345  
params_encoded_ref::
346  
unset(
346  
unset(
347  
    iterator pos) noexcept ->
347  
    iterator pos) noexcept ->
348  
        iterator
348  
        iterator
349  
{
349  
{
350  
    BOOST_ASSERT(pos.it_.nk > 0);
350  
    BOOST_ASSERT(pos.it_.nk > 0);
351  
    pct_string_view s;
351  
    pct_string_view s;
352  
    return u_->edit_params(
352  
    return u_->edit_params(
353  
        pos.it_, pos.it_.next(),
353  
        pos.it_, pos.it_.next(),
354  
        detail::param_encoded_value_iter(
354  
        detail::param_encoded_value_iter(
355  
            pos.it_.nk - 1, s, false));
355  
            pos.it_.nk - 1, s, false));
356  
}
356  
}
357  

357  

358  
inline
358  
inline
359  
auto
359  
auto
360  
params_encoded_ref::
360  
params_encoded_ref::
361  
set(
361  
set(
362  
    iterator pos,
362  
    iterator pos,
363  
    pct_string_view value) ->
363  
    pct_string_view value) ->
364  
        iterator
364  
        iterator
365  
{
365  
{
366  
    BOOST_ASSERT(pos.it_.nk > 0);
366  
    BOOST_ASSERT(pos.it_.nk > 0);
367  
    return u_->edit_params(
367  
    return u_->edit_params(
368  
        pos.it_,
368  
        pos.it_,
369  
        pos.it_.next(),
369  
        pos.it_.next(),
370  
        detail::param_encoded_value_iter(
370  
        detail::param_encoded_value_iter(
371  
            pos.it_.nk - 1, value, true));
371  
            pos.it_.nk - 1, value, true));
372  
}
372  
}
373  

373  

374  
inline
374  
inline
375  
auto
375  
auto
376  
params_encoded_ref::
376  
params_encoded_ref::
377  
set(
377  
set(
378  
    pct_string_view key,
378  
    pct_string_view key,
379  
    pct_string_view value,
379  
    pct_string_view value,
380  
    ignore_case_param ic) ->
380  
    ignore_case_param ic) ->
381  
        iterator
381  
        iterator
382  
{
382  
{
383  
    // VFALCO we can't cache end() here
383  
    // VFALCO we can't cache end() here
384  
    // because it is invalidated
384  
    // because it is invalidated
385  
    // every time we set or erase.
385  
    // every time we set or erase.
386  
    auto it0 = find(key, ic);
386  
    auto it0 = find(key, ic);
387  
    if(it0 == end())
387  
    if(it0 == end())
388  
        return append({key, value});
388  
        return append({key, value});
389  
    it0 = set(it0, value);
389  
    it0 = set(it0, value);
390  
    auto it = end();
390  
    auto it = end();
391  
    for(;;)
391  
    for(;;)
392  
    {
392  
    {
393  
        it = find_last(it, key, ic);
393  
        it = find_last(it, key, ic);
394  
        if(it == it0)
394  
        if(it == it0)
395  
            return it0;
395  
            return it0;
396  
        it = erase(it);
396  
        it = erase(it);
397  
    }
397  
    }
398  
}
398  
}
399  

399  

400  
inline
400  
inline
401  
auto
401  
auto
402  
params_encoded_ref::
402  
params_encoded_ref::
403  
erase(
403  
erase(
404  
    iterator pos) noexcept ->
404  
    iterator pos) noexcept ->
405  
        iterator
405  
        iterator
406  
{
406  
{
407  
    return erase(
407  
    return erase(
408  
        pos,
408  
        pos,
409  
        std::next(pos));
409  
        std::next(pos));
410  
}
410  
}
411  

411  

412  
inline
412  
inline
413  
auto
413  
auto
414  
params_encoded_ref::
414  
params_encoded_ref::
415  
erase(
415  
erase(
416  
    iterator first,
416  
    iterator first,
417  
    iterator last) noexcept ->
417  
    iterator last) noexcept ->
418  
        iterator
418  
        iterator
419  
{
419  
{
420  
    core::string_view s("", 0);
420  
    core::string_view s("", 0);
421  
    return u_->edit_params(
421  
    return u_->edit_params(
422  
        first.it_,
422  
        first.it_,
423  
        last.it_,
423  
        last.it_,
424  
        detail::query_string_iter(s));
424  
        detail::query_string_iter(s));
425  
}
425  
}
426  

426  

427  
} // urls
427  
} // urls
428  
} // boost
428  
} // boost
429  

429  

430  
#endif
430  
#endif