Line data Source code
1 : //
2 : // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3 : // Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
4 : //
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)
7 : //
8 : // Official repository: https://github.com/boostorg/url
9 : //
10 :
11 : #ifndef BOOST_URL_GRAMMAR_CI_STRING_HPP
12 : #define BOOST_URL_GRAMMAR_CI_STRING_HPP
13 :
14 : #include <boost/url/detail/config.hpp>
15 : #include <boost/core/detail/string_view.hpp>
16 : #include <boost/url/grammar/detail/ci_string.hpp>
17 : #include <cstdlib>
18 :
19 : namespace boost {
20 : namespace urls {
21 : namespace grammar {
22 :
23 : // Algorithms for interacting with low-ASCII
24 : // characters and strings, for implementing
25 : // semantics in RFCs. These routines do not
26 : // use std::locale.
27 :
28 : //------------------------------------------------
29 :
30 : /** Return c converted to lowercase
31 :
32 : This function returns the character,
33 : converting it to lowercase if it is
34 : uppercase.
35 : The function is defined only for
36 : low-ASCII characters.
37 :
38 : @par Example
39 : @code
40 : assert( to_lower( 'A' ) == 'a' );
41 : @endcode
42 :
43 : @par Exception Safety
44 : Throws nothing.
45 :
46 : @return The converted character
47 :
48 : @param c The character to convert
49 :
50 : @see
51 : @ref to_upper.
52 : */
53 : constexpr
54 : char
55 23172 : to_lower(char c) noexcept
56 : {
57 23172 : return detail::to_lower(c);
58 : }
59 :
60 : /** Return c converted to uppercase
61 :
62 : This function returns the character,
63 : converting it to uppercase if it is
64 : lowercase.
65 : The function is defined only for
66 : low-ASCII characters.
67 :
68 : @par Example
69 : @code
70 : assert( to_upper( 'a' ) == 'A' );
71 : @endcode
72 :
73 : @par Exception Safety
74 : Throws nothing.
75 :
76 : @return The converted character
77 :
78 : @param c The character to convert
79 :
80 : @see
81 : @ref to_lower.
82 : */
83 : constexpr
84 : char
85 209 : to_upper(char c) noexcept
86 : {
87 209 : return detail::to_upper(c);
88 : }
89 :
90 : //------------------------------------------------
91 :
92 : /** Return the case-insensitive comparison of s0 and s1
93 :
94 : This returns the lexicographical comparison
95 : of two strings, ignoring case.
96 : The function is defined only for strings
97 : containing low-ASCII characters.
98 :
99 : @par Example
100 : @code
101 : assert( ci_compare( "boost", "Boost" ) == 0 );
102 : @endcode
103 :
104 : @par Exception Safety
105 : Throws nothing.
106 :
107 : @return 0 if the strings are equal, -1 if
108 : `s0` is less than `s1`, or 1 if `s0` is
109 : greater than s1.
110 :
111 : @param s0 The first string
112 :
113 : @param s1 The second string
114 :
115 : @see
116 : @ref ci_is_equal,
117 : @ref ci_is_less.
118 : */
119 : BOOST_URL_DECL
120 : int
121 : ci_compare(
122 : core::string_view s0,
123 : core::string_view s1) noexcept;
124 :
125 : /** Return the case-insensitive digest of a string
126 :
127 : The hash function is non-cryptographic and
128 : not hardened against algorithmic complexity
129 : attacks.
130 : Returned digests are suitable for usage in
131 : unordered containers.
132 : The function is defined only for strings
133 : containing low-ASCII characters.
134 :
135 : @return The digest
136 :
137 : @param s The string
138 : */
139 : BOOST_URL_DECL
140 : std::size_t
141 : ci_digest(
142 : core::string_view s) noexcept;
143 :
144 : //------------------------------------------------
145 :
146 : /** Return true if s0 equals s1 using case-insensitive comparison
147 :
148 : The function is defined only for strings
149 : containing low-ASCII characters.
150 :
151 : @param s0 The first string
152 : @param s1 The second string
153 : @return `true` if `s0` case-insensitively equals `s1`, otherwise `false`
154 :
155 : @par Example
156 : @code
157 : assert( ci_is_equal( "Boost", "boost" ) );
158 : @endcode
159 :
160 : @see
161 : @ref ci_compare,
162 : @ref ci_is_less.
163 : */
164 : template<
165 : class String0,
166 : class String1>
167 : auto
168 252 : ci_is_equal(
169 : String0 const& s0,
170 : String1 const& s1) ->
171 : typename std::enable_if<
172 : ! std::is_convertible<
173 : String0, core::string_view>::value ||
174 : ! std::is_convertible<
175 : String1, core::string_view>::value,
176 : bool>::type
177 : {
178 : // this overload supports forward iterators and
179 : // does not assume the existence core::string_view::size
180 504 : if( detail::type_id<String0>() >
181 252 : detail::type_id<String1>())
182 0 : return detail::ci_is_equal(s1, s0);
183 252 : return detail::ci_is_equal(s0, s1);
184 : }
185 :
186 : /** Return true if s0 equals s1 using case-insensitive comparison
187 :
188 : The function is defined only for strings
189 : containing low-ASCII characters.
190 :
191 : @param s0 The first string
192 : @param s1 The second string
193 : @return `true` if `s0` case-insensitively equals `s1`, otherwise `false`
194 :
195 : @par Example
196 : @code
197 : assert( ci_is_equal( "Boost", "boost" ) );
198 : @endcode
199 :
200 : @see
201 : @ref ci_compare,
202 : @ref ci_is_less.
203 : */
204 : inline
205 : bool
206 10 : ci_is_equal(
207 : core::string_view s0,
208 : core::string_view s1) noexcept
209 : {
210 : // this overload is faster as it makes use of
211 : // core::string_view::size
212 10 : if(s0.size() != s1.size())
213 3 : return false;
214 7 : return detail::ci_is_equal(s0, s1);
215 : }
216 :
217 : /** Return true if s0 is less than s1 using case-insensitive comparison
218 :
219 : The comparison algorithm implements a
220 : case-insensitive total order on the set
221 : of all strings; however, it is not a
222 : lexicographical comparison.
223 : The function is defined only for strings
224 : containing low-ASCII characters.
225 :
226 : @param s0 The first string
227 : @param s1 The second string
228 : @return `true` if `s0` is case-insensitively less than `s1`, otherwise `false`
229 :
230 : @par Example
231 : @code
232 : assert( ! ci_is_less( "Boost", "boost" ) );
233 : @endcode
234 :
235 : @see
236 : @ref ci_compare,
237 : @ref ci_is_equal.
238 : */
239 : inline
240 : bool
241 9 : ci_is_less(
242 : core::string_view s0,
243 : core::string_view s1) noexcept
244 : {
245 9 : if(s0.size() != s1.size())
246 4 : return s0.size() < s1.size();
247 5 : return detail::ci_is_less(s0, s1);
248 : }
249 :
250 : //------------------------------------------------
251 :
252 : namespace implementation_defined {
253 : struct ci_hash
254 : {
255 : using is_transparent = void;
256 :
257 : std::size_t
258 6 : operator()(
259 : core::string_view s) const noexcept
260 : {
261 6 : return ci_digest(s);
262 : }
263 : };
264 : }
265 :
266 : /** A case-insensitive hash function object for strings
267 :
268 : The hash function is non-cryptographic and
269 : not hardened against algorithmic complexity
270 : attacks.
271 : This is a suitable hash function for
272 : unordered containers.
273 : The function is defined only for strings
274 : containing low-ASCII characters.
275 :
276 : @par Example
277 : @code
278 : boost::unordered_map< std::string, std::string, ci_hash, ci_equal > m1;
279 :
280 : std::unordered_map < std::string, std::string, ci_hash, ci_equal > m2; // (since C++20)
281 : @endcode
282 :
283 : @see
284 : @ref ci_equal,
285 : @ref ci_less.
286 : */
287 : using ci_hash = implementation_defined::ci_hash;
288 :
289 : namespace implementation_defined {
290 : struct ci_equal
291 : {
292 : using is_transparent = void;
293 :
294 : template<
295 : class String0, class String1>
296 : bool
297 3 : operator()(
298 : String0 s0,
299 : String1 s1) const noexcept
300 : {
301 3 : return ci_is_equal(s0, s1);
302 : }
303 : };
304 : } // implementation_defined
305 :
306 : /** A case-insensitive equals predicate for strings
307 :
308 : The function object returns `true` when
309 : two strings are equal, ignoring case.
310 : This is a suitable equality predicate for
311 : unordered containers.
312 : The function is defined only for strings
313 : containing low-ASCII characters.
314 :
315 : @par Example
316 : @code
317 : boost::unordered_map< std::string, std::string, ci_hash, ci_equal > m1;
318 :
319 : std::unordered_map < std::string, std::string, ci_hash, ci_equal > m2; // (since C++20)
320 : @endcode
321 :
322 : @see
323 : @ref ci_hash,
324 : @ref ci_less.
325 : */
326 : using ci_equal = implementation_defined::ci_equal;
327 :
328 : namespace implementation_defined {
329 : struct ci_less
330 : {
331 : using is_transparent = void;
332 :
333 : std::size_t
334 4 : operator()(
335 : core::string_view s0,
336 : core::string_view s1) const noexcept
337 : {
338 4 : return ci_is_less(s0, s1);
339 : }
340 : };
341 : }
342 :
343 : /** A case-insensitive less predicate for strings
344 :
345 : The comparison algorithm implements a
346 : case-insensitive total order on the set
347 : of all ASCII strings; however, it is
348 : not a lexicographical comparison.
349 : This is a suitable predicate for
350 : ordered containers.
351 : The function is defined only for strings
352 : containing low-ASCII characters.
353 :
354 : @par Example
355 : @code
356 : boost::container::map< std::string, std::string, ci_less > m1;
357 :
358 : std::map< std::string, std::string, ci_less > m2; // (since C++14)
359 : @endcode
360 :
361 : @see
362 : @ref ci_equal,
363 : @ref ci_hash.
364 : */
365 : using ci_less = implementation_defined::ci_less;
366 :
367 : } // grammar
368 : } // urls
369 : } // boost
370 :
371 : #endif
|