/*! @file Defines the `Logical` and `Comparable` models of `boost::hana::integral_constant`. @copyright Louis Dionne 2013-2017 Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) */ #ifndef BOOST_HANA_BOOL_HPP #define BOOST_HANA_BOOL_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include BOOST_HANA_NAMESPACE_BEGIN ////////////////////////////////////////////////////////////////////////// // integral_constant ////////////////////////////////////////////////////////////////////////// //! @cond namespace ic_detail { template > struct go; template struct go> { using swallow = T[]; template static constexpr void with_index(F&& f) { (void)swallow{T{}, ((void)f(integral_constant{}), i)...}; } template static constexpr void without_index(F&& f) { (void)swallow{T{}, ((void)f(), i)...}; } }; template template constexpr void with_index_t::operator()(F&& f) const { go::with_index(static_cast(f)); } template template constexpr void times_t::operator()(F&& f) const { go::without_index(static_cast(f)); } // avoid link-time error template constexpr with_index_t times_t::with_index; } // avoid link-time error template constexpr ic_detail::times_t integral_constant::times; template struct tag_of> { using type = integral_constant_tag; }; //! @endcond ////////////////////////////////////////////////////////////////////////// // Operators ////////////////////////////////////////////////////////////////////////// namespace detail { template struct comparable_operators> { static constexpr bool value = true; }; template struct orderable_operators> { static constexpr bool value = true; }; template struct arithmetic_operators> { static constexpr bool value = true; }; template struct logical_operators> { static constexpr bool value = true; }; } #define BOOST_HANA_INTEGRAL_CONSTANT_BINARY_OP(op) \ template \ constexpr integral_constant \ operator op(integral_constant, integral_constant) \ { return {}; } \ /**/ #define BOOST_HANA_INTEGRAL_CONSTANT_UNARY_OP(op) \ template \ constexpr integral_constant \ operator op(integral_constant) \ { return {}; } \ /**/ // Arithmetic BOOST_HANA_INTEGRAL_CONSTANT_UNARY_OP(+) // Bitwise BOOST_HANA_INTEGRAL_CONSTANT_UNARY_OP(~) BOOST_HANA_INTEGRAL_CONSTANT_BINARY_OP(&) BOOST_HANA_INTEGRAL_CONSTANT_BINARY_OP(|) BOOST_HANA_INTEGRAL_CONSTANT_BINARY_OP(^) BOOST_HANA_INTEGRAL_CONSTANT_BINARY_OP(<<) BOOST_HANA_INTEGRAL_CONSTANT_BINARY_OP(>>) #undef BOOST_HANA_INTEGRAL_CONSTANT_UNARY_OP #undef BOOST_HANA_INTEGRAL_CONSTANT_BINARY_OP ////////////////////////////////////////////////////////////////////////// // User-defined literal ////////////////////////////////////////////////////////////////////////// namespace ic_detail { constexpr int to_int(char c) { int result = 0; if (c >= 'A' && c <= 'F') { result = static_cast(c) - static_cast('A') + 10; } else if (c >= 'a' && c <= 'f') { result = static_cast(c) - static_cast('a') + 10; } else { result = static_cast(c) - static_cast('0'); } return result; } template constexpr long long parse(const char (&arr)[N]) { long long base = 10; std::size_t offset = 0; if (N > 2) { bool starts_with_zero = arr[0] == '0'; bool is_hex = starts_with_zero && arr[1] == 'x'; bool is_binary = starts_with_zero && arr[1] == 'b'; if (is_hex) { //0xDEADBEEF (hexadecimal) base = 16; offset = 2; } else if (is_binary) { //0b101011101 (binary) base = 2; offset = 2; } else if (starts_with_zero) { //012345 (octal) base = 8; offset = 1; } } long long number = 0; long long multiplier = 1; for (std::size_t i = 0; i < N - offset; ++i) { char c = arr[N - 1 - i]; number += to_int(c) * multiplier; multiplier *= base; } return number; } } namespace literals { template constexpr auto operator"" _c() { return hana::llong({c...})>{}; } } ////////////////////////////////////////////////////////////////////////// // Model of Constant/IntegralConstant ////////////////////////////////////////////////////////////////////////// template struct IntegralConstant> { static constexpr bool value = true; }; template struct to_impl, C, when::value>> : embedding::value> { template static constexpr auto apply(N const&) { return integral_constant{}; } }; ////////////////////////////////////////////////////////////////////////// // Optimizations ////////////////////////////////////////////////////////////////////////// template struct eval_if_impl> { template static constexpr decltype(auto) apply(Cond const&, Then&& t, Else&& e) { constexpr bool cond = static_cast(Cond::value); return eval_if_impl::apply(hana::bool_{}, static_cast(t), static_cast(e)); } template static constexpr decltype(auto) apply(hana::true_ const&, Then&& t, Else&&) { return hana::eval(static_cast(t)); } template static constexpr decltype(auto) apply(hana::false_ const&, Then&&, Else&& e) { return hana::eval(static_cast(e)); } }; template struct if_impl> { template static constexpr decltype(auto) apply(Cond const&, Then&& t, Else&& e) { constexpr bool cond = static_cast(Cond::value); return if_impl::apply(hana::bool_{}, static_cast(t), static_cast(e)); } //! @todo We could return `Then` instead of `auto` to sometimes save //! a copy, but that would break some code that would return a //! reference to a `type` object. I think the code that would be //! broken should be changed, but more thought needs to be given. template static constexpr auto apply(hana::true_ const&, Then&& t, Else&&) { return static_cast(t); } template static constexpr auto apply(hana::false_ const&, Then&&, Else&& e) { return static_cast(e); } }; BOOST_HANA_NAMESPACE_END #endif // !BOOST_HANA_BOOL_HPP