mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-06-27 17:00:35 +08:00
505 lines
12 KiB
C++
505 lines
12 KiB
C++
/*
|
|
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
|
*/
|
|
|
|
#ifndef UAVCAN_UTIL_TEMPLATES_HPP_INCLUDED
|
|
#define UAVCAN_UTIL_TEMPLATES_HPP_INCLUDED
|
|
|
|
#include <climits>
|
|
#include <cstddef>
|
|
#include <cmath>
|
|
#include <uavcan/build_config.hpp>
|
|
|
|
#ifndef UAVCAN_CPP_VERSION
|
|
# error UAVCAN_CPP_VERSION
|
|
#endif
|
|
#if UAVCAN_CPP_VERSION < UAVCAN_CPP11
|
|
# include <float.h> // cfloat may not be available
|
|
#else
|
|
# include <cfloat> // C++11 mode assumes that all standard headers are available
|
|
#endif
|
|
|
|
namespace uavcan
|
|
{
|
|
/**
|
|
* Usage:
|
|
* StaticAssert<expression>::check();
|
|
*/
|
|
template <bool Value>
|
|
struct UAVCAN_EXPORT StaticAssert;
|
|
|
|
template <>
|
|
struct UAVCAN_EXPORT StaticAssert<true>
|
|
{
|
|
static void check() { }
|
|
};
|
|
|
|
/**
|
|
* Usage:
|
|
* ShowIntegerAsError<integer_expression>::foobar();
|
|
*/
|
|
template <long N> struct ShowIntegerAsError;
|
|
|
|
/**
|
|
* Prevents copying when inherited
|
|
*/
|
|
class UAVCAN_EXPORT Noncopyable
|
|
{
|
|
Noncopyable(const Noncopyable&);
|
|
Noncopyable& operator=(const Noncopyable&);
|
|
protected:
|
|
Noncopyable() { }
|
|
~Noncopyable() { }
|
|
};
|
|
|
|
/**
|
|
* Compile time conditions
|
|
*/
|
|
template <bool B, typename T = void>
|
|
struct UAVCAN_EXPORT EnableIf { };
|
|
|
|
template <typename T>
|
|
struct UAVCAN_EXPORT EnableIf<true, T>
|
|
{
|
|
typedef T Type;
|
|
};
|
|
|
|
/**
|
|
* Lightweight type categorization.
|
|
*/
|
|
template <typename T, typename R = void>
|
|
struct UAVCAN_EXPORT EnableIfType
|
|
{
|
|
typedef R Type;
|
|
};
|
|
|
|
/**
|
|
* Compile-time type selection (Alexandrescu)
|
|
*/
|
|
template <bool Condition, typename TrueType, typename FalseType>
|
|
struct UAVCAN_EXPORT Select;
|
|
|
|
template <typename TrueType, typename FalseType>
|
|
struct UAVCAN_EXPORT Select<true, TrueType, FalseType>
|
|
{
|
|
typedef TrueType Result;
|
|
};
|
|
|
|
template <typename TrueType, typename FalseType>
|
|
struct UAVCAN_EXPORT Select<false, TrueType, FalseType>
|
|
{
|
|
typedef FalseType Result;
|
|
};
|
|
|
|
/**
|
|
* Remove reference as in <type_traits>
|
|
*/
|
|
template <typename T> struct RemoveReference { typedef T Type; };
|
|
template <typename T> struct RemoveReference<T&> { typedef T Type; };
|
|
#if UAVCAN_CPP_VERSION > UAVCAN_CPP03
|
|
template <typename T> struct RemoveReference<T&&> { typedef T Type; };
|
|
#endif
|
|
|
|
/**
|
|
* Value types
|
|
*/
|
|
template <bool> struct UAVCAN_EXPORT BooleanType { };
|
|
typedef BooleanType<true> TrueType;
|
|
typedef BooleanType<false> FalseType;
|
|
|
|
template <int N> struct IntToType { };
|
|
|
|
/**
|
|
* Relations
|
|
*/
|
|
template <typename T1, typename T2>
|
|
class UAVCAN_EXPORT IsImplicitlyConvertibleFromTo
|
|
{
|
|
template <typename U> 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<T1, T2>::test(returner<T1>())) };
|
|
};
|
|
|
|
/**
|
|
* try_implicit_cast<>(From)
|
|
* try_implicit_cast<>(From, To)
|
|
* @{
|
|
*/
|
|
template <typename From, typename To>
|
|
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 <typename To, typename From>
|
|
UAVCAN_EXPORT
|
|
To try_implicit_cast(const From& from, const To& default_)
|
|
{
|
|
return TryImplicitCastImpl<From, To>::impl(from, default_,
|
|
BooleanType<IsImplicitlyConvertibleFromTo<From, To>::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 <typename To, typename From>
|
|
UAVCAN_EXPORT
|
|
To try_implicit_cast(const From& from)
|
|
{
|
|
return TryImplicitCastImpl<From, To>::impl(from, To(),
|
|
BooleanType<IsImplicitlyConvertibleFromTo<From, To>::Result>());
|
|
}
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/**
|
|
* Compile time square root for integers.
|
|
* Useful for operations on square matrices.
|
|
*/
|
|
template <unsigned Value> 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 <typename InputIt, typename OutputIt>
|
|
UAVCAN_EXPORT
|
|
OutputIt copy(InputIt first, InputIt last, OutputIt result)
|
|
{
|
|
while (first != last)
|
|
{
|
|
*result = *first;
|
|
++first;
|
|
++result;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Replacement for std::fill(..)
|
|
*/
|
|
template <typename ForwardIt, typename T>
|
|
UAVCAN_EXPORT
|
|
void fill(ForwardIt first, ForwardIt last, const T& value)
|
|
{
|
|
while (first != last)
|
|
{
|
|
*first = value;
|
|
++first;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Replacement for std::fill_n(..)
|
|
*/
|
|
template<typename OutputIt, typename T>
|
|
UAVCAN_EXPORT
|
|
void fill_n(OutputIt first, std::size_t n, const T& value)
|
|
{
|
|
while (n--)
|
|
{
|
|
*first++ = value;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Replacement for std::min(..)
|
|
*/
|
|
template <typename T>
|
|
UAVCAN_EXPORT
|
|
const T& min(const T& a, const T& b)
|
|
{
|
|
return (b < a) ? b : a;
|
|
}
|
|
|
|
/**
|
|
* Replacement for std::max(..)
|
|
*/
|
|
template <typename T>
|
|
UAVCAN_EXPORT
|
|
const T& max(const T& a, const T& b)
|
|
{
|
|
return (a < b) ? b : a;
|
|
}
|
|
|
|
/**
|
|
* Replacement for std::lexicographical_compare(..)
|
|
*/
|
|
template<typename InputIt1, typename InputIt2>
|
|
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<typename InputIt1, typename InputIt2>
|
|
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 <typename T>
|
|
struct UAVCAN_EXPORT NumericTraits;
|
|
|
|
/// char
|
|
template <>
|
|
struct UAVCAN_EXPORT NumericTraits<char>
|
|
{
|
|
enum { IsSigned = 1 };
|
|
enum { IsInteger = 1 };
|
|
static char max() { return CHAR_MAX; }
|
|
static char min() { return CHAR_MIN; }
|
|
};
|
|
template <>
|
|
struct UAVCAN_EXPORT NumericTraits<signed char>
|
|
{
|
|
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<unsigned char>
|
|
{
|
|
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<short>
|
|
{
|
|
enum { IsSigned = 1 };
|
|
enum { IsInteger = 1 };
|
|
static short max() { return SHRT_MAX; }
|
|
static short min() { return SHRT_MIN; }
|
|
};
|
|
template <>
|
|
struct UAVCAN_EXPORT NumericTraits<unsigned short>
|
|
{
|
|
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<int>
|
|
{
|
|
enum { IsSigned = 1 };
|
|
enum { IsInteger = 1 };
|
|
static int max() { return INT_MAX; }
|
|
static int min() { return INT_MIN; }
|
|
};
|
|
template <>
|
|
struct UAVCAN_EXPORT NumericTraits<unsigned int>
|
|
{
|
|
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<long>
|
|
{
|
|
enum { IsSigned = 1 };
|
|
enum { IsInteger = 1 };
|
|
static long max() { return LONG_MAX; }
|
|
static long min() { return LONG_MIN; }
|
|
};
|
|
template <>
|
|
struct UAVCAN_EXPORT NumericTraits<unsigned long>
|
|
{
|
|
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<long long>
|
|
{
|
|
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<unsigned long long>
|
|
{
|
|
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<float>
|
|
{
|
|
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<double>
|
|
{
|
|
enum { IsSigned = 1 };
|
|
enum { IsInteger = 0 };
|
|
static double max() { return DBL_MAX; }
|
|
static double min() { return DBL_MIN; }
|
|
static double infinity() { return static_cast<double>(INFINITY) * static_cast<double>(INFINITY); }
|
|
static double epsilon() { return DBL_EPSILON; }
|
|
};
|
|
|
|
#if defined(LDBL_MAX) && defined(LDBL_MIN) && defined(LDBL_EPSILON)
|
|
/// long double
|
|
template <>
|
|
struct UAVCAN_EXPORT NumericTraits<long double>
|
|
{
|
|
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<long double>(INFINITY) * static_cast<long double>(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 <typename T>
|
|
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 <typename T>
|
|
inline bool isInfinity(T arg)
|
|
{
|
|
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
|
|
return std::isinf(arg);
|
|
#else
|
|
return (arg >= NumericTraits<T>::infinity()) || (arg <= -NumericTraits<T>::infinity());
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Replacement for std::isfinite().
|
|
* Note that direct float comparison (==, !=) is intentionally avoided.
|
|
*/
|
|
template <typename T>
|
|
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 <typename T>
|
|
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
|