1  
//
1  
//
2  
// Copyright (c) 2022 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2022 Vinnie Falco (vinnie.falco@gmail.com)
 
3 +
// Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
3  
//
4  
//
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5  
// 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)
6  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
//
7  
//
7  
// Official repository: https://github.com/boostorg/url
8  
// Official repository: https://github.com/boostorg/url
8  
//
9  
//
9  

10  

10  
#ifndef BOOST_URL_PCT_STRING_VIEW_HPP
11  
#ifndef BOOST_URL_PCT_STRING_VIEW_HPP
11  
#define BOOST_URL_PCT_STRING_VIEW_HPP
12  
#define BOOST_URL_PCT_STRING_VIEW_HPP
12  

13  

13  
#include <boost/url/detail/config.hpp>
14  
#include <boost/url/detail/config.hpp>
14  
#include <boost/url/encoding_opts.hpp>
15  
#include <boost/url/encoding_opts.hpp>
15  
#include <boost/url/error_types.hpp>
16  
#include <boost/url/error_types.hpp>
16  
#include <boost/core/detail/string_view.hpp>
17  
#include <boost/core/detail/string_view.hpp>
17  
#include <boost/url/grammar/string_token.hpp>
18  
#include <boost/url/grammar/string_token.hpp>
18  
#include <boost/url/grammar/string_view_base.hpp>
19  
#include <boost/url/grammar/string_view_base.hpp>
19  
#include <cstddef>
20  
#include <cstddef>
20  
#include <iterator>
21  
#include <iterator>
21  
#include <string>
22  
#include <string>
22  
#include <type_traits>
23  
#include <type_traits>
23  
#include <utility>
24  
#include <utility>
24  

25  

