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

12  

13  
#include <boost/url/pct_string_view.hpp>
13  
#include <boost/url/pct_string_view.hpp>
14  
#include <boost/core/detail/static_assert.hpp>
14  
#include <boost/core/detail/static_assert.hpp>
15  
#include <cstddef>
15  
#include <cstddef>
16  
#include <iterator>
16  
#include <iterator>
17  
#include <type_traits>
17  
#include <type_traits>
18  

18  

19  
namespace boost {
19  
namespace boost {
20  
namespace urls {
20  
namespace urls {
21  
namespace detail {
21  
namespace detail {
22  

22  

23  
struct BOOST_SYMBOL_VISIBLE
23  
struct BOOST_SYMBOL_VISIBLE
24  
    any_segments_iter
24  
    any_segments_iter
25  
{
25  
{
26  
protected:
26  
protected:
27  
    explicit
27  
    explicit
28  
    any_segments_iter(
28  
    any_segments_iter(
29  
        core::string_view s_ = {}) noexcept
29  
        core::string_view s_ = {}) noexcept
30  
        : s(s_)
30  
        : s(s_)
31  
    {
31  
    {
32  
    }
32  
    }
33  

33  

34  
    virtual ~any_segments_iter() = default;
34  
    virtual ~any_segments_iter() = default;
35  

35  

36  
public:
36  
public:
37  
    // this is adjusted
37  
    // this is adjusted
38  
    // when self-intersecting
38  
    // when self-intersecting
39  
    core::string_view s;
39  
    core::string_view s;
40  

40  

41  
    // the first segment,
41  
    // the first segment,
42  
    // to handle special cases
42  
    // to handle special cases
43  
    core::string_view front;
43  
    core::string_view front;
44  

44  

45  
    // quick number of segments
45  
    // quick number of segments
46  
    // 0 = zero
46  
    // 0 = zero
47  
    // 1 = one
47  
    // 1 = one
48  
    // 2 = two, or more
48  
    // 2 = two, or more
49  
    int fast_nseg = 0;
49  
    int fast_nseg = 0;
50  

50  

51  
    // whether the segments should encode colons
51  
    // whether the segments should encode colons
52  
    // when we measure and copy. the calling
52  
    // when we measure and copy. the calling
53  
    // function uses this for the first
53  
    // function uses this for the first
54  
    // segment in some cases, such as:
54  
    // segment in some cases, such as:
55  
    // "x:y:z" -> remove_scheme -> "y%3Az"
55  
    // "x:y:z" -> remove_scheme -> "y%3Az"
56  
    // as "y:z" would no longer represent a path
56  
    // as "y:z" would no longer represent a path
57  
    bool encode_colons = false;
57  
    bool encode_colons = false;
58  

58  

59  
    // Rewind the iterator to the beginning
59  
    // Rewind the iterator to the beginning
60  
    virtual void rewind() noexcept = 0;
60  
    virtual void rewind() noexcept = 0;
61  

61  

62  
    // Measure and increment the current
62  
    // Measure and increment the current
63  
    // element. n is increased by the
63  
    // element. n is increased by the
64  
    // encoded size. Returns false on
64  
    // encoded size. Returns false on
65  
    // end of range. 
65  
    // end of range. 
66  
    virtual bool measure(std::size_t& n) = 0;
66  
    virtual bool measure(std::size_t& n) = 0;
67  

67  

68  
    // Copy and increment the current
68  
    // Copy and increment the current
69  
    // element, encoding as needed.
69  
    // element, encoding as needed.
70  
    virtual void copy(char*& dest,
70  
    virtual void copy(char*& dest,
71  
        char const* end) noexcept = 0;
71  
        char const* end) noexcept = 0;
72  
};
72  
};
73  

73  

74  
//------------------------------------------------
74  
//------------------------------------------------
75  
//
75  
//
76  
// segment_iter
76  
// segment_iter
77  
//
77  
//
78  
//------------------------------------------------
78  
//------------------------------------------------
79  

79  

80  
// A 1-segment range
80  
// A 1-segment range
81  
// allowing self-intersection
81  
// allowing self-intersection
82  
struct BOOST_SYMBOL_VISIBLE
82  
struct BOOST_SYMBOL_VISIBLE
83  
    segment_iter
83  
    segment_iter
84  
    : any_segments_iter
84  
    : any_segments_iter
85  
{
85  
{
86  
    virtual ~segment_iter() = default;
86  
    virtual ~segment_iter() = default;
87  

87  

88  
    explicit
88  
    explicit
89  
    segment_iter(
89  
    segment_iter(
90  
        core::string_view s) noexcept;
90  
        core::string_view s) noexcept;
91  

91  

92  
private:
92  
private:
93  
    bool at_end_ = false;
93  
    bool at_end_ = false;
94  
    void rewind() noexcept override;
94  
    void rewind() noexcept override;
95  
    bool measure(std::size_t&) noexcept override;
95  
    bool measure(std::size_t&) noexcept override;
96  
    void copy(char*&, char const*) noexcept override;
96  
    void copy(char*&, char const*) noexcept override;
97  
};
97  
};
98  

98  

99  
//------------------------------------------------
99  
//------------------------------------------------
100  
//
100  
//
101  
// segments_iter
101  
// segments_iter
102  
//
102  
//
103  
//------------------------------------------------
103  
//------------------------------------------------
104  

104  

105  
struct segments_iter_base
105  
struct segments_iter_base
106  
{
106  
{
107  
protected:
107  
protected:
108  
    BOOST_URL_DECL static void
108  
    BOOST_URL_DECL static void
109  
    measure_impl(std::size_t&,
109  
    measure_impl(std::size_t&,
110  
        core::string_view, bool) noexcept;
110  
        core::string_view, bool) noexcept;
111  
    BOOST_URL_DECL static void
111  
    BOOST_URL_DECL static void
112  
    copy_impl(char*&, char const*,
112  
    copy_impl(char*&, char const*,
113  
        core::string_view, bool) noexcept;
113  
        core::string_view, bool) noexcept;
114  
};
114  
};
115  

115  

116  
// iterates segments in a
116  
// iterates segments in a
117  
// plain segment range
117  
// plain segment range
118  
template<class FwdIt>
118  
template<class FwdIt>
119  
struct segments_iter
119  
struct segments_iter
120  
    : any_segments_iter
120  
    : any_segments_iter
121  
    , segments_iter_base
121  
    , segments_iter_base
122  
{
122  
{
123  
    BOOST_CORE_STATIC_ASSERT(
123  
    BOOST_CORE_STATIC_ASSERT(
124  
        std::is_convertible<
124  
        std::is_convertible<
125  
            typename std::iterator_traits<
125  
            typename std::iterator_traits<
126  
                FwdIt>::reference,
126  
                FwdIt>::reference,
127  
            core::string_view>::value);
127  
            core::string_view>::value);
128  

128  

129  
    segments_iter(
129  
    segments_iter(
130  
        FwdIt first,
130  
        FwdIt first,
131  
        FwdIt last) noexcept
131  
        FwdIt last) noexcept
132  
        : it_(first)
132  
        : it_(first)
133  
        , it0_(first)
133  
        , it0_(first)
134  
        , end_(last)
134  
        , end_(last)
135  
    {
135  
    {
136  
        if(first != last)
136  
        if(first != last)
137  
        {
137  
        {
138  
            front = *first;
138  
            front = *first;
139  
            auto it = first;
139  
            auto it = first;
140  
            if(++it == last)
140  
            if(++it == last)
141  
                fast_nseg = 1;
141  
                fast_nseg = 1;
142  
            else
142  
            else
143  
                fast_nseg = 2;
143  
                fast_nseg = 2;
144  
        }
144  
        }
145  
        else
145  
        else
146  
        {
146  
        {
147  
            fast_nseg = 0;
147  
            fast_nseg = 0;
148  
        }
148  
        }
149  
    }
149  
    }
150  

150  

151  
private:
151  
private:
152  
    FwdIt it_;
152  
    FwdIt it_;
153  
    FwdIt it0_;
153  
    FwdIt it0_;
154  
    FwdIt end_;
154  
    FwdIt end_;
155  

155  

156  
    void
156  
    void
157  
    rewind() noexcept override
157  
    rewind() noexcept override
158  
    {
158  
    {
159  
        it_ = it0_;
159  
        it_ = it0_;
160  
    }
160  
    }
161  

161  

162  
    bool
162  
    bool
163  
    measure(
163  
    measure(
164  
        std::size_t& n) noexcept override
164  
        std::size_t& n) noexcept override
165  
    {
165  
    {
166  
        if(it_ == end_)
166  
        if(it_ == end_)
167  
            return false;
167  
            return false;
168  
        measure_impl(n,
168  
        measure_impl(n,
169  
            detail::to_sv(*it_),
169  
            detail::to_sv(*it_),
170  
            encode_colons);
170  
            encode_colons);
171  
        ++it_;
171  
        ++it_;
172  
        return true;
172  
        return true;
173  
    }
173  
    }
174  

174  

175  
    void
175  
    void
176  
    copy(
176  
    copy(
177  
        char*& dest,
177  
        char*& dest,
178  
        char const* end) noexcept override
178  
        char const* end) noexcept override
179  
    {
179  
    {
180  
        copy_impl(dest, end,
180  
        copy_impl(dest, end,
181  
            detail::to_sv(*it_++),
181  
            detail::to_sv(*it_++),
182  
            encode_colons);
182  
            encode_colons);
183  
    }
183  
    }
184  
};
184  
};
185  

185  

186  
//------------------------------------------------
186  
//------------------------------------------------
187  
//
187  
//
188  
// segment_encoded_iter
188  
// segment_encoded_iter
189  
//
189  
//
190  
//------------------------------------------------
190  
//------------------------------------------------
191  

191  

192  
// A 1-segment range
192  
// A 1-segment range
193  
// allowing self-intersection
193  
// allowing self-intersection
194  
struct BOOST_SYMBOL_VISIBLE
194  
struct BOOST_SYMBOL_VISIBLE
195  
    segment_encoded_iter
195  
    segment_encoded_iter
196  
    : any_segments_iter
196  
    : any_segments_iter
197  
{
197  
{
198  
    virtual ~segment_encoded_iter() = default;
198  
    virtual ~segment_encoded_iter() = default;
199  

199  

200  
    explicit
200  
    explicit
201  
    segment_encoded_iter(
201  
    segment_encoded_iter(
202  
        pct_string_view const& s) noexcept;
202  
        pct_string_view const& s) noexcept;
203  

203  

204  
private:
204  
private:
205  
    bool at_end_ = false;
205  
    bool at_end_ = false;
206  
    void rewind() noexcept override;
206  
    void rewind() noexcept override;
207  
    bool measure(std::size_t&) noexcept override;
207  
    bool measure(std::size_t&) noexcept override;
208  
    void copy(char*&, char const*) noexcept override;
208  
    void copy(char*&, char const*) noexcept override;
209  
};
209  
};
210  

210  

211  
//------------------------------------------------
211  
//------------------------------------------------
212  
//
212  
//
213  
// segments_encoded_iter
213  
// segments_encoded_iter
214  
//
214  
//
215  
//------------------------------------------------
215  
//------------------------------------------------
216  

216  

217  
// Validating and copying from
217  
// Validating and copying from
218  
// a string of encoded segments
218  
// a string of encoded segments
219  
struct segments_encoded_iter_base
219  
struct segments_encoded_iter_base
220  
{
220  
{
221  
protected:
221  
protected:
222  
    BOOST_URL_DECL static void
222  
    BOOST_URL_DECL static void
223  
    measure_impl(std::size_t&,
223  
    measure_impl(std::size_t&,
224  
        core::string_view, bool) noexcept;
224  
        core::string_view, bool) noexcept;
225  
    BOOST_URL_DECL static void
225  
    BOOST_URL_DECL static void
226  
    copy_impl(char*&, char const*,
226  
    copy_impl(char*&, char const*,
227  
        core::string_view, bool) noexcept;
227  
        core::string_view, bool) noexcept;
228  
};
228  
};
229  

229  

230  
// iterates segments in an
230  
// iterates segments in an
231  
// encoded segment range
231  
// encoded segment range
232  
template<class FwdIt>
232  
template<class FwdIt>
233  
struct segments_encoded_iter
233  
struct segments_encoded_iter
234  
    : public any_segments_iter
234  
    : public any_segments_iter
235  
    , public segments_encoded_iter_base
235  
    , public segments_encoded_iter_base
236  
{
236  
{
237  
    BOOST_CORE_STATIC_ASSERT(
237  
    BOOST_CORE_STATIC_ASSERT(
238  
        std::is_convertible<
238  
        std::is_convertible<
239  
            typename std::iterator_traits<
239  
            typename std::iterator_traits<
240  
                FwdIt>::reference,
240  
                FwdIt>::reference,
241  
            core::string_view>::value);
241  
            core::string_view>::value);
242  

242  

243  
    segments_encoded_iter(
243  
    segments_encoded_iter(
244  
        FwdIt first,
244  
        FwdIt first,
245  
        FwdIt last)
245  
        FwdIt last)
246  
        : it_(first)
246  
        : it_(first)
247  
        , it0_(first)
247  
        , it0_(first)
248  
        , end_(last)
248  
        , end_(last)
249  
    {
249  
    {
250  
        if(it_ != end_)
250  
        if(it_ != end_)
251  
        {
251  
        {
252  
            // throw on invalid input
252  
            // throw on invalid input
253  
            front = pct_string_view(
253  
            front = pct_string_view(
254  
                detail::to_sv(*first));
254  
                detail::to_sv(*first));
255  
            auto it = first;
255  
            auto it = first;
256  
            if(++it == last)
256  
            if(++it == last)
257  
                fast_nseg = 1;
257  
                fast_nseg = 1;
258  
            else
258  
            else
259  
                fast_nseg = 2;
259  
                fast_nseg = 2;
260  
        }
260  
        }
261  
        else
261  
        else
262  
        {
262  
        {
263  
            fast_nseg = 0;
263  
            fast_nseg = 0;
264  
        }
264  
        }
265  
    }
265  
    }
266  

266  

267  
private:
267  
private:
268  
    FwdIt it_;
268  
    FwdIt it_;
269  
    FwdIt it0_;
269  
    FwdIt it0_;
270  
    FwdIt end_;
270  
    FwdIt end_;
271  

271  

272  
    void
272  
    void
273  
    rewind() noexcept override
273  
    rewind() noexcept override
274  
    {
274  
    {
275  
        it_ = it0_;
275  
        it_ = it0_;
276  
    }
276  
    }
277  

277  

278  
    bool
278  
    bool
279  
    measure(
279  
    measure(
280  
        std::size_t& n) override
280  
        std::size_t& n) override
281  
    {
281  
    {
282  
        if(it_ == end_)
282  
        if(it_ == end_)
283  
            return false;
283  
            return false;
284  
        // throw on invalid input
284  
        // throw on invalid input
285  
        measure_impl(n,
285  
        measure_impl(n,
286  
            pct_string_view(
286  
            pct_string_view(
287  
                detail::to_sv(*it_++)),
287  
                detail::to_sv(*it_++)),
288  
            encode_colons);
288  
            encode_colons);
289  
        return true;
289  
        return true;
290  
    }
290  
    }
291  

291  

292  
    void
292  
    void
293  
    copy(
293  
    copy(
294  
        char*& dest,
294  
        char*& dest,
295  
        char const* end) noexcept override
295  
        char const* end) noexcept override
296  
    {
296  
    {
297  
        copy_impl(dest, end,
297  
        copy_impl(dest, end,
298  
            detail::to_sv(*it_++),
298  
            detail::to_sv(*it_++),
299  
            encode_colons);
299  
            encode_colons);
300  
    }
300  
    }
301  
};
301  
};
302  

302  

303  
//------------------------------------------------
303  
//------------------------------------------------
304  

304  

305  
template<class FwdIt>
305  
template<class FwdIt>
306  
segments_iter<FwdIt>
306  
segments_iter<FwdIt>
307  
make_segments_iter(
307  
make_segments_iter(
308  
    FwdIt first, FwdIt last)
308  
    FwdIt first, FwdIt last)
309  
{
309  
{
310  
    return segments_iter<
310  
    return segments_iter<
311  
        FwdIt>(first, last);
311  
        FwdIt>(first, last);
312  
}
312  
}
313  

313  

314  
template<class FwdIt>
314  
template<class FwdIt>
315  
segments_encoded_iter<FwdIt>
315  
segments_encoded_iter<FwdIt>
316  
make_segments_encoded_iter(
316  
make_segments_encoded_iter(
317  
    FwdIt first, FwdIt last)
317  
    FwdIt first, FwdIt last)
318  
{
318  
{
319  
    return segments_encoded_iter<
319  
    return segments_encoded_iter<
320  
        FwdIt>(first, last);
320  
        FwdIt>(first, last);
321  
}
321  
}
322  

322  

323  
} // detail
323  
} // detail
324  
} // urls
324  
} // urls
325  
} // boost
325  
} // boost
326  

326  

327  
#endif
327  
#endif