ci_string.hpp 8.2 KB

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