1  
//
1  
//
2  
// Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
2  
// Copyright (c) 2022 Alan de Freitas (alandefreitas@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_DECODE_VIEW_HPP
10  
#ifndef BOOST_URL_DECODE_VIEW_HPP
11  
#define BOOST_URL_DECODE_VIEW_HPP
11  
#define BOOST_URL_DECODE_VIEW_HPP
12  

12  

13  
#include <boost/url/detail/config.hpp>
13  
#include <boost/url/detail/config.hpp>
14  
#include <boost/core/detail/string_view.hpp>
14  
#include <boost/core/detail/string_view.hpp>
15  
#include <boost/url/encoding_opts.hpp>
15  
#include <boost/url/encoding_opts.hpp>
16  
#include <boost/url/pct_string_view.hpp>
16  
#include <boost/url/pct_string_view.hpp>
17  
#include <type_traits>
17  
#include <type_traits>
18  
#include <iterator>
18  
#include <iterator>
19  
#include <iosfwd>
19  
#include <iosfwd>
20  

20  

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

23  

24  
//------------------------------------------------
24  
//------------------------------------------------
25  

25  

26  
class decode_view;
26  
class decode_view;
27  

27  

28  
namespace detail {
28  
namespace detail {
29  

29  

30  
// unchecked
30  
// unchecked
31  
template<class... Args>
31  
template<class... Args>
32  
decode_view
32  
decode_view
33  
make_decode_view(
33  
make_decode_view(
34  
    Args&&... args) noexcept;
34  
    Args&&... args) noexcept;
35  

35  

36  
} // detail
36  
} // detail
37  

37  

38  
//------------------------------------------------
38  
//------------------------------------------------
39  

39  

