Line | Branch | Exec | Source |
---|---|---|---|
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 | 22869 | to_lower(char c) noexcept | |
56 | { | ||
57 | 22869 | 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 | 189 | to_upper(char c) noexcept | |
86 | { | ||
87 | 189 | 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 | @par Example | ||
152 | @code | ||
153 | assert( ci_is_equal( "Boost", "boost" ) ); | ||
154 | @endcode | ||
155 | |||
156 | @see | ||
157 | @ref ci_compare, | ||
158 | @ref ci_is_less. | ||
159 | */ | ||
160 | #ifdef BOOST_URL_DOCS | ||
161 | template< | ||
162 | class String0, | ||
163 | class String1> | ||
164 | bool | ||
165 | ci_is_equal( | ||
166 | String0 const& s0, | ||
167 | String1 const& s1); | ||
168 | #else | ||
169 | |||
170 | /** Return true if s0 equals s1 using case-insensitive comparison | ||
171 | |||
172 | The function is defined only for strings | ||
173 | containing low-ASCII characters. | ||
174 | |||
175 | @par Example | ||
176 | @code | ||
177 | assert( ci_is_equal( "Boost", "boost" ) ); | ||
178 | @endcode | ||
179 | |||
180 | @see | ||
181 | @ref ci_compare, | ||
182 | @ref ci_is_less. | ||
183 | */ | ||
184 | template< | ||
185 | class String0, | ||
186 | class String1> | ||
187 | auto | ||
188 | 252 | ci_is_equal( | |
189 | String0 const& s0, | ||
190 | String1 const& s1) -> | ||
191 | typename std::enable_if< | ||
192 | ! std::is_convertible< | ||
193 | String0, core::string_view>::value || | ||
194 | ! std::is_convertible< | ||
195 | String1, core::string_view>::value, | ||
196 | bool>::type | ||
197 | { | ||
198 | // this overload supports forward iterators and | ||
199 | // does not assume the existence core::string_view::size | ||
200 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 252 times.
|
504 | if( detail::type_id<String0>() > |
201 | 252 | detail::type_id<String1>()) | |
202 | ✗ | return detail::ci_is_equal(s1, s0); | |
203 | 252 | return detail::ci_is_equal(s0, s1); | |
204 | } | ||
205 | |||
206 | /** Return true if s0 equals s1 using case-insensitive comparison | ||
207 | |||
208 | The function is defined only for strings | ||
209 | containing low-ASCII characters. | ||
210 | |||
211 | @par Example | ||
212 | @code | ||
213 | assert( ci_is_equal( "Boost", "boost" ) ); | ||
214 | @endcode | ||
215 | |||
216 | @see | ||
217 | @ref ci_compare, | ||
218 | @ref ci_is_less. | ||
219 | */ | ||
220 | inline | ||
221 | bool | ||
222 | 10 | ci_is_equal( | |
223 | core::string_view s0, | ||
224 | core::string_view s1) noexcept | ||
225 | { | ||
226 | // this overload is faster as it makes use of | ||
227 | // core::string_view::size | ||
228 |
2/2✓ Branch 2 taken 3 times.
✓ Branch 3 taken 7 times.
|
10 | if(s0.size() != s1.size()) |
229 | 3 | return false; | |
230 | 7 | return detail::ci_is_equal(s0, s1); | |
231 | } | ||
232 | #endif | ||
233 | |||
234 | /** Return true if s0 is less than s1 using case-insensitive comparison | ||
235 | |||
236 | The comparison algorithm implements a | ||
237 | case-insensitive total order on the set | ||
238 | of all strings; however, it is not a | ||
239 | lexicographical comparison. | ||
240 | The function is defined only for strings | ||
241 | containing low-ASCII characters. | ||
242 | |||
243 | @par Example | ||
244 | @code | ||
245 | assert( ! ci_is_less( "Boost", "boost" ) ); | ||
246 | @endcode | ||
247 | |||
248 | @see | ||
249 | @ref ci_compare, | ||
250 | @ref ci_is_equal. | ||
251 | */ | ||
252 | inline | ||
253 | bool | ||
254 | 9 | ci_is_less( | |
255 | core::string_view s0, | ||
256 | core::string_view s1) noexcept | ||
257 | { | ||
258 |
2/2✓ Branch 2 taken 4 times.
✓ Branch 3 taken 5 times.
|
9 | if(s0.size() != s1.size()) |
259 | 4 | return s0.size() < s1.size(); | |
260 | 5 | return detail::ci_is_less(s0, s1); | |
261 | } | ||
262 | |||
263 | //------------------------------------------------ | ||
264 | |||
265 | /** A case-insensitive hash function object for strings | ||
266 | |||
267 | The hash function is non-cryptographic and | ||
268 | not hardened against algorithmic complexity | ||
269 | attacks. | ||
270 | This is a suitable hash function for | ||
271 | unordered containers. | ||
272 | The function is defined only for strings | ||
273 | containing low-ASCII characters. | ||
274 | |||
275 | @par Example | ||
276 | @code | ||
277 | boost::unordered_map< std::string, std::string, ci_hash, ci_equal > m1; | ||
278 | |||
279 | std::unordered_map < std::string, std::string, ci_hash, ci_equal > m2; // (since C++20) | ||
280 | @endcode | ||
281 | |||
282 | @see | ||
283 | @ref ci_equal, | ||
284 | @ref ci_less. | ||
285 | */ | ||
286 | #ifdef BOOST_URL_DOCS | ||
287 | using ci_hash = __see_below__; | ||
288 | #else | ||
289 | namespace see_below { | ||
290 | struct ci_hash | ||
291 | { | ||
292 | using is_transparent = void; | ||
293 | |||
294 | std::size_t | ||
295 | 6 | operator()( | |
296 | core::string_view s) const noexcept | ||
297 | { | ||
298 | 6 | return ci_digest(s); | |
299 | } | ||
300 | }; | ||
301 | } | ||
302 | |||
303 | /** A case-insensitive hash function object for strings | ||
304 | |||
305 | The hash function is non-cryptographic and | ||
306 | not hardened against algorithmic complexity | ||
307 | attacks. | ||
308 | This is a suitable hash function for | ||
309 | unordered containers. | ||
310 | The function is defined only for strings | ||
311 | containing low-ASCII characters. | ||
312 | |||
313 | @par Example | ||
314 | @code | ||
315 | boost::unordered_map< std::string, std::string, ci_hash, ci_equal > m1; | ||
316 | |||
317 | std::unordered_map < std::string, std::string, ci_hash, ci_equal > m2; // (since C++20) | ||
318 | @endcode | ||
319 | |||
320 | @see | ||
321 | @ref ci_equal, | ||
322 | @ref ci_less. | ||
323 | */ | ||
324 | using ci_hash = see_below::ci_hash; | ||
325 | #endif | ||
326 | |||
327 | /** A case-insensitive equals predicate for strings | ||
328 | |||
329 | The function object returns `true` when | ||
330 | two strings are equal, ignoring case. | ||
331 | This is a suitable equality predicate for | ||
332 | unordered containers. | ||
333 | The function is defined only for strings | ||
334 | containing low-ASCII characters. | ||
335 | |||
336 | @par Example | ||
337 | @code | ||
338 | boost::unordered_map< std::string, std::string, ci_hash, ci_equal > m1; | ||
339 | |||
340 | std::unordered_map < std::string, std::string, ci_hash, ci_equal > m2; // (since C++20) | ||
341 | @endcode | ||
342 | |||
343 | @see | ||
344 | @ref ci_hash, | ||
345 | @ref ci_less. | ||
346 | */ | ||
347 | #ifdef BOOST_URL_DOCS | ||
348 | using ci_equal = __see_below__; | ||
349 | #else | ||
350 | namespace see_below { | ||
351 | struct ci_equal | ||
352 | { | ||
353 | using is_transparent = void; | ||
354 | |||
355 | template< | ||
356 | class String0, class String1> | ||
357 | bool | ||
358 | 6 | operator()( | |
359 | String0 s0, | ||
360 | String1 s1) const noexcept | ||
361 | { | ||
362 | 6 | return ci_is_equal(s0, s1); | |
363 | } | ||
364 | }; | ||
365 | } // see_below | ||
366 | |||
367 | /** A case-insensitive equals predicate for strings | ||
368 | |||
369 | The function object returns `true` when | ||
370 | two strings are equal, ignoring case. | ||
371 | This is a suitable equality predicate for | ||
372 | unordered containers. | ||
373 | The function is defined only for strings | ||
374 | containing low-ASCII characters. | ||
375 | |||
376 | @par Example | ||
377 | @code | ||
378 | boost::unordered_map< std::string, std::string, ci_hash, ci_equal > m1; | ||
379 | |||
380 | std::unordered_map < std::string, std::string, ci_hash, ci_equal > m2; // (since C++20) | ||
381 | @endcode | ||
382 | |||
383 | @see | ||
384 | @ref ci_hash, | ||
385 | @ref ci_less. | ||
386 | */ | ||
387 | using ci_equal = see_below::ci_equal; | ||
388 | #endif | ||
389 | |||
390 | /** A case-insensitive less predicate for strings | ||
391 | |||
392 | The comparison algorithm implements a | ||
393 | case-insensitive total order on the set | ||
394 | of all ASCII strings; however, it is | ||
395 | not a lexicographical comparison. | ||
396 | This is a suitable predicate for | ||
397 | ordered containers. | ||
398 | The function is defined only for strings | ||
399 | containing low-ASCII characters. | ||
400 | |||
401 | @par Example | ||
402 | @code | ||
403 | boost::container::map< std::string, std::string, ci_less > m1; | ||
404 | |||
405 | std::map< std::string, std::string, ci_less > m2; // (since C++14) | ||
406 | @endcode | ||
407 | |||
408 | @see | ||
409 | @ref ci_equal, | ||
410 | @ref ci_hash. | ||
411 | */ | ||
412 | #ifdef BOOST_URL_DOCS | ||
413 | using ci_less = __see_below__; | ||
414 | #else | ||
415 | namespace see_below { | ||
416 | struct ci_less | ||
417 | { | ||
418 | using is_transparent = void; | ||
419 | |||
420 | std::size_t | ||
421 | 4 | operator()( | |
422 | core::string_view s0, | ||
423 | core::string_view s1) const noexcept | ||
424 | { | ||
425 | 4 | return ci_is_less(s0, s1); | |
426 | } | ||
427 | }; | ||
428 | } | ||
429 | |||
430 | /** A case-insensitive less predicate for strings | ||
431 | |||
432 | The comparison algorithm implements a | ||
433 | case-insensitive total order on the set | ||
434 | of all ASCII strings; however, it is | ||
435 | not a lexicographical comparison. | ||
436 | This is a suitable predicate for | ||
437 | ordered containers. | ||
438 | The function is defined only for strings | ||
439 | containing low-ASCII characters. | ||
440 | |||
441 | @par Example | ||
442 | @code | ||
443 | boost::container::map< std::string, std::string, ci_less > m1; | ||
444 | |||
445 | std::map< std::string, std::string, ci_less > m2; // (since C++14) | ||
446 | @endcode | ||
447 | |||
448 | @see | ||
449 | @ref ci_equal, | ||
450 | @ref ci_hash. | ||
451 | */ | ||
452 | using ci_less = see_below::ci_less; | ||
453 | #endif | ||
454 | |||
455 | } // grammar | ||
456 | } // urls | ||
457 | } // boost | ||
458 | |||
459 | #endif | ||
460 |