Browse Source

math: use type traits instead of multiple macros for math functions.

legacy
Sam Hocevar 5 years ago
parent
commit
29ea039556
1 changed files with 89 additions and 188 deletions
  1. +89
    -188
      src/lol/math/functions.h

+ 89
- 188
src/lol/math/functions.h View File

@@ -1,8 +1,7 @@
// //
// Lol Engine // Lol Engine
// //
// Copyright © 2010—2015 Sam Hocevar <sam@hocevar.net>
// © 2012—2013 Benjamin “Touky” Huet <huet.benjamin@gmail.com>
// Copyright © 2010—2019 Sam Hocevar <sam@hocevar.net>
// //
// Lol Engine is free software. It comes without any warranty, to // Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it // the extent permitted by applicable law. You can redistribute it
@@ -23,74 +22,69 @@
#include <cmath> #include <cmath>
#include <cstdio> #include <cstdio>
#include <algorithm> #include <algorithm>
#include <type_traits>


#include <stdint.h> #include <stdint.h>


namespace lol namespace lol
{ {


/* This is OUR namespace. Don't let Windows headers mess with it. */
// This is OUR namespace. Don't let Windows headers mess with it.
#undef min #undef min
#undef max #undef max


/* Standard cmath functions */
LOL_ATTR_NODISCARD static inline double sqrt(double const &x) { return std::sqrt(x); }
LOL_ATTR_NODISCARD static inline float sqrt(float const &x) { return std::sqrt(x); }

LOL_ATTR_NODISCARD static inline double cbrt(double const &x) { return std::cbrt(x); }
LOL_ATTR_NODISCARD static inline float cbrt(float const &x) { return std::cbrt(x); }

LOL_ATTR_NODISCARD static inline double exp(double const &x) { return std::exp(x); }
LOL_ATTR_NODISCARD static inline float exp(float const &x) { return std::exp(x); }

LOL_ATTR_NODISCARD static inline double sin(double const &x) { return std::sin(x); }
LOL_ATTR_NODISCARD static inline double cos(double const &x) { return std::cos(x); }
LOL_ATTR_NODISCARD static inline double tan(double const &x) { return std::tan(x); }
LOL_ATTR_NODISCARD static inline float sin(float const &x) { return std::sin(x); }
LOL_ATTR_NODISCARD static inline float cos(float const &x) { return std::cos(x); }
LOL_ATTR_NODISCARD static inline float tan(float const &x) { return std::tan(x); }

LOL_ATTR_NODISCARD static inline double asin(double const &x) { return std::asin(x); }
LOL_ATTR_NODISCARD static inline double acos(double const &x) { return std::acos(x); }
LOL_ATTR_NODISCARD static inline double atan(double const &x) { return std::atan(x); }
LOL_ATTR_NODISCARD static inline float asin(float const &x) { return std::asin(x); }
LOL_ATTR_NODISCARD static inline float acos(float const &x) { return std::acos(x); }
LOL_ATTR_NODISCARD static inline float atan(float const &x) { return std::atan(x); }

LOL_ATTR_NODISCARD static inline double atan2(double const &y, double const &x)
{
return std::atan2(y, x);
}

LOL_ATTR_NODISCARD static inline float atan2(float const &y, float const &x)
{
return std::atan2(y, x);
}

LOL_ATTR_NODISCARD static inline double pow(double const &x, double const &y)
{
return std::pow(x, y);
}

LOL_ATTR_NODISCARD static inline float pow(float const &x, float const &y)
{
return std::pow(x, y);
}

/* Our extensions */
static inline void sincos(double const &x, double *s, double *c)
{
*s = std::sin(x);
*c = std::cos(x);
}

static inline void sincos(float const &x, float *s, float *c)
// Macros for type traits
#define LOL_T_ARITHMETIC typename std::enable_if<std::is_arithmetic<T>::value, T>::type
#define LOL_T_SIGNED typename std::enable_if<std::is_signed<T>::value, T>::type
#define LOL_T_UNSIGNED typename std::enable_if<std::is_arithmetic<T>::value && \
!std::is_signed<T>::value, T>::type
#define LOL_T_INTEGRAL typename std::enable_if<std::is_integral<T>::value, T>::type
#define LOL_T_FLOATING_POINT typename std::enable_if<std::is_floating_point<T>::value, T>::type

// Mechanism to import standard cmath functions
#define LOL_FORWARD_FP_1_ARG(f) \
template<typename T, typename T2 = T, typename DUMMY = LOL_T_FLOATING_POINT> \
LOL_ATTR_NODISCARD static inline T2 f(T x) { return std::f(x); }

#define LOL_FORWARD_ARITH_2_ARGS(f) \
template<typename T, typename T2 = T, typename DUMMY = LOL_T_ARITHMETIC> \
LOL_ATTR_NODISCARD static inline T2 f(T x, T y) { return std::f(x, y); }

#define LOL_FORWARD_FP_2_ARGS(f) \
template<typename T, typename T2 = T, typename DUMMY = LOL_T_FLOATING_POINT> \
LOL_ATTR_NODISCARD static inline T2 f(T x, T y) { return std::f(x, y); }

LOL_FORWARD_FP_1_ARG(sqrt)
LOL_FORWARD_FP_1_ARG(cbrt)

LOL_FORWARD_FP_1_ARG(exp)
LOL_FORWARD_FP_2_ARGS(pow)

LOL_FORWARD_FP_1_ARG(sin)
LOL_FORWARD_FP_1_ARG(cos)
LOL_FORWARD_FP_1_ARG(tan)
LOL_FORWARD_FP_1_ARG(asin)
LOL_FORWARD_FP_1_ARG(acos)
LOL_FORWARD_FP_1_ARG(atan)
LOL_FORWARD_FP_2_ARGS(atan2)

LOL_FORWARD_ARITH_2_ARGS(min)
LOL_FORWARD_ARITH_2_ARGS(max)

LOL_FORWARD_FP_2_ARGS(fmod)
LOL_FORWARD_FP_1_ARG(floor)
LOL_FORWARD_FP_1_ARG(ceil)
LOL_FORWARD_FP_1_ARG(round)

// Our extensions
template<typename T, typename T2 = LOL_T_FLOATING_POINT>
LOL_ATTR_NODISCARD static inline T2 sincos(T x, T *s, T *c)
{ {
*s = std::sin(x); *s = std::sin(x);
*c = std::cos(x); *c = std::cos(x);
} }


/* Inherited from GLSL */
// Inherited from GLSL
LOL_ATTR_NODISCARD static inline float degrees(float radians) LOL_ATTR_NODISCARD static inline float degrees(float radians)
{ {
return radians * (180.0f / F_PI); return radians * (180.0f / F_PI);
@@ -121,8 +115,8 @@ LOL_ATTR_NODISCARD static inline ldouble radians(ldouble degrees)
return degrees * (LD_PI / 180.0L); return degrees * (LD_PI / 180.0L);
} }


/* The integer versions return floating point values. This avoids nasty
* surprises when calling radians(180) instead of radians(180.0). */
// The integer versions return floating point values. This avoids nasty
// surprises when calling radians(180) instead of radians(180.0).
LOL_ATTR_NODISCARD static inline float degrees(int8_t x) { return degrees(float(x)); } LOL_ATTR_NODISCARD static inline float degrees(int8_t x) { return degrees(float(x)); }
LOL_ATTR_NODISCARD static inline float degrees(uint8_t x) { return degrees(float(x)); } LOL_ATTR_NODISCARD static inline float degrees(uint8_t x) { return degrees(float(x)); }
LOL_ATTR_NODISCARD static inline float degrees(int16_t x) { return degrees(float(x)); } LOL_ATTR_NODISCARD static inline float degrees(int16_t x) { return degrees(float(x)); }
@@ -141,144 +135,51 @@ LOL_ATTR_NODISCARD static inline double radians(uint32_t x) { return radians(do
LOL_ATTR_NODISCARD static inline ldouble radians(int64_t x) { return radians(ldouble(x)); } LOL_ATTR_NODISCARD static inline ldouble radians(int64_t x) { return radians(ldouble(x)); }
LOL_ATTR_NODISCARD static inline ldouble radians(uint64_t x) { return radians(ldouble(x)); } LOL_ATTR_NODISCARD static inline ldouble radians(uint64_t x) { return radians(ldouble(x)); }


LOL_ATTR_NODISCARD static inline float mix(float const &a, float const &b, float const &x)
{
return a + (b - a) * x;
}

LOL_ATTR_NODISCARD static inline double mix(double const &a, double const &b, double const &x)
template<typename T, typename T2 = LOL_T_FLOATING_POINT>
LOL_ATTR_NODISCARD static inline T2 mix(T a, T b, T x)
{ {
return a + (b - a) * x; return a + (b - a) * x;
} }


LOL_ATTR_NODISCARD static inline ldouble mix(ldouble const &a, ldouble const &b, ldouble const &x)
{
return a + (b - a) * x;
}

/* Inherited from HLSL */
LOL_ATTR_NODISCARD static inline float lerp(float const &a, float const &b, float const &x)
{
return mix(a, b, x);
}

LOL_ATTR_NODISCARD static inline double lerp(double const &a, double const &b, double const &x)
{
return mix(a, b, x);
}

LOL_ATTR_NODISCARD static inline ldouble lerp(ldouble const &a, ldouble const &b, ldouble const &x)
// Inherited from HLSL
template<typename T, typename T2 = LOL_T_FLOATING_POINT>
LOL_ATTR_NODISCARD static inline T2 lerp(T a, T b, T x)
{ {
return mix(a, b, x); return mix(a, b, x);
} }


/* C++ doesn't define abs() and fmod() for all types; we add these for
* convenience to avoid adding complexity to vector.h. */
LOL_ATTR_NODISCARD static inline int8_t abs(int8_t x) { return std::abs(x); }
LOL_ATTR_NODISCARD static inline uint8_t abs(uint8_t x) { return x; }
LOL_ATTR_NODISCARD static inline int16_t abs(int16_t x) { return std::abs(x); }
LOL_ATTR_NODISCARD static inline uint16_t abs(uint16_t x) { return x; }
LOL_ATTR_NODISCARD static inline int32_t abs(int32_t x) { return std::abs(x); }
LOL_ATTR_NODISCARD static inline uint32_t abs(uint32_t x) { return x; }
#if defined __ANDROID__
/* The Android toolchain doesn't provide abs() for int64_t. */
LOL_ATTR_NODISCARD static inline int64_t abs(int64_t x) { return x > 0 ? x : -x; }
#else
LOL_ATTR_NODISCARD static inline int64_t abs(int64_t x) { return std::abs(x); }
#endif
LOL_ATTR_NODISCARD static inline uint64_t abs(uint64_t x) { return x; }
LOL_ATTR_NODISCARD static inline float abs(float x) { return std::abs(x); }
LOL_ATTR_NODISCARD static inline double abs(double x) { return std::abs(x); }
LOL_ATTR_NODISCARD static inline ldouble abs(ldouble x) { return std::abs(x); }

LOL_ATTR_NODISCARD static inline uint8_t fmod(uint8_t x, uint8_t y) { return x % y; }
LOL_ATTR_NODISCARD static inline int8_t fmod(int8_t x, int8_t y) { return x % y; }
LOL_ATTR_NODISCARD static inline uint16_t fmod(uint16_t x, uint16_t y) { return x % y; }
LOL_ATTR_NODISCARD static inline int16_t fmod(int16_t x, int16_t y) { return x % y; }
LOL_ATTR_NODISCARD static inline uint32_t fmod(uint32_t x, uint32_t y) { return x % y; }
LOL_ATTR_NODISCARD static inline int32_t fmod(int32_t x, int32_t y) { return x % y; }
LOL_ATTR_NODISCARD static inline uint64_t fmod(uint64_t x, uint64_t y) { return x % y; }
LOL_ATTR_NODISCARD static inline int64_t fmod(int64_t x, int64_t y) { return x % y; }
LOL_ATTR_NODISCARD static inline float fmod(float x, float y) { return std::fmod(x, y); }
LOL_ATTR_NODISCARD static inline double fmod(double x, double y) { return std::fmod(x, y); }
LOL_ATTR_NODISCARD static inline ldouble fmod(ldouble x, ldouble y) { return std::fmod(x, y); }

LOL_ATTR_NODISCARD static inline uint8_t floor(uint8_t x) { return x; }
LOL_ATTR_NODISCARD static inline int8_t floor(int8_t x) { return x; }
LOL_ATTR_NODISCARD static inline uint16_t floor(uint16_t x) { return x; }
LOL_ATTR_NODISCARD static inline int16_t floor(int16_t x) { return x; }
LOL_ATTR_NODISCARD static inline uint32_t floor(uint32_t x) { return x; }
LOL_ATTR_NODISCARD static inline int32_t floor(int32_t x) { return x; }
LOL_ATTR_NODISCARD static inline uint64_t floor(uint64_t x) { return x; }
LOL_ATTR_NODISCARD static inline int64_t floor(int64_t x) { return x; }
LOL_ATTR_NODISCARD static inline float floor(float x) { return std::floor(x); }
LOL_ATTR_NODISCARD static inline double floor(double x) { return std::floor(x); }
LOL_ATTR_NODISCARD static inline ldouble floor(ldouble x) { return std::floor(x); }

LOL_ATTR_NODISCARD static inline uint8_t ceil(uint8_t x) { return x; }
LOL_ATTR_NODISCARD static inline int8_t ceil(int8_t x) { return x; }
LOL_ATTR_NODISCARD static inline uint16_t ceil(uint16_t x) { return x; }
LOL_ATTR_NODISCARD static inline int16_t ceil(int16_t x) { return x; }
LOL_ATTR_NODISCARD static inline uint32_t ceil(uint32_t x) { return x; }
LOL_ATTR_NODISCARD static inline int32_t ceil(int32_t x) { return x; }
LOL_ATTR_NODISCARD static inline uint64_t ceil(uint64_t x) { return x; }
LOL_ATTR_NODISCARD static inline int64_t ceil(int64_t x) { return x; }
LOL_ATTR_NODISCARD static inline float ceil(float x) { return std::ceil(x); }
LOL_ATTR_NODISCARD static inline double ceil(double x) { return std::ceil(x); }
LOL_ATTR_NODISCARD static inline ldouble ceil(ldouble x) { return std::ceil(x); }

LOL_ATTR_NODISCARD static inline uint8_t round(uint8_t x) { return x; }
LOL_ATTR_NODISCARD static inline int8_t round(int8_t x) { return x; }
LOL_ATTR_NODISCARD static inline uint16_t round(uint16_t x) { return x; }
LOL_ATTR_NODISCARD static inline int16_t round(int16_t x) { return x; }
LOL_ATTR_NODISCARD static inline uint32_t round(uint32_t x) { return x; }
LOL_ATTR_NODISCARD static inline int32_t round(int32_t x) { return x; }
LOL_ATTR_NODISCARD static inline uint64_t round(uint64_t x) { return x; }
LOL_ATTR_NODISCARD static inline int64_t round(int64_t x) { return x; }
LOL_ATTR_NODISCARD static inline float round(float x) { return std::round(x); }
LOL_ATTR_NODISCARD static inline double round(double x) { return std::round(x); }
LOL_ATTR_NODISCARD static inline ldouble round(ldouble x) { return std::round(x); }

#define LOL_GENERIC_FUNC(T) \
LOL_ATTR_NODISCARD static inline T sq(T x) { return x * x; } \
LOL_ATTR_NODISCARD static inline T fract(T x) { return x - lol::floor(x); } \
LOL_ATTR_NODISCARD static inline T min(T x, T y) { return std::min(x, y); } \
LOL_ATTR_NODISCARD static inline T max(T x, T y) { return std::max(x, y); } \
LOL_ATTR_NODISCARD static inline T clamp(T x, T y, T z) { return min(max(x, y), z); } \
LOL_ATTR_NODISCARD static inline T saturate(T x) { return min(max(x, (T)0), (T)1); } \
LOL_ATTR_NODISCARD static inline T gcd(T x, T y) { return y == (T)0 ? lol::abs(x) : lol::gcd(y, lol::fmod(x, y)); }

#define LOL_GENERIC_FUNC_SIGNED(T) \
LOL_GENERIC_FUNC(T) \
LOL_ATTR_NODISCARD static inline T sign(T x) { return (T)(((T)0 < x) - (x < (T)0)); }

#define LOL_GENERIC_FUNC_UNSIGNED(T) \
LOL_GENERIC_FUNC(T) \
LOL_ATTR_NODISCARD static inline T sign(T x) { return (T)((T)0 < x); }

LOL_GENERIC_FUNC_UNSIGNED(uint8_t)
LOL_GENERIC_FUNC_SIGNED(int8_t)
LOL_GENERIC_FUNC_UNSIGNED(uint16_t)
LOL_GENERIC_FUNC_SIGNED(int16_t)
LOL_GENERIC_FUNC_UNSIGNED(uint32_t)
LOL_GENERIC_FUNC_SIGNED(int32_t)
LOL_GENERIC_FUNC_UNSIGNED(uint64_t)
LOL_GENERIC_FUNC_SIGNED(int64_t)
LOL_GENERIC_FUNC_SIGNED(float)
LOL_GENERIC_FUNC_SIGNED(double)
LOL_GENERIC_FUNC_SIGNED(ldouble)
#undef LOL_GENERIC_FUNC

/* Some additional implementations when ptrdiff_t != int */
#define LOL_T_PTRDIFF_T \
typename std::enable_if<!std::is_same<ptrdiff_t, int>::value \
&& std::is_same<T, ptrdiff_t>::value, T>::type
template<typename T, typename T2 = LOL_T_PTRDIFF_T>
LOL_ATTR_NODISCARD static inline T2 max(T x, T y) { return std::max(x, y); }

template<typename T, typename T2 = LOL_T_PTRDIFF_T>
LOL_ATTR_NODISCARD static inline T2 min(T x, T y) { return std::min(x, y); }
#undef LOL_T_PTRDIFF_T
// C++ doesn't define abs() or fmod() for all types; we add these for
// convenience to avoid adding complexity to vector.h.
template<typename T, typename T2 = LOL_T_SIGNED>
LOL_ATTR_NODISCARD static inline T2 abs(T x) { return std::abs(x); }
template<typename T, typename T2 = T, typename DUMMY = LOL_T_UNSIGNED>
LOL_ATTR_NODISCARD static inline T2 abs(T x) { return x; }

template<typename T, typename T2 = LOL_T_INTEGRAL>
LOL_ATTR_NODISCARD static inline T2 fmod(T x, T y) { return x % y; }
template<typename T, typename T2 = LOL_T_INTEGRAL>
LOL_ATTR_NODISCARD static inline T2 floor(T x) { return x; }
template<typename T, typename T2 = LOL_T_INTEGRAL>
LOL_ATTR_NODISCARD static inline T2 ceil(T x) { return x; }
template<typename T, typename T2 = LOL_T_INTEGRAL>
LOL_ATTR_NODISCARD static inline T2 round(T x) { return x; }

template<typename T, typename T2 = LOL_T_ARITHMETIC>
LOL_ATTR_NODISCARD static inline T2 sq(T x) { return x * x; }
template<typename T, typename T2 = LOL_T_ARITHMETIC>
LOL_ATTR_NODISCARD static inline T2 fract(T x) { return x - lol::floor(x); }

template<typename T, typename T2 = LOL_T_ARITHMETIC>
LOL_ATTR_NODISCARD static inline T2 clamp(T x, T y, T z) { return min(max(x, y), z); }
template<typename T, typename T2 = LOL_T_ARITHMETIC>
LOL_ATTR_NODISCARD static inline T2 saturate(T x) { return clamp(x, (T)0, (T)1); }
template<typename T, typename T2 = LOL_T_ARITHMETIC>
LOL_ATTR_NODISCARD static inline T2 gcd(T x, T y) { return y == (T)0 ? lol::abs(x) : lol::gcd(y, lol::fmod(x, y)); }

template<typename T, typename T2 = LOL_T_SIGNED>
LOL_ATTR_NODISCARD static inline T2 sign(T x) { return (T)(((T)0 < x) - (x < (T)0)); }
template<typename T, typename T2 = T, typename DUMMY = LOL_T_UNSIGNED>
LOL_ATTR_NODISCARD static inline T2 sign(T x) { return (T)((T)0 < x); }


} /* namespace lol */ } /* namespace lol */



Loading…
Cancel
Save