From 3876ae468ee45f0169028df3e2fbd7c8ef981f11 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 24 Sep 2020 11:08:20 +0200 Subject: [PATCH 01/16] fix class vs struct inconsistency This is not normally a problem, but clang warns that MSVC might produce linker errors for this. --- ArxTypeTraits/functional.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ArxTypeTraits/functional.h b/ArxTypeTraits/functional.h index ed1ff17..4f41fc3 100644 --- a/ArxTypeTraits/functional.h +++ b/ArxTypeTraits/functional.h @@ -19,7 +19,7 @@ namespace std { // stack overflow https://stackoverflow.com/questions/32074410/stdfunction-bind-like-type-erasure-without-standard-c-library template - struct function; + class function; template class function From 606cb1d490cea80479203419146aca362e85eea8 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 22 Sep 2020 22:16:11 +0200 Subject: [PATCH 02/16] add missing stdint.h include This is needed for WCHAR_MAX and similar macros. This was only a problem when ArxTypeTraits.h was included without stdint.h being included already (e.g. through Arduino.h usually), but include it just in case. --- ArxTypeTraits/type_traits.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ArxTypeTraits/type_traits.h b/ArxTypeTraits/type_traits.h index 0b1481f..57c3793 100644 --- a/ArxTypeTraits/type_traits.h +++ b/ArxTypeTraits/type_traits.h @@ -27,6 +27,7 @@ #include #include #include +#include namespace std { From da3c5d3cab5975e7591bd1f5c1047ead0845ead7 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 23 Sep 2020 18:51:10 +0200 Subject: [PATCH 03/16] remove unused stddef.h includes --- ArxTypeTraits.h | 1 - ArxTypeTraits/type_traits.h | 1 - 2 files changed, 2 deletions(-) diff --git a/ArxTypeTraits.h b/ArxTypeTraits.h index a9c49b4..ab4c384 100644 --- a/ArxTypeTraits.h +++ b/ArxTypeTraits.h @@ -16,7 +16,6 @@ #endif #endif -#include #ifndef ARX_TYPE_TRAITS_DISABLED #include #include diff --git a/ArxTypeTraits/type_traits.h b/ArxTypeTraits/type_traits.h index 57c3793..231adf6 100644 --- a/ArxTypeTraits/type_traits.h +++ b/ArxTypeTraits/type_traits.h @@ -24,7 +24,6 @@ } #endif -#include #include #include #include From c72c21ff92aa0e5de90a94a73fda06efcadf05a7 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Fri, 25 Sep 2020 22:18:00 +0200 Subject: [PATCH 04/16] import everything we do not define On some architectures, various C++98 and C++11 things were defined by this library. On other architectures, these are assumed to be provided from the system libraries and some headers are included to make sure they are actually available after including ArxTypeTraits. However, the list of included headers was not complete, so not all names normally defined might be available on these architectures. This has probably not shown up so far since the headers that were included might include other headers internally as well (e.g. on ESP32, `numeric_limits` was available even though `` was not included, but on SAMD this is not the case). This makes the list of includes complete, so all names should now be guaranteed to be available. --- ArxTypeTraits.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ArxTypeTraits.h b/ArxTypeTraits.h index ab4c384..bfd8821 100644 --- a/ArxTypeTraits.h +++ b/ArxTypeTraits.h @@ -17,6 +17,9 @@ #endif #ifndef ARX_TYPE_TRAITS_DISABLED + #include + #include + #include #include #include #include From 477d4a54f8d85045eca1f66484b5429ac1dab6d3 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 23 Sep 2020 10:41:34 +0200 Subject: [PATCH 05/16] replace min/max macros earlier and always This moves these replacements into their own file for clarity and includes that file earlier in ArxTypeTraits.h already, before including standard C++ headers. This fixes compilation on platforms that *do* have libstdc++ but also define min/max macros. One example of such platform is SAMD, though that was not currently broken because there ArxTypeTraits defined its own functions rather than including libstdc++ (but that can now be changed). This has probably not shown up as a problem before, since the platforms where libstdc++ was used, probably did not define min/max macros (but min/max functions). However, this is not necessarily true and any platform can define such macros, so just do the replacement always (provided these macros are defined, of course). --- ArxTypeTraits.h | 2 ++ ArxTypeTraits/replace_minmax_macros.h | 28 +++++++++++++++++++++++++++ ArxTypeTraits/type_traits.h | 19 ------------------ 3 files changed, 30 insertions(+), 19 deletions(-) create mode 100644 ArxTypeTraits/replace_minmax_macros.h diff --git a/ArxTypeTraits.h b/ArxTypeTraits.h index bfd8821..671981f 100644 --- a/ArxTypeTraits.h +++ b/ArxTypeTraits.h @@ -16,6 +16,8 @@ #endif #endif +#include "ArxTypeTraits/replace_minmax_macros.h" + #ifndef ARX_TYPE_TRAITS_DISABLED #include #include diff --git a/ArxTypeTraits/replace_minmax_macros.h b/ArxTypeTraits/replace_minmax_macros.h new file mode 100644 index 0000000..993bd6b --- /dev/null +++ b/ArxTypeTraits/replace_minmax_macros.h @@ -0,0 +1,28 @@ +#pragma once + +#ifndef ARX_TYPE_TRAITS_REPLACE_MINMAX_MACROS_H +#define ARX_TYPE_TRAITS_REPLACE_MINMAX_MACROS_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 + constexpr auto max(T1 x, T2 y) + -> decltype(x + y) + { + return (x > y) ? x : y; + } +#endif +#ifdef min + #undef min + template + constexpr auto min(T1 x, T2 y) + -> decltype(x + y) + { + return (x < y) ? x : y; + } +#endif + +#endif // ARX_TYPE_TRAITS_REPLACE_MINMAX_MACROS_H diff --git a/ArxTypeTraits/type_traits.h b/ArxTypeTraits/type_traits.h index 231adf6..40fd47c 100644 --- a/ArxTypeTraits/type_traits.h +++ b/ArxTypeTraits/type_traits.h @@ -5,25 +5,6 @@ #ifdef ARX_TYPE_TRAITS_DISABLED -#ifdef max - #undef max - template - constexpr auto max(T1 x, T2 y) - -> decltype(x + y) - { - return (x > y) ? x : y; - } -#endif -#ifdef min - #undef min - template - constexpr auto min(T1 x, T2 y) - -> decltype(x + y) - { - return (x < y) ? x : y; - } -#endif - #include #include #include From ae6d3f2df47f0c37bc5f1a961a3186d9ad2de1ac Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 24 Sep 2020 11:08:48 +0200 Subject: [PATCH 06/16] include Arduino.h in replace_minmax_macros.h This prevents the macros from creating issues when Arduino.h is not yet inluded but is included later. --- ArxTypeTraits/replace_minmax_macros.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ArxTypeTraits/replace_minmax_macros.h b/ArxTypeTraits/replace_minmax_macros.h index 993bd6b..9668ccc 100644 --- a/ArxTypeTraits/replace_minmax_macros.h +++ b/ArxTypeTraits/replace_minmax_macros.h @@ -3,6 +3,11 @@ #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 + // 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. From f9768345eea661bf40aed69e4ac1c575e1a4a5b0 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Fri, 25 Sep 2020 20:35:36 +0200 Subject: [PATCH 07/16] move initializer_list to its own file This makes it easier to update the copy of this code embedded in the ArxContainer library, since now the entire file can be copied as-is. This commit changes the preprocessor guard that was around the the definition of initializer_list, to protect it from being double-defined by ArxContanier as well. It is now a standard include guard named after the file. This might cause problems when combined with ArxContainer, which should be solved as soon as ArxContainer also includes this same file. --- ArxTypeTraits/initializer_list.h | 22 ++++++++++++++++++++++ ArxTypeTraits/type_traits.h | 21 +-------------------- 2 files changed, 23 insertions(+), 20 deletions(-) create mode 100644 ArxTypeTraits/initializer_list.h diff --git a/ArxTypeTraits/initializer_list.h b/ArxTypeTraits/initializer_list.h new file mode 100644 index 0000000..21af07d --- /dev/null +++ b/ArxTypeTraits/initializer_list.h @@ -0,0 +1,22 @@ +#pragma once + +#ifndef ARX_TYPE_TRAITS_INITIALIZER_H +#define ARX_TYPE_TRAITS_INITIALIZER_H + +namespace std { + template + 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 // ARX_TYPE_TRAITS_INITIALIZER_LIST_H diff --git a/ArxTypeTraits/type_traits.h b/ArxTypeTraits/type_traits.h index 40fd47c..46b60dc 100644 --- a/ArxTypeTraits/type_traits.h +++ b/ArxTypeTraits/type_traits.h @@ -367,28 +367,9 @@ namespace std { b = move(t); } - -#ifndef ARX_TYPE_TRAITS_INITIALIZER_LIST_DEFINED -#define ARX_TYPE_TRAITS_INITIALIZER_LIST_DEFINED - - template - 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; } - }; - -#endif // ARX_TYPE_TRAITS_INITIALIZER_LIST_DEFINED - } // namespace std +#include "initializer_list.h" #include "tuple.h" #include "functional.h" From 3c43585de2d37018e3e39f0681bbabfcf63b9258 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 23 Sep 2020 15:22:02 +0200 Subject: [PATCH 08/16] remove std:: prefixes These all refer to things inside the current std namespace, so no need to qualify them. --- ArxTypeTraits/type_traits.h | 50 ++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/ArxTypeTraits/type_traits.h b/ArxTypeTraits/type_traits.h index 46b60dc..2608d9e 100644 --- a/ArxTypeTraits/type_traits.h +++ b/ArxTypeTraits/type_traits.h @@ -247,11 +247,11 @@ namespace std { template struct is_convertible - : std::conditional < + : conditional < can_apply ::value , true_type - , typename std::conditional < - std::is_arithmetic::value && std::is_arithmetic::value, + , typename conditional < + is_arithmetic::value && is_arithmetic::value, true_type, false_type >::type @@ -268,7 +268,7 @@ namespace std { // specialization for regular functions template struct is_function : true_type {}; - // specialization for variadic functions such as std::printf + // specialization for variadic functions such as printf template struct is_function : true_type {}; // specialization for function types that have cv-qualifiers @@ -382,21 +382,21 @@ namespace std { namespace std { template - using enable_if_t = typename std::enable_if::type; + using enable_if_t = typename enable_if::type; template - using decay_t = typename std::decay::type; + using decay_t = typename decay::type; template - using remove_cv_t = typename std::remove_cv::type; + using remove_cv_t = typename remove_cv::type; template - using remove_const_t = typename std::remove_const::type; + using remove_const_t = typename remove_const::type; template - using remove_volatile_t = typename std::remove_volatile::type; + using remove_volatile_t = typename remove_volatile::type; template - using remove_reference_t = typename std::remove_reference::type; + using remove_reference_t = typename remove_reference::type; template - using remove_pointer_t = typename std::remove_pointer::type; + using remove_pointer_t = typename remove_pointer::type; template struct integer_sequence @@ -451,21 +451,21 @@ namespace std { using void_t = typename Tester::type; template - struct disjunction : std::false_type {}; + struct disjunction : false_type {}; template struct disjunction : Arg::type {}; template - struct disjunction : std::conditional>::type {}; + struct disjunction : conditional>::type {}; template - struct conjunction : std::true_type {}; + struct conjunction : true_type {}; template struct conjunction : Arg::type {}; template - struct conjunction : std::conditional, Arg>::type {}; + struct conjunction : conditional, Arg>::type {}; template - struct negation : std::integral_constant {}; + struct negation : integral_constant {}; #endif // !defined(OF_VERSION_MAJOR) || !defined(TARGET_WIN32) @@ -474,22 +474,22 @@ namespace std { template constexpr auto apply_impl(F&& f, Tuple&& t, index_sequence) - -> decltype(f(std::get(std::forward(t))...)) + -> decltype(f(get(forward(t))...)) { - return f(std::get(std::forward(t))...); + return f(get(forward(t))...); } template constexpr auto apply(F&& f, Tuple&& t) -> decltype(apply_impl( - std::forward(f), - std::forward(t), - make_index_sequence>::value>{} + forward(f), + forward(t), + make_index_sequence>::value>{} )) { return apply_impl( - std::forward(f), - std::forward(t), - make_index_sequence>::value>() + forward(f), + forward(t), + make_index_sequence>::value>() ); } @@ -504,7 +504,7 @@ namespace std { template struct remove_cvref { - typedef std::remove_cv_t> type; + typedef remove_cv_t> type; }; template< class T > From ff6901ebb861fd8d74cd106e08e575342271c912 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 23 Sep 2020 15:23:53 +0200 Subject: [PATCH 09/16] move almost everything to arx::arx_std This declares new stuff in another namespace to prevent conflicts when standard system libraries are available even when we thought they were not. By importing the new arx::arx_std namespace *into* the std namespace, users of this library do not need to be updated, they can still reference using the std namespace as before (except that in case of a conflict, they get the standard library version rather than a compilation error). In addition, this imports all of std into arx::arx_std as well, so you can *also* explicitly reference namespace arx::arx_std for everything, except that in case of a conflict, you get the arx version rather than the standard library version (this is relevant when arx defines a newer version of some name than the standard libraries, such as the C++11 arx version of numeric_limits vs the C++98 ArduinoSTL version of it). Note that it would have been nicer to name this namespace arx::std, but when doing `using namespace arx`, which imports the `std` name, this creates a conflict with the global `std` namespace. --- ArxTypeTraits.h | 25 +++++++++++++++++++++++++ ArxTypeTraits/functional.h | 4 ++-- ArxTypeTraits/tuple.h | 4 ++-- ArxTypeTraits/type_traits.h | 16 ++++++++-------- 4 files changed, 37 insertions(+), 12 deletions(-) diff --git a/ArxTypeTraits.h b/ArxTypeTraits.h index 671981f..c2adeb4 100644 --- a/ArxTypeTraits.h +++ b/ArxTypeTraits.h @@ -16,6 +16,31 @@ #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" #ifndef ARX_TYPE_TRAITS_DISABLED diff --git a/ArxTypeTraits/functional.h b/ArxTypeTraits/functional.h index 4f41fc3..1c1d86d 100644 --- a/ArxTypeTraits/functional.h +++ b/ArxTypeTraits/functional.h @@ -13,7 +13,7 @@ #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 @@ -143,7 +143,7 @@ namespace std { return static_cast(f); } -} // namespace std +} } // namespace arx::std #endif // ARX_TYPE_TRAITS_DISABLED #endif // ARX_TYPE_TRAITS_FUNCTIONAL_H diff --git a/ArxTypeTraits/tuple.h b/ArxTypeTraits/tuple.h index f8d765b..f9dff8b 100644 --- a/ArxTypeTraits/tuple.h +++ b/ArxTypeTraits/tuple.h @@ -5,7 +5,7 @@ #ifdef ARX_TYPE_TRAITS_DISABLED -namespace std { +namespace arx { namespace arx_std { // https://theolizer.com/cpp-school2/cpp-school2-15/ // https://wandbox.org/permlink/C0BWIzjqg4iO3kKZ @@ -71,7 +71,7 @@ namespace std { return std::tuple::type...>(std::forward::type>(args)...); } -} // namespace std +} } // namespace arx::std #endif // ARX_TYPE_TRAITS_DISABLED #endif // ARX_TYPE_TRAITS_TUPLE_H diff --git a/ArxTypeTraits/type_traits.h b/ArxTypeTraits/type_traits.h index 2608d9e..f500f9b 100644 --- a/ArxTypeTraits/type_traits.h +++ b/ArxTypeTraits/type_traits.h @@ -9,7 +9,7 @@ #include #include -namespace std { +namespace arx { namespace arx_std { using nullptr_t = decltype(nullptr); @@ -367,7 +367,7 @@ namespace std { b = move(t); } -} // namespace std +} } // namespace arx::arx_std #include "initializer_list.h" #include "tuple.h" @@ -379,7 +379,7 @@ namespace std { #if __cplusplus < 201402L // C++11 #if !defined(OF_VERSION_MAJOR) || !defined(TARGET_WIN32) -namespace std { +namespace arx { namespace arx_std { template using enable_if_t = typename enable_if::type; @@ -433,7 +433,7 @@ namespace std { template using index_sequence_for = make_index_sequence; -} // namespace std +} } // namespace arx::arx_std #endif // !defined(OF_VERSION_MAJOR) || !defined(TARGET_WIN32) #endif // C++11 @@ -441,7 +441,7 @@ namespace std { #if __cplusplus < 201703L // C++14 -namespace std { +namespace arx { namespace arx_std { #if !defined(OF_VERSION_MAJOR) || !defined(TARGET_WIN32) @@ -493,13 +493,13 @@ namespace std { ); } -} // namespace std +} } // namespace arx::arx_std #endif // C++14 // C++17, C++2a -namespace std { +namespace arx { namespace arx_std { template struct remove_cvref @@ -510,7 +510,7 @@ namespace std { template< class T > using remove_cvref_t = typename remove_cvref::type; -} // namespace std +} } // namespace arx::arx_std // C++17, C++2a From cc48a88aecf1b97063f1475409d4a45dd7ed2c0a Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Fri, 25 Sep 2020 21:35:47 +0200 Subject: [PATCH 10/16] remove OpenFrameworks include guards These were added to prevent conflicts with OpenFrameworks also defining some things in the std namespace. But now that we define things in our own namespace, this conflict can no longer occur and these guards can be removed. --- ArxTypeTraits/type_traits.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ArxTypeTraits/type_traits.h b/ArxTypeTraits/type_traits.h index f500f9b..3c9005e 100644 --- a/ArxTypeTraits/type_traits.h +++ b/ArxTypeTraits/type_traits.h @@ -377,7 +377,6 @@ namespace arx { namespace arx_std { #if __cplusplus < 201402L // C++11 -#if !defined(OF_VERSION_MAJOR) || !defined(TARGET_WIN32) namespace arx { namespace arx_std { @@ -435,7 +434,6 @@ namespace arx { namespace arx_std { } } // namespace arx::arx_std -#endif // !defined(OF_VERSION_MAJOR) || !defined(TARGET_WIN32) #endif // C++11 @@ -443,8 +441,6 @@ namespace arx { namespace arx_std { namespace arx { namespace arx_std { -#if !defined(OF_VERSION_MAJOR) || !defined(TARGET_WIN32) - template struct Tester { using type = void; }; template @@ -467,8 +463,6 @@ namespace arx { namespace arx_std { template struct negation : integral_constant {}; -#endif // !defined(OF_VERSION_MAJOR) || !defined(TARGET_WIN32) - // https://qiita.com/_EnumHack/items/92e6e135174f1f781dbb // without decltype(auto) From e20608194b68d56aa1e4572be05913e231517625 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 22 Sep 2020 22:14:04 +0200 Subject: [PATCH 11/16] make operator new handling more generic Previously, on some specific architectures, an inline placement new was declared, and on others `` was included. But `` is a non-portable header available only in some Arduino architectures, while declaring our own placement new might conflict with standard libraries that also declare an inline version (such as uclibc++/ArduinoSTL). This commit changes the behaviour to always include `` if it is available (assuming it is complete or at least has placement new, which seems to be the case for existing Arduino cores). If `` is not available (which only seems to be the case for megaavr and older avr cores currently), just declare placement new inline. This has a small chance of conflict, but seems to be ok for avr and megaavr now. --- ArxTypeTraits.h | 5 ----- ArxTypeTraits/functional.h | 21 ++++++++++++++++----- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/ArxTypeTraits.h b/ArxTypeTraits.h index c2adeb4..2e1a65b 100644 --- a/ArxTypeTraits.h +++ b/ArxTypeTraits.h @@ -9,11 +9,6 @@ || 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 #endif // Make sure std namespace exists diff --git a/ArxTypeTraits/functional.h b/ArxTypeTraits/functional.h index 1c1d86d..dd24fb9 100644 --- a/ArxTypeTraits/functional.h +++ b/ArxTypeTraits/functional.h @@ -3,12 +3,23 @@ #ifndef ARX_TYPE_TRAITS_FUNCTIONAL_H #define ARX_TYPE_TRAITS_FUNCTIONAL_H -#include - -#ifdef ARX_TYPE_TRAITS_NEW_DISABLED - void* operator new (const size_t size, void* ptr) { (void)size; return ptr; } +// If we have a 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 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 __has_include() +#include #else - #include +// When there is no header, there might be a 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 From ddac6e0ee4591d8a568c3d65abec695bef71f782 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Fri, 25 Sep 2020 20:54:57 +0200 Subject: [PATCH 12/16] check __has_include() This ensures that initializer_list is really only defined when not already available from the standard-named header. Unlike the other things defined by this library, initializer_list *must* be defined in std, importing it into std is not enough. This means that if it would already have been defined elsewhere, this will produce a conflict (unlike for the other things defined). --- ArxTypeTraits/initializer_list.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ArxTypeTraits/initializer_list.h b/ArxTypeTraits/initializer_list.h index 21af07d..cdd1e5d 100644 --- a/ArxTypeTraits/initializer_list.h +++ b/ArxTypeTraits/initializer_list.h @@ -3,6 +3,13 @@ #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 is really not available (e.g. +// ArduinoSTL is C++98 but *does* define ) and not +// already defined (e.g. by ArxContainer). +#if __has_include() +#include +#else namespace std { template class initializer_list @@ -18,5 +25,6 @@ namespace std { const T *end() const { return array + len; } }; } // namespace std +#endif #endif // ARX_TYPE_TRAITS_INITIALIZER_LIST_H From 68713ddb78b44195234f764dc62ad7076bc21d6d Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 23 Sep 2020 10:45:18 +0200 Subject: [PATCH 13/16] use libstdc++ on SAM, SAMD and spresense_ast These platforms have libstdc++ available normally, so just use it. This has become possible with some recent changes that prevent conflicts with the libstdc++ implementation on those platforms. --- ArxTypeTraits.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ArxTypeTraits.h b/ArxTypeTraits.h index 2e1a65b..dde483e 100644 --- a/ArxTypeTraits.h +++ b/ArxTypeTraits.h @@ -4,10 +4,7 @@ #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) + || defined(ARDUINO_ARCH_MEGAAVR) #define ARX_TYPE_TRAITS_DISABLED #endif From d6ce5eb59270e935c087b232c69bc559a4cc74a6 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 23 Sep 2020 10:39:07 +0200 Subject: [PATCH 14/16] improve decisions about what (not) to define Previously, on the (mega)AVR architectures, no standard c++ library was assumed to be available. Only on these architectures, controlled by the `ARX_TYPE_TRAITS_DISABLED` macro, all the C++98 and C++11 stuff would be defined. On all architectures (include (mega)AVR), the `__cplusplus` macro would be used to decide whether or not to define the C++14 and C++17 stuff. This is now made a lot more generic, where `TypeTraits.h` now defines a single macro with the C++ version supported by the standard library. In the other headers, this macro is used to decide what to define and what to include from the standard library. The C++98 and C++11 stuff is now split, so on e.g. AVR with ArduinoSTL the C++98 stuff can be included but the C++11 stuff still defined (which prevents defining stuff that is not needed). Determining the supported C++ version no longer relies on the Arduino architecture macros, but instead sees which library is available exactly. For gcc's libstdc++ and clang's libc++, the compiler `__cplusplus` version is assumed to be correct, for uclibc++ C++98 is assumed. Other standard libraries raise an error, since we have no idea about their capabilities. If no standard library is available (e.g. AVR without ArduinoSTL, the version macro is set to 0). --- ArxTypeTraits.h | 32 ++++++++++++------- ArxTypeTraits/functional.h | 11 +++++-- ArxTypeTraits/tuple.h | 9 ++++-- ArxTypeTraits/type_traits.h | 63 ++++++++++++++++++++++++++----------- 4 files changed, 79 insertions(+), 36 deletions(-) diff --git a/ArxTypeTraits.h b/ArxTypeTraits.h index dde483e..5ad646e 100644 --- a/ArxTypeTraits.h +++ b/ArxTypeTraits.h @@ -3,9 +3,26 @@ #ifndef ARX_TYPE_TRAITS_H #define ARX_TYPE_TRAITS_H -#if defined(ARDUINO_ARCH_AVR)\ - || defined(ARDUINO_ARCH_MEGAAVR) - #define ARX_TYPE_TRAITS_DISABLED +#if !defined(ARX_HAVE_LIBSTDCPLUSPLUS) + #if !defined(__has_include) + #error "Compiler does not support __has_include, please report a bug against the ArxTypeTraits library about this." + #endif + #if __has_include() + #include + #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 @@ -35,15 +52,6 @@ namespace std { #include "ArxTypeTraits/replace_minmax_macros.h" -#ifndef ARX_TYPE_TRAITS_DISABLED - #include - #include - #include - #include - #include - #include -#endif - #include "ArxTypeTraits/type_traits.h" #endif // ARX_TYPE_TRAITS_H diff --git a/ArxTypeTraits/functional.h b/ArxTypeTraits/functional.h index dd24fb9..fbf47e1 100644 --- a/ArxTypeTraits/functional.h +++ b/ArxTypeTraits/functional.h @@ -3,6 +3,12 @@ #ifndef ARX_TYPE_TRAITS_FUNCTIONAL_H #define ARX_TYPE_TRAITS_FUNCTIONAL_H +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + +#include + +#else // Do not have libstdc++11 + // If we have a 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 is added). @@ -22,8 +28,6 @@ inline void* operator new (const size_t size, void* ptr) noexcept { (void)size; return ptr; } #endif -#ifdef ARX_TYPE_TRAITS_DISABLED - namespace arx { namespace arx_std { // reference: @@ -156,5 +160,6 @@ namespace arx { namespace arx_std { } } // namespace arx::std -#endif // ARX_TYPE_TRAITS_DISABLED +#endif // Do not have libstdc++11 + #endif // ARX_TYPE_TRAITS_FUNCTIONAL_H diff --git a/ArxTypeTraits/tuple.h b/ArxTypeTraits/tuple.h index f9dff8b..1489533 100644 --- a/ArxTypeTraits/tuple.h +++ b/ArxTypeTraits/tuple.h @@ -3,7 +3,11 @@ #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 + +#include + +#else // Do not have libstdc++11 namespace arx { namespace arx_std { @@ -73,5 +77,6 @@ namespace arx { namespace arx_std { } } // namespace arx::std -#endif // ARX_TYPE_TRAITS_DISABLED +#endif // Do not have libstdc++11 + #endif // ARX_TYPE_TRAITS_TUPLE_H diff --git a/ArxTypeTraits/type_traits.h b/ArxTypeTraits/type_traits.h index 3c9005e..9c04d09 100644 --- a/ArxTypeTraits/type_traits.h +++ b/ArxTypeTraits/type_traits.h @@ -3,7 +3,32 @@ #ifndef ARX_TYPE_TRAITS_TYPE_TRAITS_H #define ARX_TYPE_TRAITS_TYPE_TRAITS_H -#ifdef ARX_TYPE_TRAITS_DISABLED +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 199711L // Have libstdc++98 + +#include + +#else // Do not have libstdc++98 + +namespace arx { namespace arx_std { + + template + 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 +#include + +#else // Do not have libstdc++11 #include #include @@ -358,25 +383,18 @@ namespace arx { namespace arx_std { template using result_of = details::result_of; - - template - 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++11 + #include "initializer_list.h" #include "tuple.h" #include "functional.h" -#endif // ARX_TYPE_TRAITS_DISABLE_STL - - -#if __cplusplus < 201402L // C++11 +#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 { @@ -434,10 +452,13 @@ namespace arx { namespace arx_std { } } // namespace arx::arx_std -#endif // C++11 +#endif // Do not have libstdc++14 -#if __cplusplus < 201703L // C++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 { @@ -489,10 +510,14 @@ namespace arx { namespace arx_std { } } // namespace arx::arx_std -#endif // C++14 +#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 -// C++17, C++2a namespace arx { namespace arx_std { template @@ -505,7 +530,7 @@ namespace arx { namespace arx_std { using remove_cvref_t = typename remove_cvref::type; } } // namespace arx::arx_std -// C++17, C++2a +#endif // Do not have libstdc++2a namespace arx { // others From eba2f99995aa744c76a5b13ccc438bf49c3614de Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Fri, 25 Sep 2020 22:48:10 +0200 Subject: [PATCH 15/16] error out when C++11 is not enabled in the compiler Even when the standard library might not support C++11 yet, the compiler should to allow things like variadic templates and other C++11 language constructs to be used. --- ArxTypeTraits.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ArxTypeTraits.h b/ArxTypeTraits.h index 5ad646e..29921c7 100644 --- a/ArxTypeTraits.h +++ b/ArxTypeTraits.h @@ -3,6 +3,10 @@ #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 + #if !defined(ARX_HAVE_LIBSTDCPLUSPLUS) #if !defined(__has_include) #error "Compiler does not support __has_include, please report a bug against the ArxTypeTraits library about this." From 781371dcbbbdbef86f717c89162dbf5143a288a8 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Mon, 28 Sep 2020 15:37:51 +0200 Subject: [PATCH 16/16] fix use of __has_include on ESP8266 Turns on ESP8266 does not support `__has_include`, but its libc defines a dummy version of it that always returns false, causing conflicts between system headers and ArxTypeTraits. This makes the following changes: - Replace uses of `__has_include` with a new `ARX_SYSTEM_HAS_INCLUDE` header (which defaults to just forwarding to `__has_include`). - On ESP8266, let `ARX_SYSTEM_HAS_INCLUDE` always return true (since we know that it supports the headers we check for). - On other platforms that use gcc < 5 (which does not have `__has_include` yet), flag an error (even if `__has_include` is defined, since it must then be a dummy version). - Move all this into its own header file, so it can be easily copied into ArxContainer along with "initializer_list.h". --- ArxTypeTraits.h | 7 +++---- ArxTypeTraits/functional.h | 2 +- ArxTypeTraits/has_include.h | 25 +++++++++++++++++++++++++ ArxTypeTraits/initializer_list.h | 2 +- 4 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 ArxTypeTraits/has_include.h diff --git a/ArxTypeTraits.h b/ArxTypeTraits.h index 29921c7..c9864cc 100644 --- a/ArxTypeTraits.h +++ b/ArxTypeTraits.h @@ -7,11 +7,10 @@ #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" + #if !defined(ARX_HAVE_LIBSTDCPLUSPLUS) - #if !defined(__has_include) - #error "Compiler does not support __has_include, please report a bug against the ArxTypeTraits library about this." - #endif - #if __has_include() + #if ARX_SYSTEM_HAS_INCLUDE() #include #if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) // For gcc's libstdc++ and clang's libc++, assume that diff --git a/ArxTypeTraits/functional.h b/ArxTypeTraits/functional.h index fbf47e1..06208de 100644 --- a/ArxTypeTraits/functional.h +++ b/ArxTypeTraits/functional.h @@ -14,7 +14,7 @@ // new now, but will probably get it before 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 __has_include() +#if ARX_SYSTEM_HAS_INCLUDE() #include #else // When there is no header, there might be a header, but diff --git a/ArxTypeTraits/has_include.h b/ArxTypeTraits/has_include.h new file mode 100644 index 0000000..8f7378d --- /dev/null +++ b/ArxTypeTraits/has_include.h @@ -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 diff --git a/ArxTypeTraits/initializer_list.h b/ArxTypeTraits/initializer_list.h index cdd1e5d..b1cd74f 100644 --- a/ArxTypeTraits/initializer_list.h +++ b/ArxTypeTraits/initializer_list.h @@ -7,7 +7,7 @@ // define it when is really not available (e.g. // ArduinoSTL is C++98 but *does* define ) and not // already defined (e.g. by ArxContainer). -#if __has_include() +#if ARX_SYSTEM_HAS_INCLUDE() #include #else namespace std {