#pragma once // Fix for limits.h not exposing LLONG_MIN, LLONG_MIN, and ULLONG_MAX to C++ context #ifdef __cplusplus #ifndef __STDC_VERSION__ #define __STDC_VERSION__ 201112L #endif #endif #include #include #include namespace util { // // clang-format off template struct remove_reference { using type = T; }; template struct remove_reference { using type = T; }; template struct remove_reference { using type = T; }; template using remove_reference_t = typename remove_reference::type; template struct integral_constant { static constexpr T value = v; using value_type = T; using type = integral_constant; // using injected-class-name constexpr operator value_type() const noexcept { return value; } constexpr value_type operator()() const noexcept { return value; } // since c++14 }; template using bool_constant = integral_constant; using false_type = bool_constant; using true_type = bool_constant; template struct is_const : false_type {}; template struct is_const : true_type {}; template inline constexpr bool is_const_v = is_const::value; template struct is_reference : false_type {}; template struct is_reference : true_type {}; template struct is_reference : true_type {}; template inline constexpr bool is_reference_v = is_reference::value; template struct is_lvalue_reference : false_type {}; template struct is_lvalue_reference : true_type {}; template inline constexpr bool is_lvalue_reference_v = is_lvalue_reference::value; template struct is_function : integral_constant && !is_reference_v> {}; template inline constexpr bool is_function_v = is_function::value; // Must use intrinsic, because this cannot be implemented in standard C++ template struct is_union : integral_constant {}; template inline constexpr bool is_union_v = is_union::value; namespace detail { template struct type_identity { using type = T; }; template auto try_add_pointer(int) -> type_identity *>; template auto try_add_pointer(...) -> type_identity; template auto try_add_lvalue_reference(int) -> type_identity; template auto try_add_lvalue_reference(...) -> type_identity; template auto try_add_rvalue_reference(int) -> type_identity; template auto try_add_rvalue_reference(...) -> type_identity; template struct is_pointer_helper : false_type {}; template struct is_pointer_helper : true_type {}; template struct is_member_pointer_helper : false_type {}; template struct is_member_pointer_helper : true_type {}; template struct is_member_function_pointer_helper : false_type {}; template struct is_member_function_pointer_helper : is_function {}; template integral_constant::value> is_class_helper(int T::*); template false_type is_class_helper(...); template true_type test_pre_ptr_convertible(const volatile B *); template false_type test_pre_ptr_convertible(const volatile void *); template auto test_pre_is_base_of(...) -> true_type; template auto test_pre_is_base_of(int) -> decltype(test_pre_ptr_convertible(static_cast(nullptr))); } // namespace detail template struct conditional { using type = T; }; template struct conditional { using type = F; }; template using conditional_t = typename conditional::type; template struct is_array : false_type {}; template struct is_array : true_type {}; template struct is_array : true_type {}; template inline constexpr bool is_array_v = is_array::value; template struct remove_extent { using type = T; }; template struct remove_extent { using type = T; }; template struct remove_extent { using type = T; }; template using remove_extent_t = typename remove_extent::type; template struct add_pointer : decltype(detail::try_add_pointer(0)) {}; template using add_pointer_t = typename add_pointer::type; template struct add_lvalue_reference : decltype(detail::try_add_lvalue_reference(0)) {}; template using add_lvalue_reference_t = typename add_lvalue_reference::type; template struct add_rvalue_reference : decltype(detail::try_add_rvalue_reference(0)) {}; template using add_rvalue_reference_t = typename add_rvalue_reference::type; template struct remove_cv { using type = T; }; template struct remove_cv { using type = T; }; template struct remove_cv { using type = T; }; template struct remove_cv { using type = T; }; template struct remove_const { using type = T; }; template struct remove_const { using type = T; }; template struct remove_volatile { using type = T; }; template struct remove_volatile { using type = T; }; template using remove_cv_t = typename remove_cv::type; template using remove_const_t = typename remove_const::type; template using remove_volatile_t = typename remove_volatile::type; template struct remove_cvref { using type = remove_cv_t>; }; template using remove_cvref_t = typename remove_cvref::type; template struct decay { private: using U = remove_reference_t; public: using type = conditional_t, remove_extent_t *, conditional_t::value, add_pointer_t, remove_cv_t > >; }; template using decay_t = typename decay::type; template struct is_same : false_type {}; template struct is_same : true_type {}; template inline constexpr auto is_same_v = is_same::value; template struct is_floating_point : integral_constant> || is_same_v> || is_same_v>> {}; template inline constexpr auto is_floating_point_v = is_floating_point::value; template struct is_integral : integral_constant> || is_same_v> || is_same_v> || is_same_v> || is_same_v> || is_same_v> || is_same_v> || is_same_v> || is_same_v> || is_same_v> || is_same_v> || is_same_v> || is_same_v> || is_same_v> || is_same_v>> {}; template inline constexpr auto is_integral_v = is_integral::value; template struct is_arithmetic : integral_constant::value || is_floating_point::value> {}; template inline constexpr bool is_arithmetic_v = is_arithmetic::value; template struct is_void : is_same> {}; template inline constexpr bool is_void_v = is_void::value; template struct is_pointer : detail::is_pointer_helper> {}; template inline constexpr bool is_pointer_v = is_pointer::value; template struct is_member_pointer : detail::is_member_pointer_helper> {}; template inline constexpr bool is_member_pointer_v = is_member_pointer::value; template struct is_member_function_pointer : detail::is_member_function_pointer_helper> {}; template inline constexpr bool is_member_function_pointer_v = is_member_function_pointer::value; template struct is_member_object_pointer : integral_constant && !is_member_function_pointer_v> {}; template inline constexpr bool is_member_object_pointer_v = is_member_object_pointer::value; template struct is_class : decltype(detail::is_class_helper(nullptr)) {}; template inline constexpr bool is_class_v = is_class::value; template struct is_enum : integral_constant && !is_integral_v && !is_floating_point_v && !is_array_v && !is_pointer_v && !is_reference_v && !is_member_pointer_v && !is_union_v && !is_class_v && !is_function_v> {}; template inline constexpr bool is_enum_v = is_enum::value; template struct is_null_pointer : is_same> {}; template inline constexpr bool is_null_pointer_v = is_null_pointer::value; template struct is_scalar : integral_constant || is_enum_v || is_pointer_v || is_member_pointer_v || is_null_pointer_v> {}; template inline constexpr bool is_scalar_v = is_scalar::value; template struct is_object : integral_constant || is_array_v || is_union_v || is_class_v> {}; template inline constexpr bool is_object_v = is_object::value; template struct is_base_of : integral_constant && is_class_v && decltype(detail::test_pre_is_base_of(0))::value> {}; template inline constexpr bool is_base_of_v = is_base_of::value; template struct enable_if {}; template struct enable_if { using type = T; }; template using enable_if_t = typename enable_if::type; } // namespace type ////////////////////////////////////////////////////////////////////////// // Forward declarations namespace util { template struct reference_wrapper; template inline constexpr T &&forward(util::remove_reference_t &t) noexcept; template util::add_rvalue_reference_t declval() noexcept; } // namespace util ////////////////////////////////////////////////////////////////////////// namespace util { // Everything is nothrow_invocable, because exceptions are disabled in avr-gcc template struct is_nothrow_invocable : true_type {}; template inline constexpr auto is_nothrow_invocable_v = is_nothrow_invocable::value; namespace detail { template struct is_reference_wrapper : false_type {}; template struct is_reference_wrapper> : true_type {}; template struct invoke_impl { template static auto call(Fn &&f, Args &&... args) -> decltype(util::forward(f)(util::forward(args)...)); }; template struct invoke_impl { template , typename = enable_if_t>> static auto get(T &&t) -> T &&; template , typename = enable_if_t::value>> static auto get(T &&t) -> decltype(t.get()); template , typename = enable_if_t>, typename = enable_if_t::value>> static auto get(T &&t) -> decltype(*util::forward(t)); template >> static auto call(MT1 B::*pmf, T &&t, Args &&... args) -> decltype((invoke_impl::get(util::forward(t)).*pmf)(util::forward(args)...)); template static auto call(MT B::*pmd, T &&t) -> decltype(invoke_impl::get(util::forward(t)).*pmd); }; template > auto INVOKE(Fn &&f, Args &&... args) -> decltype(invoke_impl::call(util::forward(f), util::forward(args)...)); template struct invoke_result {}; template struct invoke_result(), util::declval()...))), Fn, Args...> { using type = decltype(INVOKE(util::declval(), util::declval()...)); }; } // namespace detail template struct invoke_result : detail::invoke_result {}; template using invoke_result_t = typename invoke_result::type; // Not part of , but very useful template struct always_false : false_type {}; template inline constexpr auto always_false_v = always_false::value; // template struct numeric_limits {}; template <> struct numeric_limits { static constexpr bool min() { return false; } static constexpr bool max() { return true; } }; template <> struct numeric_limits { static constexpr char min() { return CHAR_MIN; } static constexpr char max() { return CHAR_MAX; } }; template <> struct numeric_limits { static constexpr signed char min() { return SCHAR_MIN; } static constexpr signed char max() { return SCHAR_MAX; } }; template <> struct numeric_limits { static constexpr unsigned char min() { return 0; } static constexpr unsigned char max() { return UCHAR_MAX; } }; template <> struct numeric_limits { static constexpr short min() { return SHRT_MIN; } static constexpr short max() { return SHRT_MAX; } }; template <> struct numeric_limits { static constexpr int min() { return INT_MIN; } static constexpr int max() { return INT_MAX; } }; template <> struct numeric_limits { static constexpr long int min() { return LONG_MIN; } static constexpr long int max() { return LONG_MAX; } }; template <> struct numeric_limits { static constexpr long long int min() { return LLONG_MIN; } static constexpr long long int max() { return LLONG_MAX; } }; template <> struct numeric_limits { static constexpr unsigned short min() { return 0; } static constexpr unsigned short max() { return USHRT_MAX; } }; template <> struct numeric_limits { static constexpr unsigned int min() { return 0; } static constexpr unsigned int max() { return UINT_MAX; } }; template <> struct numeric_limits { static constexpr unsigned long int min() { return 0; } static constexpr unsigned long int max() { return ULONG_MAX; } }; template <> struct numeric_limits { static constexpr unsigned long long int min() { return 0; } static constexpr unsigned long long int max() { return ULLONG_MAX; } }; template <> struct numeric_limits { static constexpr float min() { return FLT_MIN; } static constexpr float max() { return FLT_MAX; } static constexpr float lowest() { return -FLT_MAX; } }; template <> struct numeric_limits { static constexpr double min() { return DBL_MIN; } static constexpr double max() { return DBL_MAX; } static constexpr double lowest() { return -DBL_MAX; } }; template <> struct numeric_limits { static constexpr long double min() { return LDBL_MIN; } static constexpr long double max() { return LDBL_MAX; } static constexpr long double lowest() { return -LDBL_MAX; } }; // clang-format on } // namespace util