From fa3ac28f555b1b9b7405045ca030c2b6a98c4b8b Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Mon, 24 Aug 2026 14:11:11 +0200 Subject: [PATCH] Add etl::is_standard_layout and other type traits according to std (#1545) * Update _index.md * Update _index.md * Cherry pick the Docker fixes for PowerPC (#1563) Co-authored-by: John Wellbelove * Add etl::is_standard_layout and further type traits Added type traits: * etl::is_standard_layout * etl::is_null_pointer * etl::is_union * etl::is_scalar * etl::is_empty * etl::is_polymorphic * etl::is_abstract * etl::is_final * etl::is_aggregate * etl::is_destructible * etl::is_nothrow_destructible * etl::has_virtual_destructor * etl::is_swappable * etl::is_swappable_with * etl::is_nothrow_swappable * etl::is_nothrow_swappable_with * etl::has_unique_object_representation * etl::is_bounded_array * etl::is_unbounded_array * etl::is_trivial Document etl::is_pod Note that etl::swap needed adjustment to enable nothrow detection via SFINAE constraints. This change closes in to the standard. * Fix preprocessor directive formatting in header --------- Co-authored-by: John Wellbelove Co-authored-by: John Wellbelove --- docs/types/type-traits.md | 399 +++++++ .../etl/profiles/determine_builtin_support.h | 184 +++ include/etl/type_traits.h | 823 +++++++++++++ include/etl/utility.h | 27 +- test/test_type_traits.cpp | 1025 +++++++++++++++++ 5 files changed, 2457 insertions(+), 1 deletion(-) diff --git a/docs/types/type-traits.md b/docs/types/type-traits.md index 721fdfc3..98326be6 100644 --- a/docs/types/type-traits.md +++ b/docs/types/type-traits.md @@ -32,6 +32,26 @@ Not all traits have been defined as some rely on compiler intrinsics that are no `is_compound` `is_array` `is_pointer` +`is_null_pointer` +`is_scalar` +`is_union` +`is_empty` +`is_polymorphic` +`is_abstract` +`is_final` +`is_aggregate` +`is_trivial` +`is_standard_layout` +`is_destructible` +`is_nothrow_destructible` +`has_virtual_destructor` +`has_unique_object_representations` +`is_bounded_array` +`is_unbounded_array` +`is_swappable` +`is_swappable_with` +`is_nothrow_swappable` +`is_nothrow_swappable_with` `is_reference` `is_base_of` `make_signed` @@ -476,3 +496,382 @@ template inline constexpr bool is_object_pointer_v = etl::is_object_pointer::value; ``` C++17 + +## is_pod +From: `20.49.0` + +```cpp +template +struct is_pod +``` +Checks if `T` is a POD (Plain Old Data) type. +The result is found in the member `value`. + When using the STL, this is defined as `is_standard_layout && is_trivially_default_constructible && is_trivially_copyable`. + When not using the STL, this is conservatively defined as `is_fundamental || is_pointer`. + +```cpp +template +inline constexpr bool is_pod_v = etl::is_pod::value; +``` +C++17 + +## is_standard_layout +From: `20.49.0` + +```cpp +template +struct is_standard_layout +``` +Checks if `T` is a standard-layout type. +The result is found in the member `value`. + +```cpp +template +inline constexpr bool is_standard_layout_v = etl::is_standard_layout::value; +``` +C++17 + +## is_trivial +From: `20.49.0` + +```cpp +template +struct is_trivial +``` +Checks if `T` is a trivial type; i.e. it is trivially copyable and has one or more +default constructors, all of which are trivial. +The result is found in the member `value`. + +```cpp +template +inline constexpr bool is_trivial_v = etl::is_trivial::value; +``` +C++17 + +**Note:** When not using the STL, this trait requires compiler support (the `__is_trivial` intrinsic). +If that is not available then the trait is not defined, as there is no portable way of +determining whether a type is trivial. + +## is_bounded_array +From: `20.49.0` + +```cpp +template +struct is_bounded_array +``` +Checks if `T` is an array type of known bound. +`T[N]` returns `true`, `T[]` and all other types return `false`. +The result is found in the member `value`. + +```cpp +template +inline constexpr bool is_bounded_array_v = etl::is_bounded_array::value; +``` +C++17 + +## is_unbounded_array +From: `20.49.0` + +```cpp +template +struct is_unbounded_array +``` +Checks if `T` is an array type of unknown bound. +`T[]` returns `true`, `T[N]` and all other types return `false`. +The result is found in the member `value`. + +```cpp +template +inline constexpr bool is_unbounded_array_v = etl::is_unbounded_array::value; +``` +C++17 + +## is_destructible +From: `20.49.0` + +```cpp +template +struct is_destructible +``` +Checks if `T` is a destructible type; that is, an object type whose destructor is not deleted and is accessible, a reference type, or an array of a destructible type. +Incomplete types, `void`, function types and arrays of unknown bound are not destructible. +The result is found in the member `value`. + When not using the STL, the trait is detected by checking whether `declval().~T()` is a valid expression. + Requires either compiler support or C++11. When neither is available, this trait is not defined. + +```cpp +template +inline constexpr bool is_destructible_v = etl::is_destructible::value; +``` +C++17 + +## is_nothrow_destructible +From: `20.49.0` + +```cpp +template +struct is_nothrow_destructible +``` +Checks if `T` is a destructible type whose destructor is known not to throw. +Types that are not destructible are not nothrow destructible. +The result is found in the member `value`. + When not using the STL, the trait is detected by checking `noexcept(declval().~T())` for destructible types. + Requires either compiler support or C++11. When neither is available, this trait is not defined. + +```cpp +template +inline constexpr bool is_nothrow_destructible_v = etl::is_nothrow_destructible::value; +``` +C++17 + +## is_swappable +From: `20.49.0` + +```cpp +template +struct is_swappable +``` +Checks if `T` is a referenceable type and lvalues of type `T` can be swapped by an unqualified call to `swap`. +The result is found in the member `value`. + When using the STL and C++17, this is defined as `std::is_swappable`. + Otherwise the trait checks whether `swap(declval(), declval())` is a valid expression, where the `swap` considered is `etl::swap`, `std::swap` if it is available, and any `swap` found by argument dependent lookup. + Requires C++11. Without it there is no way of detecting the validity of an expression, so this trait is not defined. + Note that when using the STL with C++11 or C++14, the accuracy of this trait depends on `std::swap` being constrained by the standard library implementation. Standard libraries that only constrain `std::swap` from C++17 will cause this trait to report `true` for types that cannot actually be swapped. + +```cpp +template +inline constexpr bool is_swappable_v = etl::is_swappable::value; +``` +C++17 + +## is_swappable_with +From: `20.49.0` + +```cpp +template +struct is_swappable_with +``` +Checks if expressions of type `T` and `U` can be swapped by unqualified calls to `swap`, in both directions. +The result is found in the member `value`. + When using the STL and C++17, this is defined as `std::is_swappable_with`. + Otherwise the trait checks whether both `swap(declval(), declval())` and `swap(declval(), declval())` are valid expressions, where the `swap` considered is `etl::swap`, `std::swap` if it is available, and any `swap` found by argument dependent lookup. + Note that, unlike `is_swappable`, no references are added to `T` and `U`, so the value categories of the arguments are those of `T` and `U`. `is_swappable_with::value` is `false`, whereas `is_swappable_with::value` is `true`. + Requires C++11. Without it there is no way of detecting the validity of an expression, so this trait is not defined. + Note that when using the STL with C++11 or C++14, the accuracy of this trait depends on `std::swap` being constrained by the standard library implementation. Standard libraries that only constrain `std::swap` from C++17 will cause this trait to report `true` for types that cannot actually be swapped. + +```cpp +template +inline constexpr bool is_swappable_with_v = etl::is_swappable_with::value; +``` +C++17 + +## is_nothrow_swappable +From: `20.49.0` + +```cpp +template +struct is_nothrow_swappable +``` +Checks if `T` is a referenceable type and lvalues of type `T` can be swapped by an unqualified call to `swap`, and that the swap cannot throw. +The result is found in the member `value`. + When using the STL and C++17, this is defined as `std::is_nothrow_swappable`. + Otherwise the trait checks that `etl::is_swappable::value` is `true` and that `swap(declval(), declval())` is `noexcept`. + Requires C++11. Without it there is no way of detecting the validity of an expression, so this trait is not defined. + Note that when neither the STL nor the type traits builtins are available, `etl::is_nothrow_move_constructible` and `etl::is_nothrow_move_assignable` are conservatively `false` for class types, so `etl::swap` is not `noexcept` for them and this trait is conservatively `false` too. + +```cpp +template +inline constexpr bool is_nothrow_swappable_v = etl::is_nothrow_swappable::value; +``` +C++17 + +## is_nothrow_swappable_with +From: `20.49.0` + +```cpp +template +struct is_nothrow_swappable_with +``` +Checks if expressions of type `T` and `U` can be swapped by unqualified calls to `swap`, in both directions, and that neither swap can throw. +The result is found in the member `value`. + When using the STL and C++17, this is defined as `std::is_nothrow_swappable_with`. + Otherwise the trait checks that `etl::is_swappable_with::value` is `true` and that both `swap(declval(), declval())` and `swap(declval(), declval())` are `noexcept`. + Note that, as for `is_swappable_with`, no references are added to `T` and `U`, so the value categories of the arguments are those of `T` and `U`. `is_nothrow_swappable_with::value` is `false`, whereas `is_nothrow_swappable_with::value` is `true`. + Requires C++11. Without it there is no way of detecting the validity of an expression, so this trait is not defined. + Note that when neither the STL nor the type traits builtins are available, `etl::is_nothrow_move_constructible` and `etl::is_nothrow_move_assignable` are conservatively `false` for class types, so `etl::swap` is not `noexcept` for them and this trait is conservatively `false` too. + +```cpp +template +inline constexpr bool is_nothrow_swappable_with_v = etl::is_nothrow_swappable_with::value; +``` +C++17 + +## is_union +From: `20.49.0` + +```cpp +template +struct is_union +``` +Checks if `T` is a union type. +The result is found in the member `value`. + When the compiler does not provide the required intrinsic, this trait conservatively reports `false` for every type. + +```cpp +template +inline constexpr bool is_union_v = etl::is_union::value; +``` +C++17 + +## is_empty +From: `20.49.0` + +```cpp +template +struct is_empty +``` +Checks if `T` is an empty class type; that is, a non-union class type with no non-static data members other than zero-sized bit-fields, no virtual functions, no virtual base classes and no non-empty base classes. +The result is found in the member `value`. + Requires compiler support. When the compiler does not provide the required intrinsic, this trait is not defined. + +```cpp +template +inline constexpr bool is_empty_v = etl::is_empty::value; +``` +C++17 + +## is_polymorphic +From: `20.49.0` + +```cpp +template +struct is_polymorphic +``` +Checks if `T` is a polymorphic class type; that is, a class that declares or inherits at least one virtual function. +The result is found in the member `value`. + Requires compiler support. When the compiler does not provide the required intrinsic, this trait is not defined. + +```cpp +template +inline constexpr bool is_polymorphic_v = etl::is_polymorphic::value; +``` +C++17 + +## is_abstract +From: `20.49.0` + +```cpp +template +struct is_abstract +``` +Checks if `T` is an abstract class type; that is, a class that declares or inherits at least one pure virtual function. +The result is found in the member `value`. + Requires compiler support. When the compiler does not provide the required intrinsic, this trait is not defined. + +```cpp +template +inline constexpr bool is_abstract_v = etl::is_abstract::value; +``` +C++17 + +## is_final +From: `20.49.0` + +```cpp +template +struct is_final +``` +Checks if `T` is a class or union type marked `final`, optionally cv-qualified. +The result is found in the member `value`. + When using the STL, this requires C++14 or above. Otherwise it requires compiler support. When neither is available, this trait is not defined. + +```cpp +template +inline constexpr bool is_final_v = etl::is_final::value; +``` +C++17 + +## is_aggregate +From: `20.49.0` + +```cpp +template +struct is_aggregate +``` +Checks if `T` is an aggregate type, optionally cv-qualified. +An aggregate is an array type or a class type that has no user-declared or inherited constructors, no private or protected non-static data members, no virtual functions and no virtual, private or protected base classes. +The result is found in the member `value`. + When using the STL, this requires C++17 or above. Otherwise it requires compiler support. When neither is available, this trait is not defined. + +```cpp +template +inline constexpr bool is_aggregate_v = etl::is_aggregate::value; +``` +C++17 + +## has_virtual_destructor +From: `20.49.0` + +```cpp +template +struct has_virtual_destructor +``` +Checks if `T` is a class type with a virtual destructor, optionally cv-qualified. +The result is found in the member `value`. + When not using the STL, this requires compiler support. When it is not available, this trait is not defined. + +```cpp +template +inline constexpr bool has_virtual_destructor_v = etl::has_virtual_destructor::value; +``` +C++17 + +## has_unique_object_representations +From: `20.49.0` + +```cpp +template +struct has_unique_object_representations +``` +Checks if `T` is trivially copyable and any two objects of type `T` with the same value have the same object representation; that is, the type has no padding bits and no two distinct object representations compare equal. +Arrays and cv-qualifiers are ignored; the trait is applied to `etl::remove_all_extents::type>::type`. +The result is found in the member `value`. + When using the STL, this requires C++17 or above. Otherwise it requires compiler support. When neither is available, this trait is not defined. + +```cpp +template +inline constexpr bool has_unique_object_representations_v = etl::has_unique_object_representations::value; +``` +C++17 + +## is_null_pointer +From: `20.49.0` + +```cpp +template +struct is_null_pointer +``` +Checks if `T` is `etl::nullptr_t`, optionally cv-qualified. +The result is found in the member `value`. + +```cpp +template +inline constexpr bool is_null_pointer_v = etl::is_null_pointer::value; +``` +C++17 + +## is_scalar +From: `20.49.0` + +```cpp +template +struct is_scalar +``` +Checks if `T` is a scalar type; that is, an arithmetic, enumeration, pointer, pointer to member or `etl::nullptr_t` type, optionally cv-qualified. +The result is found in the member `value`. + +```cpp +template +inline constexpr bool is_scalar_v = etl::is_scalar::value; +``` +C++17 diff --git a/include/etl/profiles/determine_builtin_support.h b/include/etl/profiles/determine_builtin_support.h index deadec8c..3db1a474 100644 --- a/include/etl/profiles/determine_builtin_support.h +++ b/include/etl/profiles/determine_builtin_support.h @@ -57,10 +57,58 @@ SOFTWARE. #define ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE 1 #endif + #if !defined(ETL_USING_BUILTIN_IS_DESTRUCTIBLE) + #define ETL_USING_BUILTIN_IS_DESTRUCTIBLE 1 + #endif + + #if !defined(ETL_USING_BUILTIN_IS_NOTHROW_DESTRUCTIBLE) + #define ETL_USING_BUILTIN_IS_NOTHROW_DESTRUCTIBLE 1 + #endif + #if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE) #define ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE 1 #endif + #if !defined(ETL_USING_BUILTIN_IS_STANDARD_LAYOUT) + #define ETL_USING_BUILTIN_IS_STANDARD_LAYOUT 1 + #endif + + #if !defined(ETL_USING_BUILTIN_IS_TRIVIAL) + #define ETL_USING_BUILTIN_IS_TRIVIAL 1 + #endif + + #if !defined(ETL_USING_BUILTIN_IS_UNION) + #define ETL_USING_BUILTIN_IS_UNION 1 + #endif + + #if !defined(ETL_USING_BUILTIN_IS_EMPTY) + #define ETL_USING_BUILTIN_IS_EMPTY 1 + #endif + + #if !defined(ETL_USING_BUILTIN_IS_POLYMORPHIC) + #define ETL_USING_BUILTIN_IS_POLYMORPHIC 1 + #endif + + #if !defined(ETL_USING_BUILTIN_IS_ABSTRACT) + #define ETL_USING_BUILTIN_IS_ABSTRACT 1 + #endif + + #if !defined(ETL_USING_BUILTIN_IS_FINAL) + #define ETL_USING_BUILTIN_IS_FINAL 1 + #endif + + #if !defined(ETL_USING_BUILTIN_IS_AGGREGATE) + #define ETL_USING_BUILTIN_IS_AGGREGATE 1 + #endif + + #if !defined(ETL_USING_BUILTIN_HAS_VIRTUAL_DESTRUCTOR) + #define ETL_USING_BUILTIN_HAS_VIRTUAL_DESTRUCTOR 1 + #endif + + #if !defined(ETL_USING_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS) + #define ETL_USING_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS 1 + #endif + #if !defined(ETL_USING_BUILTIN_UNDERLYING_TYPE) #define ETL_USING_BUILTIN_UNDERLYING_TYPE 1 #endif @@ -124,10 +172,58 @@ SOFTWARE. #define ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE (__has_builtin(__has_trivial_destructor) || __has_builtin(__is_trivially_destructible)) #endif + #if !defined(ETL_USING_BUILTIN_IS_DESTRUCTIBLE) + #define ETL_USING_BUILTIN_IS_DESTRUCTIBLE __has_builtin(__is_destructible) + #endif + + #if !defined(ETL_USING_BUILTIN_IS_NOTHROW_DESTRUCTIBLE) + #define ETL_USING_BUILTIN_IS_NOTHROW_DESTRUCTIBLE __has_builtin(__is_nothrow_destructible) + #endif + #if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE) #define ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE (__has_builtin(__has_trivial_copy) || __has_builtin(__is_trivially_copyable)) #endif + #if !defined(ETL_USING_BUILTIN_IS_STANDARD_LAYOUT) + #define ETL_USING_BUILTIN_IS_STANDARD_LAYOUT __has_builtin(__is_standard_layout) + #endif + + #if !defined(ETL_USING_BUILTIN_IS_TRIVIAL) + #define ETL_USING_BUILTIN_IS_TRIVIAL __has_builtin(__is_trivial) + #endif + + #if !defined(ETL_USING_BUILTIN_IS_UNION) + #define ETL_USING_BUILTIN_IS_UNION __has_builtin(__is_union) + #endif + + #if !defined(ETL_USING_BUILTIN_IS_EMPTY) + #define ETL_USING_BUILTIN_IS_EMPTY __has_builtin(__is_empty) + #endif + + #if !defined(ETL_USING_BUILTIN_IS_POLYMORPHIC) + #define ETL_USING_BUILTIN_IS_POLYMORPHIC __has_builtin(__is_polymorphic) + #endif + + #if !defined(ETL_USING_BUILTIN_IS_ABSTRACT) + #define ETL_USING_BUILTIN_IS_ABSTRACT __has_builtin(__is_abstract) + #endif + + #if !defined(ETL_USING_BUILTIN_IS_FINAL) + #define ETL_USING_BUILTIN_IS_FINAL __has_builtin(__is_final) + #endif + + #if !defined(ETL_USING_BUILTIN_IS_AGGREGATE) + #define ETL_USING_BUILTIN_IS_AGGREGATE __has_builtin(__is_aggregate) + #endif + + #if !defined(ETL_USING_BUILTIN_HAS_VIRTUAL_DESTRUCTOR) + #define ETL_USING_BUILTIN_HAS_VIRTUAL_DESTRUCTOR __has_builtin(__has_virtual_destructor) + #endif + + #if !defined(ETL_USING_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS) + #define ETL_USING_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS __has_builtin(__has_unique_object_representations) + #endif + #if !defined(ETL_USING_BUILTIN_UNDERLYING_TYPE) #define ETL_USING_BUILTIN_UNDERLYING_TYPE __has_builtin(__underlying_type) #endif @@ -183,6 +279,46 @@ SOFTWARE. #define ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE 1 #endif + #if !defined(ETL_USING_BUILTIN_IS_STANDARD_LAYOUT) + #define ETL_USING_BUILTIN_IS_STANDARD_LAYOUT 1 + #endif + + #if !defined(ETL_USING_BUILTIN_IS_TRIVIAL) + #define ETL_USING_BUILTIN_IS_TRIVIAL 1 + #endif + + #if !defined(ETL_USING_BUILTIN_IS_UNION) + #define ETL_USING_BUILTIN_IS_UNION 1 + #endif + + #if !defined(ETL_USING_BUILTIN_IS_EMPTY) + #define ETL_USING_BUILTIN_IS_EMPTY 1 + #endif + + #if !defined(ETL_USING_BUILTIN_IS_POLYMORPHIC) + #define ETL_USING_BUILTIN_IS_POLYMORPHIC 1 + #endif + + #if !defined(ETL_USING_BUILTIN_IS_ABSTRACT) + #define ETL_USING_BUILTIN_IS_ABSTRACT 1 + #endif + + #if !defined(ETL_USING_BUILTIN_IS_FINAL) + #define ETL_USING_BUILTIN_IS_FINAL 1 + #endif + + #if !defined(ETL_USING_BUILTIN_IS_AGGREGATE) + #define ETL_USING_BUILTIN_IS_AGGREGATE 1 + #endif + + #if !defined(ETL_USING_BUILTIN_HAS_VIRTUAL_DESTRUCTOR) + #define ETL_USING_BUILTIN_HAS_VIRTUAL_DESTRUCTOR 1 + #endif + + #if !defined(ETL_USING_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS) + #define ETL_USING_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS 1 + #endif + // MSVC has supported __builtin_bit_cast since VS2019 16.6. __has_builtin is not // used for Microsoft (see above) to avoid a VS2022 intellisense issue, so the // intrinsic is enabled here directly for the no-STL configuration. @@ -216,10 +352,58 @@ SOFTWARE. #define ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE 0 #endif +#if !defined(ETL_USING_BUILTIN_IS_DESTRUCTIBLE) + #define ETL_USING_BUILTIN_IS_DESTRUCTIBLE 0 +#endif + +#if !defined(ETL_USING_BUILTIN_IS_NOTHROW_DESTRUCTIBLE) + #define ETL_USING_BUILTIN_IS_NOTHROW_DESTRUCTIBLE 0 +#endif + #if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE) #define ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE 0 #endif +#if !defined(ETL_USING_BUILTIN_IS_STANDARD_LAYOUT) + #define ETL_USING_BUILTIN_IS_STANDARD_LAYOUT 0 +#endif + +#if !defined(ETL_USING_BUILTIN_IS_TRIVIAL) + #define ETL_USING_BUILTIN_IS_TRIVIAL 0 +#endif + +#if !defined(ETL_USING_BUILTIN_IS_UNION) + #define ETL_USING_BUILTIN_IS_UNION 0 +#endif + +#if !defined(ETL_USING_BUILTIN_IS_EMPTY) + #define ETL_USING_BUILTIN_IS_EMPTY 0 +#endif + +#if !defined(ETL_USING_BUILTIN_IS_POLYMORPHIC) + #define ETL_USING_BUILTIN_IS_POLYMORPHIC 0 +#endif + +#if !defined(ETL_USING_BUILTIN_IS_ABSTRACT) + #define ETL_USING_BUILTIN_IS_ABSTRACT 0 +#endif + +#if !defined(ETL_USING_BUILTIN_IS_FINAL) + #define ETL_USING_BUILTIN_IS_FINAL 0 +#endif + +#if !defined(ETL_USING_BUILTIN_IS_AGGREGATE) + #define ETL_USING_BUILTIN_IS_AGGREGATE 0 +#endif + +#if !defined(ETL_USING_BUILTIN_HAS_VIRTUAL_DESTRUCTOR) + #define ETL_USING_BUILTIN_HAS_VIRTUAL_DESTRUCTOR 0 +#endif + +#if !defined(ETL_USING_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS) + #define ETL_USING_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS 0 +#endif + #if !defined(ETL_USING_BUILTIN_UNDERLYING_TYPE) #define ETL_USING_BUILTIN_UNDERLYING_TYPE 0 #endif diff --git a/include/etl/type_traits.h b/include/etl/type_traits.h index ab8d13d7..0c9da447 100644 --- a/include/etl/type_traits.h +++ b/include/etl/type_traits.h @@ -47,6 +47,12 @@ SOFTWARE. #include #endif +// Required for std::swap, which etl::is_swappable must consider in any +// configuration that does not define etl::swap. +#if ETL_USING_CPP11 && (ETL_USING_STL || defined(ETL_IN_UNIT_TEST)) + #include +#endif + namespace etl { #if ETL_USING_CPP11 @@ -741,6 +747,38 @@ namespace etl inline constexpr bool is_array_v = is_array::value; #endif + //*************************************************************************** + /// is_bounded_array + template + struct is_bounded_array : false_type + { + }; + template + struct is_bounded_array : true_type + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_bounded_array_v = is_bounded_array::value; + #endif + + //*************************************************************************** + /// is_unbounded_array + template + struct is_unbounded_array : false_type + { + }; + template + struct is_unbounded_array : true_type + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_unbounded_array_v = is_unbounded_array::value; + #endif + //*************************************************************************** /// is_pointer template @@ -846,6 +884,38 @@ namespace etl inline constexpr bool is_pod_v = etl::is_pod::value; #endif + //*************************************************************************** + /// is_standard_layout + /// Requires compiler support. Without it there is no portable way to + /// determine whether a type is standard layout, so the trait is not defined. + #if ETL_USING_BUILTIN_IS_STANDARD_LAYOUT + template + struct is_standard_layout : etl::bool_constant<__is_standard_layout(T)> + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_standard_layout_v = etl::is_standard_layout::value; + #endif + #endif + + //*************************************************************************** + /// is_trivial + /// Requires compiler support. Without it there is no portable way to + /// determine whether a type is trivial, so the trait is not defined. + #if ETL_USING_BUILTIN_IS_TRIVIAL + template + struct is_trivial : etl::bool_constant<__is_trivial(T)> + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_trivial_v = etl::is_trivial::value; + #endif + #endif + //*************************************************************************** /// conditional template @@ -1144,6 +1214,137 @@ namespace etl inline constexpr bool is_class_v = is_class::value; #endif + //*************************************************************************** + /// is_union + /// Requires compiler support. Without it there is no portable way to + /// distinguish a union from a class, so the trait is not defined. + #if ETL_USING_BUILTIN_IS_UNION + template + struct is_union : etl::bool_constant<__is_union(T)> + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_union_v = is_union::value; + #endif + #endif + + //*************************************************************************** + /// is_empty + /// Requires compiler support. Without it there is no portable way to + /// determine whether a class type is empty, so the trait is not defined. + #if ETL_USING_BUILTIN_IS_EMPTY + template + struct is_empty : etl::bool_constant<__is_empty(T)> + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_empty_v = is_empty::value; + #endif + #endif + + //*************************************************************************** + /// is_polymorphic + /// Requires compiler support. Without it there is no portable way to + /// determine whether a class type is polymorphic, so the trait is not defined. + #if ETL_USING_BUILTIN_IS_POLYMORPHIC + template + struct is_polymorphic : etl::bool_constant<__is_polymorphic(T)> + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_polymorphic_v = is_polymorphic::value; + #endif + #endif + + //*************************************************************************** + /// is_abstract + /// Requires compiler support. Without it there is no portable way to + /// determine whether a class type is abstract, so the trait is not defined. + #if ETL_USING_BUILTIN_IS_ABSTRACT + template + struct is_abstract : etl::bool_constant<__is_abstract(T)> + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_abstract_v = is_abstract::value; + #endif + #endif + + //*************************************************************************** + /// is_final + /// Requires compiler support. Without it there is no portable way to + /// determine whether a class type is final, so the trait is not defined. + #if ETL_USING_BUILTIN_IS_FINAL + template + struct is_final : etl::bool_constant<__is_final(T)> + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_final_v = is_final::value; + #endif + #endif + + //*************************************************************************** + /// is_aggregate + /// Requires compiler support. Without it there is no portable way to + /// determine whether a type is an aggregate, so the trait is not defined. + #if ETL_USING_BUILTIN_IS_AGGREGATE + template + struct is_aggregate : etl::bool_constant<__is_aggregate(typename etl::remove_cv::type)> + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_aggregate_v = is_aggregate::value; + #endif + #endif + + //*************************************************************************** + /// has_virtual_destructor + /// Requires compiler support. Without it there is no portable way to + /// determine whether a class type has a virtual destructor, so the trait is + /// not defined. + #if ETL_USING_BUILTIN_HAS_VIRTUAL_DESTRUCTOR + template + struct has_virtual_destructor : etl::bool_constant<__has_virtual_destructor(T)> + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool has_virtual_destructor_v = has_virtual_destructor::value; + #endif + #endif + + //*************************************************************************** + /// has_unique_object_representations + /// Requires compiler support. Without it there is no portable way to + /// determine whether a type has a unique object representation, so the trait + /// is not defined. + #if ETL_USING_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS + template + struct has_unique_object_representations + : etl::bool_constant<__has_unique_object_representations(typename etl::remove_cv::type>::type)> + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool has_unique_object_representations_v = has_unique_object_representations::value; + #endif + #endif + //*************************************************************************** /// is_base_of #if ETL_USING_CPP11 @@ -1464,6 +1665,132 @@ namespace etl template inline constexpr bool is_nothrow_convertible_v = etl::is_nothrow_convertible::value; + #endif + + //*************************************************************************** + /// is_destructible + /// Requires either compiler support or C++11. Without them there is no + /// portable way to determine whether a type is destructible, so the trait + /// is not defined. + #if ETL_USING_BUILTIN_IS_DESTRUCTIBLE + template + struct is_destructible : etl::bool_constant<__is_destructible(T)> + { + }; + #elif ETL_USING_CPP11 + namespace private_type_traits + { + // Selected only if 'declval().~T()' is a valid expression. + // Void types, function types and types with an inaccessible or deleted + // destructor all fail substitution and select the fallback. + template + struct is_destructible_impl + { + private: + + template ().~U())> + static etl::true_type test(int); + + template + static etl::false_type test(...); + + public: + + static ETL_CONSTANT bool value = decltype(test(0))::value; + }; + + template + struct is_destructible_helper : etl::bool_constant::type>::value> + { + }; + + // Reference types are always destructible. + template + struct is_destructible_helper : etl::true_type + { + }; + + template + struct is_destructible_helper : etl::true_type + { + }; + + // Arrays of unknown bound are incomplete types. + template + struct is_destructible_helper : etl::false_type + { + }; + } // namespace private_type_traits + + template + struct is_destructible : etl::bool_constant::value> + { + }; + #endif + + // C++17 implies C++11, so the trait is always defined when the alias is. + #if ETL_USING_CPP17 + template + inline constexpr bool is_destructible_v = etl::is_destructible::value; + #endif + + //*************************************************************************** + /// is_nothrow_destructible + /// Requires either compiler support or C++11. Without them there is no + /// portable way to determine whether a type is nothrow destructible, so the + /// trait is not defined. + #if ETL_USING_BUILTIN_IS_NOTHROW_DESTRUCTIBLE + template + struct is_nothrow_destructible : etl::bool_constant<__is_nothrow_destructible(T)> + { + }; + #elif ETL_USING_CPP11 + namespace private_type_traits + { + // Only instantiated for destructible types, so 'declval().~T()' is a valid expression. + template ::value> + struct is_nothrow_destructible_impl : etl::false_type + { + }; + + template + struct is_nothrow_destructible_impl : etl::bool_constant().~T())> + { + }; + + template + struct is_nothrow_destructible_helper : etl::bool_constant::type>::value> + { + }; + + // Reference types are always nothrow destructible. + template + struct is_nothrow_destructible_helper : etl::true_type + { + }; + + template + struct is_nothrow_destructible_helper : etl::true_type + { + }; + + // Arrays of unknown bound are incomplete types. + template + struct is_nothrow_destructible_helper : etl::false_type + { + }; + } // namespace private_type_traits + + template + struct is_nothrow_destructible : etl::bool_constant::value> + { + }; + #endif + + // C++17 implies C++11, so the trait is always defined when the alias is. + #if ETL_USING_CPP17 + template + inline constexpr bool is_nothrow_destructible_v = etl::is_nothrow_destructible::value; #endif //*************************************************************************** @@ -1849,6 +2176,56 @@ namespace etl #if ETL_USING_CPP17 template inline constexpr bool is_array_v = std::is_array_v; + #endif + + //*************************************************************************** + /// is_bounded_array + ///\ingroup type_traits + #if ETL_USING_CPP20 && defined(__cpp_lib_bounded_array_traits) + template + struct is_bounded_array : std::is_bounded_array + { + }; + #else + template + struct is_bounded_array : std::false_type + { + }; + + template + struct is_bounded_array : std::true_type + { + }; + #endif + + #if ETL_USING_CPP17 + template + inline constexpr bool is_bounded_array_v = etl::is_bounded_array::value; + #endif + + //*************************************************************************** + /// is_unbounded_array + ///\ingroup type_traits + #if ETL_USING_CPP20 && defined(__cpp_lib_bounded_array_traits) + template + struct is_unbounded_array : std::is_unbounded_array + { + }; + #else + template + struct is_unbounded_array : std::false_type + { + }; + + template + struct is_unbounded_array : std::true_type + { + }; + #endif + + #if ETL_USING_CPP17 + template + inline constexpr bool is_unbounded_array_v = etl::is_unbounded_array::value; #endif //*************************************************************************** @@ -1920,6 +2297,72 @@ namespace etl inline constexpr bool is_pod_v = std::is_standard_layout_v && std::is_trivially_default_constructible_v && std::is_trivially_copyable_v; #endif + //*************************************************************************** + /// is_standard_layout + ///\ingroup type_traits + template + struct is_standard_layout : std::is_standard_layout + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_standard_layout_v = std::is_standard_layout_v; + #endif + + //*************************************************************************** + /// is_trivial + ///\ingroup type_traits + #if ETL_USING_CPP26 + // std::is_trivial is deprecated in C++26 and later; avoid using it and + // compose the trait from is_trivially_copyable && is_trivially_default_constructible instead. + template + struct is_trivial : etl::bool_constant::value && std::is_trivially_default_constructible::value> + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_trivial_v = std::is_trivially_copyable_v && std::is_trivially_default_constructible_v; + #endif + #else + template + struct is_trivial : std::is_trivial + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_trivial_v = std::is_trivial_v; + #endif + #endif + + //*************************************************************************** + /// is_destructible + ///\ingroup type_traits + template + struct is_destructible : std::is_destructible + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_destructible_v = std::is_destructible_v; + #endif + + //*************************************************************************** + /// is_nothrow_destructible + ///\ingroup type_traits + template + struct is_nothrow_destructible : std::is_nothrow_destructible + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_nothrow_destructible_v = std::is_nothrow_destructible_v; + #endif + #if defined(ETL_COMPILER_GCC) #if ETL_COMPILER_VERSION >= 5 #define ETL_GCC_V5_TYPE_TRAITS_SUPPORTED @@ -2100,6 +2543,127 @@ namespace etl inline constexpr bool is_class_v = is_class::value; #endif + //*************************************************************************** + /// is_union + template + struct is_union : std::is_union + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_union_v = std::is_union_v; + #endif + + //*************************************************************************** + /// is_empty + template + struct is_empty : std::is_empty + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_empty_v = std::is_empty_v; + #endif + + //*************************************************************************** + /// is_polymorphic + template + struct is_polymorphic : std::is_polymorphic + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_polymorphic_v = std::is_polymorphic_v; + #endif + + //*************************************************************************** + /// is_abstract + template + struct is_abstract : std::is_abstract + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_abstract_v = std::is_abstract_v; + #endif + + //*************************************************************************** + /// is_final + /// std::is_final is only available from C++14, so for C++11 the compiler + /// builtin is used, if available. Otherwise the trait is not defined. + #if ETL_USING_CPP14 + template + struct is_final : std::is_final + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_final_v = std::is_final_v; + #endif + #elif ETL_USING_BUILTIN_IS_FINAL + template + struct is_final : etl::bool_constant<__is_final(T)> + { + }; + #endif + + //*************************************************************************** + /// is_aggregate + /// std::is_aggregate is only available from C++17, so for C++11 and C++14 the + /// compiler builtin is used, if available. Otherwise the trait is not defined. + #if ETL_USING_CPP17 + template + struct is_aggregate : std::is_aggregate + { + }; + + template + inline constexpr bool is_aggregate_v = std::is_aggregate_v; + #elif ETL_USING_BUILTIN_IS_AGGREGATE + template + struct is_aggregate : etl::bool_constant<__is_aggregate(typename etl::remove_cv::type)> + { + }; + #endif + + //*************************************************************************** + /// has_virtual_destructor + template + struct has_virtual_destructor : std::has_virtual_destructor + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool has_virtual_destructor_v = std::has_virtual_destructor_v; + #endif + + //*************************************************************************** + /// has_unique_object_representations + /// std::has_unique_object_representations is only available from C++17, so for + /// C++11 and C++14 the compiler builtin is used, if available. Otherwise the + /// trait is not defined. + #if ETL_USING_CPP17 + template + struct has_unique_object_representations : std::has_unique_object_representations + { + }; + + template + inline constexpr bool has_unique_object_representations_v = std::has_unique_object_representations_v; + #elif ETL_USING_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS + template + struct has_unique_object_representations + : etl::bool_constant<__has_unique_object_representations(typename etl::remove_cv::type>::type)> + { + }; + #endif + //*************************************************************************** /// add_lvalue_reference template @@ -2253,6 +2817,19 @@ namespace etl #endif // Condition = ETL_USING_STL && ETL_USING_CPP11 + //*************************************************************************** + /// is_null_pointer + ///\ingroup type_traits + template + struct is_null_pointer : etl::is_same::type, etl::nullptr_t> + { + }; + +#if ETL_USING_CPP17 + template + inline constexpr bool is_null_pointer_v = is_null_pointer::value; +#endif + //*************************************************************************** // ETL extended type traits. //*************************************************************************** @@ -3996,6 +4573,23 @@ namespace etl inline constexpr bool is_member_pointer_v = etl::is_member_pointer::value; #endif + //*************************************************************************** + /// is_scalar + /// An arithmetic, enumeration, pointer, pointer to member or + /// etl::nullptr_t type, optionally cv-qualified. + //*************************************************************************** + template + struct is_scalar + : etl::bool_constant::value || etl::is_enum::value || etl::is_pointer::value || etl::is_member_pointer::value + || etl::is_null_pointer::value> + { + }; + +#if ETL_USING_CPP17 + template + inline constexpr bool is_scalar_v = etl::is_scalar::value; +#endif + #if ETL_USING_CPP11 //********************************* /// Check if T is a function type @@ -4130,6 +4724,235 @@ namespace etl inline constexpr bool is_object_pointer_v = etl::is_object_pointer::value; #endif + //*************************************************************************** + /// swap + /// Declared here, and defined in utility.h, so that etl::is_swappable below + /// finds it by ordinary unqualified lookup. + /// We can't have std::swap and etl::swap templates coexisting in the unit + /// tests as the compiler will be unable to decide which one to use, due to + /// ADL. + //*************************************************************************** +#if ETL_NOT_USING_STL && !defined(ETL_IN_UNIT_TEST) + #if ETL_USING_CPP11 + namespace private_type_traits + { + template + struct is_swappable_helper; + + template + struct is_nothrow_swappable_helper; + } // namespace private_type_traits + + // Constrained, as the standard requires, so that an attempt to swap a type + // that cannot be moved is a substitution failure rather than a hard error. + // This is what allows etl::is_swappable to be implemented. + // The exception specification is conditional, as the standard requires, so + // that etl::is_nothrow_swappable can be implemented. + template + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_move_assignable::value>::type swap(T& a, T& b) + ETL_NOEXCEPT_IF(etl::is_nothrow_move_constructible::value&& etl::is_nothrow_move_assignable::value); + + template + ETL_CONSTEXPR14 typename etl::enable_if::value>::type swap(T (&a)[Size], T (&b)[Size]) + ETL_NOEXCEPT_IF(private_type_traits::is_nothrow_swappable_helper::value); + #else + template + ETL_CONSTEXPR14 void swap(T& a, T& b) ETL_NOEXCEPT; + + template + ETL_CONSTEXPR14 void swap(T (&a)[Size], T (&b)[Size]) ETL_NOEXCEPT; + #endif +#endif + + //*************************************************************************** + /// is_swappable + /// Determines whether lvalues of type T can be swapped by an unqualified + /// call to swap. + /// Requires C++11. Without it there is no way of detecting the validity of + /// an expression, so the trait is not defined. + //*************************************************************************** +#if ETL_USING_STL && ETL_USING_CPP17 + template + struct is_swappable : std::is_swappable + { + }; + + //*************************************************************************** + /// is_swappable_with + //*************************************************************************** + template + struct is_swappable_with : std::is_swappable_with + { + }; +#elif ETL_USING_CPP11 + namespace private_type_traits + { + namespace swap_detect + { + // Bring std::swap into scope, if it is available, so that the unqualified + // call below finds it in those configurations that do not define etl::swap. + // Otherwise etl::swap is found by ordinary lookup in the enclosing + // namespace. Either way, a swap found by argument dependent lookup takes + // part in overload resolution. + #if ETL_USING_STL || defined(ETL_IN_UNIT_TEST) + using std::swap; + #endif + + // Selected only if 'swap(declval(), declval())' is a valid expression. + template + struct is_swappable_test + { + private: + + template (), etl::declval()))> + static etl::true_type test(int); + + template + static etl::false_type test(...); + + public: + + static ETL_CONSTANT bool value = decltype(test(0))::value; + }; + + // Selected only if both 'swap(declval(), declval())' and + // 'swap(declval(), declval())' are valid expressions. + template + struct is_swappable_with_test + { + private: + + template (), etl::declval())), + typename = decltype(swap(etl::declval(), etl::declval()))> + static etl::true_type test(int); + + template + static etl::false_type test(...); + + public: + + static ETL_CONSTANT bool value = decltype(test(0))::value; + }; + } // namespace swap_detect + + template + struct is_swappable_helper : etl::bool_constant::value> + { + }; + + template + struct is_swappable_with_helper : etl::bool_constant::value> + { + }; + } // namespace private_type_traits + + template + struct is_swappable : etl::bool_constant::value> + { + }; + + //*************************************************************************** + /// is_swappable_with + //*************************************************************************** + template + struct is_swappable_with : etl::bool_constant::value> + { + }; +#endif + + //*************************************************************************** + /// is_nothrow_swappable + /// Determines whether lvalues of type T can be swapped by an unqualified + /// call to swap, and that the swap cannot throw. + /// Requires C++11. Without it there is no way of detecting the validity of + /// an expression, so the trait is not defined. + //*************************************************************************** +#if ETL_USING_STL && ETL_USING_CPP17 + template + struct is_nothrow_swappable : std::is_nothrow_swappable + { + }; + + //*************************************************************************** + /// is_nothrow_swappable_with + //*************************************************************************** + template + struct is_nothrow_swappable_with : std::is_nothrow_swappable_with + { + }; +#elif ETL_USING_CPP11 + namespace private_type_traits + { + namespace swap_detect + { + // Only 'true' if the type is swappable and the swap expression is noexcept. + template ::value> + struct is_nothrow_swappable_test + { + static ETL_CONSTANT bool value = false; + }; + + template + struct is_nothrow_swappable_test + { + static ETL_CONSTANT bool value = noexcept(swap(etl::declval(), etl::declval())); + }; + + // Only 'true' if the types are swappable with each other and both of the + // swap expressions are noexcept. + template ::value> + struct is_nothrow_swappable_with_test + { + static ETL_CONSTANT bool value = false; + }; + + template + struct is_nothrow_swappable_with_test + { + static ETL_CONSTANT bool value = noexcept(swap(etl::declval(), etl::declval())) && noexcept(swap(etl::declval(), etl::declval())); + }; + } // namespace swap_detect + + template + struct is_nothrow_swappable_helper : etl::bool_constant::value> + { + }; + + template + struct is_nothrow_swappable_with_helper : etl::bool_constant::value> + { + }; + } // namespace private_type_traits + + template + struct is_nothrow_swappable : etl::bool_constant::value> + { + }; + + //*************************************************************************** + /// is_nothrow_swappable_with + //*************************************************************************** + template + struct is_nothrow_swappable_with : etl::bool_constant::value> + { + }; +#endif + + // C++17 implies C++11, so the trait is always defined when the alias is. +#if ETL_USING_CPP17 + template + inline constexpr bool is_swappable_v = etl::is_swappable::value; + + template + inline constexpr bool is_swappable_with_v = etl::is_swappable_with::value; + + template + inline constexpr bool is_nothrow_swappable_v = etl::is_nothrow_swappable::value; + + template + inline constexpr bool is_nothrow_swappable_with_v = etl::is_nothrow_swappable_with::value; +#endif + #if ETL_USING_CPP11 //********************************* /// Check for the presence of operator() diff --git a/include/etl/utility.h b/include/etl/utility.h index 3c7da3a5..f11ccca8 100644 --- a/include/etl/utility.h +++ b/include/etl/utility.h @@ -340,7 +340,31 @@ namespace etl // We can't have std::swap and etl::swap templates coexisting in the unit // tests as the compiler will be unable to decide which one to use, due to // ADL. + // These are declared in type_traits.h, so that etl::is_swappable can find + // them, and defined here. #if ETL_NOT_USING_STL && !defined(ETL_IN_UNIT_TEST) + #if ETL_USING_CPP11 + //*************************************************************************** + // swap + template + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_move_assignable::value>::type swap(T& a, T& b) + ETL_NOEXCEPT_IF(etl::is_nothrow_move_constructible::value&& etl::is_nothrow_move_assignable::value) + { + T temp(ETL_MOVE(a)); + a = ETL_MOVE(b); + b = ETL_MOVE(temp); + } + + template + ETL_CONSTEXPR14 typename etl::enable_if::value>::type swap(T (&a)[Size], T (&b)[Size]) + ETL_NOEXCEPT_IF(private_type_traits::is_nothrow_swappable_helper::value) + { + for (size_t i = 0UL; i < Size; ++i) + { + swap(a[i], b[i]); + } + } + #else //*************************************************************************** // swap template @@ -351,7 +375,7 @@ namespace etl b = ETL_MOVE(temp); } - template < class T, size_t Size > + template ETL_CONSTEXPR14 void swap(T (&a)[Size], T (&b)[Size]) ETL_NOEXCEPT { for (size_t i = 0UL; i < Size; ++i) @@ -359,6 +383,7 @@ namespace etl swap(a[i], b[i]); } } + #endif #endif //*************************************************************************** diff --git a/test/test_type_traits.cpp b/test/test_type_traits.cpp index 531557de..ab2e7c4c 100644 --- a/test/test_type_traits.cpp +++ b/test/test_type_traits.cpp @@ -421,8 +421,148 @@ struct etl::is_move_assignable : public etl::true_type }; #endif +#if ETL_USING_CPP11 namespace { + //***************************************************************************** + // Types for the is_swappable tests. + struct Swappable + { + int a; + }; + + struct NonSwappable + { + NonSwappable(const NonSwappable&) = delete; + NonSwappable& operator=(const NonSwappable&) = delete; + }; + + // Detects whether the compiler allows an rvalue to bind to a non-const lvalue + // reference. This is a Microsoft extension, disabled by /permissive-, and it makes + // types such as Swappable swappable as rvalues. + template + void takes_lvalue_reference(T&); + + template + struct rvalue_binds_to_lvalue_reference : etl::false_type + { + }; + + template + struct rvalue_binds_to_lvalue_reference(etl::declval()))> > : etl::true_type + { + }; + + // Types for the is_nothrow_swappable tests. + // Swappable, as it is movable, but the move operations may throw. + struct ThrowingSwappable + { + ThrowingSwappable() {} + ThrowingSwappable(ThrowingSwappable&&) noexcept(false) {} + ThrowingSwappable& operator=(ThrowingSwappable&&) noexcept(false) + { + return *this; + } + }; +} // namespace + +namespace adl +{ + // Not movable, so only the swap found by argument dependent lookup makes + // this type swappable. + struct AdlSwappable + { + AdlSwappable(const AdlSwappable&) = delete; + AdlSwappable& operator=(const AdlSwappable&) = delete; + + int a; + }; + + inline void swap(AdlSwappable&, AdlSwappable&) {} + + // As above, but the swap found by argument dependent lookup cannot throw. + struct NothrowAdlSwappable + { + NothrowAdlSwappable(const NothrowAdlSwappable&) = delete; + NothrowAdlSwappable& operator=(const NothrowAdlSwappable&) = delete; + + int a; + }; + + inline void swap(NothrowAdlSwappable&, NothrowAdlSwappable&) noexcept {} + + // Types for the is_swappable_with tests. + struct SwapLhs + { + int a; + }; + + struct SwapRhs + { + int a; + }; + + inline void swap(SwapLhs&, SwapRhs&) {} + inline void swap(SwapRhs&, SwapLhs&) {} + + // Only swappable in one direction, so is_swappable_with is false. + struct SwapOneWay + { + int a; + }; + + inline void swap(SwapLhs&, SwapOneWay&) {} + + // Swappable only as rvalues. + struct RvalueSwappable + { + int a; + }; + + inline void swap(RvalueSwappable&&, RvalueSwappable&&) {} + + // Types for the is_nothrow_swappable_with tests. + // Swappable with each other, in both directions, without throwing. + struct NothrowSwapLhs + { + int a; + }; + + struct NothrowSwapRhs + { + int a; + }; + + inline void swap(NothrowSwapLhs&, NothrowSwapRhs&) noexcept {} + inline void swap(NothrowSwapRhs&, NothrowSwapLhs&) noexcept {} + + // Swappable with NothrowSwapLhs in both directions, but one of the swaps may throw. + struct HalfNothrowSwap + { + int a; + }; + + inline void swap(NothrowSwapLhs&, HalfNothrowSwap&) noexcept {} + inline void swap(HalfNothrowSwap&, NothrowSwapLhs&) {} +} // namespace adl +#endif + +namespace +{ + //************************************************************************* + // std::is_trivial is deprecated in C++26. + // Use the suggested replacement when compiling to that standard. + //************************************************************************* + template + struct std_is_trivial +#if ETL_USING_CPP26 + : std::integral_constant::value && std::is_trivially_default_constructible::value> +#else + : std::integral_constant::value> +#endif + { + }; + SUITE(test_type_traits) { //************************************************************************* @@ -556,6 +696,891 @@ namespace CHECK(etl::is_pointer::value == std::is_pointer::value); } + //************************************************************************* + TEST(test_is_bounded_array) + { + CHECK(etl::is_bounded_array::value); + CHECK(etl::is_bounded_array::value); + CHECK(etl::is_bounded_array::value); + CHECK(!etl::is_bounded_array::value); + CHECK(!etl::is_bounded_array::value); + CHECK(!etl::is_bounded_array::value); + CHECK(!etl::is_bounded_array::value); + +#if ETL_USING_CPP20 && defined(__cpp_lib_bounded_array_traits) + CHECK(etl::is_bounded_array::value == std::is_bounded_array::value); + CHECK(etl::is_bounded_array::value == std::is_bounded_array::value); + CHECK(etl::is_bounded_array::value == std::is_bounded_array::value); +#endif + +#if ETL_USING_CPP17 + CHECK(etl::is_bounded_array_v); + CHECK(!etl::is_bounded_array_v); + CHECK(!etl::is_bounded_array_v); +#endif + } + + //************************************************************************* + TEST(test_is_unbounded_array) + { + CHECK(etl::is_unbounded_array::value); + CHECK(etl::is_unbounded_array::value); + CHECK(etl::is_unbounded_array::value); + CHECK(!etl::is_unbounded_array::value); + CHECK(!etl::is_unbounded_array::value); + CHECK(!etl::is_unbounded_array::value); + CHECK(!etl::is_unbounded_array::value); + CHECK(!etl::is_unbounded_array::value); + +#if ETL_USING_CPP20 && defined(__cpp_lib_bounded_array_traits) + CHECK(etl::is_unbounded_array::value == std::is_unbounded_array::value); + CHECK(etl::is_unbounded_array::value == std::is_unbounded_array::value); + CHECK(etl::is_unbounded_array::value == std::is_unbounded_array::value); +#endif + +#if ETL_USING_CPP17 + CHECK(etl::is_unbounded_array_v); + CHECK(!etl::is_unbounded_array_v); + CHECK(!etl::is_unbounded_array_v); +#endif + } + + //************************************************************************* + TEST(test_is_null_pointer) + { + CHECK(etl::is_null_pointer::value); + CHECK(!etl::is_null_pointer::value); + CHECK(!etl::is_null_pointer::value); + CHECK(!etl::is_null_pointer::value); + + CHECK(etl::is_null_pointer::value); + CHECK(etl::is_null_pointer::value); + CHECK(etl::is_null_pointer::value); + +#if ETL_USING_CPP14 + CHECK(etl::is_null_pointer::value == std::is_null_pointer::value); + CHECK(etl::is_null_pointer::value == std::is_null_pointer::value); +#endif + +#if ETL_USING_CPP17 + CHECK(etl::is_null_pointer_v); + CHECK(!etl::is_null_pointer_v); +#endif + } + + //************************************************************************* + TEST(test_is_standard_layout) + { + struct StandardLayout + { + int a; + int b; + }; + + struct NonStandardLayout + { + virtual void foo() {} + int a; + }; + + CHECK(etl::is_standard_layout::value == std::is_standard_layout::value); + CHECK(etl::is_standard_layout::value == std::is_standard_layout::value); + CHECK(etl::is_standard_layout::value == std::is_standard_layout::value); + CHECK(etl::is_standard_layout::value == std::is_standard_layout::value); + CHECK(etl::is_standard_layout::value); + CHECK(!etl::is_standard_layout::value); + +#if ETL_USING_CPP17 + CHECK(etl::is_standard_layout_v); + CHECK(!etl::is_standard_layout_v); +#endif + } + + //************************************************************************* + TEST(test_is_trivial) + { + struct Trivial + { + int a; + int b; + }; + + struct NonTrivialConstructor + { + NonTrivialConstructor() + : a(1) + { + } + int a; + }; + + struct NonTrivialCopy + { + NonTrivialCopy(const NonTrivialCopy&) {} + int a; + }; + + struct NonTrivialDestructor + { + ~NonTrivialDestructor() {} + int a; + }; + + CHECK(etl::is_trivial::value == std_is_trivial::value); + CHECK(etl::is_trivial::value == std_is_trivial::value); + CHECK(etl::is_trivial::value == std_is_trivial::value); + CHECK(etl::is_trivial::value == std_is_trivial::value); + CHECK(etl::is_trivial::value == std_is_trivial::value); + CHECK(etl::is_trivial::value == std_is_trivial::value); + CHECK(etl::is_trivial::value == std_is_trivial::value); + CHECK(etl::is_trivial::value == std_is_trivial::value); + + CHECK(etl::is_trivial::value); + CHECK(etl::is_trivial::value); + CHECK(!etl::is_trivial::value); + CHECK(!etl::is_trivial::value); + CHECK(!etl::is_trivial::value); + +#if ETL_USING_CPP17 + CHECK(etl::is_trivial_v); + CHECK(!etl::is_trivial_v); +#endif + } + + //************************************************************************* + TEST(test_is_destructible) + { +#if ETL_USING_CPP11 || ETL_USING_BUILTIN_IS_DESTRUCTIBLE + CHECK(etl::is_destructible::value); + CHECK(etl::is_destructible::value); + CHECK(!etl::is_destructible::value); +#endif + +#if ETL_USING_CPP11 + struct Destructible + { + int a; + }; + + struct NonDestructible + { + ~NonDestructible() = delete; + }; + + struct ProtectedDestructor + { + protected: + + ~ProtectedDestructor() {} + }; + + CHECK(etl::is_destructible::value == std::is_destructible::value); + CHECK(etl::is_destructible::value == std::is_destructible::value); + CHECK(etl::is_destructible::value == std::is_destructible::value); + CHECK(etl::is_destructible::value == std::is_destructible::value); + CHECK(etl::is_destructible::value == std::is_destructible::value); + CHECK(etl::is_destructible::value == std::is_destructible::value); + CHECK(etl::is_destructible::value == std::is_destructible::value); + CHECK(etl::is_destructible::value == std::is_destructible::value); + CHECK(etl::is_destructible::value == std::is_destructible::value); + + CHECK(etl::is_destructible::value); + CHECK(etl::is_destructible::value); + CHECK(etl::is_destructible::value); + CHECK(!etl::is_destructible::value); + CHECK(!etl::is_destructible::value); + CHECK(!etl::is_destructible::value); + CHECK(!etl::is_destructible::value); +#endif + +#if ETL_USING_CPP17 + CHECK(etl::is_destructible_v); + CHECK(!etl::is_destructible_v); +#endif + } + + //************************************************************************* + TEST(test_is_nothrow_destructible) + { +#if ETL_USING_CPP11 || ETL_USING_BUILTIN_IS_NOTHROW_DESTRUCTIBLE + CHECK(etl::is_nothrow_destructible::value); + CHECK(etl::is_nothrow_destructible::value); + CHECK(!etl::is_nothrow_destructible::value); +#endif + +#if ETL_USING_CPP11 + struct NothrowDestructible + { + int a; + }; + + struct ThrowingDestructible + { + ~ThrowingDestructible() noexcept(false) {} + }; + + struct NotDestructible + { + ~NotDestructible() = delete; + }; + + CHECK(etl::is_nothrow_destructible::value == std::is_nothrow_destructible::value); + CHECK(etl::is_nothrow_destructible::value == std::is_nothrow_destructible::value); + CHECK(etl::is_nothrow_destructible::value == std::is_nothrow_destructible::value); + CHECK(etl::is_nothrow_destructible::value == std::is_nothrow_destructible::value); + CHECK(etl::is_nothrow_destructible::value == std::is_nothrow_destructible::value); + CHECK(etl::is_nothrow_destructible::value == std::is_nothrow_destructible::value); + CHECK(etl::is_nothrow_destructible::value == std::is_nothrow_destructible::value); + CHECK(etl::is_nothrow_destructible::value == std::is_nothrow_destructible::value); + CHECK(etl::is_nothrow_destructible::value == std::is_nothrow_destructible::value); + + CHECK(etl::is_nothrow_destructible::value); + CHECK(etl::is_nothrow_destructible::value); + CHECK(etl::is_nothrow_destructible::value); + CHECK(!etl::is_nothrow_destructible::value); + CHECK(!etl::is_nothrow_destructible::value); + CHECK(!etl::is_nothrow_destructible::value); + CHECK(!etl::is_nothrow_destructible::value); + CHECK(!etl::is_nothrow_destructible::value); +#endif + +#if ETL_USING_CPP17 + CHECK(etl::is_nothrow_destructible_v); + CHECK(!etl::is_nothrow_destructible_v); +#endif + } + +#if ETL_USING_CPP11 + //************************************************************************* + TEST(test_is_swappable) + { + CHECK(etl::is_swappable::value); + CHECK(etl::is_swappable::value); + CHECK(etl::is_swappable::value); + CHECK(etl::is_swappable::value); + CHECK(etl::is_swappable::value); + + // Not movable, so swappable only via the swap found by ADL. + CHECK(etl::is_swappable::value); + CHECK(etl::is_swappable::value); + + CHECK(!etl::is_swappable::value); + CHECK(!etl::is_swappable::value); + CHECK(!etl::is_swappable::value); + CHECK(!etl::is_swappable::value); + CHECK(!etl::is_swappable::value); + CHECK(!etl::is_swappable::value); + + #if ETL_USING_CPP17 + CHECK(etl::is_swappable::value == std::is_swappable::value); + CHECK(etl::is_swappable::value == std::is_swappable::value); + CHECK(etl::is_swappable::value == std::is_swappable::value); + CHECK(etl::is_swappable::value == std::is_swappable::value); + CHECK(etl::is_swappable::value == std::is_swappable::value); + CHECK(etl::is_swappable::value == std::is_swappable::value); + CHECK(etl::is_swappable::value == std::is_swappable::value); + CHECK(etl::is_swappable::value == std::is_swappable::value); + CHECK(etl::is_swappable::value == std::is_swappable::value); + CHECK(etl::is_swappable::value == std::is_swappable::value); + CHECK(etl::is_swappable::value == std::is_swappable::value); + CHECK(etl::is_swappable::value == std::is_swappable::value); + CHECK(etl::is_swappable::value == std::is_swappable::value); + + CHECK(etl::is_swappable_v); + CHECK(!etl::is_swappable_v); + #endif + } + + //************************************************************************* + TEST(test_is_swappable_with) + { + // Note that is_swappable_with does not add references, so the value + // categories of the arguments are those of T and U. + CHECK((etl::is_swappable_with::value)); + CHECK((etl::is_swappable_with::value)); + CHECK((etl::is_swappable_with::value)); + CHECK((etl::is_swappable_with::value)); + + // Heterogeneous swaps, found by argument dependent lookup. + CHECK((etl::is_swappable_with::value)); + CHECK((etl::is_swappable_with::value)); + + // Swappable in one direction only. + CHECK((!etl::is_swappable_with::value)); + CHECK((!etl::is_swappable_with::value)); + + // Swappable as rvalues, via the swap found by ADL. + CHECK((etl::is_swappable_with::value)); + + // Rvalues do not bind to the lvalue references taken by swap, unless the + // compiler allows it as an extension. + CHECK((!etl::is_swappable_with::value)); + CHECK((etl::is_swappable_with::value == rvalue_binds_to_lvalue_reference::value)); + + CHECK((!etl::is_swappable_with::value)); + CHECK((!etl::is_swappable_with::value)); + CHECK((!etl::is_swappable_with::value)); + CHECK((!etl::is_swappable_with::value)); + CHECK((!etl::is_swappable_with::value)); + + #if ETL_USING_CPP17 + CHECK((etl::is_swappable_with::value == std::is_swappable_with::value)); + CHECK((etl::is_swappable_with::value == std::is_swappable_with::value)); + CHECK((etl::is_swappable_with::value == std::is_swappable_with::value)); + CHECK((etl::is_swappable_with::value == std::is_swappable_with::value)); + CHECK((etl::is_swappable_with::value == std::is_swappable_with::value)); + CHECK((etl::is_swappable_with::value == std::is_swappable_with::value)); + CHECK((etl::is_swappable_with::value == std::is_swappable_with::value)); + CHECK((etl::is_swappable_with::value == std::is_swappable_with::value)); + CHECK((etl::is_swappable_with::value + == std::is_swappable_with::value)); + + CHECK((etl::is_swappable_with_v)); + CHECK((!etl::is_swappable_with_v)); + #endif + } + + //************************************************************************* + TEST(test_is_nothrow_swappable) + { + CHECK(etl::is_nothrow_swappable::value); + CHECK(etl::is_nothrow_swappable::value); + CHECK(etl::is_nothrow_swappable::value); + CHECK(etl::is_nothrow_swappable::value); + CHECK(etl::is_nothrow_swappable::value); + + // Not movable, so swappable only via the swap found by ADL, which is noexcept. + CHECK(etl::is_nothrow_swappable::value); + CHECK(etl::is_nothrow_swappable::value); + + // Swappable, but the swap may throw. + CHECK(!etl::is_nothrow_swappable::value); + CHECK(!etl::is_nothrow_swappable::value); + + // Swappable via the swap found by ADL, which is not noexcept. + CHECK(!etl::is_nothrow_swappable::value); + CHECK(!etl::is_nothrow_swappable::value); + + // Not swappable at all. + CHECK(!etl::is_nothrow_swappable::value); + CHECK(!etl::is_nothrow_swappable::value); + CHECK(!etl::is_nothrow_swappable::value); + CHECK(!etl::is_nothrow_swappable::value); + CHECK(!etl::is_nothrow_swappable::value); + CHECK(!etl::is_nothrow_swappable::value); + + #if ETL_USING_CPP17 + CHECK(etl::is_nothrow_swappable::value == std::is_nothrow_swappable::value); + CHECK(etl::is_nothrow_swappable::value == std::is_nothrow_swappable::value); + CHECK(etl::is_nothrow_swappable::value == std::is_nothrow_swappable::value); + CHECK(etl::is_nothrow_swappable::value == std::is_nothrow_swappable::value); + CHECK(etl::is_nothrow_swappable::value == std::is_nothrow_swappable::value); + CHECK(etl::is_nothrow_swappable::value == std::is_nothrow_swappable::value); + CHECK(etl::is_nothrow_swappable::value == std::is_nothrow_swappable::value); + CHECK(etl::is_nothrow_swappable::value == std::is_nothrow_swappable::value); + CHECK(etl::is_nothrow_swappable::value == std::is_nothrow_swappable::value); + CHECK(etl::is_nothrow_swappable::value == std::is_nothrow_swappable::value); + CHECK(etl::is_nothrow_swappable::value == std::is_nothrow_swappable::value); + CHECK(etl::is_nothrow_swappable::value == std::is_nothrow_swappable::value); + CHECK(etl::is_nothrow_swappable::value == std::is_nothrow_swappable::value); + CHECK(etl::is_nothrow_swappable::value == std::is_nothrow_swappable::value); + CHECK(etl::is_nothrow_swappable::value == std::is_nothrow_swappable::value); + + CHECK(etl::is_nothrow_swappable_v); + CHECK(!etl::is_nothrow_swappable_v); + #endif + } + + //************************************************************************* + TEST(test_is_nothrow_swappable_with) + { + CHECK((etl::is_nothrow_swappable_with::value)); + CHECK((etl::is_nothrow_swappable_with::value)); + + // Swappable with each other, in both directions, without throwing. + CHECK((etl::is_nothrow_swappable_with::value)); + CHECK((etl::is_nothrow_swappable_with::value)); + + // Swappable in both directions, but one of the swaps may throw. + CHECK((!etl::is_nothrow_swappable_with::value)); + CHECK((!etl::is_nothrow_swappable_with::value)); + + // Swappable with each other, but the swaps may throw. + CHECK((!etl::is_nothrow_swappable_with::value)); + + // Swappable, but the move operations may throw. + CHECK((!etl::is_nothrow_swappable_with::value)); + + // Rvalues do not bind to the lvalue references taken by swap. + CHECK((!etl::is_nothrow_swappable_with::value)); + + // Not swappable at all. + CHECK((!etl::is_nothrow_swappable_with::value)); + CHECK((!etl::is_nothrow_swappable_with::value)); + CHECK((!etl::is_nothrow_swappable_with::value)); + CHECK((!etl::is_nothrow_swappable_with::value)); + CHECK((!etl::is_nothrow_swappable_with::value)); + + #if ETL_USING_CPP17 + CHECK((etl::is_nothrow_swappable_with::value == std::is_nothrow_swappable_with::value)); + CHECK((etl::is_nothrow_swappable_with::value == std::is_nothrow_swappable_with::value)); + CHECK((etl::is_nothrow_swappable_with::value == std::is_nothrow_swappable_with::value)); + CHECK((etl::is_nothrow_swappable_with::value == std::is_nothrow_swappable_with::value)); + CHECK( + (etl::is_nothrow_swappable_with::value == std::is_nothrow_swappable_with::value)); + CHECK((etl::is_nothrow_swappable_with::value + == std::is_nothrow_swappable_with::value)); + CHECK( + (etl::is_nothrow_swappable_with::value == std::is_nothrow_swappable_with::value)); + CHECK((etl::is_nothrow_swappable_with::value + == std::is_nothrow_swappable_with::value)); + CHECK((etl::is_nothrow_swappable_with::value + == std::is_nothrow_swappable_with::value)); + + CHECK((etl::is_nothrow_swappable_with_v)); + CHECK((!etl::is_nothrow_swappable_with_v)); + #endif + } +#endif + + //************************************************************************* + TEST(test_is_union) + { + union Union + { + int a; + float b; + }; + + struct NonUnion + { + int a; + int b; + }; + + CHECK(etl::is_union::value == std::is_union::value); + CHECK(etl::is_union::value == std::is_union::value); + CHECK(etl::is_union::value == std::is_union::value); + CHECK(etl::is_union::value == std::is_union::value); + CHECK(etl::is_union::value); + CHECK(!etl::is_union::value); + CHECK(!etl::is_union::value); + +#if ETL_USING_CPP17 + CHECK(etl::is_union_v); + CHECK(!etl::is_union_v); +#endif + } + + //************************************************************************* + TEST(test_is_empty) + { + struct Empty + { + }; + + struct EmptyDerived : public Empty + { + }; + + struct NotEmpty + { + int a; + }; + + struct Virtual + { + virtual void foo() {} + }; + + CHECK(etl::is_empty::value == std::is_empty::value); + CHECK(etl::is_empty::value == std::is_empty::value); + CHECK(etl::is_empty::value == std::is_empty::value); + CHECK(etl::is_empty::value == std::is_empty::value); + CHECK(etl::is_empty::value == std::is_empty::value); + CHECK(etl::is_empty::value == std::is_empty::value); + + CHECK(etl::is_empty::value); + CHECK(etl::is_empty::value); + CHECK(!etl::is_empty::value); + CHECK(!etl::is_empty::value); + CHECK(!etl::is_empty::value); + +#if ETL_USING_CPP17 + CHECK(etl::is_empty_v); + CHECK(!etl::is_empty_v); +#endif + } + + //************************************************************************* + TEST(test_is_polymorphic) + { + struct NonPolymorphic + { + int a; + }; + + struct Polymorphic + { + virtual ~Polymorphic() {} + }; + + struct PolymorphicDerived : public Polymorphic + { + }; + + struct AbstractPolymorphic + { + virtual void foo() = 0; + }; + + CHECK(etl::is_polymorphic::value == std::is_polymorphic::value); + CHECK(etl::is_polymorphic::value == std::is_polymorphic::value); + CHECK(etl::is_polymorphic::value == std::is_polymorphic::value); + CHECK(etl::is_polymorphic::value == std::is_polymorphic::value); + CHECK(etl::is_polymorphic::value == std::is_polymorphic::value); + CHECK(etl::is_polymorphic::value == std::is_polymorphic::value); + + CHECK(etl::is_polymorphic::value); + CHECK(etl::is_polymorphic::value); + CHECK(etl::is_polymorphic::value); + CHECK(!etl::is_polymorphic::value); + CHECK(!etl::is_polymorphic::value); + +#if ETL_USING_CPP17 + CHECK(etl::is_polymorphic_v); + CHECK(!etl::is_polymorphic_v); +#endif + } + + //************************************************************************* + TEST(test_is_abstract) + { + struct NonAbstract + { + int a; + }; + + struct NonAbstractPolymorphic + { + virtual ~NonAbstractPolymorphic() {} + }; + + struct Abstract + { + virtual ~Abstract() {} + virtual void foo() = 0; + }; + + struct AbstractDerived : public Abstract + { + }; + + struct ConcreteDerived : public Abstract + { + void foo() ETL_OVERRIDE {} + }; + + CHECK(etl::is_abstract::value == std::is_abstract::value); + CHECK(etl::is_abstract::value == std::is_abstract::value); + CHECK(etl::is_abstract::value == std::is_abstract::value); + CHECK(etl::is_abstract::value == std::is_abstract::value); + CHECK(etl::is_abstract::value == std::is_abstract::value); + CHECK(etl::is_abstract::value == std::is_abstract::value); + CHECK(etl::is_abstract::value == std::is_abstract::value); + + CHECK(etl::is_abstract::value); + CHECK(etl::is_abstract::value); + CHECK(!etl::is_abstract::value); + CHECK(!etl::is_abstract::value); + CHECK(!etl::is_abstract::value); + CHECK(!etl::is_abstract::value); + +#if ETL_USING_CPP17 + CHECK(etl::is_abstract_v); + CHECK(!etl::is_abstract_v); +#endif + } + + //************************************************************************* +#if ETL_USING_CPP14 + TEST(test_is_final) + { + struct NonFinal + { + int a; + }; + + struct Final final + { + int a; + }; + + struct Base + { + virtual ~Base() {} + }; + + struct FinalDerived final : public Base + { + }; + + struct NonFinalDerived : public Base + { + }; + + union FinalUnion final + { + int a; + }; + + CHECK(etl::is_final::value == std::is_final::value); + CHECK(etl::is_final::value == std::is_final::value); + CHECK(etl::is_final::value == std::is_final::value); + CHECK(etl::is_final::value == std::is_final::value); + CHECK(etl::is_final::value == std::is_final::value); + CHECK(etl::is_final::value == std::is_final::value); + CHECK(etl::is_final::value == std::is_final::value); + CHECK(etl::is_final::value == std::is_final::value); + + CHECK(etl::is_final::value); + CHECK(etl::is_final::value); + CHECK(etl::is_final::value); + CHECK(!etl::is_final::value); + CHECK(!etl::is_final::value); + CHECK(!etl::is_final::value); + CHECK(!etl::is_final::value); + CHECK(!etl::is_final::value); + + #if ETL_USING_CPP17 + CHECK(etl::is_final_v); + CHECK(!etl::is_final_v); + #endif + } +#endif + + //************************************************************************* +#if ETL_USING_CPP17 + TEST(test_is_aggregate) + { + struct Aggregate + { + int a; + double b; + }; + + struct AggregateDerived : public Aggregate + { + int c; + }; + + struct NonAggregate + { + NonAggregate(int a_) + : a(a_) + { + } + int a; + }; + + struct Virtual + { + virtual ~Virtual() {} + int a; + }; + + union AggregateUnion + { + int a; + double b; + }; + + CHECK(etl::is_aggregate::value == std::is_aggregate::value); + CHECK(etl::is_aggregate::value == std::is_aggregate::value); + CHECK(etl::is_aggregate::value == std::is_aggregate::value); + CHECK(etl::is_aggregate::value == std::is_aggregate::value); + CHECK(etl::is_aggregate::value == std::is_aggregate::value); + CHECK(etl::is_aggregate::value == std::is_aggregate::value); + CHECK(etl::is_aggregate::value == std::is_aggregate::value); + CHECK(etl::is_aggregate::value == std::is_aggregate::value); + CHECK(etl::is_aggregate::value == std::is_aggregate::value); + + CHECK(etl::is_aggregate::value); + CHECK(etl::is_aggregate::value); + CHECK(etl::is_aggregate::value); + CHECK(etl::is_aggregate::value); + CHECK(etl::is_aggregate::value); + CHECK(!etl::is_aggregate::value); + CHECK(!etl::is_aggregate::value); + CHECK(!etl::is_aggregate::value); + CHECK(!etl::is_aggregate::value); + + CHECK(etl::is_aggregate_v); + CHECK(!etl::is_aggregate_v); + } +#endif + + //************************************************************************* + TEST(test_has_virtual_destructor) + { + struct NonVirtualDestructor + { + ~NonVirtualDestructor() {} + int a; + }; + + struct VirtualDestructor + { + virtual ~VirtualDestructor() {} + int a; + }; + + struct DerivedFromVirtualDestructor : public VirtualDestructor + { + int b; + }; + + struct VirtualFunctionOnly + { + virtual void foo() {} + int a; + }; + + CHECK(etl::has_virtual_destructor::value == std::has_virtual_destructor::value); + CHECK(etl::has_virtual_destructor::value == std::has_virtual_destructor::value); + CHECK(etl::has_virtual_destructor::value == std::has_virtual_destructor::value); + CHECK(etl::has_virtual_destructor::value == std::has_virtual_destructor::value); + CHECK(etl::has_virtual_destructor::value == std::has_virtual_destructor::value); + CHECK(etl::has_virtual_destructor::value == std::has_virtual_destructor::value); + CHECK(etl::has_virtual_destructor::value == std::has_virtual_destructor::value); + + CHECK(etl::has_virtual_destructor::value); + CHECK(etl::has_virtual_destructor::value); + CHECK(etl::has_virtual_destructor::value); + CHECK(!etl::has_virtual_destructor::value); + CHECK(!etl::has_virtual_destructor::value); + CHECK(!etl::has_virtual_destructor::value); + CHECK(!etl::has_virtual_destructor::value); + +#if ETL_USING_CPP17 + CHECK(etl::has_virtual_destructor_v); + CHECK(!etl::has_virtual_destructor_v); +#endif + } + + //************************************************************************* +#if ETL_USING_CPP17 + TEST(test_has_unique_object_representations) + { + struct NoPadding + { + int a; + int b; + }; + + struct Padded + { + char a; + int b; + }; + + CHECK(etl::has_unique_object_representations::value == std::has_unique_object_representations::value); + CHECK(etl::has_unique_object_representations::value == std::has_unique_object_representations::value); + CHECK(etl::has_unique_object_representations::value == std::has_unique_object_representations::value); + CHECK(etl::has_unique_object_representations::value == std::has_unique_object_representations::value); + CHECK(etl::has_unique_object_representations::value == std::has_unique_object_representations::value); + CHECK(etl::has_unique_object_representations::value == std::has_unique_object_representations::value); + CHECK(etl::has_unique_object_representations::value == std::has_unique_object_representations::value); + CHECK(etl::has_unique_object_representations::value == std::has_unique_object_representations::value); + + CHECK(etl::has_unique_object_representations::value); + CHECK(etl::has_unique_object_representations::value); + CHECK(etl::has_unique_object_representations::value); + CHECK(etl::has_unique_object_representations::value); + CHECK(!etl::has_unique_object_representations::value); + + CHECK(etl::has_unique_object_representations_v); + CHECK(!etl::has_unique_object_representations_v); + } +#endif + + //************************************************************************* + TEST(test_is_scalar) + { + struct Class + { + int a; + void foo() {} + }; + + union Union + { + int a; + float b; + }; + + enum Enum + { + e1 + }; + + // Arithmetic types. + CHECK(etl::is_scalar::value == std::is_scalar::value); + CHECK(etl::is_scalar::value == std::is_scalar::value); + CHECK(etl::is_scalar::value == std::is_scalar::value); + CHECK(etl::is_scalar::value == std::is_scalar::value); + CHECK(etl::is_scalar::value == std::is_scalar::value); + CHECK(etl::is_scalar::value == std::is_scalar::value); + CHECK(etl::is_scalar::value == std::is_scalar::value); + + // Enumerations. + CHECK(etl::is_scalar::value == std::is_scalar::value); + CHECK(etl::is_scalar::value == std::is_scalar::value); + + // Pointers. + CHECK(etl::is_scalar::value == std::is_scalar::value); + CHECK(etl::is_scalar::value == std::is_scalar::value); + CHECK(etl::is_scalar::value == std::is_scalar::value); + CHECK(etl::is_scalar::value == std::is_scalar::value); + + // Pointers to members. + CHECK(etl::is_scalar::value == std::is_scalar::value); + CHECK(etl::is_scalar::value == std::is_scalar::value); + CHECK(etl::is_scalar::value == std::is_scalar::value); + + // Null pointer. + CHECK(etl::is_scalar::value == std::is_scalar::value); + CHECK(etl::is_scalar::value == std::is_scalar::value); + + // Non-scalars. + CHECK(etl::is_scalar::value == std::is_scalar::value); + CHECK(etl::is_scalar::value == std::is_scalar::value); + CHECK(etl::is_scalar::value == std::is_scalar::value); + CHECK(etl::is_scalar::value == std::is_scalar::value); + CHECK(etl::is_scalar::value == std::is_scalar::value); + CHECK(etl::is_scalar::value == std::is_scalar::value); + CHECK(etl::is_scalar::value == std::is_scalar::value); + CHECK(etl::is_scalar::value == std::is_scalar::value); + + CHECK(etl::is_scalar::value); + CHECK(etl::is_scalar::value); + CHECK(etl::is_scalar::value); + CHECK(etl::is_scalar::value); + CHECK(etl::is_scalar::value); + CHECK(!etl::is_scalar::value); + CHECK(!etl::is_scalar::value); + CHECK(!etl::is_scalar::value); + +#if ETL_USING_CPP17 + CHECK(etl::is_scalar_v); + CHECK(etl::is_scalar_v); + CHECK(etl::is_scalar_v); + CHECK(etl::is_scalar_v); + CHECK(!etl::is_scalar_v); + CHECK(!etl::is_scalar_v); +#endif + } + //************************************************************************* TEST(test_is_reference) {