1  
//
1  
//
2  
// Copyright (c) 2021 Vinnie Falco (vinnie dot falco at gmail dot com)
2  
// Copyright (c) 2021 Vinnie Falco (vinnie dot falco at gmail dot 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_GRAMMAR_CHARSET_HPP
11  
#ifndef BOOST_URL_GRAMMAR_CHARSET_HPP
12  
#define BOOST_URL_GRAMMAR_CHARSET_HPP
12  
#define BOOST_URL_GRAMMAR_CHARSET_HPP
13  

13  

14  
#include <boost/url/detail/config.hpp>
14  
#include <boost/url/detail/config.hpp>
15  
#include <boost/url/grammar/detail/charset.hpp>
15  
#include <boost/url/grammar/detail/charset.hpp>
16  
#include <boost/core/detail/static_assert.hpp>
16  
#include <boost/core/detail/static_assert.hpp>
17  
#include <cstdint>
17  
#include <cstdint>
18  
#include <type_traits>
18  
#include <type_traits>
19  
#include <utility>
19  
#include <utility>
20  

20  

21  
#ifdef BOOST_URL_HAS_CONCEPTS
21  
#ifdef BOOST_URL_HAS_CONCEPTS
22  
#include <concepts>
22  
#include <concepts>
23  
#endif
23  
#endif
24  

24  

