// L============================================================================= // L This software is distributed under the MIT license. // L Copyright 2021 Péter Kardos // L============================================================================= #pragma once #include #include #include namespace mathter::impl { /// Return a value initialized to zero, or, if not possible, a value-initialized object. /// If you want special treatment for a particular type, specialize this method. template struct NullScalarInitializer { static constexpr T Get() { if constexpr (std::is_convertible_v) { return T(0); } else { return T{}; } } }; /// Return a value initialized to zero, or, if not possible, a value-initialized object. template constexpr T NullScalar() { return NullScalarInitializer::Get(); } /// Initializes an object of type T to invalid (NaN) value. /// Returns a signaling NaN, /// if not possible, a quiet NaN, /// if not possible, an infinity, /// if not possible, the highest value for T, /// if not possible, then a null-initialized value. /// If you want special treatment for a particular type, specialize this method. template struct InvalidScalarInitializer { static constexpr T Get() { if constexpr (std::numeric_limits::is_specialized) { if constexpr (std::numeric_limits::has_signaling_NaN) { return std::numeric_limits::signaling_NaN(); } else if constexpr (std::numeric_limits::has_quiet_NaN) { return std::numeric_limits::quiet_NaN(); } else if constexpr (std::numeric_limits::has_infinity) { return std::numeric_limits::infinity(); } else { return std::numeric_limits::max(); } } return NullScalar(); } }; /// Return a signaling NaN complex number. Same as the unspecialized version. template struct InvalidScalarInitializer> { static constexpr std::complex Get() { return { InvalidScalarInitializer::Get(), InvalidScalarInitializer::Get() }; } }; /// Returns a signaling NaN, /// if not possible, a quiet NaN, /// if not possible, an infinity, /// if not possible, the highest value for T, /// if not possible, then a null-initialized value. template constexpr T InvalidScalar() { return InvalidScalarInitializer::Get(); } #if !defined(MATHTER_NULL_INITIALIZE) && !defined(MATHTER_INVALID_INITIALIZE) && !defined(MATHTER_DONT_INITIALIZE) #ifdef NDEBUG #define MATHTER_DONT_INITIALIZE 1 #else #define MATHTER_INVALID_INITIALIZE 1 #endif #endif #if defined(MATHTER_NULL_INITIALIZE) #define MATHTER_SCALAR_INIT_EXPRESSION(T) mathter::impl::NullScalar() #elif defined(MATHTER_INVALID_INITIALIZE) #define MATHTER_SCALAR_INIT_EXPRESSION(T) mathter::impl::InvalidScalar() #elif defined(MATHTER_DONT_INITIALIZE) #define MATHTER_SCALAR_INIT_EXPRESSION(T) #else #error Set at least one of the MATHTER_NULL/INVALID/DONT_INITIALIZE macros. #endif #if defined(MATHTER_NULL_INITIALIZE) || defined(MATHTER_INVALID_INITIALIZE) #define MATHTER_VECTOR_INITIALIZER(T) : Vector(MATHTER_SCALAR_INIT_EXPRESSION(T)) #else #define MATHTER_VECTOR_INITIALIZER(T) #endif } // namespace mathter::impl