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 22879 : to_lower(char c) noexcept
56 : {
57 22879 : 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 : template<
161 : class String0,
162 : class String1>
163 : auto
164 252 : ci_is_equal(
165 : String0 const& s0,
166 : String1 const& s1) ->
167 : typename std::enable_if<
168 : ! std::is_convertible<
169 : String0, core::string_view>::value ||
170 : ! std::is_convertible<
171 : String1, core::string_view>::value,
172 : bool>::type
173 : {
174 : // this overload supports forward iterators and
175 : // does not assume the existence core::string_view::size
176 504 : if( detail::type_id<String0>() >
177 252 : detail::type_id<String1>())
178 0 : return detail::ci_is_equal(s1, s0);
179 252 : return detail::ci_is_equal(s0, s1);
180 : }
181 :
182 : /** Return true if s0 equals s1 using case-insensitive comparison
183 :
184 : The function is defined only for strings
185 : containing low-ASCII characters.
186 :
187 : @par Example
188 : @code
189 : assert( ci_is_equal( "Boost", "boost" ) );
190 : @endcode
191 :
192 : @see
193 : @ref ci_compare,
194 : @ref ci_is_less.
195 : */
196 : inline
197 : bool
198 10 : ci_is_equal(
199 : core::string_view s0,
200 : core::string_view s1) noexcept
201 : {
202 : // this overload is faster as it makes use of
203 : // core::string_view::size
204 10 : if(s0.size() != s1.size())
205 3 : return false;
206 7 : return detail::ci_is_equal(s0, s1);
207 : }
208 :
209 : /** Return true if s0 is less than s1 using case-insensitive comparison
210 :
211 : The comparison algorithm implements a
212 : case-insensitive total order on the set
213 : of all strings; however, it is not a
214 : lexicographical comparison.
215 : The function is defined only for strings
216 : containing low-ASCII characters.
217 :
218 : @par Example
219 : @code
220 : assert( ! ci_is_less( "Boost", "boost" ) );
221 : @endcode
222 :
223 : @see
224 : @ref ci_compare,
225 : @ref ci_is_equal.
226 : */
227 : inline
228 : bool
229 9 : ci_is_less(
230 : core::string_view s0,
231 : core::string_view s1) noexcept
232 : {
233 9 : if(s0.size() != s1.size())
234 4 : return s0.size() < s1.size();
235 5 : return detail::ci_is_less(s0, s1);
236 : }
237 :
238 : //------------------------------------------------
239 :
240 : namespace implementation_defined {
241 : struct ci_hash
242 : {
243 : using is_transparent = void;
244 :
245 : std::size_t
246 6 : operator()(
247 : core::string_view s) const noexcept
248 : {
249 6 : return ci_digest(s);
250 : }
251 : };
252 : }
253 :
254 : /** A case-insensitive hash function object for strings
255 :
256 : The hash function is non-cryptographic and
257 : not hardened against algorithmic complexity
258 : attacks.
259 : This is a suitable hash function for
260 : unordered containers.
261 : The function is defined only for strings
262 : containing low-ASCII characters.
263 :
264 : @par Example
265 : @code
266 : boost::unordered_map< std::string, std::string, ci_hash, ci_equal > m1;
267 :
268 : std::unordered_map < std::string, std::string, ci_hash, ci_equal > m2; // (since C++20)
269 : @endcode
270 :
271 : @see
272 : @ref ci_equal,
273 : @ref ci_less.
274 : */
275 : using ci_hash = implementation_defined::ci_hash;
276 :
277 : namespace implementation_defined {
278 : struct ci_equal
279 : {
280 : using is_transparent = void;
281 :
282 : template<
283 : class String0, class String1>
284 : bool
285 3 : operator()(
286 : String0 s0,
287 : String1 s1) const noexcept
288 : {
289 3 : return ci_is_equal(s0, s1);
290 : }
291 : };
292 : } // implementation_defined
293 :
294 : /** A case-insensitive equals predicate for strings
295 :
296 : The function object returns `true` when
297 : two strings are equal, ignoring case.
298 : This is a suitable equality predicate for
299 : unordered containers.
300 : The function is defined only for strings
301 : containing low-ASCII characters.
302 :
303 : @par Example
304 : @code
305 : boost::unordered_map< std::string, std::string, ci_hash, ci_equal > m1;
306 :
307 : std::unordered_map < std::string, std::string, ci_hash, ci_equal > m2; // (since C++20)
308 : @endcode
309 :
310 : @see
311 : @ref ci_hash,
312 : @ref ci_less.
313 : */
314 : using ci_equal = implementation_defined::ci_equal;
315 :
316 : namespace implementation_defined {
317 : struct ci_less
318 : {
319 : using is_transparent = void;
320 :
321 : std::size_t
322 4 : operator()(
323 : core::string_view s0,
324 : core::string_view s1) const noexcept
325 : {
326 4 : return ci_is_less(s0, s1);
327 : }
328 : };
329 : }
330 :
331 : /** A case-insensitive less predicate for strings
332 :
333 : The comparison algorithm implements a
334 : case-insensitive total order on the set
335 : of all ASCII strings; however, it is
336 : not a lexicographical comparison.
337 : This is a suitable predicate for
338 : ordered containers.
339 : The function is defined only for strings
340 : containing low-ASCII characters.
341 :
342 : @par Example
343 : @code
344 : boost::container::map< std::string, std::string, ci_less > m1;
345 :
346 : std::map< std::string, std::string, ci_less > m2; // (since C++14)
347 : @endcode
348 :
349 : @see
350 : @ref ci_equal,
351 : @ref ci_hash.
352 : */
353 : using ci_less = implementation_defined::ci_less;
354 :
355 : } // grammar
356 : } // urls
357 : } // boost
358 :
359 : #endif
|