/* * Copyright (C) 2014 Pavel Kirienko */ #ifndef UAVCAN_UTIL_TEMPLATES_HPP_INCLUDED #define UAVCAN_UTIL_TEMPLATES_HPP_INCLUDED #include #include #include #include #ifndef UAVCAN_CPP_VERSION # error UAVCAN_CPP_VERSION #endif #if UAVCAN_CPP_VERSION < UAVCAN_CPP11 # include // cfloat may not be available #else # include // C++11 mode assumes that all standard headers are available #endif namespace uavcan { /** * Usage: * StaticAssert::check(); */ template struct UAVCAN_EXPORT StaticAssert; template <> struct UAVCAN_EXPORT StaticAssert { static void check() { } }; /** * Usage: * ShowIntegerAsError::foobar(); */ template struct ShowIntegerAsError; /** * Prevents copying when inherited */ class UAVCAN_EXPORT Noncopyable { Noncopyable(const Noncopyable&); Noncopyable& operator=(const Noncopyable&); protected: Noncopyable() { } ~Noncopyable() { } }; /** * Compile time conditions */ template struct UAVCAN_EXPORT EnableIf { }; template struct UAVCAN_EXPORT EnableIf { typedef T Type; }; /** * Lightweight type categorization. */ template struct UAVCAN_EXPORT EnableIfType { typedef R Type; }; /** * Compile-time type selection (Alexandrescu) */ template struct UAVCAN_EXPORT Select; template struct UAVCAN_EXPORT Select { typedef TrueType Result; }; template struct UAVCAN_EXPORT Select { typedef FalseType Result; }; /** * Remove reference as in */ template struct RemoveReference { typedef T Type; }; template struct RemoveReference { typedef T Type; }; #if UAVCAN_CPP_VERSION > UAVCAN_CPP03 template struct RemoveReference { typedef T Type; }; #endif /** * Parameter types */ template struct ParameterType { typedef const U& Type; }; template struct ParameterType { typedef U& Type; }; #if UAVCAN_CPP_VERSION > UAVCAN_CPP03 template struct ParameterType { typedef U&& Type; }; #endif /** * Value types */ template struct UAVCAN_EXPORT BooleanType { }; typedef BooleanType TrueType; typedef BooleanType FalseType; template struct IntToType { }; /** * Relations */ template class UAVCAN_EXPORT IsImplicitlyConvertibleFromTo { template static U returner(); struct True_ { char x[2]; }; struct False_ { }; static True_ test(const T2 &); static False_ test(...); public: enum { Result = sizeof(True_) == sizeof(IsImplicitlyConvertibleFromTo::test(returner())) }; }; /** * try_implicit_cast<>(From) * try_implicit_cast<>(From, To) * @{ */ template struct UAVCAN_EXPORT TryImplicitCastImpl { static To impl(const From& from, const To&, TrueType) { return To(from); } static To impl(const From&, const To& default_, FalseType) { return default_; } }; /** * If possible, performs an implicit cast from the type From to the type To. * If the cast is not possible, returns default_ of type To. */ template UAVCAN_EXPORT To try_implicit_cast(const From& from, const To& default_) { return TryImplicitCastImpl::impl(from, default_, BooleanType::Result>()); } /** * If possible, performs an implicit cast from the type From to the type To. * If the cast is not possible, returns a default constructed object of the type To. */ template UAVCAN_EXPORT To try_implicit_cast(const From& from) { return TryImplicitCastImpl::impl(from, To(), BooleanType::Result>()); } /** * @} */ /** * Compile time square root for integers. * Useful for operations on square matrices. */ template struct UAVCAN_EXPORT CompileTimeIntSqrt; template <> struct UAVCAN_EXPORT CompileTimeIntSqrt<4> { enum { Result = 2 }; }; template <> struct UAVCAN_EXPORT CompileTimeIntSqrt<9> { enum { Result = 3 }; }; template <> struct UAVCAN_EXPORT CompileTimeIntSqrt<16> { enum { Result = 4 }; }; template <> struct UAVCAN_EXPORT CompileTimeIntSqrt<25> { enum { Result = 5 }; }; template <> struct UAVCAN_EXPORT CompileTimeIntSqrt<36> { enum { Result = 6 }; }; template <> struct UAVCAN_EXPORT CompileTimeIntSqrt<49> { enum { Result = 7 }; }; template <> struct UAVCAN_EXPORT CompileTimeIntSqrt<64> { enum { Result = 8 }; }; template <> struct UAVCAN_EXPORT CompileTimeIntSqrt<81> { enum { Result = 9 }; }; template <> struct UAVCAN_EXPORT CompileTimeIntSqrt<100> { enum { Result = 10 }; }; template <> struct UAVCAN_EXPORT CompileTimeIntSqrt<121> { enum { Result = 11 }; }; template <> struct UAVCAN_EXPORT CompileTimeIntSqrt<144> { enum { Result = 12 }; }; template <> struct UAVCAN_EXPORT CompileTimeIntSqrt<169> { enum { Result = 13 }; }; template <> struct UAVCAN_EXPORT CompileTimeIntSqrt<196> { enum { Result = 14 }; }; template <> struct UAVCAN_EXPORT CompileTimeIntSqrt<225> { enum { Result = 15 }; }; template <> struct UAVCAN_EXPORT CompileTimeIntSqrt<256> { enum { Result = 16 }; }; /** * Replacement for std::copy(..) */ template UAVCAN_EXPORT OutputIt copy(InputIt first, InputIt last, OutputIt result) { while (first != last) { *result = *first; ++first; ++result; } return result; } /** * Replacement for std::fill(..) */ template UAVCAN_EXPORT void fill(ForwardIt first, ForwardIt last, const T& value) { while (first != last) { *first = value; ++first; } } /** * Replacement for std::fill_n(..) */ template UAVCAN_EXPORT void fill_n(OutputIt first, std::size_t n, const T& value) { while (n--) { *first++ = value; } } /** * Replacement for std::min(..) */ template UAVCAN_EXPORT const T& min(const T& a, const T& b) { return (b < a) ? b : a; } /** * Replacement for std::max(..) */ template UAVCAN_EXPORT const T& max(const T& a, const T& b) { return (a < b) ? b : a; } /** * Replacement for std::lexicographical_compare(..) */ template UAVCAN_EXPORT bool lexicographical_compare(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2) { while ((first1 != last1) && (first2 != last2)) { if (*first1 < *first2) { return true; } if (*first2 < *first1) { return false; } ++first1; ++first2; } return (first1 == last1) && (first2 != last2); } /** * Replacement for std::equal(..) */ template UAVCAN_EXPORT bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2) { while (first1 != last1) { if (*first1 != *first2) { return false; } ++first1; ++first2; } return true; } /** * Numeric traits, like std::numeric_limits<> */ template struct UAVCAN_EXPORT NumericTraits; /// char template <> struct UAVCAN_EXPORT NumericTraits { enum { IsSigned = 1 }; enum { IsInteger = 1 }; static char max() { return CHAR_MAX; } static char min() { return CHAR_MIN; } }; template <> struct UAVCAN_EXPORT NumericTraits { enum { IsSigned = 1 }; enum { IsInteger = 1 }; static signed char max() { return SCHAR_MAX; } static signed char min() { return SCHAR_MIN; } }; template <> struct UAVCAN_EXPORT NumericTraits { enum { IsSigned = 0 }; enum { IsInteger = 1 }; static unsigned char max() { return UCHAR_MAX; } static unsigned char min() { return 0; } }; /// short template <> struct UAVCAN_EXPORT NumericTraits { enum { IsSigned = 1 }; enum { IsInteger = 1 }; static short max() { return SHRT_MAX; } static short min() { return SHRT_MIN; } }; template <> struct UAVCAN_EXPORT NumericTraits { enum { IsSigned = 0 }; enum { IsInteger = 1 }; static unsigned short max() { return USHRT_MAX; } static unsigned short min() { return 0; } }; /// int template <> struct UAVCAN_EXPORT NumericTraits { enum { IsSigned = 1 }; enum { IsInteger = 1 }; static int max() { return INT_MAX; } static int min() { return INT_MIN; } }; template <> struct UAVCAN_EXPORT NumericTraits { enum { IsSigned = 0 }; enum { IsInteger = 1 }; static unsigned int max() { return UINT_MAX; } static unsigned int min() { return 0; } }; /// long template <> struct UAVCAN_EXPORT NumericTraits { enum { IsSigned = 1 }; enum { IsInteger = 1 }; static long max() { return LONG_MAX; } static long min() { return LONG_MIN; } }; template <> struct UAVCAN_EXPORT NumericTraits { enum { IsSigned = 0 }; enum { IsInteger = 1 }; static unsigned long max() { return ULONG_MAX; } static unsigned long min() { return 0; } }; /// long long template <> struct UAVCAN_EXPORT NumericTraits { enum { IsSigned = 1 }; enum { IsInteger = 1 }; static long long max() { return LLONG_MAX; } static long long min() { return LLONG_MIN; } }; template <> struct UAVCAN_EXPORT NumericTraits { enum { IsSigned = 0 }; enum { IsInteger = 1 }; static unsigned long long max() { return ULLONG_MAX; } static unsigned long long min() { return 0; } }; /// float template <> struct UAVCAN_EXPORT NumericTraits { enum { IsSigned = 1 }; enum { IsInteger = 0 }; static float max() { return FLT_MAX; } static float min() { return FLT_MIN; } static float infinity() { return INFINITY; } static float epsilon() { return FLT_EPSILON; } }; /// double template <> struct UAVCAN_EXPORT NumericTraits { enum { IsSigned = 1 }; enum { IsInteger = 0 }; static double max() { return DBL_MAX; } static double min() { return DBL_MIN; } static double infinity() { return static_cast(INFINITY) * static_cast(INFINITY); } static double epsilon() { return DBL_EPSILON; } }; #if defined(LDBL_MAX) && defined(LDBL_MIN) && defined(LDBL_EPSILON) /// long double template <> struct UAVCAN_EXPORT NumericTraits { enum { IsSigned = 1 }; enum { IsInteger = 0 }; static long double max() { return LDBL_MAX; } static long double min() { return LDBL_MIN; } static long double infinity() { return static_cast(INFINITY) * static_cast(INFINITY); } static long double epsilon() { return LDBL_EPSILON; } }; #endif #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11 # undef isnan # undef isinf # undef signbit #endif /** * Replacement for std::isnan(). * Note that direct float comparison (==, !=) is intentionally avoided. */ template inline bool isNaN(T arg) { #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11 return std::isnan(arg); #else // coverity[same_on_both_sides : FALSE] // cppcheck-suppress duplicateExpression return !(arg <= arg); #endif } /** * Replacement for std::isinf(). * Note that direct float comparison (==, !=) is intentionally avoided. */ template inline bool isInfinity(T arg) { #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11 return std::isinf(arg); #else return (arg >= NumericTraits::infinity()) || (arg <= -NumericTraits::infinity()); #endif } /** * Replacement for std::isfinite(). * Note that direct float comparison (==, !=) is intentionally avoided. */ template inline bool isFinite(T arg) { #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11 return std::isfinite(arg); #else return !isNaN(arg) && !isInfinity(arg); #endif } /** * Replacement for std::signbit(). * Note that direct float comparison (==, !=) is intentionally avoided. */ template inline bool getSignBit(T arg) { #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11 return std::signbit(arg); #else // coverity[divide_by_zero : FALSE] return arg < T(0) || (((arg <= T(0)) && (arg >= T(0))) && (T(1) / arg < T(0))); #endif } } #endif // UAVCAN_UTIL_TEMPLATES_HPP_INCLUDED