40  
/** A reference to a valid, percent-encoded string
40  
/** A reference to a valid, percent-encoded string
41  

41  

42  
    These views reference strings in parts of URLs
42  
    These views reference strings in parts of URLs
43  
    or other components that are percent-encoded.
43  
    or other components that are percent-encoded.
44  
    The special characters (those not in the
44  
    The special characters (those not in the
45  
    allowed character set) are stored as three
45  
    allowed character set) are stored as three
46  
    character escapes that consist of a percent
46  
    character escapes that consist of a percent
47  
    sign ('%%') followed by a two-digit hexadecimal
47  
    sign ('%%') followed by a two-digit hexadecimal
48  
    number of the corresponding unescaped character
48  
    number of the corresponding unescaped character
49  
    code, which may be part of a UTF-8 code point
49  
    code, which may be part of a UTF-8 code point
50  
    depending on the context.
50  
    depending on the context.
51  

51  

52  
    The view refers to the original character
52  
    The view refers to the original character
53  
    buffer and only decodes escaped sequences when
53  
    buffer and only decodes escaped sequences when
54  
    needed. In particular these operations perform
54  
    needed. In particular these operations perform
55  
    percent-decoding automatically without the
55  
    percent-decoding automatically without the
56  
    need to allocate memory:
56  
    need to allocate memory:
57  

57  

58  
    @li Iteration of the string
58  
    @li Iteration of the string
59  
    @li Accessing the encoded character buffer
59  
    @li Accessing the encoded character buffer
60  
    @li Comparison to encoded or plain strings
60  
    @li Comparison to encoded or plain strings
61  

61  

62  
    These objects can only be constructed from
62  
    These objects can only be constructed from
63  
    strings that have a valid percent-encoding,
63  
    strings that have a valid percent-encoding,
64  
    otherwise construction fails. The caller is
64  
    otherwise construction fails. The caller is
65  
    responsible for ensuring that the lifetime
65  
    responsible for ensuring that the lifetime
66  
    of the character buffer from which the view
66  
    of the character buffer from which the view
67  
    is constructed extends unmodified until the
67  
    is constructed extends unmodified until the
68  
    view is no longer accessed.
68  
    view is no longer accessed.
69  
*/
69  
*/
70  
class decode_view
70  
class decode_view
71  
{
71  
{
72  
    char const* p_ = nullptr;
72  
    char const* p_ = nullptr;
73  
    std::size_t n_ = 0;
73  
    std::size_t n_ = 0;
74  
    std::size_t dn_ = 0;
74  
    std::size_t dn_ = 0;
75  
    bool space_as_plus_ = true;
75  
    bool space_as_plus_ = true;
76  

76  

77  
    template<class... Args>
77  
    template<class... Args>
78  
    friend
78  
    friend
79  
    decode_view
79  
    decode_view
80  
    detail::make_decode_view(
80  
    detail::make_decode_view(
81  
        Args&&... args) noexcept;
81  
        Args&&... args) noexcept;
82  

82  

83  
    // unchecked
83  
    // unchecked
84  
    BOOST_CXX14_CONSTEXPR
84  
    BOOST_CXX14_CONSTEXPR
85  
    explicit
85  
    explicit
86  
    decode_view(
86  
    decode_view(
87  
        core::string_view s,
87  
        core::string_view s,
88  
        std::size_t n,
88  
        std::size_t n,
89  
        encoding_opts opt) noexcept
89  
        encoding_opts opt) noexcept
90  
        : p_(s.data())
90  
        : p_(s.data())
91  
        , n_(s.size())
91  
        , n_(s.size())
92  
        , dn_(n)
92  
        , dn_(n)
93  
        , space_as_plus_(
93  
        , space_as_plus_(
94  
            opt.space_as_plus)
94  
            opt.space_as_plus)
95  
    {}
95  
    {}
96  

96  

97  
public:
97  
public:
98  
    /** The value type
98  
    /** The value type
99  
    */
99  
    */
100  
    using value_type = char;
100  
    using value_type = char;
101  

101  

102  
    /** The reference type
102  
    /** The reference type
103  
    */
103  
    */
104  
    using reference = char;
104  
    using reference = char;
105  

105  

106  
    /// @copydoc reference
106  
    /// @copydoc reference
107  
    using const_reference = char;
107  
    using const_reference = char;
108  

108  

109  
    /** The unsigned integer type
109  
    /** The unsigned integer type
110  
    */
110  
    */
111  
    using size_type = std::size_t;
111  
    using size_type = std::size_t;
112  

112  

113  
    /** The signed integer type
113  
    /** The signed integer type
114  
    */
114  
    */
115  
    using difference_type = std::ptrdiff_t;
115  
    using difference_type = std::ptrdiff_t;
116  

116  

117  
    /** An iterator of constant, decoded characters.
117  
    /** An iterator of constant, decoded characters.
118  

118  

119  
        This iterator is used to access the encoded
119  
        This iterator is used to access the encoded
120  
        string as a *bidirectional* range of characters
120  
        string as a *bidirectional* range of characters
121  
        with percent-decoding applied. Escape sequences
121  
        with percent-decoding applied. Escape sequences
122  
        are not decoded until the iterator is
122  
        are not decoded until the iterator is
123  
        dereferenced.
123  
        dereferenced.
124  
    */
124  
    */
125  
    class iterator;
125  
    class iterator;
126  

126  

127  
    /// @copydoc iterator
127  
    /// @copydoc iterator
128  
    using const_iterator = iterator;
128  
    using const_iterator = iterator;
129  

129  

130  
    //--------------------------------------------
130  
    //--------------------------------------------
131  
    //
131  
    //
132  
    // Special Members
132  
    // Special Members
133  
    //
133  
    //
134  
    //--------------------------------------------
134  
    //--------------------------------------------
135  

135  

136  
    /** Constructor
136  
    /** Constructor
137  

137  

138  
        Default-constructed views represent
138  
        Default-constructed views represent
139  
        empty strings.
139  
        empty strings.
140  

140  

141  
        @par Example
141  
        @par Example
142  
        @code
142  
        @code
143  
        decode_view ds;
143  
        decode_view ds;
144  
        @endcode
144  
        @endcode
145  

145  

146  
        @par Postconditions
146  
        @par Postconditions
147  
        @code
147  
        @code
148  
        this->empty() == true
148  
        this->empty() == true
149  
        @endcode
149  
        @endcode
150  

150  

151  
        @par Complexity
151  
        @par Complexity
152  
        Constant.
152  
        Constant.
153  

153  

154  
        @par Exception Safety
154  
        @par Exception Safety
155  
        Throws nothing.
155  
        Throws nothing.
156  
    */
156  
    */
157  
    BOOST_CXX14_CONSTEXPR
157  
    BOOST_CXX14_CONSTEXPR
158  
    decode_view() noexcept = default;
158  
    decode_view() noexcept = default;
159  

159  

160  
    /** Constructor
160  
    /** Constructor
161  

161  

162  
        This constructs a view from the character
162  
        This constructs a view from the character
163  
        buffer `s`, which must remain valid and
163  
        buffer `s`, which must remain valid and
164  
        unmodified until the view is no longer
164  
        unmodified until the view is no longer
165  
        accessed.
165  
        accessed.
166  

166  

167  
        @par Example
167  
        @par Example
168  
        @code
168  
        @code
169  
        decode_view ds( "Program%20Files" );
169  
        decode_view ds( "Program%20Files" );
170  
        @endcode
170  
        @endcode
171  

171  

172  
        @par Postconditions
172  
        @par Postconditions
173  
        @code
173  
        @code
174  
        this->encoded() == s
174  
        this->encoded() == s
175  
        @endcode
175  
        @endcode
176  

176  

177  
        @par Complexity
177  
        @par Complexity
178  
        Linear in `s.size()`.
178  
        Linear in `s.size()`.
179  

179  

180  
        @par Exception Safety
180  
        @par Exception Safety
181  
        Although this function does not throw exceptions,
181  
        Although this function does not throw exceptions,
182  
        implicitly constructing a @ref pct_string_view
182  
        implicitly constructing a @ref pct_string_view
183  
        for the first argument can throw exceptions
183  
        for the first argument can throw exceptions
184  
        on invalid input.
184  
        on invalid input.
185  

185  

186  
        @param s A percent-encoded string that has
186  
        @param s A percent-encoded string that has
187  
        already been validated. Implicit conversion
187  
        already been validated. Implicit conversion
188  
        from other string types is supported but
188  
        from other string types is supported but
189  
        may throw exceptions.
189  
        may throw exceptions.
190  

190  

191  
        @param opt The options for decoding. If
191  
        @param opt The options for decoding. If
192  
        this parameter is omitted, the default
192  
        this parameter is omitted, the default
193  
        options are used.
193  
        options are used.
194  
    */
194  
    */
195  
    BOOST_CXX14_CONSTEXPR
195  
    BOOST_CXX14_CONSTEXPR
196  
    explicit
196  
    explicit
197  
    decode_view(
197  
    decode_view(
198  
        pct_string_view s,
198  
        pct_string_view s,
199  
        encoding_opts opt = {}) noexcept
199  
        encoding_opts opt = {}) noexcept
200  
        : decode_view(
200  
        : decode_view(
201  
            detail::to_sv(s),
201  
            detail::to_sv(s),
202  
            s.decoded_size(),
202  
            s.decoded_size(),
203  
            opt)
203  
            opt)
204  
    {
204  
    {
205  
    }
205  
    }
206  

206  

207  
    //--------------------------------------------
207  
    //--------------------------------------------
208  
    //
208  
    //
209  
    // Observers
209  
    // Observers
210  
    //
210  
    //
211  
    //--------------------------------------------
211  
    //--------------------------------------------
212  

212  

213  
    /** Return true if the string is empty
213  
    /** Return true if the string is empty
214  

214  

215  
        @par Example
215  
        @par Example
216  
        @code
216  
        @code
217  
        assert( decode_view( "" ).empty() );
217  
        assert( decode_view( "" ).empty() );
218  
        @endcode
218  
        @endcode
219  

219  

220  
        @par Complexity
220  
        @par Complexity
221  
        Constant.
221  
        Constant.
222  

222  

223  
        @par Exception Safety
223  
        @par Exception Safety
224  
        Throws nothing.
224  
        Throws nothing.
225  

225  

226  
        @return `true` if the string is empty
226  
        @return `true` if the string is empty
227  
    */
227  
    */
228  
    bool
228  
    bool
229  
    empty() const noexcept
229  
    empty() const noexcept
230  
    {
230  
    {
231  
        return n_ == 0;
231  
        return n_ == 0;
232  
    }
232  
    }
233  

233  

234  
    /** Return the number of decoded characters
234  
    /** Return the number of decoded characters
235  

235  

236  
        @par Example
236  
        @par Example
237  
        @code
237  
        @code
238  
        assert( decode_view( "Program%20Files" ).size() == 13 );
238  
        assert( decode_view( "Program%20Files" ).size() == 13 );
239  
        @endcode
239  
        @endcode
240  

240  

241  
        @par Effects
241  
        @par Effects
242  
        @code
242  
        @code
243  
        return std::distance( this->begin(), this->end() );
243  
        return std::distance( this->begin(), this->end() );
244  
        @endcode
244  
        @endcode
245  

245  

246  
        @par Complexity
246  
        @par Complexity
247  
        Constant.
247  
        Constant.
248  

248  

249  
        @par Exception Safety
249  
        @par Exception Safety
250  
        Throws nothing.
250  
        Throws nothing.
251  

251  

252  
        @return The number of decoded characters
252  
        @return The number of decoded characters
253  
    */
253  
    */
254  
    size_type
254  
    size_type
255  
    size() const noexcept
255  
    size() const noexcept
256  
    {
256  
    {
257  
        return dn_;
257  
        return dn_;
258  
    }
258  
    }
259  

259  

260  
    /** Return an iterator to the beginning
260  
    /** Return an iterator to the beginning
261  

261  

262  
        @par Example
262  
        @par Example
263  
        @code
263  
        @code
264  
        auto it = this->begin();
264  
        auto it = this->begin();
265  
        @endcode
265  
        @endcode
266  

266  

267  
        @par Complexity
267  
        @par Complexity
268  
        Constant.
268  
        Constant.
269  

269  

270  
        @par Exception Safety
270  
        @par Exception Safety
271  
        Throws nothing.
271  
        Throws nothing.
272  

272  

273  
        @return An iterator to the first decoded character
273  
        @return An iterator to the first decoded character
274  
    */
274  
    */
275  
    iterator
275  
    iterator
276  
    begin() const noexcept;
276  
    begin() const noexcept;
277  

277  

278  
    /** Return an iterator to the end
278  
    /** Return an iterator to the end
279  

279  

280  
        @par Example
280  
        @par Example
281  
        @code
281  
        @code
282  
        auto it = this->end();
282  
        auto it = this->end();
283  
        @endcode
283  
        @endcode
284  

284  

285  
        @par Complexity
285  
        @par Complexity
286  
        Constant.
286  
        Constant.
287  

287  

288  
        @par Exception Safety
288  
        @par Exception Safety
289  
        Throws nothing.
289  
        Throws nothing.
290  

290  

291  
        @return An iterator to one past the last decoded character
291  
        @return An iterator to one past the last decoded character
292  
    */
292  
    */
293  
    iterator
293  
    iterator
294  
    end() const noexcept;
294  
    end() const noexcept;
295  

295  

296  
    /** Return the first character
296  
    /** Return the first character
297  

297  

298  
        @par Example
298  
        @par Example
299  
        @code
299  
        @code
300  
        assert( decode_view( "Program%20Files" ).front() == 'P' );
300  
        assert( decode_view( "Program%20Files" ).front() == 'P' );
301  
        @endcode
301  
        @endcode
302  

302  

303  
        @par Preconditions
303  
        @par Preconditions
304  
        @code
304  
        @code
305  
        not this->empty()
305  
        not this->empty()
306  
        @endcode
306  
        @endcode
307  

307  

308  
        @par Complexity
308  
        @par Complexity
309  
        Constant.
309  
        Constant.
310  

310  

311  
        @par Exception Safety
311  
        @par Exception Safety
312  
        Throws nothing.
312  
        Throws nothing.
313  

313  

314  
        @return The first decoded character
314  
        @return The first decoded character
315  
    */
315  
    */
316  
    reference
316  
    reference
317  
    front() const noexcept;
317  
    front() const noexcept;
318  

318  

319  
    /** Return the last character
319  
    /** Return the last character
320  

320  

321  
        @par Example
321  
        @par Example
322  
        @code
322  
        @code
323  
        assert( decode_view( "Program%20Files" ).back() == 's' );
323  
        assert( decode_view( "Program%20Files" ).back() == 's' );
324  
        @endcode
324  
        @endcode
325  

325  

326  
        @par Preconditions
326  
        @par Preconditions
327  
        @code
327  
        @code
328  
        not this->empty()
328  
        not this->empty()
329  
        @endcode
329  
        @endcode
330  

330  

331  
        @par Complexity
331  
        @par Complexity
332  
        Constant.
332  
        Constant.
333  

333  

334  
        @par Exception Safety
334  
        @par Exception Safety
335  
        Throws nothing.
335  
        Throws nothing.
336  

336  

337  
        @return The last decoded character
337  
        @return The last decoded character
338  
    */
338  
    */
339  
    reference
339  
    reference
340  
    back() const noexcept;
340  
    back() const noexcept;
341  

341  

342  
    /** Checks if the string begins with the given prefix
342  
    /** Checks if the string begins with the given prefix
343  

343  

344  
        @par Example
344  
        @par Example
345  
        @code
345  
        @code
346  
        assert( decode_view( "Program%20Files" ).starts_with("Program") );
346  
        assert( decode_view( "Program%20Files" ).starts_with("Program") );
347  
        @endcode
347  
        @endcode
348  

348  

349  
        @par Complexity
349  
        @par Complexity
350  
        Linear.
350  
        Linear.
351  

351  

352  
        @par Exception Safety
352  
        @par Exception Safety
353  
        Throws nothing.
353  
        Throws nothing.
354  

354  

355  
        @param s The string to search for
355  
        @param s The string to search for
356  
        @return `true` if the decoded string starts with `s`
356  
        @return `true` if the decoded string starts with `s`
357  
    */
357  
    */
358  
    BOOST_URL_DECL
358  
    BOOST_URL_DECL
359  
    bool
359  
    bool
360  
    starts_with( core::string_view s ) const noexcept;
360  
    starts_with( core::string_view s ) const noexcept;
361  

361  

362  
    /** Checks if the string ends with the given prefix
362  
    /** Checks if the string ends with the given prefix
363  

363  

364  
        @par Example
364  
        @par Example
365  
        @code
365  
        @code
366  
        assert( decode_view( "Program%20Files" ).ends_with("Files") );
366  
        assert( decode_view( "Program%20Files" ).ends_with("Files") );
367  
        @endcode
367  
        @endcode
368  

368  

369  
        @par Complexity
369  
        @par Complexity
370  
        Linear.
370  
        Linear.
371  

371  

372  
        @par Exception Safety
372  
        @par Exception Safety
373  
        Throws nothing.
373  
        Throws nothing.
374  

374  

375  
        @param s The string to search for
375  
        @param s The string to search for
376  
        @return `true` if the decoded string ends with `s`
376  
        @return `true` if the decoded string ends with `s`
377  
    */
377  
    */
378  
    BOOST_URL_DECL
378  
    BOOST_URL_DECL
379  
    bool
379  
    bool
380  
    ends_with( core::string_view s ) const noexcept;
380  
    ends_with( core::string_view s ) const noexcept;
381  

381  

382  
    /** Checks if the string begins with the given prefix
382  
    /** Checks if the string begins with the given prefix
383  

383  

384  
        @par Example
384  
        @par Example
385  
        @code
385  
        @code
386  
        assert( decode_view( "Program%20Files" ).starts_with('P') );
386  
        assert( decode_view( "Program%20Files" ).starts_with('P') );
387  
        @endcode
387  
        @endcode
388  

388  

389  
        @par Complexity
389  
        @par Complexity
390  
        Constant.
390  
        Constant.
391  

391  

392  
        @par Exception Safety
392  
        @par Exception Safety
393  
        Throws nothing.
393  
        Throws nothing.
394  

394  

395  
        @param ch The character to search for
395  
        @param ch The character to search for
396  
        @return `true` if the decoded string starts with `ch`
396  
        @return `true` if the decoded string starts with `ch`
397  
    */
397  
    */
398  
    BOOST_URL_DECL
398  
    BOOST_URL_DECL
399  
    bool
399  
    bool
400  
    starts_with( char ch ) const noexcept;
400  
    starts_with( char ch ) const noexcept;
401  

401  

402  
    /** Checks if the string ends with the given prefix
402  
    /** Checks if the string ends with the given prefix
403  

403  

404  
        @par Example
404  
        @par Example
405  
        @code
405  
        @code
406  
        assert( decode_view( "Program%20Files" ).ends_with('s') );
406  
        assert( decode_view( "Program%20Files" ).ends_with('s') );
407  
        @endcode
407  
        @endcode
408  

408  

409  
        @par Complexity
409  
        @par Complexity
410  
        Constant.
410  
        Constant.
411  

411  

412  
        @par Exception Safety
412  
        @par Exception Safety
413  
        Throws nothing.
413  
        Throws nothing.
414  

414  

415  
        @param ch The character to search for
415  
        @param ch The character to search for
416  
        @return `true` if the decoded string ends with `ch`
416  
        @return `true` if the decoded string ends with `ch`
417  
    */
417  
    */
418  
    BOOST_URL_DECL
418  
    BOOST_URL_DECL
419  
    bool
419  
    bool
420  
    ends_with( char ch ) const noexcept;
420  
    ends_with( char ch ) const noexcept;
421  

421  

422  
    /** Finds the first occurrence of character in this view
422  
    /** Finds the first occurrence of character in this view
423  

423  

424  
        @par Complexity
424  
        @par Complexity
425  
        Linear.
425  
        Linear.
426  

426  

427  
        @par Exception Safety
427  
        @par Exception Safety
428  
        Throws nothing.
428  
        Throws nothing.
429  

429  

430  
        @param ch The character to search for
430  
        @param ch The character to search for
431  
        @return An iterator to the first decoded occurrence of `ch` or `end()`
431  
        @return An iterator to the first decoded occurrence of `ch` or `end()`
432  
    */
432  
    */
433  
    BOOST_URL_DECL
433  
    BOOST_URL_DECL
434  
    const_iterator
434  
    const_iterator
435  
    find( char ch ) const noexcept;
435  
    find( char ch ) const noexcept;
436  

436  

437  
    /** Finds the first occurrence of character in this view
437  
    /** Finds the first occurrence of character in this view
438  

438  

439  
        @par Complexity
439  
        @par Complexity
440  
        Linear.
440  
        Linear.
441  

441  

442  
        @par Exception Safety
442  
        @par Exception Safety
443  
        Throws nothing.
443  
        Throws nothing.
444  

444  

445  
        @param ch The character to search for
445  
        @param ch The character to search for
446  
        @return An iterator to the last occurrence of `ch` or `end()`
446  
        @return An iterator to the last occurrence of `ch` or `end()`
447  
    */
447  
    */
448  
    BOOST_URL_DECL
448  
    BOOST_URL_DECL
449  
    const_iterator
449  
    const_iterator
450  
    rfind( char ch ) const noexcept;
450  
    rfind( char ch ) const noexcept;
451  

451  

452  
    /** Remove the first characters
452  
    /** Remove the first characters
453  

453  

454  
        @par Example
454  
        @par Example
455  
        @code
455  
        @code
456  
        decode_view d( "Program%20Files" );
456  
        decode_view d( "Program%20Files" );
457  
        d.remove_prefix( 8 );
457  
        d.remove_prefix( 8 );
458  
        assert( d == "Files" );
458  
        assert( d == "Files" );
459  
        @endcode
459  
        @endcode
460  

460  

461  
        @par Preconditions
461  
        @par Preconditions
462  
        @code
462  
        @code
463  
        not this->empty()
463  
        not this->empty()
464  
        @endcode
464  
        @endcode
465  

465  

466  
        @par Complexity
466  
        @par Complexity
467  
        Linear.
467  
        Linear.
468  

468  

469  
        @param n The number of characters to remove
469  
        @param n The number of characters to remove
470  
    */
470  
    */
471  
    BOOST_URL_DECL
471  
    BOOST_URL_DECL
472  
    void
472  
    void
473  
    remove_prefix( size_type n );
473  
    remove_prefix( size_type n );
474  

474  

475  
    /** Remove the last characters
475  
    /** Remove the last characters
476  

476  

477  
        @par Example
477  
        @par Example
478  
        @code
478  
        @code
479  
        decode_view d( "Program%20Files" );
479  
        decode_view d( "Program%20Files" );
480  
        d.remove_prefix( 6 );
480  
        d.remove_prefix( 6 );
481  
        assert( d == "Program" );
481  
        assert( d == "Program" );
482  
        @endcode
482  
        @endcode
483  

483  

484  
        @par Preconditions
484  
        @par Preconditions
485  
        @code
485  
        @code
486  
        not this->empty()
486  
        not this->empty()
487  
        @endcode
487  
        @endcode
488  

488  

489  
        @par Complexity
489  
        @par Complexity
490  
        Linear.
490  
        Linear.
491  

491  

492  
        @param n The number of characters to remove
492  
        @param n The number of characters to remove
493  
    */
493  
    */
494  
    BOOST_URL_DECL
494  
    BOOST_URL_DECL
495  
    void
495  
    void
496  
    remove_suffix( size_type n );
496  
    remove_suffix( size_type n );
497  

497  

498  
    /** Return the decoding options
498  
    /** Return the decoding options
499  

499  

500  
        @return The decoding options used by this view
500  
        @return The decoding options used by this view
501  
     */
501  
     */
502  
    encoding_opts
502  
    encoding_opts
503  
    options() const noexcept
503  
    options() const noexcept
504  
    {
504  
    {
505  
        encoding_opts opt;
505  
        encoding_opts opt;
506  
        opt.space_as_plus = space_as_plus_;
506  
        opt.space_as_plus = space_as_plus_;
507  
        return opt;
507  
        return opt;
508  
    }
508  
    }
509  

509  

510  
    //--------------------------------------------
510  
    //--------------------------------------------
511  
    //
511  
    //
512  
    // Comparison
512  
    // Comparison
513  
    //
513  
    //
514  
    //--------------------------------------------
514  
    //--------------------------------------------
515  

515  

516  
    /** Return the result of comparing to another string
516  
    /** Return the result of comparing to another string
517  

517  

518  
        The length of the sequences to compare is the smaller of
518  
        The length of the sequences to compare is the smaller of
519  
        `size()` and `other.size()`.
519  
        `size()` and `other.size()`.
520  

520  

521  
        The function compares the two strings as if by calling
521  
        The function compares the two strings as if by calling
522  
        `char_traits<char>::compare(to_string().data(), v.data(), rlen)`.
522  
        `char_traits<char>::compare(to_string().data(), v.data(), rlen)`.
523  
        This means the comparison is performed with
523  
        This means the comparison is performed with
524  
        percent-decoding applied to the current string.
524  
        percent-decoding applied to the current string.
525  

525  

526  
        @param other string to compare
526  
        @param other string to compare
527  

527  

528  
        @return Negative value if this string is less than the other
528  
        @return Negative value if this string is less than the other
529  
        character sequence, zero if the both character sequences are
529  
        character sequence, zero if the both character sequences are
530  
        equal, positive value if this string is greater than the other
530  
        equal, positive value if this string is greater than the other
531  
        character sequence
531  
        character sequence
532  
    */
532  
    */
533  
    BOOST_CXX14_CONSTEXPR
533  
    BOOST_CXX14_CONSTEXPR
534  
    int
534  
    int
535  
    compare(core::string_view other) const noexcept;
535  
    compare(core::string_view other) const noexcept;
536  

536  

537  
    /** Return the result of comparing to another string
537  
    /** Return the result of comparing to another string
538  

538  

539  
        The length of the sequences to compare is the smaller of
539  
        The length of the sequences to compare is the smaller of
540  
        `size()` and `other.size()`.
540  
        `size()` and `other.size()`.
541  

541  

542  
        The function compares the two strings as if by calling
542  
        The function compares the two strings as if by calling
543  
        `char_traits<char>::compare(to_string().data(), v.to_string().data(), rlen)`.
543  
        `char_traits<char>::compare(to_string().data(), v.to_string().data(), rlen)`.
544  
        This means the comparison is performed with
544  
        This means the comparison is performed with
545  
        percent-decoding applied to the current string.
545  
        percent-decoding applied to the current string.
546  

546  

547  
        @param other string to compare
547  
        @param other string to compare
548  

548  

549  
        @return Negative value if this string is less than the other
549  
        @return Negative value if this string is less than the other
550  
        character sequence, zero if the both character sequences are
550  
        character sequence, zero if the both character sequences are
551  
        equal, positive value if this string is greater than the other
551  
        equal, positive value if this string is greater than the other
552  
        character sequence
552  
        character sequence
553  
    */
553  
    */
554  
    BOOST_CXX14_CONSTEXPR
554  
    BOOST_CXX14_CONSTEXPR
555  
    int
555  
    int
556  
    compare(decode_view other) const noexcept;
556  
    compare(decode_view other) const noexcept;
557  

557  

558  
    //--------------------------------------------
558  
    //--------------------------------------------
559  

559  

560  
    // relational operators
560  
    // relational operators
561  
private:
561  
private:
562  
    template<class S0, class S1>
562  
    template<class S0, class S1>
563  
    using is_match = std::integral_constant<bool,
563  
    using is_match = std::integral_constant<bool,
564  
        // both decode_view or convertible to core::string_view
564  
        // both decode_view or convertible to core::string_view
565  
        (
565  
        (
566  
            std::is_same<typename std::decay<S0>::type, decode_view>::value ||
566  
            std::is_same<typename std::decay<S0>::type, decode_view>::value ||
567  
            std::is_convertible<S0, core::string_view>::value) &&
567  
            std::is_convertible<S0, core::string_view>::value) &&
568  
        (
568  
        (
569  
            std::is_same<typename std::decay<S1>::type, decode_view>::value ||
569  
            std::is_same<typename std::decay<S1>::type, decode_view>::value ||
570  
            std::is_convertible<S1, core::string_view>::value) &&
570  
            std::is_convertible<S1, core::string_view>::value) &&
571  
        // not both are convertible to string view
571  
        // not both are convertible to string view
572  
        (
572  
        (
573  
            !std::is_convertible<S0, core::string_view>::value ||
573  
            !std::is_convertible<S0, core::string_view>::value ||
574  
            !std::is_convertible<S1, core::string_view>::value)>;
574  
            !std::is_convertible<S1, core::string_view>::value)>;
575  

575  

576  
    BOOST_CXX14_CONSTEXPR
576  
    BOOST_CXX14_CONSTEXPR
577  
    static
577  
    static
578  
    int
578  
    int
579  
    decode_compare(decode_view s0, decode_view s1) noexcept
579  
    decode_compare(decode_view s0, decode_view s1) noexcept
580  
    {
580  
    {
581  
        return s0.compare(s1);
581  
        return s0.compare(s1);
582  
    }
582  
    }
583  

583  

584  
    template <class S>
584  
    template <class S>
585  
    BOOST_CXX14_CONSTEXPR
585  
    BOOST_CXX14_CONSTEXPR
586  
    static
586  
    static
587  
    int
587  
    int
588  
    decode_compare(decode_view s0, S const& s1) noexcept
588  
    decode_compare(decode_view s0, S const& s1) noexcept
589  
    {
589  
    {
590  
        return s0.compare(s1);
590  
        return s0.compare(s1);
591  
    }
591  
    }
592  

592  

593  
    template <class S>
593  
    template <class S>
594  
    BOOST_CXX14_CONSTEXPR
594  
    BOOST_CXX14_CONSTEXPR
595  
    static
595  
    static
596  
    int
596  
    int
597  
    decode_compare(S const& s0, decode_view s1) noexcept
597  
    decode_compare(S const& s0, decode_view s1) noexcept
598  
    {
598  
    {
599  
        return -s1.compare(s0);
599  
        return -s1.compare(s0);
600  
    }
600  
    }
601  

601  

602  
public:
602  
public:
603  
#ifndef BOOST_URL_HAS_CONCEPTS
603  
#ifndef BOOST_URL_HAS_CONCEPTS
604  
    /** Compare two decode views for equality
604  
    /** Compare two decode views for equality
605  

605  

606  
        @param lhs The left-hand-side decode view to compare
606  
        @param lhs The left-hand-side decode view to compare
607  
        @param rhs The right-hand-side decode view to compare
607  
        @param rhs The right-hand-side decode view to compare
608  
        @return `true` if decoded `lhs` is equal to the decoded `rhs`
608  
        @return `true` if decoded `lhs` is equal to the decoded `rhs`
609  
     */
609  
     */
610  
    template<class S0, class S1>
610  
    template<class S0, class S1>
611  
    BOOST_CXX14_CONSTEXPR friend auto operator==(
611  
    BOOST_CXX14_CONSTEXPR friend auto operator==(
612  
        S0 const& lhs, S1 const& rhs) noexcept ->
612  
        S0 const& lhs, S1 const& rhs) noexcept ->
613  
        typename std::enable_if<
613  
        typename std::enable_if<
614  
            is_match<S0, S1>::value, bool>::type
614  
            is_match<S0, S1>::value, bool>::type
615  
    {
615  
    {
616  
        return decode_compare(lhs, rhs) == 0;
616  
        return decode_compare(lhs, rhs) == 0;
617  
    }
617  
    }
618  
#else
618  
#else
619  
    /** Compare two decode views for equality
619  
    /** Compare two decode views for equality
620  

620  

621  
        @param lhs The left-hand-side decode view to compare
621  
        @param lhs The left-hand-side decode view to compare
622  
        @param rhs The right-hand-side decode view to compare
622  
        @param rhs The right-hand-side decode view to compare
623  
        @return `true` if decoded `lhs` is equal to the decoded `rhs`
623  
        @return `true` if decoded `lhs` is equal to the decoded `rhs`
624  
     */
624  
     */
625  
    BOOST_CXX14_CONSTEXPR
625  
    BOOST_CXX14_CONSTEXPR
626  
    friend
626  
    friend
627  
    bool
627  
    bool
628  
    operator==(
628  
    operator==(
629  
        decode_view const& lhs,
629  
        decode_view const& lhs,
630  
        decode_view const& rhs) noexcept
630  
        decode_view const& rhs) noexcept
631  
    {
631  
    {
632  
        return decode_compare(lhs, rhs) == 0;
632  
        return decode_compare(lhs, rhs) == 0;
633  
    }
633  
    }
634  

634  

635  
    /** Compare two decode views for equality
635  
    /** Compare two decode views for equality
636  

636  

637  
        @param lhs The left-hand-side decode view to compare
637  
        @param lhs The left-hand-side decode view to compare
638  
        @param rhs The right-hand-side decode view to compare
638  
        @param rhs The right-hand-side decode view to compare
639  
        @return `true` if decoded `lhs` is equal to the decoded `rhs`
639  
        @return `true` if decoded `lhs` is equal to the decoded `rhs`
640  
     */
640  
     */
641  
    template <std::convertible_to<core::string_view> S>
641  
    template <std::convertible_to<core::string_view> S>
642  
    BOOST_CXX14_CONSTEXPR
642  
    BOOST_CXX14_CONSTEXPR
643  
    friend
643  
    friend
644  
    bool
644  
    bool
645  
    operator==(
645  
    operator==(
646  
        decode_view const& lhs,
646  
        decode_view const& lhs,
647  
        S const& rhs) noexcept
647  
        S const& rhs) noexcept
648  
    {
648  
    {
649  
        return decode_compare(lhs, rhs) == 0;
649  
        return decode_compare(lhs, rhs) == 0;
650  
    }
650  
    }
651  

651  

652  
    /** Compare two decode views for equality
652  
    /** Compare two decode views for equality
653  

653  

654  
        @param lhs The left-hand-side decode view to compare
654  
        @param lhs The left-hand-side decode view to compare
655  
        @param rhs The right-hand-side decode view to compare
655  
        @param rhs The right-hand-side decode view to compare
656  
        @return `true` if decoded `lhs` is equal to the decoded `rhs`
656  
        @return `true` if decoded `lhs` is equal to the decoded `rhs`
657  
     */
657  
     */
658  
    template <std::convertible_to<core::string_view> S>
658  
    template <std::convertible_to<core::string_view> S>
659  
    BOOST_CXX14_CONSTEXPR
659  
    BOOST_CXX14_CONSTEXPR
660  
    friend
660  
    friend
661  
    bool
661  
    bool
662  
    operator==(
662  
    operator==(
663  
        S const& lhs,
663  
        S const& lhs,
664  
        decode_view const& rhs) noexcept
664  
        decode_view const& rhs) noexcept
665  
    {
665  
    {
666  
        return decode_compare(lhs, rhs) == 0;
666  
        return decode_compare(lhs, rhs) == 0;
667  
    }
667  
    }
668  
#endif
668  
#endif
669  

669  

670  
#ifndef BOOST_URL_HAS_CONCEPTS
670  
#ifndef BOOST_URL_HAS_CONCEPTS
671  
    /** Compare two decode views for inequality
671  
    /** Compare two decode views for inequality
672  

672  

673  
        @param lhs The left-hand-side decode view to compare
673  
        @param lhs The left-hand-side decode view to compare
674  
        @param rhs The right-hand-side decode view to compare
674  
        @param rhs The right-hand-side decode view to compare
675  
        @return `true` if decoded `lhs` is not equal to the decoded `rhs`
675  
        @return `true` if decoded `lhs` is not equal to the decoded `rhs`
676  
     */
676  
     */
677  
    template<class S0, class S1>
677  
    template<class S0, class S1>
678  
    BOOST_CXX14_CONSTEXPR friend auto operator!=(
678  
    BOOST_CXX14_CONSTEXPR friend auto operator!=(
679  
        S0 const& lhs, S1 const& rhs) noexcept ->
679  
        S0 const& lhs, S1 const& rhs) noexcept ->
680  
        typename std::enable_if<
680  
        typename std::enable_if<
681  
            is_match<S0, S1>::value, bool>::type
681  
            is_match<S0, S1>::value, bool>::type
682  
    {
682  
    {
683  
        return decode_compare(lhs, rhs) != 0;
683  
        return decode_compare(lhs, rhs) != 0;
684  
    }
684  
    }
685  
#else
685  
#else
686  
    /** Compare two decode views for inequality
686  
    /** Compare two decode views for inequality
687  

687  

688  
        @param lhs The left-hand-side decode view to compare
688  
        @param lhs The left-hand-side decode view to compare
689  
        @param rhs The right-hand-side decode view to compare
689  
        @param rhs The right-hand-side decode view to compare
690  
        @return `true` if decoded `lhs` is not equal to the decoded `rhs`
690  
        @return `true` if decoded `lhs` is not equal to the decoded `rhs`
691  
     */
691  
     */
692  
    BOOST_CXX14_CONSTEXPR
692  
    BOOST_CXX14_CONSTEXPR
693  
    friend
693  
    friend
694  
    bool
694  
    bool
695  
    operator!=(
695  
    operator!=(
696  
        decode_view const& lhs,
696  
        decode_view const& lhs,
697  
        decode_view const& rhs) noexcept
697  
        decode_view const& rhs) noexcept
698  
    {
698  
    {
699  
        return decode_compare(lhs, rhs) != 0;
699  
        return decode_compare(lhs, rhs) != 0;
700  
    }
700  
    }
701  

701  

702  
    /** Compare two decode views for inequality
702  
    /** Compare two decode views for inequality
703  

703  

704  
        @param lhs The left-hand-side decode view to compare
704  
        @param lhs The left-hand-side decode view to compare
705  
        @param rhs The right-hand-side decode view to compare
705  
        @param rhs The right-hand-side decode view to compare
706  
        @return `true` if decoded `lhs` is not equal to the decoded `rhs`
706  
        @return `true` if decoded `lhs` is not equal to the decoded `rhs`
707  
     */
707  
     */
708  
    template <std::convertible_to<core::string_view> S>
708  
    template <std::convertible_to<core::string_view> S>
709  
    BOOST_CXX14_CONSTEXPR
709  
    BOOST_CXX14_CONSTEXPR
710  
    friend
710  
    friend
711  
    bool
711  
    bool
712  
    operator!=(
712  
    operator!=(
713  
        decode_view const& lhs,
713  
        decode_view const& lhs,
714  
        S const& rhs) noexcept
714  
        S const& rhs) noexcept
715  
    {
715  
    {
716  
        return decode_compare(lhs, rhs) != 0;
716  
        return decode_compare(lhs, rhs) != 0;
717  
    }
717  
    }
718  

718  

719  
    /** Compare two decode views for inequality
719  
    /** Compare two decode views for inequality
720  

720  

721  
        @param lhs The left-hand-side decode view to compare
721  
        @param lhs The left-hand-side decode view to compare
722  
        @param rhs The right-hand-side decode view to compare
722  
        @param rhs The right-hand-side decode view to compare
723  
        @return `true` if decoded `lhs` is not equal to the decoded `rhs`
723  
        @return `true` if decoded `lhs` is not equal to the decoded `rhs`
724  
     */
724  
     */
725  
    template <std::convertible_to<core::string_view> S>
725  
    template <std::convertible_to<core::string_view> S>
726  
    BOOST_CXX14_CONSTEXPR
726  
    BOOST_CXX14_CONSTEXPR
727  
    friend
727  
    friend
728  
    bool
728  
    bool
729  
    operator!=(
729  
    operator!=(
730  
        S const& lhs,
730  
        S const& lhs,
731  
        decode_view const& rhs) noexcept
731  
        decode_view const& rhs) noexcept
732  
    {
732  
    {
733  
        return decode_compare(lhs, rhs) != 0;
733  
        return decode_compare(lhs, rhs) != 0;
734  
    }
734  
    }
735  
#endif
735  
#endif
736  

736  

737  
#ifndef BOOST_URL_HAS_CONCEPTS
737  
#ifndef BOOST_URL_HAS_CONCEPTS
738  
    /** Compare two decode views for less than
738  
    /** Compare two decode views for less than
739  

739  

740  
        @param lhs The left-hand-side decode view to compare
740  
        @param lhs The left-hand-side decode view to compare
741  
        @param rhs The right-hand-side decode view to compare
741  
        @param rhs The right-hand-side decode view to compare
742  
        @return `true` if decoded `lhs` is less than to the decoded `rhs`
742  
        @return `true` if decoded `lhs` is less than to the decoded `rhs`
743  
     */
743  
     */
744  
    template<class S0, class S1>
744  
    template<class S0, class S1>
745  
    BOOST_CXX14_CONSTEXPR friend auto operator<(
745  
    BOOST_CXX14_CONSTEXPR friend auto operator<(
746  
        S0 const& lhs, S1 const& rhs) noexcept ->
746  
        S0 const& lhs, S1 const& rhs) noexcept ->
747  
        typename std::enable_if<
747  
        typename std::enable_if<
748  
            is_match<S0, S1>::value, bool>::type
748  
            is_match<S0, S1>::value, bool>::type
749  
    {
749  
    {
750  
        return decode_compare(lhs, rhs) < 0;
750  
        return decode_compare(lhs, rhs) < 0;
751  
    }
751  
    }
752  
#else
752  
#else
753  
    /** Compare two decode views for less than
753  
    /** Compare two decode views for less than
754  

754  

755  
        @param lhs The left-hand-side decode view to compare
755  
        @param lhs The left-hand-side decode view to compare
756  
        @param rhs The right-hand-side decode view to compare
756  
        @param rhs The right-hand-side decode view to compare
757  
        @return `true` if decoded `lhs` is less than to the decoded `rhs`
757  
        @return `true` if decoded `lhs` is less than to the decoded `rhs`
758  
     */
758  
     */
759  
    BOOST_CXX14_CONSTEXPR
759  
    BOOST_CXX14_CONSTEXPR
760  
    friend
760  
    friend
761  
    bool
761  
    bool
762  
    operator<(
762  
    operator<(
763  
        decode_view const& lhs,
763  
        decode_view const& lhs,
764  
        decode_view const& rhs) noexcept
764  
        decode_view const& rhs) noexcept
765  
    {
765  
    {
766  
        return decode_compare(lhs, rhs) < 0;
766  
        return decode_compare(lhs, rhs) < 0;
767  
    }
767  
    }
768  

768  

769  
    /** Compare two decode views for less than
769  
    /** Compare two decode views for less than
770  

770  

771  
        @param lhs The left-hand-side decode view to compare
771  
        @param lhs The left-hand-side decode view to compare
772  
        @param rhs The right-hand-side decode view to compare
772  
        @param rhs The right-hand-side decode view to compare
773  
        @return `true` if decoded `lhs` is less than to the decoded `rhs`
773  
        @return `true` if decoded `lhs` is less than to the decoded `rhs`
774  
     */
774  
     */
775  
    template <std::convertible_to<core::string_view> S>
775  
    template <std::convertible_to<core::string_view> S>
776  
    BOOST_CXX14_CONSTEXPR
776  
    BOOST_CXX14_CONSTEXPR
777  
    friend
777  
    friend
778  
    bool
778  
    bool
779  
    operator<(
779  
    operator<(
780  
        decode_view const& lhs,
780  
        decode_view const& lhs,
781  
        S const& rhs) noexcept
781  
        S const& rhs) noexcept
782  
    {
782  
    {
783  
        return decode_compare(lhs, rhs) < 0;
783  
        return decode_compare(lhs, rhs) < 0;
784  
    }
784  
    }
785  

785  

786  
    /** Compare two decode views for less than
786  
    /** Compare two decode views for less than
787  

787  

788  
        @param lhs The left-hand-side decode view to compare
788  
        @param lhs The left-hand-side decode view to compare
789  
        @param rhs The right-hand-side decode view to compare
789  
        @param rhs The right-hand-side decode view to compare
790  
        @return `true` if decoded `lhs` is less than to the decoded `rhs`
790  
        @return `true` if decoded `lhs` is less than to the decoded `rhs`
791  
     */
791  
     */
792  
    template <std::convertible_to<core::string_view> S>
792  
    template <std::convertible_to<core::string_view> S>
793  
    BOOST_CXX14_CONSTEXPR
793  
    BOOST_CXX14_CONSTEXPR
794  
    friend
794  
    friend
795  
    bool
795  
    bool
796  
    operator<(
796  
    operator<(
797  
        S const& lhs,
797  
        S const& lhs,
798  
        decode_view const& rhs) noexcept
798  
        decode_view const& rhs) noexcept
799  
    {
799  
    {
800  
        return decode_compare(lhs, rhs) < 0;
800  
        return decode_compare(lhs, rhs) < 0;
801  
    }
801  
    }
802  
#endif
802  
#endif
803  

803  

804  
#ifndef BOOST_URL_HAS_CONCEPTS
804  
#ifndef BOOST_URL_HAS_CONCEPTS
805  
    /** Compare two decode views for less than or equal
805  
    /** Compare two decode views for less than or equal
806  

806  

807  
        @param lhs The left-hand-side decode view to compare
807  
        @param lhs The left-hand-side decode view to compare
808  
        @param rhs The right-hand-side decode view to compare
808  
        @param rhs The right-hand-side decode view to compare
809  
        @return `true` if decoded `lhs` is less than or equal to the decoded `rhs`
809  
        @return `true` if decoded `lhs` is less than or equal to the decoded `rhs`
810  
     */
810  
     */
811  
    template<class S0, class S1>
811  
    template<class S0, class S1>
812  
    BOOST_CXX14_CONSTEXPR friend auto operator<=(
812  
    BOOST_CXX14_CONSTEXPR friend auto operator<=(
813  
        S0 const& lhs, S1 const& rhs) noexcept ->
813  
        S0 const& lhs, S1 const& rhs) noexcept ->
814  
        typename std::enable_if<
814  
        typename std::enable_if<
815  
            is_match<S0, S1>::value, bool>::type
815  
            is_match<S0, S1>::value, bool>::type
816  
    {
816  
    {
817  
        return decode_compare(lhs, rhs) <= 0;
817  
        return decode_compare(lhs, rhs) <= 0;
818  
    }
818  
    }
819  
#else
819  
#else
820  
    /** Compare two decode views for less than or equal
820  
    /** Compare two decode views for less than or equal
821  

821  

822  
        @param lhs The left-hand-side decode view to compare
822  
        @param lhs The left-hand-side decode view to compare
823  
        @param rhs The right-hand-side decode view to compare
823  
        @param rhs The right-hand-side decode view to compare
824  
        @return `true` if decoded `lhs` is less than or equal to the decoded `rhs`
824  
        @return `true` if decoded `lhs` is less than or equal to the decoded `rhs`
825  
     */
825  
     */
826  
    BOOST_CXX14_CONSTEXPR
826  
    BOOST_CXX14_CONSTEXPR
827  
    friend
827  
    friend
828  
    bool
828  
    bool
829  
    operator<=(
829  
    operator<=(
830  
        decode_view const& lhs,
830  
        decode_view const& lhs,
831  
        decode_view const& rhs) noexcept
831  
        decode_view const& rhs) noexcept
832  
    {
832  
    {
833  
        return decode_compare(lhs, rhs) <= 0;
833  
        return decode_compare(lhs, rhs) <= 0;
834  
    }
834  
    }
835  

835  

836  
    /** Compare two decode views for less than or equal
836  
    /** Compare two decode views for less than or equal
837  

837  

838  
        @param lhs The left-hand-side decode view to compare
838  
        @param lhs The left-hand-side decode view to compare
839  
        @param rhs The right-hand-side decode view to compare
839  
        @param rhs The right-hand-side decode view to compare
840  
        @return `true` if decoded `lhs` is less than or equal to the decoded `rhs`
840  
        @return `true` if decoded `lhs` is less than or equal to the decoded `rhs`
841  
     */
841  
     */
842  
    template <std::convertible_to<core::string_view> S>
842  
    template <std::convertible_to<core::string_view> S>
843  
    BOOST_CXX14_CONSTEXPR
843  
    BOOST_CXX14_CONSTEXPR
844  
    friend
844  
    friend
845  
    bool
845  
    bool
846  
    operator<=(
846  
    operator<=(
847  
        decode_view const& lhs,
847  
        decode_view const& lhs,
848  
        S const& rhs) noexcept
848  
        S const& rhs) noexcept
849  
    {
849  
    {
850  
        return decode_compare(lhs, rhs) <= 0;
850  
        return decode_compare(lhs, rhs) <= 0;
851  
    }
851  
    }
852  

852  

853  
    /** Compare two decode views for less than or equal
853  
    /** Compare two decode views for less than or equal
854  

854  

855  
        @param lhs The left-hand-side decode view to compare
855  
        @param lhs The left-hand-side decode view to compare
856  
        @param rhs The right-hand-side decode view to compare
856  
        @param rhs The right-hand-side decode view to compare
857  
        @return `true` if decoded `lhs` is less than or equal to the decoded `rhs`
857  
        @return `true` if decoded `lhs` is less than or equal to the decoded `rhs`
858  
     */
858  
     */
859  
    template <std::convertible_to<core::string_view> S>
859  
    template <std::convertible_to<core::string_view> S>
860  
    BOOST_CXX14_CONSTEXPR
860  
    BOOST_CXX14_CONSTEXPR
861  
    friend
861  
    friend
862  
    bool
862  
    bool
863  
    operator<=(
863  
    operator<=(
864  
        S const& lhs,
864  
        S const& lhs,
865  
        decode_view const& rhs) noexcept
865  
        decode_view const& rhs) noexcept
866  
    {
866  
    {
867  
        return decode_compare(lhs, rhs) <= 0;
867  
        return decode_compare(lhs, rhs) <= 0;
868  
    }
868  
    }
869  
#endif
869  
#endif
870  

870  

871  
#ifndef BOOST_URL_HAS_CONCEPTS
871  
#ifndef BOOST_URL_HAS_CONCEPTS
872  
    /** Compare two decode views for greater than
872  
    /** Compare two decode views for greater than
873  

873  

874  
        @param lhs The left-hand-side decode view to compare
874  
        @param lhs The left-hand-side decode view to compare
875  
        @param rhs The right-hand-side decode view to compare
875  
        @param rhs The right-hand-side decode view to compare
876  
        @return `true` if decoded `lhs` is greater than to the decoded `rhs`
876  
        @return `true` if decoded `lhs` is greater than to the decoded `rhs`
877  
     */
877  
     */
878  
    template<class S0, class S1>
878  
    template<class S0, class S1>
879  
    BOOST_CXX14_CONSTEXPR friend auto operator>(
879  
    BOOST_CXX14_CONSTEXPR friend auto operator>(
880  
        S0 const& lhs, S1 const& rhs) noexcept ->
880  
        S0 const& lhs, S1 const& rhs) noexcept ->
881  
        typename std::enable_if<
881  
        typename std::enable_if<
882  
            is_match<S0, S1>::value, bool>::type
882  
            is_match<S0, S1>::value, bool>::type
883  
    {
883  
    {
884  
        return decode_compare(lhs, rhs) > 0;
884  
        return decode_compare(lhs, rhs) > 0;
885  
    }
885  
    }
886  
#else
886  
#else
887  
    /** Compare two decode views for greater than
887  
    /** Compare two decode views for greater than
888  

888  

889  
        @param lhs The left-hand-side decode view to compare
889  
        @param lhs The left-hand-side decode view to compare
890  
        @param rhs The right-hand-side decode view to compare
890  
        @param rhs The right-hand-side decode view to compare
891  
        @return `true` if decoded `lhs` is greater than to the decoded `rhs`
891  
        @return `true` if decoded `lhs` is greater than to the decoded `rhs`
892  
     */
892  
     */
893  
    BOOST_CXX14_CONSTEXPR
893  
    BOOST_CXX14_CONSTEXPR
894  
    friend
894  
    friend
895  
    bool
895  
    bool
896  
    operator>(
896  
    operator>(
897  
        decode_view const& lhs,
897  
        decode_view const& lhs,
898  
        decode_view const& rhs) noexcept
898  
        decode_view const& rhs) noexcept
899  
    {
899  
    {
900  
        return decode_compare(lhs, rhs) > 0;
900  
        return decode_compare(lhs, rhs) > 0;
901  
    }
901  
    }
902  

902  

903  
    /** Compare two decode views for greater than
903  
    /** Compare two decode views for greater than
904  

904  

905  
        @param lhs The left-hand-side decode view to compare
905  
        @param lhs The left-hand-side decode view to compare
906  
        @param rhs The right-hand-side decode view to compare
906  
        @param rhs The right-hand-side decode view to compare
907  
        @return `true` if decoded `lhs` is greater than to the decoded `rhs`
907  
        @return `true` if decoded `lhs` is greater than to the decoded `rhs`
908  
     */
908  
     */
909  
    template <std::convertible_to<core::string_view> S>
909  
    template <std::convertible_to<core::string_view> S>
910  
    BOOST_CXX14_CONSTEXPR
910  
    BOOST_CXX14_CONSTEXPR
911  
    friend
911  
    friend
912  
    bool
912  
    bool
913  
    operator>(
913  
    operator>(
914  
        decode_view const& lhs,
914  
        decode_view const& lhs,
915  
        S const& rhs) noexcept
915  
        S const& rhs) noexcept
916  
    {
916  
    {
917  
        return decode_compare(lhs, rhs) > 0;
917  
        return decode_compare(lhs, rhs) > 0;
918  
    }
918  
    }
919  

919  

920  
    /** Compare two decode views for greater than
920  
    /** Compare two decode views for greater than
921  

921  

922  
        @param lhs The left-hand-side decode view to compare
922  
        @param lhs The left-hand-side decode view to compare
923  
        @param rhs The right-hand-side decode view to compare
923  
        @param rhs The right-hand-side decode view to compare
924  
        @return `true` if decoded `lhs` is greater than to the decoded `rhs`
924  
        @return `true` if decoded `lhs` is greater than to the decoded `rhs`
925  
     */
925  
     */
926  
    template <std::convertible_to<core::string_view> S>
926  
    template <std::convertible_to<core::string_view> S>
927  
    BOOST_CXX14_CONSTEXPR
927  
    BOOST_CXX14_CONSTEXPR
928  
    friend
928  
    friend
929  
    bool
929  
    bool
930  
    operator>(
930  
    operator>(
931  
        S const& lhs,
931  
        S const& lhs,
932  
        decode_view const& rhs) noexcept
932  
        decode_view const& rhs) noexcept
933  
    {
933  
    {
934  
        return decode_compare(lhs, rhs) > 0;
934  
        return decode_compare(lhs, rhs) > 0;
935  
    }
935  
    }
936  
#endif
936  
#endif
937  

937  

938  
#ifndef BOOST_URL_HAS_CONCEPTS
938  
#ifndef BOOST_URL_HAS_CONCEPTS
939  
    /** Compare two decode views for greater than or equal
939  
    /** Compare two decode views for greater than or equal
940  

940  

941  
        @param lhs The left-hand-side decode view to compare
941  
        @param lhs The left-hand-side decode view to compare
942  
        @param rhs The right-hand-side decode view to compare
942  
        @param rhs The right-hand-side decode view to compare
943  
        @return `true` if decoded `lhs` is greater than or equal to the decoded `rhs`
943  
        @return `true` if decoded `lhs` is greater than or equal to the decoded `rhs`
944  
     */
944  
     */
945  
    template<class S0, class S1>
945  
    template<class S0, class S1>
946  
    BOOST_CXX14_CONSTEXPR friend auto operator>=(
946  
    BOOST_CXX14_CONSTEXPR friend auto operator>=(
947  
        S0 const& lhs, S1 const& rhs) noexcept ->
947  
        S0 const& lhs, S1 const& rhs) noexcept ->
948  
        typename std::enable_if<
948  
        typename std::enable_if<
949  
            is_match<S0, S1>::value, bool>::type
949  
            is_match<S0, S1>::value, bool>::type
950  
    {
950  
    {
951  
        return decode_compare(lhs, rhs) >= 0;
951  
        return decode_compare(lhs, rhs) >= 0;
952  
    }
952  
    }
953  
#else
953  
#else
954  
    /** Compare two decode views for greater than or equal
954  
    /** Compare two decode views for greater than or equal
955  

955  

956  
        @param lhs The left-hand-side decode view to compare
956  
        @param lhs The left-hand-side decode view to compare
957  
        @param rhs The right-hand-side decode view to compare
957  
        @param rhs The right-hand-side decode view to compare
958  
        @return `true` if decoded `lhs` is greater than or equal to the decoded `rhs`
958  
        @return `true` if decoded `lhs` is greater than or equal to the decoded `rhs`
959  
     */
959  
     */
960  
    BOOST_CXX14_CONSTEXPR
960  
    BOOST_CXX14_CONSTEXPR
961  
    friend
961  
    friend
962  
    bool
962  
    bool
963  
    operator>=(
963  
    operator>=(
964  
        decode_view const& lhs,
964  
        decode_view const& lhs,
965  
        decode_view const& rhs) noexcept
965  
        decode_view const& rhs) noexcept
966  
    {
966  
    {
967  
        return decode_compare(lhs, rhs) >= 0;
967  
        return decode_compare(lhs, rhs) >= 0;
968  
    }
968  
    }
969  

969  

970  
    /** Compare two decode views for greater than or equal
970  
    /** Compare two decode views for greater than or equal
971  

971  

972  
        @param lhs The left-hand-side decode view to compare
972  
        @param lhs The left-hand-side decode view to compare
973  
        @param rhs The right-hand-side decode view to compare
973  
        @param rhs The right-hand-side decode view to compare
974  
        @return `true` if decoded `lhs` is greater than or equal to the decoded `rhs`
974  
        @return `true` if decoded `lhs` is greater than or equal to the decoded `rhs`
975  
     */
975  
     */
976  
    template <std::convertible_to<core::string_view> S>
976  
    template <std::convertible_to<core::string_view> S>
977  
    BOOST_CXX14_CONSTEXPR
977  
    BOOST_CXX14_CONSTEXPR
978  
    friend
978  
    friend
979  
    bool
979  
    bool
980  
    operator>=(
980  
    operator>=(
981  
        decode_view const& lhs,
981  
        decode_view const& lhs,
982  
        S const& rhs) noexcept
982  
        S const& rhs) noexcept
983  
    {
983  
    {
984  
        return decode_compare(lhs, rhs) >= 0;
984  
        return decode_compare(lhs, rhs) >= 0;
985  
    }
985  
    }
986  

986  

987  
    /** Compare two decode views for greater than or equal
987  
    /** Compare two decode views for greater than or equal
988  

988  

989  
        @param lhs The left-hand-side decode view to compare
989  
        @param lhs The left-hand-side decode view to compare
990  
        @param rhs The right-hand-side decode view to compare
990  
        @param rhs The right-hand-side decode view to compare
991  
        @return `true` if decoded `lhs` is greater than or equal to the decoded `rhs`
991  
        @return `true` if decoded `lhs` is greater than or equal to the decoded `rhs`
992  
     */
992  
     */
993  
    template <std::convertible_to<core::string_view> S>
993  
    template <std::convertible_to<core::string_view> S>
994  
    BOOST_CXX14_CONSTEXPR
994  
    BOOST_CXX14_CONSTEXPR
995  
    friend
995  
    friend
996  
    bool
996  
    bool
997  
    operator>=(
997  
    operator>=(
998  
        S const& lhs,
998  
        S const& lhs,
999  
        decode_view const& rhs) noexcept
999  
        decode_view const& rhs) noexcept
1000  
    {
1000  
    {
1001  
        return decode_compare(lhs, rhs) >= 0;
1001  
        return decode_compare(lhs, rhs) >= 0;
1002  
    }
1002  
    }
1003  
#endif
1003  
#endif
1004  

1004  

1005  
    /** Format the string with percent-decoding applied to the output stream
1005  
    /** Format the string with percent-decoding applied to the output stream
1006  

1006  

1007  
        This hidden friend function serializes the decoded view
1007  
        This hidden friend function serializes the decoded view
1008  
        to the output stream.
1008  
        to the output stream.
1009  

1009  

1010  
        @return A reference to the output stream, for chaining
1010  
        @return A reference to the output stream, for chaining
1011  

1011  

1012  
        @param os The output stream to write to
1012  
        @param os The output stream to write to
1013  

1013  

1014  
        @param s The decoded view to write
1014  
        @param s The decoded view to write
1015  
    */
1015  
    */
1016  
    friend
1016  
    friend
1017  
    std::ostream&
1017  
    std::ostream&
1018  
    operator<<(
1018  
    operator<<(
1019  
        std::ostream& os,
1019  
        std::ostream& os,
1020  
        decode_view const& s)
1020  
        decode_view const& s)
1021  
    {
1021  
    {
1022  
        // hidden friend
1022  
        // hidden friend
1023  
        s.write(os);
1023  
        s.write(os);
1024  
        return os;
1024  
        return os;
1025  
    }
1025  
    }
1026  

1026  

1027  
private:
1027  
private:
1028  
    BOOST_URL_DECL
1028  
    BOOST_URL_DECL
1029  
    void
1029  
    void
1030  
    write(std::ostream& os) const;
1030  
    write(std::ostream& os) const;
1031  
};
1031  
};
1032  

