ci_string.hpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  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. @par Example
  116. @code
  117. assert( ci_is_equal( "Boost", "boost" ) );
  118. @endcode
  119. @see
  120. @ref ci_compare,
  121. @ref ci_is_less.
  122. */
  123. #ifdef BOOST_URL_DOCS
  124. template<
  125. class String0,
  126. class String1>
  127. bool
  128. ci_is_equal(
  129. String0 const& s0,
  130. String1 const& s1);
  131. #else
  132. template<
  133. class String0,
  134. class String1>
  135. auto
  136. ci_is_equal(
  137. String0 const& s0,
  138. String1 const& s1) ->
  139. typename std::enable_if<
  140. ! std::is_convertible<
  141. String0, core::string_view>::value ||
  142. ! std::is_convertible<
  143. String1, core::string_view>::value,
  144. bool>::type
  145. {
  146. // this overload supports forward iterators and
  147. // does not assume the existence core::string_view::size
  148. if( detail::type_id<String0>() >
  149. detail::type_id<String1>())
  150. return detail::ci_is_equal(s1, s0);
  151. return detail::ci_is_equal(s0, s1);
  152. }
  153. inline
  154. bool
  155. ci_is_equal(
  156. core::string_view s0,
  157. core::string_view s1) noexcept
  158. {
  159. // this overload is faster as it makes use of
  160. // core::string_view::size
  161. if(s0.size() != s1.size())
  162. return false;
  163. return detail::ci_is_equal(s0, s1);
  164. }
  165. #endif
  166. /** Return true if s0 is less than s1 using case-insensitive comparison
  167. The comparison algorithm implements a
  168. case-insensitive total order on the set
  169. of all strings; however, it is not a
  170. lexicographical comparison.
  171. The function is defined only for strings
  172. containing low-ASCII characters.
  173. @par Example
  174. @code
  175. assert( ! ci_is_less( "Boost", "boost" ) );
  176. @endcode
  177. @see
  178. @ref ci_compare,
  179. @ref ci_is_equal.
  180. */
  181. inline
  182. bool
  183. ci_is_less(
  184. core::string_view s0,
  185. core::string_view s1) noexcept
  186. {
  187. if(s0.size() != s1.size())
  188. return s0.size() < s1.size();
  189. return detail::ci_is_less(s0, s1);
  190. }
  191. //------------------------------------------------
  192. /** A case-insensitive hash function object for strings
  193. The hash function is non-cryptographic and
  194. not hardened against algorithmic complexity
  195. attacks.
  196. This is a suitable hash function for
  197. unordered containers.
  198. The function is defined only for strings
  199. containing low-ASCII characters.
  200. @par Example
  201. @code
  202. boost::unordered_map< std::string, std::string, ci_hash, ci_equal > m1;
  203. std::unordered_map < std::string, std::string, ci_hash, ci_equal > m2; // (since C++20)
  204. @endcode
  205. @see
  206. @ref ci_equal,
  207. @ref ci_less.
  208. */
  209. #ifdef BOOST_URL_DOCS
  210. using ci_hash = __see_below__;
  211. #else
  212. struct ci_hash
  213. {
  214. using is_transparent = void;
  215. std::size_t
  216. operator()(
  217. core::string_view s) const noexcept
  218. {
  219. return ci_digest(s);
  220. }
  221. };
  222. #endif
  223. /** A case-insensitive equals predicate for strings
  224. The function object returns `true` when
  225. two strings are equal, ignoring case.
  226. This is a suitable equality predicate for
  227. unordered containers.
  228. The function is defined only for strings
  229. containing low-ASCII characters.
  230. @par Example
  231. @code
  232. boost::unordered_map< std::string, std::string, ci_hash, ci_equal > m1;
  233. std::unordered_map < std::string, std::string, ci_hash, ci_equal > m2; // (since C++20)
  234. @endcode
  235. @see
  236. @ref ci_hash,
  237. @ref ci_less.
  238. */
  239. #ifdef BOOST_URL_DOCS
  240. using ci_equal = __see_below__;
  241. #else
  242. struct ci_equal
  243. {
  244. using is_transparent = void;
  245. template<
  246. class String0, class String1>
  247. bool
  248. operator()(
  249. String0 s0,
  250. String1 s1) const noexcept
  251. {
  252. return ci_is_equal(s0, s1);
  253. }
  254. };
  255. #endif
  256. /** A case-insensitive less predicate for strings
  257. The comparison algorithm implements a
  258. case-insensitive total order on the set
  259. of all ASCII strings; however, it is
  260. not a lexicographical comparison.
  261. This is a suitable predicate for
  262. ordered containers.
  263. The function is defined only for strings
  264. containing low-ASCII characters.
  265. @par Example
  266. @code
  267. boost::container::map< std::string, std::string, ci_less > m1;
  268. std::map< std::string, std::string, ci_less > m2; // (since C++14)
  269. @endcode
  270. @see
  271. @ref ci_equal,
  272. @ref ci_hash.
  273. */
  274. #ifdef BOOST_URL_DOCS
  275. using ci_less = __see_below__;
  276. #else
  277. struct ci_less
  278. {
  279. using is_transparent = void;
  280. std::size_t
  281. operator()(
  282. core::string_view s0,
  283. core::string_view s1) const noexcept
  284. {
  285. return ci_is_less(s0, s1);
  286. }
  287. };
  288. #endif
  289. } // grammar
  290. } // urls
  291. } // boost
  292. #endif