270 lines
9.7 KiB
C++
270 lines
9.7 KiB
C++
|
/*!
|
||
|
@file
|
||
|
Defines the `Logical` and `Comparable` models of `boost::hana::integral_constant`.
|
||
|
|
||
|
@copyright Louis Dionne 2013-2016
|
||
|
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 <boost/hana/fwd/bool.hpp>
|
||
|
|
||
|
#include <boost/hana/concept/integral_constant.hpp>
|
||
|
#include <boost/hana/config.hpp>
|
||
|
#include <boost/hana/core/to.hpp>
|
||
|
#include <boost/hana/core/when.hpp>
|
||
|
#include <boost/hana/detail/operators/arithmetic.hpp>
|
||
|
#include <boost/hana/detail/operators/comparable.hpp>
|
||
|
#include <boost/hana/detail/operators/logical.hpp>
|
||
|
#include <boost/hana/detail/operators/orderable.hpp>
|
||
|
#include <boost/hana/eval.hpp>
|
||
|
#include <boost/hana/fwd/core/tag_of.hpp>
|
||
|
#include <boost/hana/fwd/eval_if.hpp>
|
||
|
#include <boost/hana/fwd/if.hpp>
|
||
|
#include <boost/hana/fwd/value.hpp>
|
||
|
|
||
|
#include <cstddef>
|
||
|
#include <type_traits>
|
||
|
#include <utility>
|
||
|
|
||
|
|
||
|
BOOST_HANA_NAMESPACE_BEGIN
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// integral_constant
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//! @cond
|
||
|
namespace ic_detail {
|
||
|
template <typename T, T N, typename = std::make_integer_sequence<T, N>>
|
||
|
struct go;
|
||
|
|
||
|
template <typename T, T N, T ...i>
|
||
|
struct go<T, N, std::integer_sequence<T, i...>> {
|
||
|
using swallow = T[];
|
||
|
|
||
|
template <typename F>
|
||
|
static constexpr void with_index(F&& f)
|
||
|
{ (void)swallow{T{}, ((void)f(integral_constant<T, i>{}), i)...}; }
|
||
|
|
||
|
template <typename F>
|
||
|
static constexpr void without_index(F&& f)
|
||
|
{ (void)swallow{T{}, ((void)f(), i)...}; }
|
||
|
};
|
||
|
|
||
|
template <typename T, T v>
|
||
|
template <typename F>
|
||
|
constexpr void with_index_t<T, v>::operator()(F&& f) const
|
||
|
{ go<T, ((void)sizeof(&f), v)>::with_index(static_cast<F&&>(f)); }
|
||
|
|
||
|
template <typename T, T v>
|
||
|
template <typename F>
|
||
|
constexpr void times_t<T, v>::operator()(F&& f) const
|
||
|
{ go<T, ((void)sizeof(&f), v)>::without_index(static_cast<F&&>(f)); }
|
||
|
|
||
|
// avoid link-time error
|
||
|
template <typename T, T v>
|
||
|
constexpr with_index_t<T, v> times_t<T, v>::with_index;
|
||
|
}
|
||
|
|
||
|
// avoid link-time error
|
||
|
template <typename T, T v>
|
||
|
constexpr ic_detail::times_t<T, v> integral_constant<T, v>::times;
|
||
|
|
||
|
template <typename T, T v>
|
||
|
struct tag_of<integral_constant<T, v>> {
|
||
|
using type = integral_constant_tag<T>;
|
||
|
};
|
||
|
//! @endcond
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Operators
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
namespace detail {
|
||
|
template <typename T>
|
||
|
struct comparable_operators<integral_constant_tag<T>> {
|
||
|
static constexpr bool value = true;
|
||
|
};
|
||
|
template <typename T>
|
||
|
struct orderable_operators<integral_constant_tag<T>> {
|
||
|
static constexpr bool value = true;
|
||
|
};
|
||
|
template <typename T>
|
||
|
struct arithmetic_operators<integral_constant_tag<T>> {
|
||
|
static constexpr bool value = true;
|
||
|
};
|
||
|
template <typename T>
|
||
|
struct logical_operators<integral_constant_tag<T>> {
|
||
|
static constexpr bool value = true;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
#define BOOST_HANA_INTEGRAL_CONSTANT_BINARY_OP(op) \
|
||
|
template <typename U, U u, typename V, V v> \
|
||
|
constexpr integral_constant<decltype(u op v), (u op v)> \
|
||
|
operator op(integral_constant<U, u>, integral_constant<V, v>) \
|
||
|
{ return {}; } \
|
||
|
/**/
|
||
|
|
||
|
#define BOOST_HANA_INTEGRAL_CONSTANT_UNARY_OP(op) \
|
||
|
template <typename U, U u> \
|
||
|
constexpr integral_constant<decltype(op u), (op u)> \
|
||
|
operator op(integral_constant<U, u>) \
|
||
|
{ 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<int>(c) - static_cast<int>('A') + 10;
|
||
|
}
|
||
|
else if (c >= 'a' && c <= 'f') {
|
||
|
result = static_cast<int>(c) - static_cast<int>('a') + 10;
|
||
|
}
|
||
|
else {
|
||
|
result = static_cast<int>(c) - static_cast<int>('0');
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
template<std::size_t N>
|
||
|
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 <char ...c>
|
||
|
constexpr auto operator"" _c() {
|
||
|
return hana::llong<ic_detail::parse<sizeof...(c)>({c...})>{};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Model of Constant/IntegralConstant
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
template <typename T>
|
||
|
struct IntegralConstant<integral_constant_tag<T>> {
|
||
|
static constexpr bool value = true;
|
||
|
};
|
||
|
|
||
|
template <typename T, typename C>
|
||
|
struct to_impl<integral_constant_tag<T>, C, when<hana::IntegralConstant<C>::value>>
|
||
|
: embedding<is_embedded<typename C::value_type, T>::value>
|
||
|
{
|
||
|
template <typename N>
|
||
|
static constexpr auto apply(N const&)
|
||
|
{ return integral_constant<T, N::value>{}; }
|
||
|
};
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Optimizations
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
template <typename T>
|
||
|
struct eval_if_impl<integral_constant_tag<T>> {
|
||
|
template <typename Cond, typename Then, typename Else>
|
||
|
static constexpr decltype(auto)
|
||
|
apply(Cond const&, Then&& t, Else&& e) {
|
||
|
constexpr bool cond = static_cast<bool>(Cond::value);
|
||
|
return eval_if_impl::apply(hana::bool_<cond>{},
|
||
|
static_cast<Then&&>(t),
|
||
|
static_cast<Else&&>(e));
|
||
|
}
|
||
|
|
||
|
template <typename Then, typename Else>
|
||
|
static constexpr decltype(auto)
|
||
|
apply(hana::true_ const&, Then&& t, Else&&)
|
||
|
{ return hana::eval(static_cast<Then&&>(t)); }
|
||
|
|
||
|
template <typename Then, typename Else>
|
||
|
static constexpr decltype(auto)
|
||
|
apply(hana::false_ const&, Then&&, Else&& e)
|
||
|
{ return hana::eval(static_cast<Else&&>(e)); }
|
||
|
};
|
||
|
|
||
|
template <typename T>
|
||
|
struct if_impl<integral_constant_tag<T>> {
|
||
|
template <typename Cond, typename Then, typename Else>
|
||
|
static constexpr decltype(auto)
|
||
|
apply(Cond const&, Then&& t, Else&& e) {
|
||
|
constexpr bool cond = static_cast<bool>(Cond::value);
|
||
|
return if_impl::apply(hana::bool_<cond>{},
|
||
|
static_cast<Then&&>(t),
|
||
|
static_cast<Else&&>(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 <typename Then, typename Else>
|
||
|
static constexpr auto
|
||
|
apply(hana::true_ const&, Then&& t, Else&&)
|
||
|
{ return static_cast<Then&&>(t); }
|
||
|
|
||
|
template <typename Then, typename Else>
|
||
|
static constexpr auto
|
||
|
apply(hana::false_ const&, Then&&, Else&& e)
|
||
|
{ return static_cast<Else&&>(e); }
|
||
|
};
|
||
|
BOOST_HANA_NAMESPACE_END
|
||
|
|
||
|
#endif // !BOOST_HANA_BOOL_HPP
|