Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 48 additions & 16 deletions ArxTypeTraits.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,58 @@
#ifndef ARX_TYPE_TRAITS_H
#define ARX_TYPE_TRAITS_H

#if defined(ARDUINO_ARCH_AVR)\
|| defined(ARDUINO_ARCH_MEGAAVR)\
|| defined(ARDUINO_ARCH_SAM)\
|| defined(ARDUINO_ARCH_SAMD)\
|| defined(ARDUINO_spresense_ast)
#define ARX_TYPE_TRAITS_DISABLED
#if defined(ARDUINO_ARCH_MEGAAVR)\
|| defined(ARDUINO_ARCH_SAMD)\
|| defined(ARDUINO_spresense_ast)
#define ARX_TYPE_TRAITS_NEW_DISABLED
#endif
#if __cplusplus < 201103L
#error "C++11 must be enabled in the compiler for this library to work, please check your compiler flags"
#endif

#include <stddef.h>
#ifndef ARX_TYPE_TRAITS_DISABLED
#include <type_traits>
#include <tuple>
#include <functional>
#include "ArxTypeTraits/has_include.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

// 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
36 changes: 26 additions & 10 deletions ArxTypeTraits/functional.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,38 @@
#ifndef ARX_TYPE_TRAITS_FUNCTIONAL_H
#define ARX_TYPE_TRAITS_FUNCTIONAL_H

#include <Arduino.h>
#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11

#ifdef ARX_TYPE_TRAITS_NEW_DISABLED
void* operator new (const size_t size, void* ptr) { (void)size; return ptr; }
#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
#include <new.h>
// 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

#ifdef ARX_TYPE_TRAITS_DISABLED

namespace std {
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>
struct function;
class function;

template<class R, class... Args>
class function<R(Args...)>
Expand Down Expand Up @@ -143,7 +158,8 @@ namespace std {
return static_cast<bool>(f);
}

} // namespace std
} } // namespace arx::std

#endif // Do not have libstdc++11

#endif // ARX_TYPE_TRAITS_DISABLED
#endif // ARX_TYPE_TRAITS_FUNCTIONAL_H
25 changes: 25 additions & 0 deletions ArxTypeTraits/has_include.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#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
#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
30 changes: 30 additions & 0 deletions ArxTypeTraits/initializer_list.h
Original file line number Diff line number Diff line change
@@ -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
33 changes: 33 additions & 0 deletions ArxTypeTraits/replace_minmax_macros.h
Original file line number Diff line number Diff line change
@@ -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
13 changes: 9 additions & 4 deletions ArxTypeTraits/tuple.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
#ifndef ARX_TYPE_TRAITS_TUPLE_H
#define ARX_TYPE_TRAITS_TUPLE_H

#ifdef ARX_TYPE_TRAITS_DISABLED
#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11

namespace std {
#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
Expand Down Expand Up @@ -71,7 +75,8 @@ namespace std {
return std::tuple<typename std::remove_reference<Types>::type...>(std::forward<typename std::remove_reference<Types>::type>(args)...);
}

} // namespace std
} } // namespace arx::std

#endif // Do not have libstdc++11

#endif // ARX_TYPE_TRAITS_DISABLED
#endif // ARX_TYPE_TRAITS_TUPLE_H
Loading