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  
#ifndef BOOST_URL_DETAIL_IMPL_PARAMS_ITER_IMPL_HPP
10  
#ifndef BOOST_URL_DETAIL_IMPL_PARAMS_ITER_IMPL_HPP
11  
#define BOOST_URL_DETAIL_IMPL_PARAMS_ITER_IMPL_HPP
11  
#define BOOST_URL_DETAIL_IMPL_PARAMS_ITER_IMPL_HPP
12  

12  

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  
inline
26  
inline
27  
params_iter_impl::
27  
params_iter_impl::
28  
params_iter_impl(
28  
params_iter_impl(
29  
    query_ref const& ref_) noexcept
29  
    query_ref const& ref_) noexcept
30  
    : ref(ref_)
30  
    : ref(ref_)
31  
    , index(0)
31  
    , index(0)
32  
    , pos(0)
32  
    , pos(0)
33  
{
33  
{
34  
    if(index < ref_.nparam())
34  
    if(index < ref_.nparam())
35  
        setup();
35  
        setup();
36  
}
36  
}
37  

37  

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

48  

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

64  

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

103  

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

122  

123  
inline
123  
inline
124  
void
124  
void
125  
params_iter_impl::
125  
params_iter_impl::
126  
increment() noexcept
126  
increment() noexcept
127  
{
127  
{
128  
    BOOST_ASSERT(
128  
    BOOST_ASSERT(
129  
        index < ref.nparam());
129  
        index < ref.nparam());
130  
    pos += nk + nv;
130  
    pos += nk + nv;
131  
    ++index;
131  
    ++index;
132  
    if(index < ref.nparam())
132  
    if(index < ref.nparam())
133  
        setup();
133  
        setup();
134  
}
134  
}
135  

135  

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

215  

216  
inline
216  
inline
217  
param_pct_view
217  
param_pct_view
218  
params_iter_impl::
218  
params_iter_impl::
219  
dereference() const noexcept
219  
dereference() const noexcept
220  
{
220  
{
221  
    BOOST_ASSERT(index < ref.nparam());
221  
    BOOST_ASSERT(index < ref.nparam());
222  
    BOOST_ASSERT(pos < ref.size());
222  
    BOOST_ASSERT(pos < ref.size());
223  
    auto const p = ref.begin() + pos;
223  
    auto const p = ref.begin() + pos;
224  
    if(nv)
224  
    if(nv)
225  
        return {
225  
        return {
226  
            make_pct_string_view_unsafe(
226  
            make_pct_string_view_unsafe(
227  
                p, nk - 1, dk),
227  
                p, nk - 1, dk),
228  
            make_pct_string_view_unsafe(
228  
            make_pct_string_view_unsafe(
229  
                p + nk, nv - 1, dv)};
229  
                p + nk, nv - 1, dv)};
230  
    return {
230  
    return {
231  
        make_pct_string_view_unsafe(
231  
        make_pct_string_view_unsafe(
232  
            p, nk - 1, dk),
232  
            p, nk - 1, dk),
233  
        no_value};
233  
        no_value};
234  
}
234  
}
235  

235  

236  
inline
236  
inline
237  
pct_string_view
237  
pct_string_view
238  
params_iter_impl::
238  
params_iter_impl::
239  
key() const noexcept
239  
key() const noexcept
240  
{
240  
{
241  
    BOOST_ASSERT(index < ref.nparam());
241  
    BOOST_ASSERT(index < ref.nparam());
242  
    BOOST_ASSERT(pos < ref.size());
242  
    BOOST_ASSERT(pos < ref.size());
243  
    auto const p = ref.begin() + pos;
243  
    auto const p = ref.begin() + pos;
244  
    return make_pct_string_view_unsafe(
244  
    return make_pct_string_view_unsafe(
245  
        p, nk - 1, dk);
245  
        p, nk - 1, dk);
246  
}
246  
}
247  

247  

248  
} // detail
248  
} // detail
249  
} // urls
249  
} // urls
250  
} // boost
250  
} // boost
251  

251  

252  
#endif
252  
#endif