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  
// Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
4  
//
4  
//
5  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
6  
// 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)
7  
//
7  
//
8  
// Official repository: https://github.com/boostorg/url
8  
// Official repository: https://github.com/boostorg/url
9  
//
9  
//
10  

10  

11  
#ifndef BOOST_URL_PCT_STRING_VIEW_HPP
11  
#ifndef BOOST_URL_PCT_STRING_VIEW_HPP
12  
#define BOOST_URL_PCT_STRING_VIEW_HPP
12  
#define BOOST_URL_PCT_STRING_VIEW_HPP
13  

13  

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

25  

26  
namespace boost {
26  
namespace boost {
27  
namespace urls {
27  
namespace urls {
28  

28  

29  
//------------------------------------------------
29  
//------------------------------------------------
30  

30  

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

34  

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

40  

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

46  

47  
//------------------------------------------------
47  
//------------------------------------------------
48  

48  

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

50  

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

56  

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

65  

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

73  

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

78  

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

89  

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

95  

96  
public:
96  
public:
97  
    /** Constructor
97  
    /** Constructor
98  

98  

99  
        Default constructed string are empty.
99  
        Default constructed string are empty.
100  

100  

101  
        @par Complexity
101  
        @par Complexity
102  
        Constant.
102  
        Constant.
103  

103  

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

108  

109  
    /** Constructor
109  
    /** Constructor
110  

110  

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

114  

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

119  

120  
        @par Complexity
120  
        @par Complexity
121  
        Constant.
121  
        Constant.
122  

122  

123  
        @par Exception Safety
123  
        @par Exception Safety
124  
        Throws nothing.
124  
        Throws nothing.
125  

125  

126  
        @param other The string to copy.
126  
        @param other The string to copy.
127  

127  

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

132  

133  
    /** Constructor
133  
    /** Constructor
134  

134  

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

138  

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

143  

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

146  

147  
        @par Exception Safety
147  
        @par Exception Safety
148  
        Exceptions thrown on invalid input.
148  
        Exceptions thrown on invalid input.
149  

149  

150  
        @throw system_error
150  
        @throw system_error
151  
        The string contains an invalid percent encoding.
151  
        The string contains an invalid percent encoding.
152  

152  

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

154  

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

174  

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

179  

180  
    /** Constructor
180  
    /** Constructor
181  

181  

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

185  

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

190  

191  
        @par Complexity
191  
        @par Complexity
192  
        Linear in `len`.
192  
        Linear in `len`.
193  

193  

194  
        @par Exception Safety
194  
        @par Exception Safety
195  
        Exceptions thrown on invalid input.
195  
        Exceptions thrown on invalid input.
196  

196  

197  
        @throw system_error
197  
        @throw system_error
198  
         The string contains an invalid percent encoding.
198  
         The string contains an invalid percent encoding.
199  

199  

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

210  

211  
    /** Constructor
211  
    /** Constructor
212  

212  

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

216  

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

221  

222  
        @par Complexity
222  
        @par Complexity
223  
        Linear in `s.size()`.
223  
        Linear in `s.size()`.
224  

224  

225  
        @par Exception Safety
225  
        @par Exception Safety
226  
        Exceptions thrown on invalid input.
226  
        Exceptions thrown on invalid input.
227  

227  

228  
        @throw system_error
228  
        @throw system_error
229  
        The string contains an invalid percent encoding.
229  
        The string contains an invalid percent encoding.
230  

230  

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

236  

237  
    /** Assignment
237  
    /** Assignment
238  

238  

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

242  

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

247  

248  
        @par Complexity
248  
        @par Complexity
249  
        Constant.
249  
        Constant.
250  

250  

251  
        @par Exception Safety
251  
        @par Exception Safety
252  
        Throws nothing.
252  
        Throws nothing.
253  

253  

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

259  

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

265  

266  
    //--------------------------------------------
266  
    //--------------------------------------------
267  

267  

268  
    /** Return the decoded size
268  
    /** Return the decoded size
269  

269  

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

274  

275  
        @par Complexity
275  
        @par Complexity
276  
        Constant.
276  
        Constant.
277  

277  

278  
        @par Exception Safety
278  
        @par Exception Safety
279  
        Throws nothing.
279  
        Throws nothing.
280  

280  

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

289  

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

291  

292  
        @par Complexity
292  
        @par Complexity
293  
        Constant.
293  
        Constant.
294  

294  

295  
        @par Exception Safety
295  
        @par Exception Safety
296  
        Throws nothing.
296  
        Throws nothing.
297  

297  

298  
        @see
298  
        @see
299  
            @ref decode_view.
299  
            @ref decode_view.
300  

300  

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

305  

306  
    /** Return the string with percent-decoding
306  
    /** Return the string with percent-decoding
307  

307  

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

316  

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

321  

322  
        @par Complexity
322  
        @par Complexity
323  
        Linear in `this->size()`.
323  
        Linear in `this->size()`.
324  

324  

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

328  

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

332  

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

338  

339  
        @return The decoded string.
339  
        @return The decoded string.
340  

340  

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

360  

361  
        decode_impl(token, opt);
361  
        decode_impl(token, opt);
362  
        return token.result();
362  
        return token.result();
363  
    }
363  
    }
364  

364  

365  
#ifndef BOOST_URL_DOCS
365  
#ifndef BOOST_URL_DOCS
366  
    /** Arrow support
366  
    /** Arrow support
367  

367  

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

376  

377  
    //--------------------------------------------
377  
    //--------------------------------------------
378  

378  

379  
    // VFALCO No idea why this fails in msvc
379  
    // VFALCO No idea why this fails in msvc
380  
    /** Swap
380  
    /** Swap
381  

381  

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

391  

392  
//------------------------------------------------
392  
//------------------------------------------------
393  

393  

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

405  

406  
} // detail
406  
} // detail
407  
#endif
407  
#endif
408  

408  

409  
//------------------------------------------------
409  
//------------------------------------------------
410  

410  

411  
/** Return a valid percent-encoded string
411  
/** Return a valid percent-encoded string
412  

412  

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

421  

422  
    @par Complexity
422  
    @par Complexity
423  
    Linear in `s.size()`.
423  
    Linear in `s.size()`.
424  

424  

425  
    @par Exception Safety
425  
    @par Exception Safety
426  
    Throws nothing.
426  
    Throws nothing.
427  

427  

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

435  

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

454  

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

467  

468  
} // urls
468  
} // urls
469  
} // boost
469  
} // boost
470  

470  

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

473  

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

483  

484  
#endif
484  
#endif