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

13  

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

20  

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

24  

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

28  

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

33  

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

44  

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

46  

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

50  

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

56  

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

64  

64  
    @tparam T the type to check.
65  
    @tparam T the type to check.
65  
*/
66  
*/
66  
template<class T>
67  
template<class T>
67  
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>);
68  

69  

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

72  

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

75  

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

79  

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

82  

82  
    @par Exemplar
83  
    @par Exemplar
83  

84  

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

87  

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

92  

92  
        // These are both optional. If either or both are left
93  
        // These are both optional. If either or both are left
93  
        // unspecified, a default implementation will be used.
94  
        // unspecified, a default implementation will be used.
94  
        //
95  
        //
95  
        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;
96  
        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;
97  
    };
98  
    };
98  
    @endcode
99  
    @endcode
99  

100  

100  
    @par Models
101  
    @par Models
101  

102  

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

108  

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

113  

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

122  

122  

123  

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

125  

125  
/** 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.
126  

127  

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

130  

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

133  

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

136  

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

139  

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

141  

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

160  

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

164  

163  
/** 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
164  

166  

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

169  

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

172  

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

175  

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

178  

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

180  

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

199  

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

203  

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

205  

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

211  

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

218  

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

228  

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

240  

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

242  

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

255  

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

271  

267  
} // grammar
272  
} // grammar
268  
} // urls
273  
} // urls
269  
} // boost
274  
} // boost
270  

275  

271  
#endif
276  
#endif