add ArxTypeTraits

master
Hideaki Tai 4 years ago
parent a7fb95ce81
commit 91dd8bc6fa

@ -252,6 +252,7 @@ Please use only sender OR receiver.
## Embedded Libraries ## Embedded Libraries
- [ArxContainer v0.3.9](https://github.com/hideakitai/ArxContainer) - [ArxContainer v0.3.9](https://github.com/hideakitai/ArxContainer)
- [ArxTypeTraits v0.2.0](https://github.com/hideakitai/ArxTypeTraits)
- [TeensyDirtySTLErrorSolution v0.1.0](https://github.com/hideakitai/TeensyDirtySTLErrorSolution) - [TeensyDirtySTLErrorSolution v0.1.0](https://github.com/hideakitai/TeensyDirtySTLErrorSolution)

@ -0,0 +1,42 @@
#pragma once
#ifndef ARX_TYPE_TRAITS_H
#define ARX_TYPE_TRAITS_H
#if __cplusplus < 201103L
#error "C++11 must be enabled in the compiler for this library to work, please check your compiler flags"
#endif
#include "ArxTypeTraits/has_include.h"
#include "ArxTypeTraits/has_libstdcplusplus.h"
// Make sure std namespace exists
namespace std { }
// Import everything from the std namespace into arx::std, so that
// anything we import rather than define is also available through
// arx::arx_std.
// This includes everything yet to be defined, so we can do this early
// (and must do so, to allow e.g. the C++14 additions in the arx::std
// namespace to reference the C++11 stuff from the system headers.
namespace arx {
namespace arx_std {
using namespace ::std;
}
}
// Import everything from arx::std back into the normal std namespace.
// This ensures that you can just use `std::foo` everywhere and you get
// the standard library version if it is available, falling back to arx
// versions for things not supplied by the standard library. Only when
// you really need the arx version (e.g. for constexpr numeric_limits
// when also using ArduinoSTL), you need to qualify with arx::arx_std::
namespace std {
using namespace ::arx::arx_std;
}
#include "ArxTypeTraits/replace_minmax_macros.h"
#include "ArxTypeTraits/type_traits.h"
#endif // ARX_TYPE_TRAITS_H

@ -0,0 +1,165 @@
#pragma once
#ifndef ARX_TYPE_TRAITS_FUNCTIONAL_H
#define ARX_TYPE_TRAITS_FUNCTIONAL_H
#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11
#include <functional>
#else // Do not have libstdc++11
// If we have a <new> header, include it and assume it has placement new
// (for AVR this has always been true, MEGAAVR does not have placement
// new now, but will probably get it before <new> is added).
// This also handles the case where ArduinoSTL is used, which defines an
// inline placement new which would conflict with the below definition.
#if ARX_SYSTEM_HAS_INCLUDE(<new>)
#include <new>
#else
// When there is no <new> header, there might be a <new.h> header, but
// not all Arduino platform (versions) define a placement new operator
// in there.
// However, it is hard to detect whether it is or is not defined, but
// the versions that do define it, do not define it inline in the
// header, so we can just define it inline here without conflicts.
// Note that there is no need to include anything to declare the
// non-placement new operators, since those are implicit.
inline void* operator new (const size_t size, void* ptr) noexcept { (void)size; return ptr; }
#endif
namespace arx { namespace arx_std {
// reference:
// stack overflow https://stackoverflow.com/questions/32074410/stdfunction-bind-like-type-erasure-without-standard-c-library
template<class Signature>
class function;
template<class R, class... Args>
class function<R(Args...)>
{
struct vtable_t
{
void (*mover)(void* src, void* dest);
void (*destroyer)(void*);
R (*invoke)(void const* t, Args&&... args);
template <class T>
static vtable_t const* get()
{
static const vtable_t table =
{
// mover
[] (void* src, void* dest)
{
new(dest) T(move(*static_cast<T*>(src)));
},
// destroyer
[] (void* t)
{
static_cast<T*>(t)->~T();
},
// invoke
[] (void const* t, Args&&... args) -> R
{
return (*static_cast<T const*>(t))(std::forward<Args>(args)...);
}
};
return &table;
}
};
vtable_t const* table {nullptr};
void* data {nullptr};
public:
template <
class Func,
class dF = typename std::decay<Func>::type,
typename enable_if <!std::is_same<dF, function>{}>::type* = nullptr,
typename enable_if <std::is_convertible<typename result_of<dF&(Args...)>::type, R>{}>::type* = nullptr
>
function(const Func& f)
: table(vtable_t::template get<dF>())
{
data = reinterpret_cast<void*>(new Func(f));
}
function(const function& o)
: table(o.table)
{
data = o.data;
}
function(function&& o)
: table(o.table)
{
if (table) table->mover(o.data, data);
}
function()
{
}
~function()
{
if (table) table->destroyer(data);
}
function& operator= (const function& o)
{
this->~function();
new(this) function(move(o));
return *this;
}
function& operator= (function&& o)
{
this->~function();
new(this) function(move(o));
return *this;
}
function& operator= (std::nullptr_t p)
{
(void)p;
this->~function();
return *this;
}
explicit operator bool() const
{
return table;
}
R operator()(Args...args) const
{
return table->invoke(data, forward<Args>(args)...);
}
};
template<class R, class... Args>
inline bool operator== (const function<R(Args...)>& f, std::nullptr_t)
{
return !static_cast<bool>(f);
}
template<class R, class... Args>
inline bool operator== (std::nullptr_t, const function<R(Args...)>& f)
{
return !static_cast<bool>(f);
}
template<class R, class... Args>
inline bool operator!= (const function<R(Args...)>& f, std::nullptr_t)
{
return static_cast<bool>(f);
}
template<class R, class... Args>
inline bool operator!= (std::nullptr_t, const function<R(Args...)>& f)
{
return static_cast<bool>(f);
}
} } // namespace arx::std
#endif // Do not have libstdc++11
#endif // ARX_TYPE_TRAITS_FUNCTIONAL_H

@ -0,0 +1,29 @@
#pragma once
#ifndef ARX_TYPE_TRAITS_HAS_INCLUDE_H
#define ARX_TYPE_TRAITS_HAS_INCLUDE_H
// Check whether __has_include is available, but also check the GCC
// version (__has_include was introduced in gcc 5) to catch
// environments (such as ESP8266) where gcc is old, but some system
// header provides a fake __has_include. We also need to check
// against __clang__ here, since clang pretends to be GCC
// 4.something and would otherwise be detected incorrectly here...
#if !defined(__has_include) || defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
#if defined(ARDUINO_ARCH_ESP8266)
// ESP8266 does not have a working __has_include, but we
// know it does have a working libstdc++ with all the
// headers we care about, so provide a fake has_include
#define ARX_SYSTEM_HAS_INCLUDE(x) 1
#elif defined(ARDUINO_SAM_DUE)
// Arduino DUE's GCC version is 4.8.3 (GCC < 5.0).
// And it has not libstdc++
#define ARX_SYSTEM_HAS_INCLUDE(x) 0
#else
#error "Compiler does not support __has_include, please report a bug against the ArxTypeTraits library about this."
#endif
#else
#define ARX_SYSTEM_HAS_INCLUDE(x) __has_include(x)
#endif
#endif // ARX_TYPE_TRAITS_HAS_INCLUDE_H

@ -0,0 +1,25 @@
#pragma once
#ifndef ARX_TYPE_TRAITS_HAS_LIBSTDCPLUSPLUS_H
#define ARX_TYPE_TRAITS_HAS_LIBSTDCPLUSPLUS_H
#if !defined(ARX_HAVE_LIBSTDCPLUSPLUS)
#if ARX_SYSTEM_HAS_INCLUDE(<cstdlib>)
#include <cstdlib>
#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION)
// For gcc's libstdc++ and clang's libc++, assume that
// __cplusplus tells us what the standard includes support
#define ARX_HAVE_LIBSTDCPLUSPLUS __cplusplus
#elif defined(__UCLIBCXX_MAJOR__)
// For uclibc++, assume C++98 support only.
#define ARX_HAVE_LIBSTDCPLUSPLUS 199711L
#else
#error "Unknown C++ library found, please report a bug against the ArxTypeTraits library about this."
#endif
#else
// Assume no standard library is available at all (e.g. on AVR)
#define ARX_HAVE_LIBSTDCPLUSPLUS 0
#endif
#endif
#endif // ARX_TYPE_TRAITS_HAS_LIBSTDCPLUSPLUS_H

@ -0,0 +1,30 @@
#pragma once
#ifndef ARX_TYPE_TRAITS_INITIALIZER_H
#define ARX_TYPE_TRAITS_INITIALIZER_H
// Initializer_list *must* be defined in std, so take extra care to only
// define it when <initializer_list> is really not available (e.g.
// ArduinoSTL is C++98 but *does* define <initializer_list>) and not
// already defined (e.g. by ArxContainer).
#if ARX_SYSTEM_HAS_INCLUDE(<initializer_list>)
#include <initializer_list>
#else
namespace std {
template<class T>
class initializer_list
{
private:
const T* array;
size_t len;
initializer_list(const T* a, size_t l) : array(a), len(l) {}
public:
initializer_list() : array(nullptr), len(0) {}
size_t size() const { return len; }
const T *begin() const { return array; }
const T *end() const { return array + len; }
};
} // namespace std
#endif
#endif // ARX_TYPE_TRAITS_INITIALIZER_LIST_H

@ -0,0 +1,33 @@
#pragma once
#ifndef ARX_TYPE_TRAITS_REPLACE_MINMAX_MACROS_H
#define ARX_TYPE_TRAITS_REPLACE_MINMAX_MACROS_H
// Make sure Arduino.h is actually included, since otherwise it might be
// included later and break *uses* of the min/max methods, rather than
// the declarations of it.
#include <Arduino.h>
// These macros are defined by Arduino.h on some platforms, and conflict
// with min/max methods defined or included by ArxTypeTraits, so replace
// them with macros here.
#ifdef max
#undef max
template <typename T1, typename T2>
constexpr auto max(T1 x, T2 y)
-> decltype(x + y)
{
return (x > y) ? x : y;
}
#endif
#ifdef min
#undef min
template <typename T1, typename T2>
constexpr auto min(T1 x, T2 y)
-> decltype(x + y)
{
return (x < y) ? x : y;
}
#endif
#endif // ARX_TYPE_TRAITS_REPLACE_MINMAX_MACROS_H

@ -0,0 +1,82 @@
#pragma once
#ifndef ARX_TYPE_TRAITS_TUPLE_H
#define ARX_TYPE_TRAITS_TUPLE_H
#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11
#include <tuple>
#else // Do not have libstdc++11
namespace arx { namespace arx_std {
// https://theolizer.com/cpp-school2/cpp-school2-15/
// https://wandbox.org/permlink/C0BWIzjqg4iO3kKZ
template<typename... Ts>
struct tuple
{
tuple() {}
};
template<typename tFirst, typename... tRest>
class tuple<tFirst, tRest...> : public tuple<tRest...>
{
template<size_t N, typename... tTypes> friend struct get_helper;
tFirst mMember;
public:
tuple(tFirst const& iFirst, tRest const&... iRest)
: tuple<tRest...>(iRest...)
, mMember(iFirst)
{ }
constexpr tuple() {}
};
template<size_t N, typename... tTypes>
struct get_helper { };
template<typename tFirst, typename... tRest>
struct get_helper<0, tFirst, tRest...>
{
typedef tFirst type;
static type& get(tuple<tFirst, tRest...>& iTuple)
{
return iTuple.mMember;
}
};
template<size_t N, typename tFirst, typename... tRest>
struct get_helper<N, tFirst, tRest...>
{
typedef typename get_helper<N - 1, tRest...>::type type;
static type& get(tuple<tFirst, tRest...>& iTuple)
{
return get_helper<N - 1, tRest...>::get(iTuple);
}
};
template<size_t N, typename... tTypes>
typename get_helper<N, tTypes...>::type& get(tuple<tTypes...>& iTuple)
{
return get_helper<N, tTypes...>::get(iTuple);
}
template <class T> class tuple_size;
template <class T> class tuple_size<const T>;
template <class T> class tuple_size<volatile T>;
template <class T> class tuple_size<const volatile T>;
template <class... Types>
class tuple_size <tuple<Types...>>
: public integral_constant <size_t, sizeof...(Types)> {};
template <class... Types>
auto make_tuple(Types&&... args)
-> std::tuple<typename std::remove_reference<Types>::type...>
{
return std::tuple<typename std::remove_reference<Types>::type...>(std::forward<typename std::remove_reference<Types>::type>(args)...);
}
} } // namespace arx::std
#endif // Do not have libstdc++11
#endif // ARX_TYPE_TRAITS_TUPLE_H

@ -0,0 +1,617 @@
#pragma once
#ifndef ARX_TYPE_TRAITS_TYPE_TRAITS_H
#define ARX_TYPE_TRAITS_TYPE_TRAITS_H
#if ARX_HAVE_LIBSTDCPLUSPLUS >= 199711L // Have libstdc++98
#include <utility>
#else // Do not have libstdc++98
namespace arx { namespace arx_std {
template <class T>
void swap(T& a, T& b)
{
T t = move(a);
a = move(b);
b = move(t);
}
} } // namespace arx::arx_std
#endif // Do not have libstdc++98
#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11
#include <limits>
#include <type_traits>
#else // Do not have libstdc++11
#include <float.h>
#include <limits.h>
#include <stdint.h>
namespace arx { namespace arx_std {
using nullptr_t = decltype(nullptr);
// numeric_limits
template <typename T>
struct numeric_limits
{
static constexpr T max() { return T(); }
static constexpr T min() { return T(); }
};
template <> constexpr bool numeric_limits<bool>::max() { return true; }
template <> constexpr char numeric_limits<char>::max() { return CHAR_MAX; }
template <> constexpr signed char numeric_limits<signed char>::max() { return SCHAR_MAX; }
template <> constexpr unsigned char numeric_limits<unsigned char>::max() { return UCHAR_MAX; }
template <> constexpr wchar_t numeric_limits<wchar_t>::max() { return WCHAR_MAX; }
// template <> constexpr char8_t numeric_limits<char8_t>::max() { return UCHAR_MAX; }
template <> constexpr char16_t numeric_limits<char16_t>::max() { return UINT_LEAST16_MAX; }
template <> constexpr char32_t numeric_limits<char32_t>::max() { return UINT_LEAST32_MAX; }
template <> constexpr short numeric_limits<short>::max() { return SHRT_MAX; }
template <> constexpr unsigned short numeric_limits<unsigned short>::max() { return USHRT_MAX; }
template <> constexpr int numeric_limits<int>::max() { return INT_MAX; }
template <> constexpr unsigned int numeric_limits<unsigned int>::max() { return UINT_MAX; }
template <> constexpr long numeric_limits<long>::max() { return LONG_MAX; }
template <> constexpr unsigned long numeric_limits<unsigned long>::max() { return ULONG_MAX; }
// template <> constexpr long long numeric_limits<long long>::max() { return LLONG_MAX; }
// template <> constexpr unsigned long long numeric_limits<unsigned long long>::max() { return ULLONG_MAX; }
template <> constexpr float numeric_limits<float>::max() { return FLT_MAX; }
template <> constexpr double numeric_limits<double>::max() { return DBL_MAX; }
template <> constexpr long double numeric_limits<long double>::max() { return LDBL_MAX; }
template <> constexpr bool numeric_limits<bool>::min() { return false; }
template <> constexpr char numeric_limits<char>::min() { return CHAR_MIN; }
template <> constexpr signed char numeric_limits<signed char>::min() { return SCHAR_MIN; }
template <> constexpr unsigned char numeric_limits<unsigned char>::min() { return 0; }
template <> constexpr wchar_t numeric_limits<wchar_t>::min() { return WCHAR_MIN; }
// template <> constexpr char8_t numeric_limits<char8_t>::min() { return 0; }
template <> constexpr char16_t numeric_limits<char16_t>::min() { return 0; }
template <> constexpr char32_t numeric_limits<char32_t>::min() { return 0; }
template <> constexpr short numeric_limits<short>::min() { return SHRT_MIN; }
template <> constexpr unsigned short numeric_limits<unsigned short>::min() { return 0; }
template <> constexpr int numeric_limits<int>::min() { return INT_MIN; }
template <> constexpr unsigned int numeric_limits<unsigned int>::min() { return 0; }
template <> constexpr long numeric_limits<long>::min() { return LONG_MIN; }
template <> constexpr unsigned long numeric_limits<unsigned long>::min() { return 0; }
// template <> constexpr long long numeric_limits<long long>::min() { return LLONG_MIN; }
// template <> constexpr unsigned long long numeric_limits<unsigned long long>::min() { return 0; }
template <> constexpr float numeric_limits<float>::min() { return FLT_MIN; }
template <> constexpr double numeric_limits<double>::min() { return DBL_MIN; }
template <> constexpr long double numeric_limits<long double>::min() { return LDBL_MIN; }
// integral_constant
template<class T, T v>
struct integral_constant
{
static constexpr T value = v;
using value_type = T;
using type = integral_constant;
constexpr operator value_type() const noexcept { return value; }
constexpr value_type operator()() const noexcept { return value; }
};
using true_type = integral_constant<bool, true>;
using false_type = integral_constant<bool, false>;
template <class T>
T declval(); // no implementation
template <bool, typename T = void>
struct enable_if;
template <typename T>
struct enable_if <true, T> { using type = T; };
template<bool, class T, class F>
struct conditional { using type = T; };
template<class T, class F>
struct conditional<false, T, F> { using type = F; };
template <class T> struct remove_cv { using type = T; };
template <class T> struct remove_cv<const T> { using type = T; };
template <class T> struct remove_cv<volatile T> { using type = T; };
template <class T> struct remove_cv<const volatile T> { using type = T; };
template <class T> struct remove_const { using type = T; };
template <class T> struct remove_const<const T> { using type = T; };
template <class T> struct remove_volatile { using type = T; };
template <class T> struct remove_volatile<volatile T> { using type = T; };
template <class T> struct remove_pointer { using type = T; };
template <class T> struct remove_pointer<T*> { using type = T; };
template <class T> struct remove_pointer<T* const> { using type = T; };
template <class T> struct remove_pointer<T* volatile> { using type = T; };
template <class T> struct remove_pointer<T* const volatile> { using type = T; };
template <class T> struct remove_reference { using type = T; };
template <class T> struct remove_reference<T&> { using type = T; };
template <class T> struct remove_reference<T&&> { using type = T; };
template<class T> struct remove_extent { typedef T type; };
template<class T> struct remove_extent<T[]> { typedef T type; };
template<class T, size_t N> struct remove_extent<T[N]> { typedef T type; };
template<class T>
T&& move(T& t){ return static_cast<T&&>(t); }
template <class T>
constexpr T&& forward(typename remove_reference<T>::type& t) noexcept
{
return static_cast<T&&>(t);
}
template <class T>
constexpr T&& forward(typename remove_reference<T>::type&& t) noexcept
{
return static_cast<T&&>(t);
}
namespace detail
{
template <class T>
struct type_identity { using type = T; };
template <class T>
auto try_add_pointer(int) -> type_identity<typename remove_reference<T>::type*>;
template <class T>
auto try_add_pointer(...) -> type_identity<T>;
}
template <class T>
struct add_pointer : decltype(detail::try_add_pointer<T>(0)) {};
template <typename T, typename U>
struct is_same : false_type {};
template <typename T>
struct is_same <T, T> : true_type {};
template <typename T>
struct is_integral : false_type {};
template <> struct is_integral <bool> : true_type {};
template <> struct is_integral <char> : true_type {};
template <> struct is_integral <signed char> : true_type {};
template <> struct is_integral <unsigned char> : true_type {};
template <> struct is_integral <char16_t> : true_type {};
template <> struct is_integral <char32_t> : true_type {};
template <> struct is_integral <wchar_t> : true_type {};
template <> struct is_integral <short> : true_type {};
template <> struct is_integral <unsigned short> : true_type {};
template <> struct is_integral <int> : true_type {};
template <> struct is_integral <unsigned> : true_type {};
template <> struct is_integral <long> : true_type {};
template <> struct is_integral <unsigned long> : true_type {};
template <> struct is_integral <long long> : true_type {};
template <> struct is_integral <unsigned long long> : true_type {};
template <typename T>
struct is_floating_point : false_type {};
template <> struct is_floating_point<float> : true_type {};
template <> struct is_floating_point<double> : true_type {};
template <> struct is_floating_point<long double> : true_type {};
template <typename T>
struct is_arithmetic
: conditional<
is_integral<T>::value || is_floating_point<T>::value,
true_type,
false_type
>::type
{};
namespace detail
{
template <typename T, bool = is_arithmetic<T>::value>
struct is_signed : integral_constant<bool, T(-1) < T(0)> {};
template <typename T>
struct is_signed<T, false> : false_type {};
}
template <typename T>
struct is_signed : detail::is_signed<T>::type {};
namespace detail
{
template<typename T, bool = is_arithmetic<T>::value>
struct is_unsigned : integral_constant<bool, T(0) < T(-1)> {};
template<typename T>
struct is_unsigned<T, false> : false_type {};
}
template<typename T>
struct is_unsigned : detail::is_unsigned<T>::type {};
template <class T> struct is_pointer_helper : false_type {};
template <class T> struct is_pointer_helper<T*> : true_type {};
template <class T> struct is_pointer : is_pointer_helper<typename remove_cv<T>::type> {};
template<class T>
struct is_array : false_type {};
template<class T>
struct is_array<T[]> : true_type {};
template<class T, size_t N>
struct is_array<T[N]> : true_type {};
namespace details
{
template <class... Ts>
struct Tester { using type = void; };
template <class... Ts>
using void_t = typename Tester<Ts...>::type;
template<template<class...>class Z, class, class...Ts>
struct can_apply : false_type{};
template<template<class...>class Z, class...Ts>
struct can_apply<Z, void_t<Z<Ts...>>, Ts...> : true_type{};
template<class From, class To>
using try_convert = decltype(To{declval<From>()});
}
template<template<class...>class Z, class...Ts>
using can_apply = details::can_apply<Z, void, Ts...>;
template<class From, class To>
struct is_convertible
: conditional <
can_apply <details::try_convert, From, To>::value
, true_type
, typename conditional <
is_arithmetic<From>::value && is_arithmetic<To>::value,
true_type,
false_type
>::type
>::type
{};
template<>
struct is_convertible<void, void> : true_type{};
// primary template
template<class>
struct is_function : false_type { };
// specialization for regular functions
template<class Ret, class... Args>
struct is_function<Ret(Args...)> : true_type {};
// specialization for variadic functions such as printf
template<class Ret, class... Args>
struct is_function<Ret(Args......)> : true_type {};
// specialization for function types that have cv-qualifiers
template<class Ret, class... Args>
struct is_function<Ret(Args...) const> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile> : true_type {};
// specialization for function types that have ref-qualifiers
template<class Ret, class... Args>
struct is_function<Ret(Args...) &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) &&> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const &&> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile &&> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile &&> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) &&> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const &&> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile &&> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile &&> : true_type {};
template<typename T>
struct is_empty : public integral_constant<bool, __is_empty(T)> { };
template <class T>
class decay
{
typedef typename remove_reference<T>::type U;
public:
typedef typename conditional<
is_array<U>::value,
typename remove_extent<U>::type*,
typename conditional<
is_function<U>::value,
typename add_pointer<U>::type,
typename remove_cv<U>::type
>::type
>::type type;
};
namespace details
{
template<class T> struct tag { using type=T; };
template<class Tag> using type_t = typename Tag::type;
template<class G, class...Args>
using invoke_t = decltype( declval<G>()(declval<Args>()...) );
template<class Sig, class = void>
struct result_of {};
template<class G, class...Args>
struct result_of<G(Args...), void_t<invoke_t<G, Args...>>>
: tag <invoke_t<G, Args...>>
{};
}
template<class Sig>
using result_of = details::result_of<Sig>;
} } // namespace arx::arx_std
#endif // Do not have libstdc++11
#include "initializer_list.h"
#include "tuple.h"
#include "functional.h"
#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201402L // Have libstdc++14
// Nothing to include here, relevant header files were already included
// for C++11 above.
#else // Do not have libstdc++14
namespace arx { namespace arx_std {
template <bool B, typename T = void>
using enable_if_t = typename enable_if<B, T>::type;
template <typename T>
using decay_t = typename decay<T>::type;
template<class T>
using remove_cv_t = typename remove_cv<T>::type;
template<class T>
using remove_const_t = typename remove_const<T>::type;
template<class T>
using remove_volatile_t = typename remove_volatile<T>::type;
template<class T>
using remove_reference_t = typename remove_reference<T>::type;
template<class T>
using remove_pointer_t = typename remove_pointer<T>::type;
template<typename T, T ...Ts>
struct integer_sequence
{
using type = integer_sequence;
using value_type = T;
static constexpr size_t size() noexcept { return sizeof...(Ts); }
};
template <size_t ...Is>
using index_sequence = integer_sequence<size_t, Is...>;
// https://stackoverflow.com/questions/17424477/implementation-c14-make-integer-sequence
template<typename S1, typename S2>
struct concat_impl;
template<typename S1, typename S2>
using concat = typename concat_impl<S1, S2>::type;
template<size_t... I1, size_t... I2>
struct concat_impl <index_sequence<I1...>, index_sequence<I2...>>
: index_sequence<I1..., (sizeof...(I1) + I2)...> {};
template<size_t N>
struct make_index_sequence_impl;
template<size_t N>
using make_index_sequence = typename make_index_sequence_impl<N>::type;
template<size_t N>
struct make_index_sequence_impl
: concat<make_index_sequence <N/2>, make_index_sequence <N - N/2>> {};
template<>
struct make_index_sequence_impl <0> : index_sequence<>{};
template<>
struct make_index_sequence_impl <1> : index_sequence<0>{};
template<typename... Ts>
using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
} } // namespace arx::arx_std
#endif // Do not have libstdc++14
#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201703L // Have libstdc++17
// Nothing to include here, relevant header files were already included
// for C++11 above.
#else // Do not have libstdc++17
namespace arx { namespace arx_std {
template <class... Ts>
struct Tester { using type = void; };
template <class... Ts>
using void_t = typename Tester<Ts...>::type;
template <typename ...Args>
struct disjunction : false_type {};
template <typename Arg>
struct disjunction <Arg> : Arg::type {};
template <typename Arg, typename ...Args>
struct disjunction <Arg, Args...> : conditional<Arg::value, Arg, disjunction<Args...>>::type {};
template <typename ...Args>
struct conjunction : true_type {};
template <typename Arg>
struct conjunction <Arg> : Arg::type {};
template <typename Arg, typename ...Args>
struct conjunction <Arg, Args...> : conditional<Arg::value, conjunction<Args...>, Arg>::type {};
template <typename T>
struct negation : integral_constant<bool, !T::value> {};
// https://qiita.com/_EnumHack/items/92e6e135174f1f781dbb
// without decltype(auto)
template <class F, class Tuple, size_t... I>
constexpr auto apply_impl(F&& f, Tuple&& t, index_sequence<I...>)
-> decltype(f(get<I>(forward<Tuple>(t))...))
{
return f(get<I>(forward<Tuple>(t))...);
}
template <class F, class Tuple>
constexpr auto apply(F&& f, Tuple&& t)
-> decltype(apply_impl(
forward<F>(f),
forward<Tuple>(t),
make_index_sequence<tuple_size<decay_t<Tuple>>::value>{}
))
{
return apply_impl(
forward<F>(f),
forward<Tuple>(t),
make_index_sequence<tuple_size<decay_t<Tuple>>::value>()
);
}
} } // namespace arx::arx_std
#endif // Do not have libstdc++17
#if ARX_HAVE_LIBSTDCPLUSPLUS > 201703L // Have libstdc++2a
// Nothing to include here, relevant header files were already included
// for C++11 above.
#else // Do not have libstdc++2a
namespace arx { namespace arx_std {
template<class T>
struct remove_cvref
{
typedef remove_cv_t<remove_reference_t<T>> type;
};
template< class T >
using remove_cvref_t = typename remove_cvref<T>::type;
} } // namespace arx::arx_std
#endif // Do not have libstdc++2a
namespace arx { // others
template <class AlwaysVoid, template<class...> class Check, class... T>
struct is_detected_impl : std::false_type {};
template <template <class...> class Check, class... T>
struct is_detected_impl <std::void_t<Check<T...>>, Check, T...> : std::true_type {};
template <template <class...> class Check, class... T>
using is_detected = is_detected_impl<void, Check, T...>;
template <typename T>
struct is_callable {
template <typename U, decltype(&U::operator()) = &U::operator()>
struct checker {};
template <typename U> static std::true_type test(checker<U> *);
template <typename> static std::false_type test(...);
static constexpr bool value = decltype(test<T>(nullptr))::value;
};
template <typename R, typename ... Arguments>
struct is_callable<R(*)(Arguments ...)> {
static constexpr bool value = true;
};
template <typename R, typename ... Arguments>
struct is_callable<R(*&)(Arguments ...)> {
static constexpr bool value = true;
};
template <typename R, typename ... Arguments>
struct is_callable<R(&)(Arguments ...)> {
static constexpr bool value = true;
};
template <typename R, typename ... Arguments>
struct is_callable<R(Arguments ...)> {
static constexpr bool value = true;
};
template <typename R, typename ... Arguments>
struct is_callable<std::function<R(Arguments ...)>> {
static constexpr bool value = true;
};
namespace detail {
template <typename ret, typename ... arguments>
struct function_traits {
static constexpr size_t arity = sizeof...(arguments);
using result_type = ret;
using arguments_types_tuple = std::tuple<arguments ...>;
// template <size_t index>
// using argument_type = type_at<index, arguments ...>;
using function_type = std::function<ret(arguments ...)>;
template <typename function_t>
static constexpr function_type cast(function_t f) {
return static_cast<function_type>(f);
}
};
};
template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())> {};
template <typename class_type, typename ret, typename ... arguments>
struct function_traits<ret(class_type::*)(arguments ...) const>
: detail::function_traits<ret, arguments ...> {};
template <typename class_type, typename ret, typename ... arguments>
struct function_traits<ret(class_type::*)(arguments ...)>
: detail::function_traits<ret, arguments ...> {};
template <typename ret, typename ... arguments>
struct function_traits<ret(*)(arguments ...)>
: detail::function_traits<ret, arguments ...> {};
template <typename ret, typename ... arguments>
struct function_traits<ret(*&)(arguments ...)>
: detail::function_traits<ret, arguments ...> {};
template <typename ret, typename ... arguments>
struct function_traits<ret(arguments ...)>
: detail::function_traits<ret, arguments ...> {};
template <typename ret, typename ... arguments>
struct function_traits<std::function<ret(arguments ...)>>
: detail::function_traits<ret, arguments ...> {};
} // namespace arx
#endif // ARX_TYPE_TRAITS_TYPE_TRAITS_H

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Hideaki Tai
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -0,0 +1,114 @@
# ArxTypeTraits
C++ type_traits for Arduino which cannot use it as default
## Features
- automatically use standard library first if the boards can
- if standard library is not enough (e.g. only C++11 is available), add missing parts listed below
- works almost all Arduino platforms (Let me know if you have errors)
- compatible with [ArduinoSTL](https://github.com/mike-matera/ArduinoSTL) or other [uClibc++](https://www.uclibc.org/) libraries (include them before `ArxTypeTraits`)
- thx @matthijskooijman
## Supported Class Templates
### C++11 (defined only for platforms above which cannot use `type_traits`)
- `std::integral_constant`
- `std::true_type`
- `std::false_type`
- `std::declval`
- `std::enable_if`
- `std::conditional`
- `std::remove_cv`
- `std::remove_const`
- `std::remove_volatile`
- `std::remove_pointer`
- `std::remove_reference`
- `std::remove_extent`
- `std::add_pointer`
- `std::forward`
- `std::is_same`
- `std::is_integral`
- `std::is_floating_point`
- `std::is_arithmetic`
- `std::is_signed`
- `std::is_unsigned`
- `std::is_pointer`
- `std::is_array`
- `std::is_convertible`
- `std::is_function`
- `std::is_empty`
- `std::decay`
- `std::result_of`
#### for utility
- `std::numeric_limits` (only `max()` and `min()` now)
- `std::swap`
- `std::initializer_list`
- `std::tuple`
- `std::get`
- `std::tuple_size`
- `std::function`
### C++14 (defined only for boards before C++14)
- `std::enable_if_t`
- `std::decay_t`
- `std::remove_cv_t`
- `std::remove_const_t`
- `std::remove_volatile_t`
- `std::remove_reference_t`
- `std::remove_pointer_t`
- `std::integer_sequence`
- `std::index_sequence`
- `std::make_index_sequence`
- `std::index_sequence_for`
### C++17 (defined only for boards before C++17)
- `std::void_t`
- `std::disjunction`
- `std::conjunction`
- `std::negation`
- `std::apply`
### C++2a
- `std::remove_cvref`
- `std::remove_cvref_t`
### Others (defined for all boards)
- `arx::is_detected`
- `arx::is_callable`
- `arx::function_traits`
## Used Inside of
- [Packetizer](https://github.com/hideakitai/Packetizer)
- [MsgPack](https://github.com/hideakitai/MsgPack)
- [MsgPacketizer](https://github.com/hideakitai/MsgPacketizer)
- [ArduinoOSC](https://github.com/hideakitai/ArduinoOSC)
- [PollingTimer](https://github.com/hideakitai/PollingTimer)
- [Tween](https://github.com/hideakitai/Tween)
- [ArxStringUtils](https://github.com/hideakitai/ArxStringUtils)
## Contributors
- [Matthijs Kooijman](https://github.com/matthijskooijman)
## License
MIT

@ -0,0 +1,18 @@
{
"name": "ArxTypeTraits",
"keywords": "type traits, functional, tuple, stl",
"description": "C++ type_traits for Arduino which cannot use it as default",
"repository": {
"type": "git",
"url": "https://github.com/hideakitai/ArxTypeTraits.git"
},
"authors": {
"name": "Hideaki Tai",
"url": "https://github.com/hideakitai",
"maintainer": true
},
"version": "0.2.0",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*"
}

@ -0,0 +1,9 @@
name=ArxTypeTraits
version=0.2.0
author=hideakitai
maintainer=hideakitai
sentence=C++ type_traits for Arduino which cannot use it as default
paragraph=C++ type_traits for Arduino which cannot use it as default
category=Data Storage
url=https://github.com/hideakitai/ArxTypeTraits
architectures=*
Loading…
Cancel
Save