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

9  

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

12  

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

24  

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

27  

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

29  

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

33  

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

38  

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

44  

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

46  

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

48  

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

54  

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

63  

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

70  

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

75  

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

86  

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

92  

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

95  

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

97  

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

100  

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

105  

106  
    /** Constructor
106  
    /** Constructor
107  

107  

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

111  

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

116  

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

119  

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

122  

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

124  

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

129  

130  
    /** Constructor
130  
    /** Constructor
131  

131  

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

135  

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

140  

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

143  

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

146  

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

149  

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

151  

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

171  

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

176  

177  
    /** Constructor
177  
    /** Constructor
178  

178  

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

182  

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

187  

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

190  

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

193  

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

196  

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

207  

208  
    /** Constructor
208  
    /** Constructor
209  

209  

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

213  

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

218  

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

221  

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

224  

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

227  

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

233  

234  
    /** Assignment
234  
    /** Assignment
235  

235  

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

239  

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

244  

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

247  

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

250  

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

256  

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

262  

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

264  

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

266  

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

271  

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

274  

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

277  

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

286  

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

288  

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

291  

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

294  

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

297  

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

302  

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

304  

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

313  

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

318  

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

321  

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

325  

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

329  

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

335  

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

337  

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

357  

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

361  

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

364  

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

373  

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

375  

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

378  

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

388  

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

390  

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

402  

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

405  

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

407  

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

409  

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

418  

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

421  

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

424  

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

432  

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

450  

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

463  

464  
} // urls
464  
} // urls
465  
} // boost
465  
} // boost
466  

466  

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

469  

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

479  

480  
#endif
480  
#endif