#pragma once #include #include #include #include #ifdef __MSC_VER #define HPR_CONSTEXPR #else #define HPR_CONSTEXPR constexpr #endif namespace hpr { using Size = std::size_t; template struct is_size : public std::integral_constant::value && std::is_unsigned::value> {}; template concept IsSize = is_size::value || std::convertible_to; template struct is_integer : public std::is_integral {}; template concept IsInteger = is_integer::value; template struct is_scalar : public std::is_floating_point {}; template concept IsScalar = is_scalar::value; template concept IsReal = is_integer::value || is_scalar::value; #ifndef HPR_SCALAR #define HPR_SCALAR float #endif #ifdef HPR_SCALAR_IMPLEMENTATION template class Scalar { public: using type = Scalar; using value_type = T; protected: value_type p_value; public: // constructors constexpr Scalar() : p_value {} {} template constexpr Scalar(const Scalar& value) : p_value {static_cast(value.p_value)} {} template constexpr Scalar(const X& value) : p_value {static_cast(value)} {} template constexpr type& operator=(const Scalar& value) { p_value = static_cast(value.p_value); return *this; } template constexpr type& operator=(const X& value) { p_value = static_cast(value); return *this; } virtual constexpr ~Scalar() = default; // conversion constexpr operator double() const { return static_cast(p_value); } constexpr operator float() const { return static_cast(p_value); } constexpr operator long double() const { return static_cast(p_value); } constexpr operator bool() const { return static_cast(p_value); } // access [[nodiscard]] constexpr value_type value() const { return p_value; } constexpr value_type& value() { return p_value; } }; using scalar_type = HPR_SCALAR; using scalar = Scalar; // template<> scalar::value_type scalar::s_precision = static_cast(1e-15); /// scalar vs scalar constexpr scalar operator+(const scalar& s) { return s; } constexpr scalar operator-(const scalar& s) { return -s.value(); } constexpr bool operator!(const scalar& s) { return !static_cast(s.value()); } constexpr scalar& operator+=(scalar& lhs, const scalar& rhs) { lhs.value() += static_cast(rhs.value()); return lhs; } constexpr scalar& operator-=(scalar& lhs, const scalar& rhs) { lhs.value() -= static_cast(rhs.value()); return lhs; } constexpr scalar& operator*=(scalar& lhs, const scalar& rhs) { lhs.value() *= static_cast(rhs.value()); return lhs; } constexpr scalar& operator/=(scalar& lhs, const scalar& rhs) { lhs.value() /= static_cast(rhs.value()); return lhs; } constexpr scalar operator+(const scalar& lhs, const scalar& rhs) { return lhs.value() + rhs.value(); } constexpr scalar operator-(const scalar& lhs, const scalar& rhs) { return lhs.value() - rhs.value(); } constexpr scalar operator*(const scalar& lhs, const scalar& rhs) { return lhs.value() * rhs.value(); } constexpr scalar operator/(const scalar& lhs, const scalar& rhs) { return lhs.value() / rhs.value(); } constexpr bool operator==(const scalar& lhs, const scalar& rhs) { return lhs.value() == rhs.value(); } constexpr bool operator!=(const scalar& lhs, const scalar& rhs) { return lhs.value() != rhs.value(); } constexpr bool operator&&(const scalar& lhs, const scalar& rhs) { return static_cast(lhs) && static_cast(rhs); } constexpr bool operator||(const scalar& lhs, const scalar& rhs) { return static_cast(lhs) || static_cast(rhs); } constexpr bool operator>(const scalar& lhs, const scalar& rhs) { return lhs.value() > rhs.value(); } constexpr bool operator<(const scalar& lhs, const scalar& rhs) { return lhs.value() < rhs.value(); } constexpr bool operator>=(const scalar& lhs, const scalar& rhs) { return lhs.value() >= rhs.value(); } constexpr bool operator<=(const scalar& lhs, const scalar& rhs) { return lhs.value() <= rhs.value(); } // std::ostream& operator<<(std::ostream& stream, const scalar& s) { return stream << s.value(); } /// scalar vs Scalar template constexpr scalar& operator+=(scalar& lhs, const Scalar& rhs) { lhs.value() += static_cast(rhs.value()); return lhs; } template constexpr scalar& operator-=(scalar& lhs, const Scalar& rhs) { lhs.value() -= static_cast(rhs.value()); return lhs; } template constexpr scalar& operator*=(scalar& lhs, const Scalar& rhs) { lhs.value() *= static_cast(rhs.value()); return lhs; } template constexpr scalar& operator/=(scalar& lhs, const Scalar& rhs) { lhs.value() /= static_cast(rhs.value()); return lhs; } template constexpr scalar operator+(const scalar& lhs, const Scalar& rhs) { return lhs.value() + static_cast(rhs.value()); } template constexpr scalar operator+(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) + rhs.value(); } template constexpr scalar operator-(const scalar& lhs, const Scalar& rhs) { return lhs.value() - static_cast(rhs.value()); } template constexpr scalar operator-(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) - rhs.value(); } template constexpr scalar operator*(const scalar& lhs, const Scalar& rhs) { return lhs.value() * static_cast(rhs.value()); } template constexpr scalar operator*(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) * rhs.value(); } template constexpr scalar operator/(const scalar& lhs, const Scalar& rhs) { return lhs.value() / static_cast(rhs.value()); } template constexpr scalar operator/(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) / rhs.value(); } template constexpr bool operator==(const scalar& lhs, const Scalar& rhs) { return lhs.value() == static_cast(rhs.value()); } template constexpr bool operator==(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) == rhs.value(); } template constexpr bool operator!=(const scalar& lhs, const Scalar& rhs) { return lhs.value() != static_cast(rhs.value()); } template constexpr bool operator!=(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) != rhs.value(); } template constexpr bool operator&&(const scalar& lhs, const Scalar& rhs) { return static_cast(lhs) && static_cast(rhs); } template constexpr bool operator&&(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs) && static_cast(rhs); } template constexpr bool operator||(const scalar& lhs, const Scalar& rhs) { return static_cast(lhs) || static_cast(rhs); } template constexpr bool operator||(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs) || static_cast(rhs); } template constexpr bool operator>(const scalar& lhs, const Scalar& rhs) { return lhs.value() > static_cast(rhs.value()); } template constexpr bool operator>(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) > rhs.value(); } template constexpr bool operator<(const scalar& lhs, const Scalar& rhs) { return lhs.value() < static_cast(rhs.value()); } template constexpr bool operator<(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) < rhs.value(); } template constexpr bool operator>=(const scalar& lhs, const Scalar& rhs) { return lhs.value() >= static_cast(rhs.value()); } template constexpr bool operator>=(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) >= rhs.value(); } template constexpr bool operator<=(const scalar& lhs, const Scalar& rhs) { return lhs.value() <= static_cast(rhs.value()); } template constexpr bool operator<=(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) <= rhs.value(); } template std::ostream& operator<<(std::ostream& stream, const Scalar& s) { return stream << s.value(); } template std::istream& operator>>(std::istream& stream, Scalar& s) { return stream >> s.value(); } /// scalar vs real template constexpr scalar& operator+=(scalar& lhs, const T& rhs) { lhs.value() += static_cast(rhs); return lhs; } template constexpr scalar& operator-=(scalar& lhs, const T& rhs) { lhs.value() -= static_cast(rhs); return lhs; } template constexpr scalar& operator*=(scalar& lhs, const T& rhs) { lhs.value() *= static_cast(rhs); return lhs; } template constexpr scalar& operator/=(scalar& lhs, const T& rhs) { lhs.value() /= static_cast(rhs); return lhs; } template constexpr T& operator+=(T& lhs, const scalar& rhs) { lhs += static_cast(rhs); return lhs; } template constexpr T& operator-=(T& lhs, const scalar& rhs) { lhs -= static_cast(rhs); return lhs; } template constexpr T& operator*=(T& lhs, const scalar& rhs) { lhs *= static_cast(rhs); return lhs; } template constexpr T& operator/=(T& lhs, const scalar& rhs) { lhs /= static_cast(rhs); return lhs; } template constexpr scalar operator+(const scalar& lhs, const T& rhs) { return lhs.value() + static_cast(rhs); } template constexpr scalar operator+(const T& lhs, const scalar& rhs) { return static_cast(lhs) + rhs.value(); } template constexpr scalar operator-(const scalar& lhs, const T& rhs) { return lhs.value() - static_cast(rhs); } template constexpr scalar operator-(const T& lhs, const scalar& rhs) { return static_cast(lhs) - rhs.value(); } template constexpr scalar operator*(const scalar& lhs, const T& rhs) { return lhs.value() * static_cast(rhs); } template constexpr scalar operator*(const T& lhs, const scalar& rhs) { return static_cast(lhs) * rhs.value(); } template constexpr scalar operator/(const scalar& lhs, const T& rhs) { return lhs.value() / static_cast(rhs); } template constexpr scalar operator/(const T& lhs, const scalar& rhs) { return static_cast(lhs) / rhs.value(); } template constexpr bool operator==(const scalar& lhs, const T& rhs) { return lhs.value() == static_cast(rhs); } template constexpr bool operator==(const T& lhs, const scalar& rhs) { return static_cast(lhs) == rhs.value(); } template constexpr bool operator!=(const scalar& lhs, const T& rhs) { return lhs.value() != static_cast(rhs); } template constexpr bool operator!=(const T& lhs, const scalar& rhs) { return static_cast(lhs) != rhs.value(); } template constexpr bool operator&&(const scalar& lhs, const T& rhs) { return static_cast(lhs) && static_cast(rhs); } template constexpr bool operator&&(const T& lhs, const scalar& rhs) { return static_cast(lhs) && static_cast(rhs); } template constexpr bool operator||(const scalar& lhs, const T& rhs) { return static_cast(lhs) || static_cast(rhs); } template constexpr bool operator||(const T& lhs, const scalar& rhs) { return static_cast(lhs) || static_cast(rhs); } template constexpr bool operator>(const scalar& lhs, const T& rhs) { return lhs.value() > static_cast(rhs); } template constexpr bool operator>(const T& lhs, const scalar& rhs) { return static_cast(lhs) > rhs.value(); } template constexpr bool operator<(const scalar& lhs, const T& rhs) { return lhs.value() < static_cast(rhs); } template constexpr bool operator<(const T& lhs, const scalar& rhs) { return static_cast(lhs) < rhs.value(); } template constexpr bool operator>=(const scalar& lhs, const T& rhs) { return lhs.value() >= static_cast(rhs); } template constexpr bool operator>=(const T& lhs, const scalar& rhs) { return static_cast(lhs) >= rhs.value(); } template constexpr bool operator<=(const scalar& lhs, const T& rhs) { return lhs.value() <= static_cast(rhs); } template constexpr bool operator<=(const T& lhs, const scalar& rhs) { return static_cast(lhs) <= rhs.value(); } #else using scalar_type = HPR_SCALAR; using scalar = HPR_SCALAR; #endif // constants HPR_CONSTEXPR scalar pi() { return std::numbers::pi_v; } HPR_CONSTEXPR scalar e() { return std::numbers::e_v; } // transcendentals template HPR_CONSTEXPR scalar cos(const T& s) { return std::cos(static_cast(s));} template HPR_CONSTEXPR scalar acos(const T& s) { return std::acos(static_cast(s)); } template HPR_CONSTEXPR scalar cosh(const T& s) { return std::cosh(static_cast(s)); } template HPR_CONSTEXPR scalar acosh(const T& s) { return std::acosh(static_cast(s)); } template HPR_CONSTEXPR scalar sin(const T& s) { return std::sin(static_cast(s)); } template HPR_CONSTEXPR scalar asin(const T& s) { return std::asin(static_cast(s)); } template HPR_CONSTEXPR scalar sinh(const T& s) { return std::sinh(static_cast(s)); } template HPR_CONSTEXPR scalar asinh(const T& s) { return std::asinh(static_cast(s)); } template HPR_CONSTEXPR scalar tan(const T& s) { return std::tan(static_cast(s)); } template HPR_CONSTEXPR scalar atan(const T& s) { return std::atan(static_cast(s)); } template HPR_CONSTEXPR scalar atan2(const T& s, const X& s2) { return std::atan2(static_cast(s), static_cast(s2)); } template HPR_CONSTEXPR scalar tanh(const T& s) { return std::tanh(static_cast(s)); } template HPR_CONSTEXPR scalar atanh(const T& s) { return std::atanh(static_cast(s)); } template HPR_CONSTEXPR scalar exp(const T& s) { return std::exp(static_cast(s)); } template HPR_CONSTEXPR scalar log(const T& s) { return std::log(static_cast(s)); } template HPR_CONSTEXPR scalar log10(const T& s) { return std::log10(static_cast(s)); } template HPR_CONSTEXPR scalar pow(const T& s, const X& d) { return std::pow(static_cast(s), static_cast(d)); } template HPR_CONSTEXPR scalar sqrt(const T& s) { return std::sqrt(static_cast(s)); } template HPR_CONSTEXPR scalar isqrt(const T& s) { return static_cast(1) / sqrt(static_cast(s)); } // static scalar_type scalar_precision = static_cast(1e-15); inline scalar_type precision() { return scalar_precision; } template inline void precision(const T& precision) { scalar_precision = static_cast(precision); } HPR_CONSTEXPR scalar inf() { return std::numeric_limits::infinity(); } HPR_CONSTEXPR scalar epsilon() { return std::numeric_limits::epsilon(); } HPR_CONSTEXPR scalar isnan(const scalar& s) { return std::isnan(static_cast(s)); } HPR_CONSTEXPR scalar abs(const scalar& s) { return std::abs(static_cast(s)); } HPR_CONSTEXPR scalar mag(const scalar& s) { return std::abs(static_cast(s)); } HPR_CONSTEXPR bool equal(const scalar& lhs, const scalar& rhs, const scalar& precision = hpr::precision()) { return abs(lhs - rhs) < precision; } //! Convert degrees to radians HPR_CONSTEXPR scalar rad(const scalar& s) { return s * pi() / static_cast(180); } //! Convert radians to degrees HPR_CONSTEXPR scalar deg(const scalar& s) { return s * static_cast(180) / pi(); } HPR_CONSTEXPR scalar min(const scalar& s1, const scalar& s2) { return std::min(static_cast(s1), static_cast(s2));} HPR_CONSTEXPR scalar max(const scalar& s1, const scalar& s2) { return std::max(static_cast(s1), static_cast(s2)); } HPR_CONSTEXPR scalar clip(const scalar& s, const scalar& sMin, const scalar& sMax) { return min(sMax, max(s, sMin)); } } // end namespace hpr #ifdef HPR_SCALAR_IMPLEMENTATION namespace std { template struct is_floating_point : true_type {}; } // end namespace std #endif