fix math/comparison.hpp

This commit is contained in:
bolero-MURAKAMI 2012-07-07 14:58:46 +09:00
parent 1c65d59971
commit 3b6ba46f17
23 changed files with 389 additions and 175 deletions

7
sprout/math.hpp Normal file
View file

@ -0,0 +1,7 @@
#ifndef SPROUT_MATH_HPP
#define SPROUT_MATH_HPP
#include <sprout/config.hpp>
#include <sprout/math/functions.hpp>
#endif // #ifndef SPROUT_MATH_HPP

View file

@ -6,7 +6,7 @@
#include <sprout/math/detail/config.hpp> #include <sprout/math/detail/config.hpp>
#include <sprout/math/atan.hpp> #include <sprout/math/atan.hpp>
#include <sprout/math/constants.hpp> #include <sprout/math/constants.hpp>
#include <sprout/math/float_promote.hpp> #include <sprout/type_traits/float_promote.hpp>
#include <sprout/type_traits/enabler_if.hpp> #include <sprout/type_traits/enabler_if.hpp>
namespace sprout { namespace sprout {
@ -31,9 +31,9 @@ namespace sprout {
std::is_arithmetic<ArithmeticType1>::value && std::is_arithmetic<ArithmeticType2>::value std::is_arithmetic<ArithmeticType1>::value && std::is_arithmetic<ArithmeticType2>::value
>::type = sprout::enabler >::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR typename sprout::math::float_promote<ArithmeticType1, ArithmeticType2>::type inline SPROUT_CONSTEXPR typename sprout::float_promote<ArithmeticType1, ArithmeticType2>::type
atan2(ArithmeticType1 y, ArithmeticType2 x) { atan2(ArithmeticType1 y, ArithmeticType2 x) {
typedef typename sprout::math::float_promote<ArithmeticType1, ArithmeticType2>::type type; typedef typename sprout::float_promote<ArithmeticType1, ArithmeticType2>::type type;
return sprout::math::detail::atan2(static_cast<type>(y), static_cast<type>(x)); return sprout::math::detail::atan2(static_cast<type>(y), static_cast<type>(x));
} }
} // namespace detail } // namespace detail

View file

@ -4,33 +4,24 @@
#include <type_traits> #include <type_traits>
#include <sprout/config.hpp> #include <sprout/config.hpp>
#include <sprout/math/equal_to.hpp> #include <sprout/math/equal_to.hpp>
#include <sprout/math/float_promote.hpp> #include <sprout/math/less.hpp>
#include <sprout/type_traits/enabler_if.hpp> #include <sprout/type_traits/enabler_if.hpp>
namespace sprout { namespace sprout {
namespace math { namespace math {
namespace detail {
template<typename T>
inline SPROUT_CONSTEXPR int
compare_impl(T x, T y) {
return sprout::math::equal_to(x, y) ? 0
: x < y ? -1
: 1
;
}
} // namespace detail
// //
// compare // compare
// //
template< template<
typename T1, typename T, typename U,
typename T2, typename sprout::enabler_if<std::is_arithmetic<T>::value && std::is_arithmetic<U>::value>::type = sprout::enabler
typename sprout::enabler_if<std::is_arithmetic<T1>::value && std::is_arithmetic<T2>::value>::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR int inline SPROUT_CONSTEXPR int
compare(T1 x, T2 y) { compare(T x, U y) {
typedef typename sprout::math::float_promote<T1, T2>::type promoted; return sprout::math::equal_to(x, y) ? 0
return sprout::math::detail::compare_impl<promoted>(x, y); : sprout::math::less(x, y) ? -1
: 1
;
} }
} // namespace math } // namespace math
} // namespace sprout } // namespace sprout

View file

@ -6,7 +6,7 @@
#include <sprout/config.hpp> #include <sprout/config.hpp>
#include <sprout/algorithm/max.hpp> #include <sprout/algorithm/max.hpp>
#include <sprout/math/abs.hpp> #include <sprout/math/abs.hpp>
#include <sprout/math/float_promote.hpp> #include <sprout/type_traits/arithmetic_promote.hpp>
#include <sprout/type_traits/enabler_if.hpp> #include <sprout/type_traits/enabler_if.hpp>
namespace sprout { namespace sprout {
@ -18,12 +18,9 @@ namespace sprout {
return sprout::max(sprout::max(x, y), z); return sprout::max(sprout::max(x, y), z);
} }
template< template<typename FloatType>
typename FloatType,
typename sprout::enabler_if<std::is_floating_point<FloatType>::value>::type = sprout::enabler
>
inline SPROUT_CONSTEXPR bool inline SPROUT_CONSTEXPR bool
equal_to(FloatType x, FloatType y) { equal_to_impl(FloatType x, FloatType y) {
return x == y return x == y
|| sprout::abs(x - y) || sprout::abs(x - y)
<= std::numeric_limits<FloatType>::epsilon() * sprout::math::detail::max3(std::abs(x), std::abs(y), FloatType(1.0)) <= std::numeric_limits<FloatType>::epsilon() * sprout::math::detail::max3(std::abs(x), std::abs(y), FloatType(1.0))
@ -31,11 +28,25 @@ namespace sprout {
} }
template< template<
typename IntType, typename FloatType1, typename FloatType2,
typename sprout::enabler_if<std::is_integral<IntType>::value>::type = sprout::enabler typename sprout::enabler_if<
std::is_floating_point<typename sprout::arithmetic_promote<FloatType1, FloatType2>::type>::value
>::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR bool inline SPROUT_CONSTEXPR bool
equal_to(IntType x, IntType y) { equal_to(FloatType1 x, FloatType2 y) {
typedef typename sprout::arithmetic_promote<FloatType1, FloatType2>::type type;
return sprout::math::detail::equal_to_impl<type>(x, y);
}
template<
typename IntType1, typename IntType2,
typename sprout::enabler_if<
std::is_integral<typename sprout::arithmetic_promote<IntType1, IntType2>::type>::value
>::type = sprout::enabler
>
inline SPROUT_CONSTEXPR bool
equal_to(IntType1 x, IntType2 y) {
return x == y; return x == y;
} }
} // namespace detail } // namespace detail
@ -43,14 +54,12 @@ namespace sprout {
// equal_to // equal_to
// //
template< template<
typename T1, typename T, typename U,
typename T2, typename sprout::enabler_if<std::is_arithmetic<T>::value && std::is_arithmetic<U>::value>::type = sprout::enabler
typename sprout::enabler_if<std::is_arithmetic<T1>::value && std::is_arithmetic<T2>::value>::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR bool inline SPROUT_CONSTEXPR bool
equal_to(T1 x, T2 y) { equal_to(T x, U y) {
typedef typename sprout::math::float_promote<T1, T2>::type promoted; return sprout::math::detail::equal_to(x, y);
return sprout::math::detail::equal_to<promoted>(x, y);
} }
} // namespace math } // namespace math
} // namespace sprout } // namespace sprout

View file

@ -4,7 +4,7 @@
#include <type_traits> #include <type_traits>
#include <sprout/config.hpp> #include <sprout/config.hpp>
#include <sprout/math/detail/config.hpp> #include <sprout/math/detail/config.hpp>
#include <sprout/math/float_promote.hpp> #include <sprout/type_traits/float_promote.hpp>
#include <sprout/type_traits/enabler_if.hpp> #include <sprout/type_traits/enabler_if.hpp>
namespace sprout { namespace sprout {
@ -26,9 +26,9 @@ namespace sprout {
std::is_arithmetic<ArithmeticType1>::value && std::is_arithmetic<ArithmeticType2>::value std::is_arithmetic<ArithmeticType1>::value && std::is_arithmetic<ArithmeticType2>::value
>::type = sprout::enabler >::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR typename sprout::math::float_promote<ArithmeticType1, ArithmeticType2>::type inline SPROUT_CONSTEXPR typename sprout::float_promote<ArithmeticType1, ArithmeticType2>::type
fdim(ArithmeticType1 x, ArithmeticType2 y) { fdim(ArithmeticType1 x, ArithmeticType2 y) {
typedef typename sprout::math::float_promote<ArithmeticType1, ArithmeticType2>::type type; typedef typename sprout::float_promote<ArithmeticType1, ArithmeticType2>::type type;
return sprout::math::detail::fdim(static_cast<type>(x), static_cast<type>(y)); return sprout::math::detail::fdim(static_cast<type>(x), static_cast<type>(y));
} }
} // namespace detail } // namespace detail

View file

@ -1,50 +0,0 @@
#ifndef SPROUT_MATH_FLOAT_PROMOTE_HPP
#define SPROUT_MATH_FLOAT_PROMOTE_HPP
#include <type_traits>
#include <sprout/config.hpp>
namespace sprout {
namespace math {
namespace detail {
template<typename T, typename U>
struct float_promote2
: public std::conditional<
(std::is_same<T, long double>::value || std::is_same<U, long double>::value),
std::common_type<long double>,
typename std::conditional<
(std::is_same<T, float>::value && std::is_same<U, float>::value),
float,
double
>
>::type
{
static_assert(std::is_arithmetic<U>::value, "float_promote requires arithmetic type.");
};
template<typename Current, typename Head, typename... Tail>
struct float_promote_impl
: public sprout::math::detail::float_promote_impl<
typename sprout::math::detail::float_promote2<Current, Head>::type,
Tail...
>
{};
template<typename Current, typename Head>
struct float_promote_impl<Current, Head>
: public sprout::math::detail::float_promote2<Current, Head>
{};
} // namespace detail
//
// float_promote
//
template<typename... Types>
struct float_promote
: public sprout::math::detail::float_promote_impl<
float, typename std::remove_cv<Types>::type...
>
{};
} // namespace math
} // namespace sprout
#endif // #ifndef SPROUT_MATH_FLOAT_PROMOTE_HPP

View file

@ -4,7 +4,7 @@
#include <type_traits> #include <type_traits>
#include <sprout/config.hpp> #include <sprout/config.hpp>
#include <sprout/math/detail/config.hpp> #include <sprout/math/detail/config.hpp>
#include <sprout/math/float_promote.hpp> #include <sprout/type_traits/float_promote.hpp>
#include <sprout/type_traits/enabler_if.hpp> #include <sprout/type_traits/enabler_if.hpp>
namespace sprout { namespace sprout {
@ -29,11 +29,11 @@ namespace sprout {
&& std::is_arithmetic<ArithmeticType3>::value && std::is_arithmetic<ArithmeticType3>::value
>::type = sprout::enabler >::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR typename sprout::math::float_promote< inline SPROUT_CONSTEXPR typename sprout::float_promote<
ArithmeticType1, ArithmeticType2, ArithmeticType3 ArithmeticType1, ArithmeticType2, ArithmeticType3
>::type >::type
fma(ArithmeticType1 x, ArithmeticType2 y, ArithmeticType3 z) { fma(ArithmeticType1 x, ArithmeticType2 y, ArithmeticType3 z) {
typedef typename sprout::math::float_promote< typedef typename sprout::float_promote<
ArithmeticType1, ArithmeticType2, ArithmeticType3 ArithmeticType1, ArithmeticType2, ArithmeticType3
>::type type; >::type type;
return sprout::math::detail::fma(static_cast<type>(x), static_cast<type>(y), static_cast<type>(z)); return sprout::math::detail::fma(static_cast<type>(x), static_cast<type>(y), static_cast<type>(z));

View file

@ -4,7 +4,7 @@
#include <type_traits> #include <type_traits>
#include <sprout/config.hpp> #include <sprout/config.hpp>
#include <sprout/math/detail/config.hpp> #include <sprout/math/detail/config.hpp>
#include <sprout/math/float_promote.hpp> #include <sprout/type_traits/float_promote.hpp>
#include <sprout/type_traits/enabler_if.hpp> #include <sprout/type_traits/enabler_if.hpp>
namespace sprout { namespace sprout {
@ -26,9 +26,9 @@ namespace sprout {
std::is_arithmetic<ArithmeticType1>::value && std::is_arithmetic<ArithmeticType2>::value std::is_arithmetic<ArithmeticType1>::value && std::is_arithmetic<ArithmeticType2>::value
>::type = sprout::enabler >::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR typename sprout::math::float_promote<ArithmeticType1, ArithmeticType2>::type inline SPROUT_CONSTEXPR typename sprout::float_promote<ArithmeticType1, ArithmeticType2>::type
fmax(ArithmeticType1 x, ArithmeticType2 y) { fmax(ArithmeticType1 x, ArithmeticType2 y) {
typedef typename sprout::math::float_promote<ArithmeticType1, ArithmeticType2>::type type; typedef typename sprout::float_promote<ArithmeticType1, ArithmeticType2>::type type;
return sprout::math::detail::fmax(static_cast<type>(x), static_cast<type>(y)); return sprout::math::detail::fmax(static_cast<type>(x), static_cast<type>(y));
} }
} // namespace detail } // namespace detail

View file

@ -4,7 +4,7 @@
#include <type_traits> #include <type_traits>
#include <sprout/config.hpp> #include <sprout/config.hpp>
#include <sprout/math/detail/config.hpp> #include <sprout/math/detail/config.hpp>
#include <sprout/math/float_promote.hpp> #include <sprout/type_traits/float_promote.hpp>
#include <sprout/type_traits/enabler_if.hpp> #include <sprout/type_traits/enabler_if.hpp>
namespace sprout { namespace sprout {
@ -26,9 +26,9 @@ namespace sprout {
std::is_arithmetic<ArithmeticType1>::value && std::is_arithmetic<ArithmeticType2>::value std::is_arithmetic<ArithmeticType1>::value && std::is_arithmetic<ArithmeticType2>::value
>::type = sprout::enabler >::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR typename sprout::math::float_promote<ArithmeticType1, ArithmeticType2>::type inline SPROUT_CONSTEXPR typename sprout::float_promote<ArithmeticType1, ArithmeticType2>::type
fmin(ArithmeticType1 x, ArithmeticType2 y) { fmin(ArithmeticType1 x, ArithmeticType2 y) {
typedef typename sprout::math::float_promote<ArithmeticType1, ArithmeticType2>::type type; typedef typename sprout::float_promote<ArithmeticType1, ArithmeticType2>::type type;
return sprout::math::detail::fmin(static_cast<type>(x), static_cast<type>(y)); return sprout::math::detail::fmin(static_cast<type>(x), static_cast<type>(y));
} }
} // namespace detail } // namespace detail

View file

@ -4,42 +4,73 @@
#include <type_traits> #include <type_traits>
#include <sprout/config.hpp> #include <sprout/config.hpp>
#include <sprout/math/not_equal_to.hpp> #include <sprout/math/not_equal_to.hpp>
#include <sprout/math/float_promote.hpp> #include <sprout/type_traits/arithmetic_promote.hpp>
#include <sprout/type_traits/enabler_if.hpp> #include <sprout/type_traits/enabler_if.hpp>
namespace sprout { namespace sprout {
namespace math { namespace math {
namespace detail { namespace detail {
template< template<
typename FloatType, typename FloatType1, typename FloatType2,
typename sprout::enabler_if<std::is_floating_point<FloatType>::value>::type = sprout::enabler typename sprout::enabler_if<
std::is_floating_point<typename sprout::arithmetic_promote<FloatType1, FloatType2>::type>::value
>::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR bool inline SPROUT_CONSTEXPR bool
greater(FloatType x, FloatType y) { greater(FloatType1 x, FloatType2 y) {
return sprout::math::not_equal_to(x, y) && x > y; return sprout::math::not_equal_to(x, y) && x > y;
} }
template< template<
typename IntType, typename IntType1, typename IntType2,
typename sprout::enabler_if<std::is_integral<IntType>::value>::type = sprout::enabler typename sprout::enabler_if<
std::is_integral<typename sprout::arithmetic_promote<IntType1, IntType2>::type>::value
&& (std::is_unsigned<IntType1>::value == std::is_unsigned<IntType2>::value)
>::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR bool inline SPROUT_CONSTEXPR bool
greater(IntType x, IntType y) { greater(IntType1 x, IntType2 y) {
return x > y; return x > y;
} }
template<
typename IntType1, typename IntType2,
typename sprout::enabler_if<
std::is_integral<typename sprout::arithmetic_promote<IntType1, IntType2>::type>::value
&& std::is_signed<IntType1>::value && std::is_unsigned<IntType2>::value
>::type = sprout::enabler
>
inline SPROUT_CONSTEXPR bool
greater(IntType1 x, IntType2 y) {
typedef typename std::make_unsigned<typename sprout::arithmetic_promote<IntType1, IntType2>::type>::type type;
return x < 0 ? false
: static_cast<type>(x) > static_cast<type>(y)
;
}
template<
typename IntType1, typename IntType2,
typename sprout::enabler_if<
std::is_integral<typename sprout::arithmetic_promote<IntType1, IntType2>::type>::value
&& std::is_unsigned<IntType1>::value && std::is_signed<IntType2>::value
>::type = sprout::enabler
>
inline SPROUT_CONSTEXPR bool
greater(IntType1 x, IntType2 y) {
typedef typename std::make_unsigned<typename sprout::arithmetic_promote<IntType1, IntType2>::type>::type type;
return y < 0 ? true
: static_cast<type>(x) > static_cast<type>(y)
;
}
} // namespace detail } // namespace detail
// //
// greater // greater
// //
template< template<
typename T1, typename T, typename U,
typename T2, typename sprout::enabler_if<std::is_arithmetic<T>::value && std::is_arithmetic<U>::value>::type = sprout::enabler
typename sprout::enabler_if<std::is_arithmetic<T1>::value && std::is_arithmetic<T2>::value>::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR bool inline SPROUT_CONSTEXPR bool
greater(T1 x, T2 y) { greater(T x, U y) {
typedef typename sprout::math::float_promote<T1, T2>::type promoted; return sprout::math::detail::greater(x, y);
return sprout::math::detail::greater<promoted>(x, y);
} }
} // namespace math } // namespace math
} // namespace sprout } // namespace sprout

View file

@ -4,42 +4,73 @@
#include <type_traits> #include <type_traits>
#include <sprout/config.hpp> #include <sprout/config.hpp>
#include <sprout/math/equal_to.hpp> #include <sprout/math/equal_to.hpp>
#include <sprout/math/float_promote.hpp> #include <sprout/type_traits/arithmetic_promote.hpp>
#include <sprout/type_traits/enabler_if.hpp> #include <sprout/type_traits/enabler_if.hpp>
namespace sprout { namespace sprout {
namespace math { namespace math {
namespace detail { namespace detail {
template< template<
typename FloatType, typename FloatType1, typename FloatType2,
typename sprout::enabler_if<std::is_floating_point<FloatType>::value>::type = sprout::enabler typename sprout::enabler_if<
std::is_floating_point<typename sprout::arithmetic_promote<FloatType1, FloatType2>::type>::value
>::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR bool inline SPROUT_CONSTEXPR bool
greater_equal(FloatType x, FloatType y) { greater_equal_equal(FloatType1 x, FloatType2 y) {
return sprout::math::equal_to(x, y) || x > y; return sprout::math::equal_to(x, y) || x > y;
} }
template< template<
typename IntType, typename IntType1, typename IntType2,
typename sprout::enabler_if<std::is_integral<IntType>::value>::type = sprout::enabler typename sprout::enabler_if<
std::is_integral<typename sprout::arithmetic_promote<IntType1, IntType2>::type>::value
&& (std::is_unsigned<IntType1>::value == std::is_unsigned<IntType2>::value)
>::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR bool inline SPROUT_CONSTEXPR bool
greater_equal(IntType x, IntType y) { greater_equal(IntType1 x, IntType2 y) {
return x >= y; return x >= y;
} }
template<
typename IntType1, typename IntType2,
typename sprout::enabler_if<
std::is_integral<typename sprout::arithmetic_promote<IntType1, IntType2>::type>::value
&& std::is_signed<IntType1>::value && std::is_unsigned<IntType2>::value
>::type = sprout::enabler
>
inline SPROUT_CONSTEXPR bool
greater_equal(IntType1 x, IntType2 y) {
typedef typename std::make_unsigned<typename sprout::arithmetic_promote<IntType1, IntType2>::type>::type type;
return x < 0 ? false
: static_cast<type>(x) >= static_cast<type>(y)
;
}
template<
typename IntType1, typename IntType2,
typename sprout::enabler_if<
std::is_integral<typename sprout::arithmetic_promote<IntType1, IntType2>::type>::value
&& std::is_unsigned<IntType1>::value && std::is_signed<IntType2>::value
>::type = sprout::enabler
>
inline SPROUT_CONSTEXPR bool
greater_equal(IntType1 x, IntType2 y) {
typedef typename std::make_unsigned<typename sprout::arithmetic_promote<IntType1, IntType2>::type>::type type;
return y < 0 ? true
: static_cast<type>(x) >= static_cast<type>(y)
;
}
} // namespace detail } // namespace detail
// //
// greater_equal // greater_equal_equal
// //
template< template<
typename T1, typename T, typename U,
typename T2, typename sprout::enabler_if<std::is_arithmetic<T>::value && std::is_arithmetic<U>::value>::type = sprout::enabler
typename sprout::enabler_if<std::is_arithmetic<T1>::value && std::is_arithmetic<T2>::value>::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR bool inline SPROUT_CONSTEXPR bool
greater_equal(T1 x, T2 y) { greater_equal(T x, U y) {
typedef typename sprout::math::float_promote<T1, T2>::type promoted; return sprout::math::detail::greater_equal(x, y);
return sprout::math::detail::greater_equal<promoted>(x, y);
} }
} // namespace math } // namespace math
} // namespace sprout } // namespace sprout

View file

@ -3,10 +3,10 @@
#include <type_traits> #include <type_traits>
#include <sprout/config.hpp> #include <sprout/config.hpp>
#include <sprout/math/detail/config.hpp> #include <sprout/type_traits/float_promote.hpp>
#include <sprout/math/float_promote.hpp>
#include <sprout/math/sqrt.hpp>
#include <sprout/type_traits/enabler_if.hpp> #include <sprout/type_traits/enabler_if.hpp>
#include <sprout/math/detail/config.hpp>
#include <sprout/math/sqrt.hpp>
namespace sprout { namespace sprout {
namespace math { namespace math {
@ -27,9 +27,9 @@ namespace sprout {
std::is_arithmetic<ArithmeticType1>::value && std::is_arithmetic<ArithmeticType2>::value std::is_arithmetic<ArithmeticType1>::value && std::is_arithmetic<ArithmeticType2>::value
>::type = sprout::enabler >::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR typename sprout::math::float_promote<ArithmeticType1, ArithmeticType2>::type inline SPROUT_CONSTEXPR typename sprout::float_promote<ArithmeticType1, ArithmeticType2>::type
hypot(ArithmeticType1 x, ArithmeticType2 y) { hypot(ArithmeticType1 x, ArithmeticType2 y) {
typedef typename sprout::math::float_promote<ArithmeticType1, ArithmeticType2>::type type; typedef typename sprout::float_promote<ArithmeticType1, ArithmeticType2>::type type;
return sprout::math::detail::hypot(static_cast<type>(x), static_cast<type>(y)); return sprout::math::detail::hypot(static_cast<type>(x), static_cast<type>(y));
} }
} // namespace detail } // namespace detail

View file

@ -4,42 +4,73 @@
#include <type_traits> #include <type_traits>
#include <sprout/config.hpp> #include <sprout/config.hpp>
#include <sprout/math/not_equal_to.hpp> #include <sprout/math/not_equal_to.hpp>
#include <sprout/math/float_promote.hpp> #include <sprout/type_traits/arithmetic_promote.hpp>
#include <sprout/type_traits/enabler_if.hpp> #include <sprout/type_traits/enabler_if.hpp>
namespace sprout { namespace sprout {
namespace math { namespace math {
namespace detail { namespace detail {
template< template<
typename FloatType, typename FloatType1, typename FloatType2,
typename sprout::enabler_if<std::is_floating_point<FloatType>::value>::type = sprout::enabler typename sprout::enabler_if<
std::is_floating_point<typename sprout::arithmetic_promote<FloatType1, FloatType2>::type>::value
>::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR bool inline SPROUT_CONSTEXPR bool
less(FloatType x, FloatType y) { less(FloatType1 x, FloatType2 y) {
return sprout::math::not_equal_to(x, y) && x < y; return sprout::math::not_equal_to(x, y) && x < y;
} }
template< template<
typename IntType, typename IntType1, typename IntType2,
typename sprout::enabler_if<std::is_integral<IntType>::value>::type = sprout::enabler typename sprout::enabler_if<
std::is_integral<typename sprout::arithmetic_promote<IntType1, IntType2>::type>::value
&& (std::is_unsigned<IntType1>::value == std::is_unsigned<IntType2>::value)
>::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR bool inline SPROUT_CONSTEXPR bool
less(IntType x, IntType y) { less(IntType1 x, IntType2 y) {
return x < y; return x < y;
} }
template<
typename IntType1, typename IntType2,
typename sprout::enabler_if<
std::is_integral<typename sprout::arithmetic_promote<IntType1, IntType2>::type>::value
&& std::is_signed<IntType1>::value && std::is_unsigned<IntType2>::value
>::type = sprout::enabler
>
inline SPROUT_CONSTEXPR bool
less(IntType1 x, IntType2 y) {
typedef typename std::make_unsigned<typename sprout::arithmetic_promote<IntType1, IntType2>::type>::type type;
return x < 0 ? true
: static_cast<type>(x) < static_cast<type>(y)
;
}
template<
typename IntType1, typename IntType2,
typename sprout::enabler_if<
std::is_integral<typename sprout::arithmetic_promote<IntType1, IntType2>::type>::value
&& std::is_unsigned<IntType1>::value && std::is_signed<IntType2>::value
>::type = sprout::enabler
>
inline SPROUT_CONSTEXPR bool
less(IntType1 x, IntType2 y) {
typedef typename std::make_unsigned<typename sprout::arithmetic_promote<IntType1, IntType2>::type>::type type;
return y < 0 ? false
: static_cast<type>(x) < static_cast<type>(y)
;
}
} // namespace detail } // namespace detail
// //
// less // less
// //
template< template<
typename T1, typename T, typename U,
typename T2, typename sprout::enabler_if<std::is_arithmetic<T>::value && std::is_arithmetic<U>::value>::type = sprout::enabler
typename sprout::enabler_if<std::is_arithmetic<T1>::value && std::is_arithmetic<T2>::value>::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR bool inline SPROUT_CONSTEXPR bool
less(T1 x, T2 y) { less(T x, U y) {
typedef typename sprout::math::float_promote<T1, T2>::type promoted; return sprout::math::detail::less(x, y);
return sprout::math::detail::less<promoted>(x, y);
} }
} // namespace math } // namespace math
} // namespace sprout } // namespace sprout

View file

@ -4,42 +4,73 @@
#include <type_traits> #include <type_traits>
#include <sprout/config.hpp> #include <sprout/config.hpp>
#include <sprout/math/equal_to.hpp> #include <sprout/math/equal_to.hpp>
#include <sprout/math/float_promote.hpp> #include <sprout/type_traits/arithmetic_promote.hpp>
#include <sprout/type_traits/enabler_if.hpp> #include <sprout/type_traits/enabler_if.hpp>
namespace sprout { namespace sprout {
namespace math { namespace math {
namespace detail { namespace detail {
template< template<
typename FloatType, typename FloatType1, typename FloatType2,
typename sprout::enabler_if<std::is_floating_point<FloatType>::value>::type = sprout::enabler typename sprout::enabler_if<
std::is_floating_point<typename sprout::arithmetic_promote<FloatType1, FloatType2>::type>::value
>::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR bool inline SPROUT_CONSTEXPR bool
less_equal(FloatType x, FloatType y) { less_equal(FloatType1 x, FloatType2 y) {
return sprout::math::equal_to(x, y) || x < y; return sprout::math::not_equal_to(x, y) || x < y;
} }
template< template<
typename IntType, typename IntType1, typename IntType2,
typename sprout::enabler_if<std::is_integral<IntType>::value>::type = sprout::enabler typename sprout::enabler_if<
std::is_integral<typename sprout::arithmetic_promote<IntType1, IntType2>::type>::value
&& (std::is_unsigned<IntType1>::value == std::is_unsigned<IntType2>::value)
>::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR bool inline SPROUT_CONSTEXPR bool
less_equal(IntType x, IntType y) { less_equal(IntType1 x, IntType2 y) {
return x <= y; return x <= y;
} }
template<
typename IntType1, typename IntType2,
typename sprout::enabler_if<
std::is_integral<typename sprout::arithmetic_promote<IntType1, IntType2>::type>::value
&& std::is_signed<IntType1>::value && std::is_unsigned<IntType2>::value
>::type = sprout::enabler
>
inline SPROUT_CONSTEXPR bool
less_equal(IntType1 x, IntType2 y) {
typedef typename std::make_unsigned<typename sprout::arithmetic_promote<IntType1, IntType2>::type>::type type;
return x < 0 ? true
: static_cast<type>(x) <= static_cast<type>(y)
;
}
template<
typename IntType1, typename IntType2,
typename sprout::enabler_if<
std::is_integral<typename sprout::arithmetic_promote<IntType1, IntType2>::type>::value
&& std::is_unsigned<IntType1>::value && std::is_signed<IntType2>::value
>::type = sprout::enabler
>
inline SPROUT_CONSTEXPR bool
less_equal(IntType1 x, IntType2 y) {
typedef typename std::make_unsigned<typename sprout::arithmetic_promote<IntType1, IntType2>::type>::type type;
return y < 0 ? false
: static_cast<type>(x) <= static_cast<type>(y)
;
}
} // namespace detail } // namespace detail
// //
// less_equal // less_equal
// //
template< template<
typename T1, typename T, typename U,
typename T2, typename sprout::enabler_if<std::is_arithmetic<T>::value && std::is_arithmetic<U>::value>::type = sprout::enabler
typename sprout::enabler_if<std::is_arithmetic<T1>::value && std::is_arithmetic<T2>::value>::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR bool inline SPROUT_CONSTEXPR bool
less_equal(T1 x, T2 y) { less_equal(T x, U y) {
typedef typename sprout::math::float_promote<T1, T2>::type promoted; return sprout::math::detail::less_equal(x, y);
return sprout::math::detail::less_equal<promoted>(x, y);
} }
} // namespace math } // namespace math
} // namespace sprout } // namespace sprout

View file

@ -12,12 +12,11 @@ namespace sprout {
// not_equal_to // not_equal_to
// //
template< template<
typename T1, typename T, typename U,
typename T2, typename sprout::enabler_if<std::is_arithmetic<T>::value && std::is_arithmetic<U>::value>::type = sprout::enabler
typename sprout::enabler_if<std::is_arithmetic<T1>::value && std::is_arithmetic<T2>::value>::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR bool inline SPROUT_CONSTEXPR bool
not_equal_to(T1 x, T2 y) { not_equal_to(T x, U y) {
return !sprout::math::equal_to(x, y); return !sprout::math::equal_to(x, y);
} }
} // namespace math } // namespace math

View file

@ -7,7 +7,7 @@
#include <sprout/math/exp.hpp> #include <sprout/math/exp.hpp>
#include <sprout/math/log.hpp> #include <sprout/math/log.hpp>
#include <sprout/math/constants.hpp> #include <sprout/math/constants.hpp>
#include <sprout/math/float_promote.hpp> #include <sprout/type_traits/float_promote.hpp>
#include <sprout/type_traits/enabler_if.hpp> #include <sprout/type_traits/enabler_if.hpp>
namespace sprout { namespace sprout {
@ -31,9 +31,9 @@ namespace sprout {
std::is_arithmetic<ArithmeticType1>::value && std::is_arithmetic<ArithmeticType2>::value std::is_arithmetic<ArithmeticType1>::value && std::is_arithmetic<ArithmeticType2>::value
>::type = sprout::enabler >::type = sprout::enabler
> >
inline SPROUT_CONSTEXPR typename sprout::math::float_promote<ArithmeticType1, ArithmeticType2>::type inline SPROUT_CONSTEXPR typename sprout::float_promote<ArithmeticType1, ArithmeticType2>::type
pow(ArithmeticType1 x, ArithmeticType2 y) { pow(ArithmeticType1 x, ArithmeticType2 y) {
typedef typename sprout::math::float_promote<ArithmeticType1, ArithmeticType2>::type type; typedef typename sprout::float_promote<ArithmeticType1, ArithmeticType2>::type type;
return sprout::math::detail::pow(static_cast<type>(x), static_cast<type>(y)); return sprout::math::detail::pow(static_cast<type>(x), static_cast<type>(y));
} }
} // namespace detail } // namespace detail

View file

@ -8,6 +8,8 @@
#include <sprout/type_traits/is_c_str.hpp> #include <sprout/type_traits/is_c_str.hpp>
#include <sprout/type_traits/lvalue_reference.hpp> #include <sprout/type_traits/lvalue_reference.hpp>
#include <sprout/type_traits/const_reference.hpp> #include <sprout/type_traits/const_reference.hpp>
#include <sprout/type_traits/arithmetic_promote.hpp>
#include <sprout/type_traits/float_promote.hpp>
#include <sprout/type_traits/enabler_if.hpp> #include <sprout/type_traits/enabler_if.hpp>
#include <sprout/type_traits/has_xxx.hpp> #include <sprout/type_traits/has_xxx.hpp>
#include <sprout/type_traits/inherit_if_xxx.hpp> #include <sprout/type_traits/inherit_if_xxx.hpp>

View file

@ -0,0 +1,56 @@
#ifndef SPROUT_TYPE_TRAITS_ARITHMETIC_PROMOTE_HPP
#define SPROUT_TYPE_TRAITS_ARITHMETIC_PROMOTE_HPP
#include <type_traits>
#include <utility>
#include <sprout/config.hpp>
namespace sprout {
namespace detail {
template <typename T>
struct arithmetic_promote1
: public std::common_type<T>
{
static_assert(
std::is_arithmetic<T>::value,
"arithmetic_promote requires arithmetic types."
);
};
template <typename T, typename U>
struct arithmetic_promote2
: public std::decay<decltype(std::declval<T>() + std::declval<U>())>
{
static_assert(
std::is_arithmetic<T>::value && std::is_arithmetic<U>::value,
"arithmetic_promote requires arithmetic types."
);
};
template<typename... Types>
struct arithmetic_promote_impl;
template<typename T, typename U, typename... Tail>
struct arithmetic_promote_impl<T, U, Tail...>
: public sprout::detail::arithmetic_promote_impl<
typename sprout::detail::arithmetic_promote2<T, U>::type,
Tail...
>
{};
template<typename T>
struct arithmetic_promote_impl<T>
: public sprout::detail::arithmetic_promote1<T>
{};
} // namespace detail
//
// arithmetic_promote
//
template<typename... Types>
struct arithmetic_promote
: public sprout::detail::arithmetic_promote_impl<
typename std::remove_cv<Types>::type...
>
{};
} // namespace sprout
#endif // #ifndef SPROUT_TYPE_TRAITS_ARITHMETIC_PROMOTE_HPP

View file

@ -0,0 +1,67 @@
#ifndef SPROUT_TYPE_TRAITS_FLOAT_PROMOTE_HPP
#define SPROUT_TYPE_TRAITS_FLOAT_PROMOTE_HPP
#include <type_traits>
#include <sprout/config.hpp>
namespace sprout {
namespace detail {
template<typename T>
struct float_promote1
: public std::conditional<
std::is_floating_point<T>::value,
std::common_type<T>,
std::common_type<double>
>::type
{
static_assert(
std::is_arithmetic<T>::value,
"float_promote requires arithmetic type."
);
};
template<typename T, typename U>
struct float_promote2
: public std::conditional<
(std::is_same<T, long double>::value || std::is_same<U, long double>::value),
std::common_type<long double>,
typename std::conditional<
(std::is_same<T, float>::value && std::is_same<U, float>::value),
float,
double
>
>::type
{
static_assert(
std::is_arithmetic<T>::value && std::is_arithmetic<U>::value,
"float_promote requires arithmetic type."
);
};
template<typename... Types>
struct float_promote_impl;
template<typename T, typename U, typename... Tail>
struct float_promote_impl<T, U, Tail...>
: public sprout::detail::float_promote_impl<
typename sprout::detail::float_promote2<T, U>::type,
Tail...
>
{};
template<typename T>
struct float_promote_impl<T>
: public sprout::detail::float_promote1<T>
{};
} // namespace detail
//
// float_promote
//
template<typename... Types>
struct float_promote
: public sprout::detail::float_promote_impl<
typename std::remove_cv<Types>::type...
>
{};
} // namespace sprout
#endif // #ifndef SPROUT_TYPE_TRAITS_FLOAT_PROMOTE_HPP

View file

@ -1,19 +1,22 @@
#ifndef SPROUT_UTILITY_AS_CONST_HPP #ifndef SPROUT_UTILITY_AS_CONST_HPP
#define SPROUT_UTILITY_AS_CONST_HPP #define SPROUT_UTILITY_AS_CONST_HPP
#include <type_traits>
#include <sprout/config.hpp> #include <sprout/config.hpp>
#include <sprout/utility/forward.hpp>
namespace sprout { namespace sprout {
// //
// as_const // as_const
// //
template<typename T> template<typename T>
inline T const& as_const(T& t) { inline SPROUT_CONSTEXPR typename std::conditional<
return t; std::is_lvalue_reference<T>::value,
} typename std::remove_reference<T>::type const&,
template<typename T> typename std::remove_reference<T>::type const&&
inline SPROUT_CONSTEXPR T const& as_const(T const& t) { >::type
return t; as_const(T&& t) {
return sprout::forward<T>(t);
} }
} // namespace sprout } // namespace sprout

View file

@ -8,11 +8,13 @@ namespace sprout {
// as_lvalue // as_lvalue
// //
template<typename T> template<typename T>
inline T& as_lvalue(T& t) { inline SPROUT_CONSTEXPR T&
as_lvalue(T& t) {
return t; return t;
} }
template<typename T> template<typename T>
inline SPROUT_CONSTEXPR T const& as_lvalue(T const& t) { inline SPROUT_CONSTEXPR T const&
as_lvalue(T const& t) {
return t; return t;
} }
} // namespace sprout } // namespace sprout

View file

@ -9,11 +9,13 @@ namespace sprout {
// forward // forward
// //
template<typename T> template<typename T>
inline SPROUT_CONSTEXPR T&& forward(typename std::remove_reference<T>::type& t) SPROUT_NOEXCEPT { inline SPROUT_CONSTEXPR T&&
forward(typename std::remove_reference<T>::type& t) SPROUT_NOEXCEPT {
return static_cast<T&&>(t); return static_cast<T&&>(t);
} }
template<typename T> template<typename T>
inline SPROUT_CONSTEXPR T&& forward(typename std::remove_reference<T>::type&& t) SPROUT_NOEXCEPT = delete; inline SPROUT_CONSTEXPR T&&
forward(typename std::remove_reference<T>::type&& t) SPROUT_NOEXCEPT = delete;
} // namespace sprout } // namespace sprout
#endif // #ifndef SPROUT_UTILITY_FORWARD_HPP #endif // #ifndef SPROUT_UTILITY_FORWARD_HPP

View file

@ -9,7 +9,8 @@ namespace sprout {
// move // move
// //
template<typename T> template<typename T>
inline SPROUT_CONSTEXPR typename std::remove_reference<T>::type&& move(T&& x) SPROUT_NOEXCEPT { inline SPROUT_CONSTEXPR typename std::remove_reference<T>::type&&
move(T&& x) SPROUT_NOEXCEPT {
return static_cast<typename std::remove_reference<T>::type&&>(x); return static_cast<typename std::remove_reference<T>::type&&>(x);
} }
@ -21,7 +22,8 @@ namespace sprout {
!std::is_nothrow_move_constructible<T>::value && std::is_copy_constructible<T>::value, !std::is_nothrow_move_constructible<T>::value && std::is_copy_constructible<T>::value,
T const&, T const&,
T&& T&&
>::type move_if_noexcept(T& x) SPROUT_NOEXCEPT { >::type
move_if_noexcept(T& x) SPROUT_NOEXCEPT {
return sprout::move(x); return sprout::move(x);
} }
} // namespace sprout } // namespace sprout