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 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 504 : if( detail::type_id<String0>() >
201 252 : detail::type_id<String1>())
202 0 : 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 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 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 3 : operator()(
359 : String0 s0,
360 : String1 s1) const noexcept
361 : {
362 3 : 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
|