string.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. /*!
  2. @file
  3. Defines `boost::hana::string`.
  4. Copyright Louis Dionne 2013-2022
  5. Distributed under the Boost Software License, Version 1.0.
  6. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  7. */
  8. #ifndef BOOST_HANA_STRING_HPP
  9. #define BOOST_HANA_STRING_HPP
  10. #include <boost/hana/fwd/string.hpp>
  11. #include <boost/hana/bool.hpp>
  12. #include <boost/hana/concept/constant.hpp>
  13. #include <boost/hana/config.hpp>
  14. #include <boost/hana/core/make.hpp>
  15. #include <boost/hana/detail/algorithm.hpp>
  16. #include <boost/hana/detail/operators/adl.hpp>
  17. #include <boost/hana/detail/operators/comparable.hpp>
  18. #include <boost/hana/detail/operators/iterable.hpp>
  19. #include <boost/hana/detail/operators/orderable.hpp>
  20. #include <boost/hana/fwd/at.hpp>
  21. #include <boost/hana/fwd/contains.hpp>
  22. #include <boost/hana/fwd/core/tag_of.hpp>
  23. #include <boost/hana/fwd/core/to.hpp>
  24. #include <boost/hana/fwd/drop_front.hpp>
  25. #include <boost/hana/fwd/equal.hpp>
  26. #include <boost/hana/fwd/find.hpp>
  27. #include <boost/hana/fwd/front.hpp>
  28. #include <boost/hana/fwd/hash.hpp>
  29. #include <boost/hana/fwd/is_empty.hpp>
  30. #include <boost/hana/fwd/length.hpp>
  31. #include <boost/hana/fwd/less.hpp>
  32. #include <boost/hana/fwd/plus.hpp>
  33. #include <boost/hana/fwd/unpack.hpp>
  34. #include <boost/hana/fwd/zero.hpp>
  35. #include <boost/hana/if.hpp>
  36. #include <boost/hana/integral_constant.hpp>
  37. #include <boost/hana/optional.hpp>
  38. #include <boost/hana/type.hpp>
  39. #include <utility>
  40. #include <cstddef>
  41. #include <type_traits>
  42. namespace boost { namespace hana {
  43. //////////////////////////////////////////////////////////////////////////
  44. // string<>
  45. //////////////////////////////////////////////////////////////////////////
  46. //! @cond
  47. namespace detail {
  48. template <char ...s>
  49. constexpr char const string_storage[sizeof...(s) + 1] = {s..., '\0'};
  50. }
  51. template <char ...s>
  52. struct string
  53. : detail::operators::adl<string<s...>>
  54. , detail::iterable_operators<string<s...>>
  55. {
  56. static constexpr char const* c_str() {
  57. return &detail::string_storage<s...>[0];
  58. }
  59. };
  60. //! @endcond
  61. template <char ...s>
  62. struct tag_of<string<s...>> {
  63. using type = string_tag;
  64. };
  65. //////////////////////////////////////////////////////////////////////////
  66. // make<string_tag>
  67. //////////////////////////////////////////////////////////////////////////
  68. template <>
  69. struct make_impl<string_tag> {
  70. template <typename ...Chars>
  71. static constexpr auto apply(Chars const& ...) {
  72. return hana::string<hana::value<Chars>()...>{};
  73. }
  74. };
  75. //////////////////////////////////////////////////////////////////////////
  76. // BOOST_HANA_STRING
  77. //////////////////////////////////////////////////////////////////////////
  78. namespace string_detail {
  79. template <typename S, std::size_t ...N>
  80. constexpr string<S::get()[N]...>
  81. prepare_impl(S, std::index_sequence<N...>)
  82. { return {}; }
  83. template <typename S>
  84. constexpr decltype(auto) prepare(S s) {
  85. return prepare_impl(s,
  86. std::make_index_sequence<sizeof(S::get()) - 1>{});
  87. }
  88. }
  89. #define BOOST_HANA_STRING(s) \
  90. (::boost::hana::string_detail::prepare([]{ \
  91. struct tmp { \
  92. static constexpr decltype(auto) get() { return s; } \
  93. }; \
  94. return tmp{}; \
  95. }())) \
  96. /**/
  97. #ifdef BOOST_HANA_CONFIG_ENABLE_STRING_UDL
  98. //////////////////////////////////////////////////////////////////////////
  99. // _s user-defined literal
  100. //////////////////////////////////////////////////////////////////////////
  101. namespace literals {
  102. template <typename CharT, CharT ...s>
  103. constexpr auto operator"" _s() {
  104. static_assert(std::is_same<CharT, char>::value,
  105. "hana::string: Only narrow string literals are supported with "
  106. "the _s string literal right now. See https://github.com/boostorg/hana/issues/80 "
  107. "if you need support for fancier types of compile-time strings.");
  108. return hana::string_c<s...>;
  109. }
  110. }
  111. #endif
  112. //////////////////////////////////////////////////////////////////////////
  113. // Operators
  114. //////////////////////////////////////////////////////////////////////////
  115. namespace detail {
  116. template <>
  117. struct comparable_operators<string_tag> {
  118. static constexpr bool value = true;
  119. };
  120. template <>
  121. struct orderable_operators<string_tag> {
  122. static constexpr bool value = true;
  123. };
  124. }
  125. //////////////////////////////////////////////////////////////////////////
  126. // to<char const*>
  127. //////////////////////////////////////////////////////////////////////////
  128. template <>
  129. struct to_impl<char const*, string_tag> {
  130. template <char ...c>
  131. static constexpr char const* apply(string<c...> const&)
  132. { return string<c...>::c_str(); }
  133. };
  134. //////////////////////////////////////////////////////////////////////////
  135. // to<string_tag>
  136. //////////////////////////////////////////////////////////////////////////
  137. namespace detail {
  138. constexpr std::size_t cx_strlen(char const* s) {
  139. std::size_t n = 0u;
  140. while (*s != '\0')
  141. ++s, ++n;
  142. return n;
  143. }
  144. template <typename S, std::size_t ...I>
  145. constexpr hana::string<hana::value<S>()[I]...> expand(std::index_sequence<I...>)
  146. { return {}; }
  147. }
  148. template <typename IC>
  149. struct to_impl<hana::string_tag, IC, hana::when<
  150. hana::Constant<IC>::value &&
  151. std::is_convertible<typename IC::value_type, char const*>::value
  152. >> {
  153. template <typename S>
  154. static constexpr auto apply(S const&) {
  155. constexpr char const* s = hana::value<S>();
  156. constexpr std::size_t len = detail::cx_strlen(s);
  157. return detail::expand<S>(std::make_index_sequence<len>{});
  158. }
  159. };
  160. //////////////////////////////////////////////////////////////////////////
  161. // Comparable
  162. //////////////////////////////////////////////////////////////////////////
  163. template <>
  164. struct equal_impl<string_tag, string_tag> {
  165. template <typename S>
  166. static constexpr auto apply(S const&, S const&)
  167. { return hana::true_c; }
  168. template <typename S1, typename S2>
  169. static constexpr auto apply(S1 const&, S2 const&)
  170. { return hana::false_c; }
  171. };
  172. //////////////////////////////////////////////////////////////////////////
  173. // Orderable
  174. //////////////////////////////////////////////////////////////////////////
  175. template <>
  176. struct less_impl<string_tag, string_tag> {
  177. template <char ...s1, char ...s2>
  178. static constexpr auto
  179. apply(string<s1...> const&, string<s2...> const&) {
  180. // We put a '\0' at the end only to avoid empty arrays.
  181. constexpr char const c_str1[] = {s1..., '\0'};
  182. constexpr char const c_str2[] = {s2..., '\0'};
  183. return hana::bool_c<detail::lexicographical_compare(
  184. c_str1, c_str1 + sizeof...(s1),
  185. c_str2, c_str2 + sizeof...(s2)
  186. )>;
  187. }
  188. };
  189. //////////////////////////////////////////////////////////////////////////
  190. // Monoid
  191. //////////////////////////////////////////////////////////////////////////
  192. template <>
  193. struct plus_impl<string_tag, string_tag> {
  194. template <char ...s1, char ...s2>
  195. static constexpr auto
  196. apply(string<s1...> const&, string<s2...> const&) {
  197. return string<s1..., s2...>{};
  198. }
  199. };
  200. template <>
  201. struct zero_impl<string_tag> {
  202. static constexpr auto apply() {
  203. return string<>{};
  204. }
  205. };
  206. template <char ...s1, char ...s2>
  207. constexpr auto operator+(string<s1...> const&, string<s2...> const&) {
  208. return hana::string<s1..., s2...>{};
  209. }
  210. //////////////////////////////////////////////////////////////////////////
  211. // Foldable
  212. //////////////////////////////////////////////////////////////////////////
  213. template <>
  214. struct unpack_impl<string_tag> {
  215. template <char ...s, typename F>
  216. static constexpr decltype(auto) apply(string<s...> const&, F&& f)
  217. { return static_cast<F&&>(f)(char_<s>{}...); }
  218. };
  219. template <>
  220. struct length_impl<string_tag> {
  221. template <char ...s>
  222. static constexpr auto apply(string<s...> const&)
  223. { return hana::size_c<sizeof...(s)>; }
  224. };
  225. //////////////////////////////////////////////////////////////////////////
  226. // Iterable
  227. //////////////////////////////////////////////////////////////////////////
  228. template <>
  229. struct front_impl<string_tag> {
  230. template <char x, char ...xs>
  231. static constexpr auto apply(string<x, xs...> const&)
  232. { return hana::char_c<x>; }
  233. };
  234. template <>
  235. struct drop_front_impl<string_tag> {
  236. template <std::size_t N, char ...xs, std::size_t ...i>
  237. static constexpr auto helper(string<xs...> const&, std::index_sequence<i...>) {
  238. constexpr char s[] = {xs...};
  239. return hana::string_c<s[i + N]...>;
  240. }
  241. template <char ...xs, typename N>
  242. static constexpr auto apply(string<xs...> const& s, N const&) {
  243. return helper<N::value>(s, std::make_index_sequence<
  244. (N::value < sizeof...(xs)) ? sizeof...(xs) - N::value : 0
  245. >{});
  246. }
  247. template <typename N>
  248. static constexpr auto apply(string<> const& s, N const&)
  249. { return s; }
  250. };
  251. template <>
  252. struct is_empty_impl<string_tag> {
  253. template <char ...s>
  254. static constexpr auto apply(string<s...> const&)
  255. { return hana::bool_c<sizeof...(s) == 0>; }
  256. };
  257. template <>
  258. struct at_impl<string_tag> {
  259. template <char ...s, typename N>
  260. static constexpr auto apply(string<s...> const&, N const&) {
  261. // We put a '\0' at the end to avoid an empty array.
  262. constexpr char characters[] = {s..., '\0'};
  263. constexpr auto n = N::value;
  264. return hana::char_c<characters[n]>;
  265. }
  266. };
  267. //////////////////////////////////////////////////////////////////////////
  268. // Searchable
  269. //////////////////////////////////////////////////////////////////////////
  270. template <>
  271. struct contains_impl<string_tag> {
  272. template <char ...s, typename C>
  273. static constexpr auto
  274. helper(string<s...> const&, C const&, hana::true_) {
  275. constexpr char const characters[] = {s..., '\0'};
  276. constexpr char c = hana::value<C>();
  277. return hana::bool_c<
  278. detail::find(characters, characters + sizeof...(s), c)
  279. != characters + sizeof...(s)
  280. >;
  281. }
  282. template <typename S, typename C>
  283. static constexpr auto helper(S const&, C const&, hana::false_)
  284. { return hana::false_c; }
  285. template <typename S, typename C>
  286. static constexpr auto apply(S const& s, C const& c)
  287. { return helper(s, c, hana::bool_c<hana::Constant<C>::value>); }
  288. };
  289. template <>
  290. struct find_impl<string_tag> {
  291. template <char ...s, typename Char>
  292. static constexpr auto apply(string<s...> const& str, Char const& c) {
  293. return hana::if_(contains_impl<string_tag>::apply(str, c),
  294. hana::just(c),
  295. hana::nothing
  296. );
  297. }
  298. };
  299. //////////////////////////////////////////////////////////////////////////
  300. // Hashable
  301. //////////////////////////////////////////////////////////////////////////
  302. template <>
  303. struct hash_impl<string_tag> {
  304. template <typename String>
  305. static constexpr auto apply(String const&) {
  306. return hana::type_c<String>;
  307. }
  308. };
  309. }} // end namespace boost::hana
  310. #endif // !BOOST_HANA_STRING_HPP