1032  

1033  
/** Format the string with percent-decoding applied to the output stream
1033  
/** Format the string with percent-decoding applied to the output stream
1034  

1034  

1035  
    This function serializes the decoded view
1035  
    This function serializes the decoded view
1036  
    to the output stream.
1036  
    to the output stream.
1037  

1037  

1038  
    @return A reference to the output stream, for chaining
1038  
    @return A reference to the output stream, for chaining
1039  

1039  

1040  
    @param os The output stream to write to
1040  
    @param os The output stream to write to
1041  

1041  

1042  
    @param s The decoded view to write
1042  
    @param s The decoded view to write
1043  
*/
1043  
*/
1044  
inline
1044  
inline
1045  
std::ostream&
1045  
std::ostream&
1046  
operator<<(
1046  
operator<<(
1047  
    std::ostream& os,
1047  
    std::ostream& os,
1048  
    decode_view const& s);
1048  
    decode_view const& s);
1049  

1049  

1050  
//------------------------------------------------
1050  
//------------------------------------------------
1051  

1051  

1052  
inline
1052  
inline
1053  
decode_view
1053  
decode_view
1054  
pct_string_view::operator*() const noexcept
1054  
pct_string_view::operator*() const noexcept
1055  
{
1055  
{
1056  
    return decode_view(*this);
1056  
    return decode_view(*this);
1057  
}
1057  
}
1058  