25  
namespace boost {
25  
namespace boost {
26  
namespace urls {
26  
namespace urls {
27  
namespace grammar {
27  
namespace grammar {
28  

28  

29  
namespace implementation_defined
29  
namespace implementation_defined
30  
{
30  
{
31  
template<class T, class = void>
31  
template<class T, class = void>
32  
struct is_charset : std::false_type {};
32  
struct is_charset : std::false_type {};
33  

33  

34  
template<class T>
34  
template<class T>
35  
struct is_charset<T, void_t<
35  
struct is_charset<T, void_t<
36  
    decltype(
36  
    decltype(
37  
    std::declval<bool&>() =
37  
    std::declval<bool&>() =
38  
        std::declval<T const&>().operator()(
38  
        std::declval<T const&>().operator()(
39  
            std::declval<char>())
39  
            std::declval<char>())
40  
            ) > > : std::true_type
40  
            ) > > : std::true_type
41  
{
41  
{
42  
};
42  
};
43  
}
43  
}
44  

44  

45  
/** Alias for `std::true_type` if T satisfies @ref CharSet.
45  
/** Alias for `std::true_type` if T satisfies @ref CharSet.
46  

46  

47  
    This metafunction determines if the
47  
    This metafunction determines if the
48  
    type `T` meets these requirements of
48  
    type `T` meets these requirements of
49  
    <em>CharSet</em>:
49  
    <em>CharSet</em>:
50  

50  

51  
    @li An instance of `T` is invocable
51  
    @li An instance of `T` is invocable
52  
    with this equivalent function signature:
52  
    with this equivalent function signature:
53  
    @code
53  
    @code
54  
    bool T::operator()( char ) const noexcept;
54  
    bool T::operator()( char ) const noexcept;
55  
    @endcode
55  
    @endcode
56  

56  

57  
    @par Example
57  
    @par Example
58  
    Use with `enable_if` on the return value:
58  
    Use with `enable_if` on the return value:
59  
    @code
59  
    @code
60  
    template< class CharSet >
60  
    template< class CharSet >
61  
    typename std::enable_if< is_charset<T>::value >::type
61  
    typename std::enable_if< is_charset<T>::value >::type
62  
    func( CharSet const& cs );
62  
    func( CharSet const& cs );
63  
    @endcode
63  
    @endcode
64  

64  

65  
    @tparam T the type to check.
65  
    @tparam T the type to check.
66  
*/
66  
*/
67  
template<class T>
67  
template<class T>
68  
using is_charset = BOOST_URL_SEE_BELOW(implementation_defined::is_charset<T>);
68  
using is_charset = BOOST_URL_SEE_BELOW(implementation_defined::is_charset<T>);
69  

69  

70  
#ifdef BOOST_URL_HAS_CONCEPTS
70  
#ifdef BOOST_URL_HAS_CONCEPTS
71  
/** Concept for a CharSet
71  
/** Concept for a CharSet
72  

72  

73  
    A `CharSet` is a unary predicate which is invocable with
73  
    A `CharSet` is a unary predicate which is invocable with
74  
    this equivalent signature:
74  
    this equivalent signature:
75  

75  

76  
    @code
76  
    @code
77  
    bool( char ch ) const noexcept;
77  
    bool( char ch ) const noexcept;
78  
    @endcode
78  
    @endcode
79  

79  

80  
    The predicate returns `true` if `ch` is a member of the
80  
    The predicate returns `true` if `ch` is a member of the
81  
    set, or `false` otherwise.
81  
    set, or `false` otherwise.
82  

82  

83  
    @par Exemplar
83  
    @par Exemplar
84  

84  

85  
    For best results, it is suggested that all constructors and
85  
    For best results, it is suggested that all constructors and
86  
    member functions for character sets be marked `constexpr`.
86  
    member functions for character sets be marked `constexpr`.
87  

87  

88  
    @code
88  
    @code
89  
    struct CharSet
89  
    struct CharSet
90  
    {
90  
    {
91  
        bool operator()( char c ) const noexcept;
91  
        bool operator()( char c ) const noexcept;
92  

92  

93  
        // These are both optional. If either or both are left
93  
        // These are both optional. If either or both are left
94  
        // unspecified, a default implementation will be used.
94  
        // unspecified, a default implementation will be used.
95  
        //
95  
        //
96  
        char const* find_if( char const* first, char const* last ) const noexcept;
96  
        char const* find_if( char const* first, char const* last ) const noexcept;
97  
        char const* find_if_not( char const* first, char const* last ) const noexcept;
97  
        char const* find_if_not( char const* first, char const* last ) const noexcept;
98  
    };
98  
    };
99  
    @endcode
99  
    @endcode
100  

100  

101  
    @par Models
101  
    @par Models
102  

102  

103  
    @li @ref alnum_chars
103  
    @li @ref alnum_chars
104  
    @li @ref alpha_chars
104  
    @li @ref alpha_chars
105  
    @li @ref digit_chars
105  
    @li @ref digit_chars
106  
    @li @ref hexdig_chars
106  
    @li @ref hexdig_chars
107  
    @li @ref lut_chars
107  
    @li @ref lut_chars
108  

108  

109  
    @see
109  
    @see
110  
        @ref is_charset,
110  
        @ref is_charset,
111  
        @ref find_if,
111  
        @ref find_if,
112  
        @ref find_if_not.
112  
        @ref find_if_not.
113  

113  

114  
 */
114  
 */
115  
template <class T>
115  
template <class T>
116  
concept CharSet =
116  
concept CharSet =
117  
    requires (T const t, char c)
117  
    requires (T const t, char c)
118  
{
118  
{
119  
    { t(c) } -> std::convertible_to<bool>;
119  
    { t(c) } -> std::convertible_to<bool>;
120  
};
120  
};
121  
#endif
121  
#endif
122  

122  

123  

123  

124  
//------------------------------------------------
124  
//------------------------------------------------
125  

125  

126  
/** Find the first character in the string that is in the set.
126  
/** Find the first character in the string that is in the set.
127  

127  

128  
    @par Exception Safety
128  
    @par Exception Safety
129  
    Throws nothing.
129  
    Throws nothing.
130  

130  

131  
    @return A pointer to the found character,
131  
    @return A pointer to the found character,
132  
    otherwise the value `last`.
132  
    otherwise the value `last`.
133  

133  

134  
    @param first A pointer to the first character
134  
    @param first A pointer to the first character
135  
    in the string to search.
135  
    in the string to search.
136  

136  

137  
    @param last A pointer to one past the last
137  
    @param last A pointer to one past the last
138  
    character in the string to search.
138  
    character in the string to search.
139  

139  

140  
    @param cs The character set to use.
140  
    @param cs The character set to use.
141  

141  

142  
    @see
142  
    @see
143  
        @ref find_if_not.
143  
        @ref find_if_not.
144  
*/
144  
*/
145  
template<BOOST_URL_CONSTRAINT(CharSet) CS>
145  
template<BOOST_URL_CONSTRAINT(CharSet) CS>
146  
BOOST_URL_CXX14_CONSTEXPR
146  
BOOST_URL_CXX14_CONSTEXPR
147  
char const*
147  
char const*
148  
find_if(
148  
find_if(
149  
    char const* const first,
149  
    char const* const first,
150  
    char const* const last,
150  
    char const* const last,
151  
    CS const& cs) noexcept
151  
    CS const& cs) noexcept
152  
{
152  
{
153  
    // If you get a compile error here
153  
    // If you get a compile error here
154  
    // it means your type does not meet
154  
    // it means your type does not meet
155  
    // the requirements. Please check the
155  
    // the requirements. Please check the
156  
    // documentation.
156  
    // documentation.
157  
    static_assert(
157  
    static_assert(
158  
        is_charset<CS>::value,
158  
        is_charset<CS>::value,
159  
        "CharSet requirements not met");
159  
        "CharSet requirements not met");
160  

160  

161  
    return detail::find_if(first, last, cs,
161  
    return detail::find_if(first, last, cs,
162  
        detail::has_find_if<CS>{});
162  
        detail::has_find_if<CS>{});
163  
}
163  
}
164  

164  

165  
/** Find the first character in the string that is not in CharSet
165  
/** Find the first character in the string that is not in CharSet
166  

166  

167  
    @par Exception Safety
167  
    @par Exception Safety
168  
    Throws nothing.
168  
    Throws nothing.
169  

169  

170  
    @return A pointer to the found character,
170  
    @return A pointer to the found character,
171  
    otherwise the value `last`.
171  
    otherwise the value `last`.
172  

172  

173  
    @param first A pointer to the first character
173  
    @param first A pointer to the first character
174  
    in the string to search.
174  
    in the string to search.
175  

175  

176  
    @param last A pointer to one past the last
176  
    @param last A pointer to one past the last
177  
    character in the string to search.
177  
    character in the string to search.
178  

178  

179  
    @param cs The character set to use.
179  
    @param cs The character set to use.
180  

180  

181  
    @see
181  
    @see
182  
        @ref find_if_not.
182  
        @ref find_if_not.
183  
*/
183  
*/
184  
template<BOOST_URL_CONSTRAINT(CharSet) CS>
184  
template<BOOST_URL_CONSTRAINT(CharSet) CS>
185  
BOOST_URL_CXX14_CONSTEXPR
185  
BOOST_URL_CXX14_CONSTEXPR
186  
char const*
186  
char const*
187  
find_if_not(
187  
find_if_not(
188  
    char const* const first,
188  
    char const* const first,
189  
    char const* const last,
189  
    char const* const last,
190  
    CS const& cs) noexcept
190  
    CS const& cs) noexcept
191  
{
191  
{
192  
    // If you get a compile error here
192  
    // If you get a compile error here
193  
    // it means your type does not meet
193  
    // it means your type does not meet
194  
    // the requirements. Please check the
194  
    // the requirements. Please check the
195  
    // documentation.
195  
    // documentation.
196  
    static_assert(
196  
    static_assert(
197  
        is_charset<CS>::value,
197  
        is_charset<CS>::value,
198  
        "CharSet requirements not met");
198  
        "CharSet requirements not met");
199  

199  

200  
    return detail::find_if_not(first, last, cs,
200  
    return detail::find_if_not(first, last, cs,
201  
        detail::has_find_if_not<CS>{});
201  
        detail::has_find_if_not<CS>{});
202  
}
202  
}
203  

203  

204  
//------------------------------------------------
204  
//------------------------------------------------
205  

205  

206  
namespace implementation_defined {
206  
namespace implementation_defined {
207  
template<class CharSet>
207  
template<class CharSet>
208  
struct charset_ref
208  
struct charset_ref
209  
{
209  
{
210  
    CharSet const& cs_;
210  
    CharSet const& cs_;
211  

211  

212  
    constexpr
212  
    constexpr
213  
    bool
213  
    bool
214  
    operator()(char ch) const noexcept
214  
    operator()(char ch) const noexcept
215  
    {
215  
    {
216  
        return cs_(ch);
216  
        return cs_(ch);
217  
    }
217  
    }
218  

218  

219  
    BOOST_URL_CXX14_CONSTEXPR
219  
    BOOST_URL_CXX14_CONSTEXPR
220  
    char const*
220  
    char const*
221  
    find_if(
221  
    find_if(
222  
        char const* first,
222  
        char const* first,
223  
        char const* last) const noexcept
223  
        char const* last) const noexcept
224  
    {
224  
    {
225  
        return grammar::find_if(
225  
        return grammar::find_if(
226  
            first, last, cs_);
226  
            first, last, cs_);
227  
    }
227  
    }
228  

228  

229  
    BOOST_URL_CXX14_CONSTEXPR
229  
    BOOST_URL_CXX14_CONSTEXPR
230  
    char const*
230  
    char const*
231  
    find_if_not(
231  
    find_if_not(
232  
        char const* first,
232  
        char const* first,
233  
        char const* last) const noexcept
233  
        char const* last) const noexcept
234  
    {
234  
    {
235  
        return grammar::find_if_not(
235  
        return grammar::find_if_not(
236  
            first, last, cs_ );
236  
            first, last, cs_ );
237  
    }
237  
    }
238  
};
238  
};
239  
} // implementation_defined
239  
} // implementation_defined
240  

240  

241  
/** Return a reference to a character set
241  
/** Return a reference to a character set
242  

242  

243  
    This function returns a character set which
243  
    This function returns a character set which
244  
    references the specified object. This is
244  
    references the specified object. This is
245  
    used to reduce the number of bytes of
245  
    used to reduce the number of bytes of
246  
    storage (`sizeof`) required by a combinator
246  
    storage (`sizeof`) required by a combinator
247  
    when it stores a copy of the object.
247  
    when it stores a copy of the object.
248  
    <br>
248  
    <br>
249  
    Ownership of the object is not transferred;
249  
    Ownership of the object is not transferred;
250  
    the caller is responsible for ensuring the
250  
    the caller is responsible for ensuring the
251  
    lifetime of the object is extended until it
251  
    lifetime of the object is extended until it
252  
    is no longer referenced. For best results,
252  
    is no longer referenced. For best results,
253  
    `ref` should only be used with compile-time
253  
    `ref` should only be used with compile-time
254  
    constants.
254  
    constants.
255  

255  

256  
    @tparam CharSet The character set type
256  
    @tparam CharSet The character set type
257  
    @param cs The character set to use
257  
    @param cs The character set to use
258  
    @return The character set as a reference type
258  
    @return The character set as a reference type
259  
*/
259  
*/
260  
template<BOOST_URL_CONSTRAINT(CharSet) CS>
260  
template<BOOST_URL_CONSTRAINT(CharSet) CS>
261  
constexpr
261  
constexpr
262  
typename std::enable_if<
262  
typename std::enable_if<
263  
    is_charset<CS>::value &&
263  
    is_charset<CS>::value &&
264  
    ! std::is_same<CS,
264  
    ! std::is_same<CS,
265  
        implementation_defined::charset_ref<CS> >::value,
265  
        implementation_defined::charset_ref<CS> >::value,
266  
    implementation_defined::charset_ref<CS> >::type
266  
    implementation_defined::charset_ref<CS> >::type
267  
ref(CS const& cs) noexcept
267  
ref(CS const& cs) noexcept
268  
{
268  
{
269  
    return implementation_defined::charset_ref<CS>{cs};
269  
    return implementation_defined::charset_ref<CS>{cs};
270  
}
270  
}
271  

271  

272  
} // grammar
272  
} // grammar
273  
} // urls
273  
} // urls
274  
} // boost
274  
} // boost
275  

275  

276  
#endif
276  
#endif