25  
namespace boost {
26  
namespace boost {
26  
namespace urls {
27  
namespace urls {
27  

28  

28  
//------------------------------------------------
29  
//------------------------------------------------
29  

30  

30  
#ifndef BOOST_URL_DOCS
31  
#ifndef BOOST_URL_DOCS
31  
class decode_view;
32  
class decode_view;
32  
class pct_string_view;
33  
class pct_string_view;
33  

34  

 
35 +
BOOST_CXX14_CONSTEXPR
34  
pct_string_view
36  
pct_string_view
35  
make_pct_string_view_unsafe(
37  
make_pct_string_view_unsafe(
36  
    char const*, std::size_t,
38  
    char const*, std::size_t,
37  
        std::size_t) noexcept;
39  
        std::size_t) noexcept;
38  

40  

39  
namespace detail {
41  
namespace detail {
40  
core::string_view&
42  
core::string_view&
41  
ref(pct_string_view& s) noexcept;
43  
ref(pct_string_view& s) noexcept;
42  
} // detail
44  
} // detail
43  
#endif
45  
#endif
44  

46  

45  
//------------------------------------------------
47  
//------------------------------------------------
46  

48  

47  
/** A reference to a valid percent-encoded string
49  
/** A reference to a valid percent-encoded string
48  

50  

49  
    Objects of this type behave like a
51  
    Objects of this type behave like a
50  
    `core::string_view` and have the same interface,
52  
    `core::string_view` and have the same interface,
51  
    but offer an additional invariant: they can
53  
    but offer an additional invariant: they can
52  
    only be constructed from strings containing
54  
    only be constructed from strings containing
53  
    valid percent-escapes.
55  
    valid percent-escapes.
54  

56  

55  
    Attempting construction from a string
57  
    Attempting construction from a string
56  
    containing invalid or malformed percent
58  
    containing invalid or malformed percent
57  
    escapes results in an exception.
59  
    escapes results in an exception.
58  
*/
60  
*/
59  
class pct_string_view final
61  
class pct_string_view final
60  
    : public grammar::string_view_base
62  
    : public grammar::string_view_base
61  
{
63  
{
62  
    std::size_t dn_ = 0;
64  
    std::size_t dn_ = 0;
63  

65  

64  
#ifndef BOOST_URL_DOCS
66  
#ifndef BOOST_URL_DOCS
65  
    friend
67  
    friend
 
68 +
    BOOST_CXX14_CONSTEXPR
66  
    pct_string_view
69  
    pct_string_view
67  
    make_pct_string_view_unsafe(
70  
    make_pct_string_view_unsafe(
68  
        char const*, std::size_t,
71  
        char const*, std::size_t,
69  
            std::size_t) noexcept;
72  
            std::size_t) noexcept;
70  

73  

71  
    friend
74  
    friend
72  
    core::string_view&
75  
    core::string_view&
73  
    detail::ref(pct_string_view&) noexcept;
76  
    detail::ref(pct_string_view&) noexcept;
74  
#endif
77  
#endif
75  

78  

76  
    // unsafe
79  
    // unsafe
77  
    BOOST_CXX14_CONSTEXPR
80  
    BOOST_CXX14_CONSTEXPR
78  
    pct_string_view(
81  
    pct_string_view(
79  
        char const* data,
82  
        char const* data,
80  
        std::size_t size,
83  
        std::size_t size,
81  
        std::size_t dn) noexcept
84  
        std::size_t dn) noexcept
82  
        : string_view_base(data, size)
85  
        : string_view_base(data, size)
83  
        , dn_(dn)
86  
        , dn_(dn)
84  
    {
87  
    {
85  
    }
88  
    }
86  

89  

87  
    BOOST_URL_DECL
90  
    BOOST_URL_DECL
88  
    void
91  
    void
89  
    decode_impl(
92  
    decode_impl(
90  
        string_token::arg& dest,
93  
        string_token::arg& dest,
91  
        encoding_opts opt) const;
94  
        encoding_opts opt) const;
92  

95  

93  
public:
96  
public:
94  
    /** Constructor
97  
    /** Constructor
95  

98  

96  
        Default constructed string are empty.
99  
        Default constructed string are empty.
97  

100  

98  
        @par Complexity
101  
        @par Complexity
99  
        Constant.
102  
        Constant.
100  

103  

101  
        @par Exception Safety
104  
        @par Exception Safety
102  
        Throws nothing.
105  
        Throws nothing.
103  
    */
106  
    */
104  
    constexpr pct_string_view() = default;
107  
    constexpr pct_string_view() = default;
105  

108  

106  
    /** Constructor
109  
    /** Constructor
107  

110  

108  
        The copy references the same
111  
        The copy references the same
109  
        underlying character buffer.
112  
        underlying character buffer.
110  
        Ownership is not transferred.
113  
        Ownership is not transferred.
111  

114  

112  
        @par Postconditions
115  
        @par Postconditions
113  
        @code
116  
        @code
114  
        this->data() == other.data()
117  
        this->data() == other.data()
115  
        @endcode
118  
        @endcode
116  

119  

117  
        @par Complexity
120  
        @par Complexity
118  
        Constant.
121  
        Constant.
119  

122  

120  
        @par Exception Safety
123  
        @par Exception Safety
121  
        Throws nothing.
124  
        Throws nothing.
122  

125  

123  
        @param other The string to copy.
126  
        @param other The string to copy.
124  

127  

125  
    */
128  
    */
126  
    constexpr
129  
    constexpr
127  
    pct_string_view(
130  
    pct_string_view(
128  
        pct_string_view const& other) = default;
131  
        pct_string_view const& other) = default;
129  

132  

130  
    /** Constructor
133  
    /** Constructor
131  

134  

132  
        The newly constructed string references
135  
        The newly constructed string references
133  
        the specified character buffer.
136  
        the specified character buffer.
134  
        Ownership is not transferred.
137  
        Ownership is not transferred.
135  

138  

136  
        @par Postconditions
139  
        @par Postconditions
137  
        @code
140  
        @code
138  
        this->data() == core::string_view(s).data()
141  
        this->data() == core::string_view(s).data()
139  
        @endcode
142  
        @endcode
140  

143  

141  
        @par Complexity
144  
        @par Complexity
142  
        Linear in `core::string_view(s).size()`.
145  
        Linear in `core::string_view(s).size()`.
143  

146  

144  
        @par Exception Safety
147  
        @par Exception Safety
145  
        Exceptions thrown on invalid input.
148  
        Exceptions thrown on invalid input.
146  

149  

147  
        @throw system_error
150  
        @throw system_error
148  
        The string contains an invalid percent encoding.
151  
        The string contains an invalid percent encoding.
149  

152  

150  
        @tparam String A type convertible to `core::string_view`
153  
        @tparam String A type convertible to `core::string_view`
151  

154  

152  
        @param s The string to construct from.
155  
        @param s The string to construct from.
153  
    */
156  
    */
154  
    template<
157  
    template<
155  
        BOOST_URL_CONSTRAINT(std::convertible_to<core::string_view>) String
158  
        BOOST_URL_CONSTRAINT(std::convertible_to<core::string_view>) String
156  
#ifndef BOOST_URL_DOCS
159  
#ifndef BOOST_URL_DOCS
157  
        , class = typename std::enable_if<
160  
        , class = typename std::enable_if<
158  
            std::is_convertible<
161  
            std::is_convertible<
159  
                String,
162  
                String,
160  
                core::string_view
163  
                core::string_view
161  
                    >::value>::type
164  
                    >::value>::type
162  
#endif
165  
#endif
163  
    >
166  
    >
164  
    BOOST_CXX14_CONSTEXPR
167  
    BOOST_CXX14_CONSTEXPR
165  
    pct_string_view(
168  
    pct_string_view(
166  
        String const& s)
169  
        String const& s)
167  
        : pct_string_view(
170  
        : pct_string_view(
168  
            detail::to_sv(s))
171  
            detail::to_sv(s))
169  
    {
172  
    {
170  
    }
173  
    }
171  

174  

172  
    /** Constructor (deleted)
175  
    /** Constructor (deleted)
173  
    */
176  
    */
174  
    pct_string_view(
177  
    pct_string_view(
175  
        std::nullptr_t) = delete;
178  
        std::nullptr_t) = delete;
176  

179  

177  
    /** Constructor
180  
    /** Constructor
178  

181  

179  
        The newly constructed string references
182  
        The newly constructed string references
180  
        the specified character buffer. Ownership
183  
        the specified character buffer. Ownership
181  
        is not transferred.
184  
        is not transferred.
182  

185  

183  
        @par Postconditions
186  
        @par Postconditions
184  
        @code
187  
        @code
185  
        this->data() == s && this->size() == len
188  
        this->data() == s && this->size() == len
186  
        @endcode
189  
        @endcode
187  

190  

188  
        @par Complexity
191  
        @par Complexity
189  
        Linear in `len`.
192  
        Linear in `len`.
190  

193  

191  
        @par Exception Safety
194  
        @par Exception Safety
192  
        Exceptions thrown on invalid input.
195  
        Exceptions thrown on invalid input.
193  

196  

194  
        @throw system_error
197  
        @throw system_error
195  
         The string contains an invalid percent encoding.
198  
         The string contains an invalid percent encoding.
196  

199  

197  
        @param s The string to construct from.
200  
        @param s The string to construct from.
198  
        @param len The length of the string.
201  
        @param len The length of the string.
199  
    */
202  
    */
200  
    pct_string_view(
203  
    pct_string_view(
201  
        char const* s,
204  
        char const* s,
202  
        std::size_t len)
205  
        std::size_t len)
203  
        : pct_string_view(
206  
        : pct_string_view(
204  
            core::string_view(s, len))
207  
            core::string_view(s, len))
205  
    {
208  
    {
206  
    }
209  
    }
207  

210  

208  
    /** Constructor
211  
    /** Constructor
209  

212  

210  
        The newly constructed string references
213  
        The newly constructed string references
211  
        the specified character buffer. Ownership
214  
        the specified character buffer. Ownership
212  
        is not transferred.
215  
        is not transferred.
213  

216  

214  
        @par Postconditions
217  
        @par Postconditions
215  
        @code
218  
        @code
216  
        this->data() == s.data() && this->size() == s.size()
219  
        this->data() == s.data() && this->size() == s.size()
217  
        @endcode
220  
        @endcode
218  

221  

219  
        @par Complexity
222  
        @par Complexity
220  
        Linear in `s.size()`.
223  
        Linear in `s.size()`.
221  

224  

222  
        @par Exception Safety
225  
        @par Exception Safety
223  
        Exceptions thrown on invalid input.
226  
        Exceptions thrown on invalid input.
224  

227  

225  
        @throw system_error
228  
        @throw system_error
226  
        The string contains an invalid percent encoding.
229  
        The string contains an invalid percent encoding.
227  

230  

228  
        @param s The string to construct from.
231  
        @param s The string to construct from.
229  
    */
232  
    */
230  
    BOOST_URL_DECL
233  
    BOOST_URL_DECL
231  
    pct_string_view(
234  
    pct_string_view(
232  
        core::string_view s);
235  
        core::string_view s);
233  

236  

234  
    /** Assignment
237  
    /** Assignment
235  

238  

236  
        The copy references the same
239  
        The copy references the same
237  
        underlying character buffer.
240  
        underlying character buffer.
238  
        Ownership is not transferred.
241  
        Ownership is not transferred.
239  

242  

240  
        @par Postconditions
243  
        @par Postconditions
241  
        @code
244  
        @code
242  
        this->data() == other.data()
245  
        this->data() == other.data()
243  
        @endcode
246  
        @endcode
244  

247  

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

250  

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

253  

251  
        @param other The string to copy.
254  
        @param other The string to copy.
252  
        @return A reference to this object.
255  
        @return A reference to this object.
253  
    */
256  
    */
254  
    pct_string_view& operator=(
257  
    pct_string_view& operator=(
255  
        pct_string_view const& other) = default;
258  
        pct_string_view const& other) = default;
256  

259  

257  
    friend
260  
    friend
258  
    BOOST_URL_DECL
261  
    BOOST_URL_DECL
259  
    system::result<pct_string_view>
262  
    system::result<pct_string_view>
260  
    make_pct_string_view(
263  
    make_pct_string_view(
261  
        core::string_view s) noexcept;
264  
        core::string_view s) noexcept;
262  

265  

263  
    //--------------------------------------------
266  
    //--------------------------------------------
264  

267  

265  
    /** Return the decoded size
268  
    /** Return the decoded size
266  

269  

267  
        This function returns the number of
270  
        This function returns the number of
268  
        characters in the resulting string if
271  
        characters in the resulting string if
269  
        percent escapes were converted into
272  
        percent escapes were converted into
270  
        ordinary characters.
273  
        ordinary characters.
271  

274  

272  
        @par Complexity
275  
        @par Complexity
273  
        Constant.
276  
        Constant.
274  

277  

275  
        @par Exception Safety
278  
        @par Exception Safety
276  
        Throws nothing.
279  
        Throws nothing.
277  

280  

278  
        @return The number of characters in the decoded string.
281  
        @return The number of characters in the decoded string.
279  
    */
282  
    */
280  
    BOOST_CXX14_CONSTEXPR
283  
    BOOST_CXX14_CONSTEXPR
281  
    std::size_t
284  
    std::size_t
282  
    decoded_size() const noexcept
285  
    decoded_size() const noexcept
283  
    {
286  
    {
284  
        return dn_;
287  
        return dn_;
285  
    }
288  
    }
286  

289  

287  
    /** Return the string as a range of decoded characters
290  
    /** Return the string as a range of decoded characters
288  

291  

289  
        @par Complexity
292  
        @par Complexity
290  
        Constant.
293  
        Constant.
291  

294  

292  
        @par Exception Safety
295  
        @par Exception Safety
293  
        Throws nothing.
296  
        Throws nothing.
294  

297  

295  
        @see
298  
        @see
296  
            @ref decode_view.
299  
            @ref decode_view.
297  

300  

298  
        @return A range of decoded characters.
301  
        @return A range of decoded characters.
299  
    */
302  
    */
300  
    decode_view
303  
    decode_view
301  
    operator*() const noexcept;
304  
    operator*() const noexcept;
302  

305  

303  
    /** Return the string with percent-decoding
306  
    /** Return the string with percent-decoding
304  

307  

305  
        This function converts percent escapes
308  
        This function converts percent escapes
306  
        in the string into ordinary characters
309  
        in the string into ordinary characters
307  
        and returns the result.
310  
        and returns the result.
308  
        When called with no arguments, the
311  
        When called with no arguments, the
309  
        return type is `std::string`.
312  
        return type is `std::string`.
310  
        Otherwise, the return type and style
313  
        Otherwise, the return type and style
311  
        of output is determined by which string
314  
        of output is determined by which string
312  
        token is passed.
315  
        token is passed.
313  

316  

314  
        @par Example
317  
        @par Example
315  
        @code
318  
        @code
316  
        assert( pct_string_view( "Program%20Files" ).decode() == "Program Files" );
319  
        assert( pct_string_view( "Program%20Files" ).decode() == "Program Files" );
317  
        @endcode
320  
        @endcode
318  

321  

319  
        @par Complexity
322  
        @par Complexity
320  
        Linear in `this->size()`.
323  
        Linear in `this->size()`.
321  

324  

322  
        @par Exception Safety
325  
        @par Exception Safety
323  
        Calls to allocate may throw.
326  
        Calls to allocate may throw.
324  
        String tokens may throw exceptions.
327  
        String tokens may throw exceptions.
325  

328  

326  
        @param opt The options for encoding. If
329  
        @param opt The options for encoding. If
327  
        this parameter is omitted, the default
330  
        this parameter is omitted, the default
328  
        options are used.
331  
        options are used.
329  

332  

330  
        @param token An optional string token.
333  
        @param token An optional string token.
331  
        If this parameter is omitted, then
334  
        If this parameter is omitted, then
332  
        a new `std::string` is returned.
335  
        a new `std::string` is returned.
333  
        Otherwise, the function return type
336  
        Otherwise, the function return type
334  
        is the result type of the token.
337  
        is the result type of the token.
335  

338  

336  
        @return The decoded string.
339  
        @return The decoded string.
337  

340  

338  
        @see
341  
        @see
339  
            @ref encoding_opts,
342  
            @ref encoding_opts,
340  
            @ref string_token::return_string.
343  
            @ref string_token::return_string.
341  
    */
344  
    */
342  
    template<BOOST_URL_STRTOK_TPARAM>
345  
    template<BOOST_URL_STRTOK_TPARAM>
343  
    BOOST_URL_STRTOK_RETURN
346  
    BOOST_URL_STRTOK_RETURN
344  
    decode(
347  
    decode(
345  
        encoding_opts opt = {},
348  
        encoding_opts opt = {},
346  
        BOOST_URL_STRTOK_ARG(token)) const
349  
        BOOST_URL_STRTOK_ARG(token)) const
347  
    {
350  
    {
348  
/*      If you get a compile error here, it
351  
/*      If you get a compile error here, it
349  
        means that the token you passed does
352  
        means that the token you passed does
350  
        not meet the requirements stated
353  
        not meet the requirements stated
351  
        in the documentation.
354  
        in the documentation.
352  
*/
355  
*/
353  
        static_assert(
356  
        static_assert(
354  
            string_token::is_token<
357  
            string_token::is_token<
355  
                StringToken>::value,
358  
                StringToken>::value,
356  
            "Type requirements not met");
359  
            "Type requirements not met");
357  

360  

358  
        decode_impl(token, opt);
361  
        decode_impl(token, opt);
359  
        return token.result();
362  
        return token.result();
360  
    }
363  
    }
361  

364  

362  
#ifndef BOOST_URL_DOCS
365  
#ifndef BOOST_URL_DOCS
363  
    /** Arrow support
366  
    /** Arrow support
364  

367  

365  
        @return A pointer to this object.
368  
        @return A pointer to this object.
366  
    */
369  
    */
367  
    pct_string_view const*
370  
    pct_string_view const*
368  
    operator->() const noexcept
371  
    operator->() const noexcept
369  
    {
372  
    {
370  
        return this;
373  
        return this;
371  
    }
374  
    }
372  
#endif
375  
#endif
373  

376  

374  
    //--------------------------------------------
377  
    //--------------------------------------------
375  

378  

376  
    // VFALCO No idea why this fails in msvc
379  
    // VFALCO No idea why this fails in msvc
377  
    /** Swap
380  
    /** Swap
378  

381  

379  
        @param s The object to swap with
382  
        @param s The object to swap with
380  
    */
383  
    */
381  
    /*BOOST_CXX14_CONSTEXPR*/ void swap(
384  
    /*BOOST_CXX14_CONSTEXPR*/ void swap(
382  
        pct_string_view& s ) noexcept
385  
        pct_string_view& s ) noexcept
383  
    {
386  
    {
384  
        string_view_base::swap(s);
387  
        string_view_base::swap(s);
385  
        std::swap(dn_, s.dn_);
388  
        std::swap(dn_, s.dn_);
386  
    }
389  
    }
387  
};
390  
};
388  

391  

389  
//------------------------------------------------
392  
//------------------------------------------------
390  

393  

391  
#ifndef BOOST_URL_DOCS
394  
#ifndef BOOST_URL_DOCS
392  
namespace detail {
395  
namespace detail {
393  
// obtain modifiable reference to
396  
// obtain modifiable reference to
394  
// underlying string, to handle
397  
// underlying string, to handle
395  
// self-intersection on modifiers.
398  
// self-intersection on modifiers.
396  
inline
399  
inline
397  
core::string_view&
400  
core::string_view&
398  
ref(pct_string_view& s) noexcept
401  
ref(pct_string_view& s) noexcept
399  
{
402  
{
400  
    return s.s_;
403  
    return s.s_;
401  
}
404  
}
402  

405  

403  
} // detail
406  
} // detail
404  
#endif
407  
#endif
405  

408  

406  
//------------------------------------------------
409  
//------------------------------------------------
407  

410  

408  
/** Return a valid percent-encoded string
411  
/** Return a valid percent-encoded string
409  

412  

410  
    If `s` is a valid percent-encoded string,
413  
    If `s` is a valid percent-encoded string,
411  
    the function returns the buffer as a valid
414  
    the function returns the buffer as a valid
412  
    view which may be used to perform decoding
415  
    view which may be used to perform decoding
413  
    or measurements.
416  
    or measurements.
414  
    Otherwise the result contains an error code.
417  
    Otherwise the result contains an error code.
415  
    Upon success, the returned view references
418  
    Upon success, the returned view references
416  
    the original character buffer;
419  
    the original character buffer;
417  
    Ownership is not transferred.
420  
    Ownership is not transferred.
418  

421  

419  
    @par Complexity
422  
    @par Complexity
420  
    Linear in `s.size()`.
423  
    Linear in `s.size()`.
421  

424  

422  
    @par Exception Safety
425  
    @par Exception Safety
423  
    Throws nothing.
426  
    Throws nothing.
424  

427  

425  
    @param s The string to validate.
428  
    @param s The string to validate.
426  
    @return On success, the valid percent-encoded string.
429  
    @return On success, the valid percent-encoded string.
427  
*/
430  
*/
428  
BOOST_URL_DECL
431  
BOOST_URL_DECL
429  
system::result<pct_string_view>
432  
system::result<pct_string_view>
430  
make_pct_string_view(
433  
make_pct_string_view(
431  
    core::string_view s) noexcept;
434  
    core::string_view s) noexcept;
432  

435  

433  
#ifndef BOOST_URL_DOCS
436  
#ifndef BOOST_URL_DOCS
434  
// VFALCO semi-private for now
437  
// VFALCO semi-private for now
435  
inline
438  
inline
 
439 +
BOOST_CXX14_CONSTEXPR
436  
pct_string_view
440  
pct_string_view
437  
make_pct_string_view_unsafe(
441  
make_pct_string_view_unsafe(
438  
    char const* data,
442  
    char const* data,
439  
    std::size_t size,
443  
    std::size_t size,
440  
    std::size_t decoded_size) noexcept
444  
    std::size_t decoded_size) noexcept
441  
{
445  
{
442  
#if 0
446  
#if 0
443  
    BOOST_ASSERT(! make_pct_string_view(
447  
    BOOST_ASSERT(! make_pct_string_view(
444  
        core::string_view(data, size)).has_error());
448  
        core::string_view(data, size)).has_error());
445  
#endif
449  
#endif
446  
    return pct_string_view(
450  
    return pct_string_view(
447  
        data, size, decoded_size);
451  
        data, size, decoded_size);
448  
}
452  
}
449  
#endif
453  
#endif
450  

454  

451  
#ifndef BOOST_URL_DOCS
455  
#ifndef BOOST_URL_DOCS
452  
namespace detail {
456  
namespace detail {
453  
template <>
457  
template <>
454  
inline
458  
inline
455  
BOOST_CXX14_CONSTEXPR
459  
BOOST_CXX14_CONSTEXPR
456  
core::string_view
460  
core::string_view
457  
to_sv(pct_string_view const& s) noexcept
461  
to_sv(pct_string_view const& s) noexcept
458  
{
462  
{
459  
    return s.substr();
463  
    return s.substr();
460  
}
464  
}
461  
} // detail
465  
} // detail
462  
#endif
466  
#endif
463  

467  

464  
} // urls
468  
} // urls
465  
} // boost
469  
} // boost
466  

470  

467  
// Ensure decode_view is complete for operator*()
471  
// Ensure decode_view is complete for operator*()
468  
#include <boost/url/decode_view.hpp>
472  
#include <boost/url/decode_view.hpp>
469  

473  

470  
#ifdef BOOST_URL_HAS_CONCEPTS
474  
#ifdef BOOST_URL_HAS_CONCEPTS
471  
#include <ranges>
475  
#include <ranges>
472  
namespace std::ranges {
476  
namespace std::ranges {
473  
    template<>
477  
    template<>
474  
    inline constexpr bool
478  
    inline constexpr bool
475  
        enable_borrowed_range<
479  
        enable_borrowed_range<
476  
            boost::urls::pct_string_view> = true;
480  
            boost::urls::pct_string_view> = true;
477  
} // std::ranges
481  
} // std::ranges
478  
#endif
482  
#endif
479  

483  

480  
#endif
484  
#endif