1058  

1059  
namespace detail {
1059  
namespace detail {
1060  
template<class... Args>
1060  
template<class... Args>
1061  
decode_view
1061  
decode_view
1062  
make_decode_view(
1062  
make_decode_view(
1063  
    Args&&... args) noexcept
1063  
    Args&&... args) noexcept
1064  
{
1064  
{
1065  
    return decode_view(
1065  
    return decode_view(
1066  
        std::forward<Args>(args)...);
1066  
        std::forward<Args>(args)...);
1067  
}
1067  
}
1068  
} // detail
1068  
} // detail
1069  

1069  

1070  
//------------------------------------------------
1070  
//------------------------------------------------
1071  

1071  

1072  
} // urls
1072  
} // urls
1073  
} // boost
1073  
} // boost
1074  

1074  

1075  
#include <boost/url/impl/decode_view.hpp>
1075  
#include <boost/url/impl/decode_view.hpp>
1076  

1076  

1077  
//------------------------------------------------
1077  
//------------------------------------------------
1078  
//
1078  
//
1079  
// std::ranges::enable_borrowed_range
1079  
// std::ranges::enable_borrowed_range
1080  
//
1080  
//
1081  
//------------------------------------------------
1081  
//------------------------------------------------
1082  

1082  

1083  
#ifdef BOOST_URL_HAS_CONCEPTS
1083  
#ifdef BOOST_URL_HAS_CONCEPTS
1084  
#include <ranges>
1084  
#include <ranges>
1085  
namespace std::ranges {
1085  
namespace std::ranges {
1086  
    template<>
1086  
    template<>
1087  
    inline constexpr bool
1087  
    inline constexpr bool
1088  
        enable_borrowed_range<
1088  
        enable_borrowed_range<
1089  
            boost::urls::decode_view> = true;
1089  
            boost::urls::decode_view> = true;
1090  
} // std::ranges
1090  
} // std::ranges
1091  
#endif
1091  
#endif
1092  

1092  

1093  
#endif
1093  
#endif