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