1  
//
1  
//
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2019 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 <boost/url/detail/params_iter_impl.hpp>
12  
#include <boost/url/detail/params_iter_impl.hpp>
13  
#include <boost/assert.hpp>
13  
#include <boost/assert.hpp>
14  

14  

15  
namespace boost {
15  
namespace boost {
16  
namespace urls {
16  
namespace urls {
17  
namespace detail {
17  
namespace detail {
18  

18  

19  
/*  index   zero-based index of param
19  
/*  index   zero-based index of param
20  
    pos     offset from start   0 = '?'
20  
    pos     offset from start   0 = '?'
21  
    nk      size of key         with '?' or '&'
21  
    nk      size of key         with '?' or '&'
22  
    nv      size of value       with '='
22  
    nv      size of value       with '='
23  
    dk      decoded key size    no '?' or '&'
23  
    dk      decoded key size    no '?' or '&'
24  
    dv      decoded value size  no '='
24  
    dv      decoded value size  no '='
25  
*/
25  
*/
26  
params_iter_impl::
26  
params_iter_impl::
27  
params_iter_impl(
27  
params_iter_impl(
28  
    query_ref const& ref_) noexcept
28  
    query_ref const& ref_) noexcept
29  
    : ref(ref_)
29  
    : ref(ref_)
30  
    , index(0)
30  
    , index(0)
31  
    , pos(0)
31  
    , pos(0)
32  
{
32  
{
33  
    if(index < ref_.nparam())
33  
    if(index < ref_.nparam())
34  
        setup();
34  
        setup();
35  
}
35  
}
36  

36  

37  
params_iter_impl::
37  
params_iter_impl::
38  
params_iter_impl(
38  
params_iter_impl(
39  
    query_ref const& ref_,
39  
    query_ref const& ref_,
40  
    int) noexcept
40  
    int) noexcept
41  
    : ref(ref_)
41  
    : ref(ref_)
42  
    , index(ref_.nparam())
42  
    , index(ref_.nparam())
43  
    , pos(ref_.size())
43  
    , pos(ref_.size())
44  
{
44  
{
45  
}
45  
}
46  

46  

47  
params_iter_impl::
47  
params_iter_impl::
48  
params_iter_impl(
48  
params_iter_impl(
49  
    query_ref const& ref_,
49  
    query_ref const& ref_,
50  
    std::size_t pos_,
50  
    std::size_t pos_,
51  
    std::size_t index_) noexcept
51  
    std::size_t index_) noexcept
52  
    : ref(ref_)
52  
    : ref(ref_)
53  
    , index(index_)
53  
    , index(index_)
54  
    , pos(pos_)
54  
    , pos(pos_)
55  
{
55  
{
56  
    BOOST_ASSERT(
56  
    BOOST_ASSERT(
57  
        pos <= ref.size());
57  
        pos <= ref.size());
58  
    if(index < ref_.nparam())
58  
    if(index < ref_.nparam())
59  
        setup();
59  
        setup();
60  
}
60  
}
61  

61  

62  
// set up state for key/value at pos
62  
// set up state for key/value at pos
63  
void
63  
void
64  
params_iter_impl::
64  
params_iter_impl::
65  
setup() noexcept
65  
setup() noexcept
66  
{
66  
{
67  
    dk = 1;
67  
    dk = 1;
68  
    dv = 0;
68  
    dv = 0;
69  
    auto const end = ref.end();
69  
    auto const end = ref.end();
70  
    BOOST_ASSERT(pos != ref.size());
70  
    BOOST_ASSERT(pos != ref.size());
71  
    auto p0 = ref.begin() + pos;
71  
    auto p0 = ref.begin() + pos;
72  
    auto p = p0;
72  
    auto p = p0;
73  
    // key
73  
    // key
74  
    for(;;)
74  
    for(;;)
75  
    {
75  
    {
76  
        if( p == end ||
76  
        if( p == end ||
77  
            *p == '&')
77  
            *p == '&')
78  
        {
78  
        {
79  
            // no value
79  
            // no value
80  
            nk = 1 + p - p0;
80  
            nk = 1 + p - p0;
81  
            dk = nk - dk;
81  
            dk = nk - dk;
82  
            nv = 0;
82  
            nv = 0;
83  
            return;
83  
            return;
84  
        }
84  
        }
85  
        if(*p == '=')
85  
        if(*p == '=')
86  
            break;
86  
            break;
87  
        if(*p == '%')
87  
        if(*p == '%')
88  
        {
88  
        {
89  
            BOOST_ASSERT(
89  
            BOOST_ASSERT(
90  
                end - p >= 3);
90  
                end - p >= 3);
91  
            dk += 2;
91  
            dk += 2;
92  
            p += 2;
92  
            p += 2;
93  
        }
93  
        }
94  
        ++p;
94  
        ++p;
95  
    }
95  
    }
96  
    nk = 1 + p - p0;
96  
    nk = 1 + p - p0;
97  
    dk = nk - dk;
97  
    dk = nk - dk;
98  
    p0 = p;
98  
    p0 = p;
99  

99  

100  
    // value
100  
    // value
101  
    for(;;)
101  
    for(;;)
102  
    {
102  
    {
103  
        ++p;
103  
        ++p;
104  
        if( p == end ||
104  
        if( p == end ||
105  
            *p == '&')
105  
            *p == '&')
106  
            break;
106  
            break;
107  
        if(*p == '%')
107  
        if(*p == '%')
108  
        {
108  
        {
109  
            BOOST_ASSERT(
109  
            BOOST_ASSERT(
110  
                end - p >= 3);
110  
                end - p >= 3);
111  
            dv += 2;
111  
            dv += 2;
112  
            p += 2;
112  
            p += 2;
113  
        }
113  
        }
114  
    }
114  
    }
115  
    nv = p - p0;
115  
    nv = p - p0;
116  
    dv = nv - dv - 1;
116  
    dv = nv - dv - 1;
117  
}
117  
}
118  

118  

119  
void
119  
void
120  
params_iter_impl::
120  
params_iter_impl::
121  
increment() noexcept
121  
increment() noexcept
122  
{
122  
{
123  
    BOOST_ASSERT(
123  
    BOOST_ASSERT(
124  
        index < ref.nparam());
124  
        index < ref.nparam());
125  
    pos += nk + nv;
125  
    pos += nk + nv;
126  
    ++index;
126  
    ++index;
127  
    if(index < ref.nparam())
127  
    if(index < ref.nparam())
128  
        setup();
128  
        setup();
129  
}
129  
}
130  

130  

131  
void
131  
void
132  
params_iter_impl::
132  
params_iter_impl::
133  
decrement() noexcept
133  
decrement() noexcept
134  
{
134  
{
135  
    BOOST_ASSERT(index > 0);
135  
    BOOST_ASSERT(index > 0);
136  
    --index;
136  
    --index;
137  
    dk = 1; // for '&' or '?'
137  
    dk = 1; // for '&' or '?'
138  
    dv = 1; // for '='
138  
    dv = 1; // for '='
139  
    auto const begin = ref.begin();
139  
    auto const begin = ref.begin();
140  
    BOOST_ASSERT(pos > 0);
140  
    BOOST_ASSERT(pos > 0);
141  
    auto p1 = begin + (pos - 1);
141  
    auto p1 = begin + (pos - 1);
142  
    auto p = p1;
142  
    auto p = p1;
143  
    // find key or '='
143  
    // find key or '='
144  
    for(;;)
144  
    for(;;)
145  
    {
145  
    {
146  
        if(p == begin)
146  
        if(p == begin)
147  
        {
147  
        {
148  
            // key
148  
            // key
149  
            nk = 1 + p1 - p; // with '?'
149  
            nk = 1 + p1 - p; // with '?'
150  
            dk = nk - dv;
150  
            dk = nk - dv;
151  
            nv = 0;
151  
            nv = 0;
152  
            dv = 0;
152  
            dv = 0;
153  
            pos -= nk;
153  
            pos -= nk;
154  
            return;
154  
            return;
155  
        }
155  
        }
156  
        else if(*--p == '&')
156  
        else if(*--p == '&')
157  
        {
157  
        {
158  
            // key
158  
            // key
159  
            nk = p1 - p; // with '&'
159  
            nk = p1 - p; // with '&'
160  
            dk = nk - dv;
160  
            dk = nk - dv;
161  
            nv = 0;
161  
            nv = 0;
162  
            dv = 0;
162  
            dv = 0;
163  
            pos -= nk;
163  
            pos -= nk;
164  
            return;
164  
            return;
165  
        }
165  
        }
166  
        if(*p == '=')
166  
        if(*p == '=')
167  
        {
167  
        {
168  
            // value
168  
            // value
169  
            nv = p1 - p; // with '='
169  
            nv = p1 - p; // with '='
170  
            break;
170  
            break;
171  
        }
171  
        }
172  
        if(*p == '%')
172  
        if(*p == '%')
173  
            dv += 2;
173  
            dv += 2;
174  
    }
174  
    }
175  
    // find key and value
175  
    // find key and value
176  
    for(;;)
176  
    for(;;)
177  
    {
177  
    {
178  
        if(p == begin)
178  
        if(p == begin)
179  
        {
179  
        {
180  
            // key and value
180  
            // key and value
181  
            nk = 1 + p1 - p - nv; // with '?'
181  
            nk = 1 + p1 - p - nv; // with '?'
182  
            dk = nk - dk;
182  
            dk = nk - dk;
183  
            dv = nv - dv;
183  
            dv = nv - dv;
184  
            pos -= nk + nv;
184  
            pos -= nk + nv;
185  
            return;
185  
            return;
186  
        }
186  
        }
187  
        if(*--p == '&')
187  
        if(*--p == '&')
188  
        {
188  
        {
189  
            // key and value
189  
            // key and value
190  
            nk = p1 - p - nv; // with '&'
190  
            nk = p1 - p - nv; // with '&'
191  
            dk = nk - dk;
191  
            dk = nk - dk;
192  
            dv = nv - dv;
192  
            dv = nv - dv;
193  
            pos -= nk + nv;
193  
            pos -= nk + nv;
194  
            return;
194  
            return;
195  
        }
195  
        }
196  
        if(*p == '=')
196  
        if(*p == '=')
197  
        {
197  
        {
198  
            // value
198  
            // value
199  
            nv = p1 - p; // with '='
199  
            nv = p1 - p; // with '='
200  
            dv += dk;
200  
            dv += dk;
201  
            dk = 0;
201  
            dk = 0;
202  
        }
202  
        }
203  
        else if(*p == '%')
203  
        else if(*p == '%')
204  
        {
204  
        {
205  
            dk += 2;
205  
            dk += 2;
206  
        }
206  
        }
207  
    }
207  
    }
208  
}
208  
}
209  

209  

210  
param_pct_view
210  
param_pct_view
211  
params_iter_impl::
211  
params_iter_impl::
212  
dereference() const noexcept
212  
dereference() const noexcept
213  
{
213  
{
214  
    BOOST_ASSERT(index < ref.nparam());
214  
    BOOST_ASSERT(index < ref.nparam());
215  
    BOOST_ASSERT(pos < ref.size());
215  
    BOOST_ASSERT(pos < ref.size());
216  
    auto const p = ref.begin() + pos;
216  
    auto const p = ref.begin() + pos;
217  
    if(nv)
217  
    if(nv)
218  
        return {
218  
        return {
219  
            make_pct_string_view_unsafe(
219  
            make_pct_string_view_unsafe(
220  
                p, nk - 1, dk),
220  
                p, nk - 1, dk),
221  
            make_pct_string_view_unsafe(
221  
            make_pct_string_view_unsafe(
222  
                p + nk, nv - 1, dv)};
222  
                p + nk, nv - 1, dv)};
223  
    return {
223  
    return {
224  
        make_pct_string_view_unsafe(
224  
        make_pct_string_view_unsafe(
225  
            p, nk - 1, dk),
225  
            p, nk - 1, dk),
226  
        no_value};
226  
        no_value};
227  
}
227  
}
228  

228  

229  
pct_string_view
229  
pct_string_view
230  
params_iter_impl::
230  
params_iter_impl::
231  
key() const noexcept
231  
key() const noexcept
232  
{
232  
{
233  
    BOOST_ASSERT(index < ref.nparam());
233  
    BOOST_ASSERT(index < ref.nparam());
234  
    BOOST_ASSERT(pos < ref.size());
234  
    BOOST_ASSERT(pos < ref.size());
235  
    auto const p = ref.begin() + pos;
235  
    auto const p = ref.begin() + pos;
236  
    return make_pct_string_view_unsafe(
236  
    return make_pct_string_view_unsafe(
237  
        p, nk - 1, dk);
237  
        p, nk - 1, dk);
238  
}
238  
}
239  

239  

240  
} // detail
240  
} // detail
241  
} // url
241  
} // url
242  
} // boost
242  
} // boost
243  

243