#pragma once
#include <utility>
namespace panda {
namespace detail {
template <bool...> struct bool_pack {};
}
/// bool_or returns its first argument converted to bool if it is possible, or default value (second arg) if type is not convertible to bool
template <typename T>
inline bool bool_or (T&& val, decltype(bool(val))) {
return bool(val);
}
template <typename T, typename = typename std::enable_if<!std::is_constructible<bool, T>::value>::type>
inline bool bool_or (T&&, bool default_val) {
return default_val;
}
template <typename T, bool Trivial = std::is_class<T>::value>
struct is_comparable {
static const bool value = true;
};
template <typename T>
struct is_comparable<T, true> {
struct fallback { bool operator==(const fallback& oth); };
struct mixed_type: std::remove_reference<T>::type, fallback {};
template < typename U, U > struct type_check {};
template < typename U > static std::false_type test( type_check< bool (fallback::*)(const fallback&), &U::operator== >* = 0 );
template < typename U > static std::true_type test( ... );
static const bool value = std::is_same<decltype(test<mixed_type>(nullptr)), std::true_type>::value;
};
template <typename T, typename... Args>
struct has_call_operator {
private:
typedef std::true_type yes;
typedef std::false_type no;
template<typename U> static auto test(int) -> decltype(std::declval<U>()(std::declval<Args>()...), yes());
template<typename> static no test(...);
public:
static constexpr bool value = std::is_same<decltype(test<T>(0)),yes>::value;
};
template <class FROM, class TO> using enable_if_convertible_t = std::enable_if_t<std::is_convertible<FROM, TO>::value>;
template <bool...T> using conjunction = std::is_same<detail::bool_pack<true,T...>, detail::bool_pack<T..., true>>;
template <bool...T> using disjunction = std::integral_constant<bool, !std::is_same<detail::bool_pack<false,T...>, detail::bool_pack<T..., false>>::value>;
template <class T, class...Args> using is_one_of = disjunction<std::is_same<T,Args>::value...>;
template <class T, class...Args> using enable_if_one_of_t = std::enable_if_t<is_one_of<T,Args...>::value, T>;
template <class T, class...Args> using enable_if_one_of_vt = std::enable_if_t<is_one_of<T,Args...>::value, void>;
template <class T, class R = T> using enable_if_arithmetic_t = std::enable_if_t<std::is_arithmetic<T>::value, R>;
template <class T, class R = T> using enable_if_signed_integral_t = std::enable_if_t<std::is_integral<T>::value && std::is_signed<T>::value, R>;
template <class T, class R = T> using enable_if_unsigned_integral_t = std::enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value, R>;
template <class T, class R = T> using enable_if_floatp_t = std::enable_if_t<std::is_floating_point<T>::value, R>;
template <typename T, typename F> auto static_if(std::true_type, T t, F) { return t; }
template <typename T, typename F> auto static_if(std::false_type, T, F f) { return f; }
template <bool B, typename T, typename F> auto static_if(T t, F f) { return static_if(std::integral_constant<bool, B>{}, t, f); }
template <bool B, typename T> auto static_if(T t) { return static_if(std::integral_constant<bool, B>{}, t, [](auto&&...){}); }
}