add ArxTypeTraits
parent
a7fb95ce81
commit
91dd8bc6fa
@ -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…
Reference in New Issue