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  
//
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_GRAMMAR_CHARSET_HPP
10  
#ifndef BOOST_URL_GRAMMAR_CHARSET_HPP
11  
#define BOOST_URL_GRAMMAR_CHARSET_HPP
11  
#define BOOST_URL_GRAMMAR_CHARSET_HPP
12  

12  

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

19  

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

23  

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

27  

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

32  

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

43  

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

45  

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

49  

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

55  

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

63  

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

68  

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

71  

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

74  

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

78  

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

81  

82  
    @par Exemplar
82  
    @par Exemplar
83  

83  

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

86  

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

91  

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

99  

100  
    @par Models
100  
    @par Models
101  

101  

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

107  

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

112  

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

121  

122  

122  

123  
//------------------------------------------------
123  
//------------------------------------------------
124  

124  

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

126  

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

129  

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

132  

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

135  

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

138  

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

140  

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

158  

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

162  

163  
/** Find the first character in the string that is not in CharSet
163  
/** Find the first character in the string that is not in CharSet
164  

164  

165  
    @par Exception Safety
165  
    @par Exception Safety
166  
    Throws nothing.
166  
    Throws nothing.
167  

167  

168  
    @return A pointer to the found character,
168  
    @return A pointer to the found character,
169  
    otherwise the value `last`.
169  
    otherwise the value `last`.
170  

170  

171  
    @param first A pointer to the first character
171  
    @param first A pointer to the first character
172  
    in the string to search.
172  
    in the string to search.
173  

173  

174  
    @param last A pointer to one past the last
174  
    @param last A pointer to one past the last
175  
    character in the string to search.
175  
    character in the string to search.
176  

176  

177  
    @param cs The character set to use.
177  
    @param cs The character set to use.
178  

178  

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

196  

197  
    return detail::find_if_not(first, last, cs,
197  
    return detail::find_if_not(first, last, cs,
198  
        detail::has_find_if_not<CS>{});
198  
        detail::has_find_if_not<CS>{});
199  
}
199  
}
200  

200  

201  
//------------------------------------------------
201  
//------------------------------------------------
202  

202  

203  
namespace implementation_defined {
203  
namespace implementation_defined {
204  
template<class CharSet>
204  
template<class CharSet>
205  
struct charset_ref
205  
struct charset_ref
206  
{
206  
{
207  
    CharSet const& cs_;
207  
    CharSet const& cs_;
208  

208  

209  
    constexpr
209  
    constexpr
210  
    bool
210  
    bool
211  
    operator()(char ch) const noexcept
211  
    operator()(char ch) const noexcept
212  
    {
212  
    {
213  
        return cs_(ch);
213  
        return cs_(ch);
214  
    }
214  
    }
215  

215  

216  
    char const*
216  
    char const*
217  
    find_if(
217  
    find_if(
218  
        char const* first,
218  
        char const* first,
219  
        char const* last) const noexcept
219  
        char const* last) const noexcept
220  
    {
220  
    {
221  
        return grammar::find_if(
221  
        return grammar::find_if(
222  
            first, last, cs_);
222  
            first, last, cs_);
223  
    }
223  
    }
224  

224  

225  
    char const*
225  
    char const*
226  
    find_if_not(
226  
    find_if_not(
227  
        char const* first,
227  
        char const* first,
228  
        char const* last) const noexcept
228  
        char const* last) const noexcept
229  
    {
229  
    {
230  
        return grammar::find_if_not(
230  
        return grammar::find_if_not(
231  
            first, last, cs_ );
231  
            first, last, cs_ );
232  
    }
232  
    }
233  
};
233  
};
234  
} // implementation_defined
234  
} // implementation_defined
235  

235  

236  
/** Return a reference to a character set
236  
/** Return a reference to a character set
237  

237  

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

250  

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

266  

267  
} // grammar
267  
} // grammar
268  
} // urls
268  
} // urls
269  
} // boost
269  
} // boost
270  

270  

271  
#endif
271  
#endif