1 /*! 2 @file 3 Defines the `Logical` and `Comparable` models of `boost::hana::integral_constant`. 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_BOOL_HPP 11 #define BOOST_HANA_BOOL_HPP 12 13 #include <boost/hana/fwd/bool.hpp> 14 15 #include <boost/hana/concept/integral_constant.hpp> 16 #include <boost/hana/config.hpp> 17 #include <boost/hana/core/to.hpp> 18 #include <boost/hana/core/when.hpp> 19 #include <boost/hana/detail/operators/arithmetic.hpp> 20 #include <boost/hana/detail/operators/comparable.hpp> 21 #include <boost/hana/detail/operators/logical.hpp> 22 #include <boost/hana/detail/operators/orderable.hpp> 23 #include <boost/hana/eval.hpp> 24 #include <boost/hana/fwd/core/tag_of.hpp> 25 #include <boost/hana/fwd/eval_if.hpp> 26 #include <boost/hana/fwd/if.hpp> 27 #include <boost/hana/fwd/value.hpp> 28 29 #include <cstddef> 30 #include <type_traits> 31 #include <utility> 32 33 34 BOOST_HANA_NAMESPACE_BEGIN 35 ////////////////////////////////////////////////////////////////////////// 36 // integral_constant 37 ////////////////////////////////////////////////////////////////////////// 38 //! @cond 39 namespace ic_detail { 40 template <typename T, T N, typename = std::make_integer_sequence<T, N>> 41 struct go; 42 43 template <typename T, T N, T ...i> 44 struct go<T, N, std::integer_sequence<T, i...>> { 45 using swallow = T[]; 46 47 template <typename F> with_indexic_detail::go48 static constexpr void with_index(F&& f) 49 { (void)swallow{T{}, ((void)f(integral_constant<T, i>{}), i)...}; } 50 51 template <typename F> without_indexic_detail::go52 static constexpr void without_index(F&& f) 53 { (void)swallow{T{}, ((void)f(), i)...}; } 54 }; 55 56 template <typename T, T v> 57 template <typename F> operator ()(F && f) const58 constexpr void with_index_t<T, v>::operator()(F&& f) const 59 { go<T, ((void)sizeof(&f), v)>::with_index(static_cast<F&&>(f)); } 60 61 template <typename T, T v> 62 template <typename F> operator ()(F && f) const63 constexpr void times_t<T, v>::operator()(F&& f) const 64 { go<T, ((void)sizeof(&f), v)>::without_index(static_cast<F&&>(f)); } 65 66 // avoid link-time error 67 template <typename T, T v> 68 constexpr with_index_t<T, v> times_t<T, v>::with_index; 69 } 70 71 // avoid link-time error 72 template <typename T, T v> 73 constexpr ic_detail::times_t<T, v> integral_constant<T, v>::times; 74 75 template <typename T, T v> 76 struct tag_of<integral_constant<T, v>> { 77 using type = integral_constant_tag<T>; 78 }; 79 //! @endcond 80 81 ////////////////////////////////////////////////////////////////////////// 82 // Operators 83 ////////////////////////////////////////////////////////////////////////// 84 namespace detail { 85 template <typename T> 86 struct comparable_operators<integral_constant_tag<T>> { 87 static constexpr bool value = true; 88 }; 89 template <typename T> 90 struct orderable_operators<integral_constant_tag<T>> { 91 static constexpr bool value = true; 92 }; 93 template <typename T> 94 struct arithmetic_operators<integral_constant_tag<T>> { 95 static constexpr bool value = true; 96 }; 97 template <typename T> 98 struct logical_operators<integral_constant_tag<T>> { 99 static constexpr bool value = true; 100 }; 101 } 102 103 #define BOOST_HANA_INTEGRAL_CONSTANT_BINARY_OP(op) \ 104 template <typename U, U u, typename V, V v> \ 105 constexpr integral_constant<decltype(u op v), (u op v)> \ 106 operator op(integral_constant<U, u>, integral_constant<V, v>) \ 107 { return {}; } \ 108 /**/ 109 110 #define BOOST_HANA_INTEGRAL_CONSTANT_UNARY_OP(op) \ 111 template <typename U, U u> \ 112 constexpr integral_constant<decltype(op u), (op u)> \ 113 operator op(integral_constant<U, u>) \ 114 { return {}; } \ 115 /**/ 116 117 // Arithmetic 118 BOOST_HANA_INTEGRAL_CONSTANT_UNARY_OP(+) 119 120 // Bitwise 121 BOOST_HANA_INTEGRAL_CONSTANT_UNARY_OP(~) 122 BOOST_HANA_INTEGRAL_CONSTANT_BINARY_OP(&) 123 BOOST_HANA_INTEGRAL_CONSTANT_BINARY_OP(|) 124 BOOST_HANA_INTEGRAL_CONSTANT_BINARY_OP(^) 125 BOOST_HANA_INTEGRAL_CONSTANT_BINARY_OP(<<) 126 BOOST_HANA_INTEGRAL_CONSTANT_BINARY_OP(>>) 127 128 #undef BOOST_HANA_INTEGRAL_CONSTANT_UNARY_OP 129 #undef BOOST_HANA_INTEGRAL_CONSTANT_BINARY_OP 130 131 132 ////////////////////////////////////////////////////////////////////////// 133 // User-defined literal 134 ////////////////////////////////////////////////////////////////////////// 135 namespace ic_detail { 136 to_int(char c)137 constexpr int to_int(char c) { 138 int result = 0; 139 140 if (c >= 'A' && c <= 'F') { 141 result = static_cast<int>(c) - static_cast<int>('A') + 10; 142 } 143 else if (c >= 'a' && c <= 'f') { 144 result = static_cast<int>(c) - static_cast<int>('a') + 10; 145 } 146 else { 147 result = static_cast<int>(c) - static_cast<int>('0'); 148 } 149 150 return result; 151 } 152 153 template<std::size_t N> parse(const char (& arr)[N])154 constexpr long long parse(const char (&arr)[N]) { 155 long long base = 10; 156 std::size_t offset = 0; 157 158 if (N > 2) { 159 bool starts_with_zero = arr[0] == '0'; 160 bool is_hex = starts_with_zero && arr[1] == 'x'; 161 bool is_binary = starts_with_zero && arr[1] == 'b'; 162 163 if (is_hex) { 164 //0xDEADBEEF (hexadecimal) 165 base = 16; 166 offset = 2; 167 } 168 else if (is_binary) { 169 //0b101011101 (binary) 170 base = 2; 171 offset = 2; 172 } 173 else if (starts_with_zero) { 174 //012345 (octal) 175 base = 8; 176 offset = 1; 177 } 178 } 179 180 long long number = 0; 181 long long multiplier = 1; 182 183 for (std::size_t i = 0; i < N - offset; ++i) { 184 char c = arr[N - 1 - i]; 185 if (c != '\'') { // skip digit separators 186 number += to_int(c) * multiplier; 187 multiplier *= base; 188 } 189 } 190 191 return number; 192 } 193 } 194 195 namespace literals { 196 template <char ...c> operator ""_c()197 constexpr auto operator"" _c() { 198 return hana::llong<ic_detail::parse<sizeof...(c)>({c...})>{}; 199 } 200 } 201 202 ////////////////////////////////////////////////////////////////////////// 203 // Model of Constant/IntegralConstant 204 ////////////////////////////////////////////////////////////////////////// 205 template <typename T> 206 struct IntegralConstant<integral_constant_tag<T>> { 207 static constexpr bool value = true; 208 }; 209 210 template <typename T, typename C> 211 struct to_impl<integral_constant_tag<T>, C, when<hana::IntegralConstant<C>::value>> 212 : embedding<is_embedded<typename C::value_type, T>::value> 213 { 214 template <typename N> applyto_impl215 static constexpr auto apply(N const&) 216 { return integral_constant<T, N::value>{}; } 217 }; 218 219 ////////////////////////////////////////////////////////////////////////// 220 // Optimizations 221 ////////////////////////////////////////////////////////////////////////// 222 template <typename T> 223 struct eval_if_impl<integral_constant_tag<T>> { 224 template <typename Cond, typename Then, typename Else> 225 static constexpr decltype(auto) applyeval_if_impl226 apply(Cond const&, Then&& t, Else&& e) { 227 constexpr bool cond = static_cast<bool>(Cond::value); 228 return eval_if_impl::apply(hana::bool_<cond>{}, 229 static_cast<Then&&>(t), 230 static_cast<Else&&>(e)); 231 } 232 233 template <typename Then, typename Else> 234 static constexpr decltype(auto) applyeval_if_impl235 apply(hana::true_ const&, Then&& t, Else&&) 236 { return hana::eval(static_cast<Then&&>(t)); } 237 238 template <typename Then, typename Else> 239 static constexpr decltype(auto) applyeval_if_impl240 apply(hana::false_ const&, Then&&, Else&& e) 241 { return hana::eval(static_cast<Else&&>(e)); } 242 }; 243 244 template <typename T> 245 struct if_impl<integral_constant_tag<T>> { 246 template <typename Cond, typename Then, typename Else> 247 static constexpr decltype(auto) applyif_impl248 apply(Cond const&, Then&& t, Else&& e) { 249 constexpr bool cond = static_cast<bool>(Cond::value); 250 return if_impl::apply(hana::bool_<cond>{}, 251 static_cast<Then&&>(t), 252 static_cast<Else&&>(e)); 253 } 254 255 //! @todo We could return `Then` instead of `auto` to sometimes save 256 //! a copy, but that would break some code that would return a 257 //! reference to a `type` object. I think the code that would be 258 //! broken should be changed, but more thought needs to be given. 259 template <typename Then, typename Else> 260 static constexpr auto applyif_impl261 apply(hana::true_ const&, Then&& t, Else&&) 262 { return static_cast<Then&&>(t); } 263 264 template <typename Then, typename Else> 265 static constexpr auto applyif_impl266 apply(hana::false_ const&, Then&&, Else&& e) 267 { return static_cast<Else&&>(e); } 268 }; 269 BOOST_HANA_NAMESPACE_END 270 271 #endif // !BOOST_HANA_BOOL_HPP 272