From 4e3064a3a8e5295688c985768ad83676b9162cc0 Mon Sep 17 00:00:00 2001 From: Liam Mitchell Date: Wed, 13 Oct 2021 16:05:11 -0700 Subject: [PATCH 1/3] Release candidate for EASTL version 3.18.00. Feature additions and standard updates: - Implemented eastl::bit_cast. - Implemented eastl::is_nothrow_invocable. - Implemented eastl::to_underlying. - Implemented LWG defect 2106: move_iterator doesn't work with iterators which don't return a reference Bugfixes: - eastl::invoke fixes: - invoke now correctly deduces the function signature when invoking a member function or member data pointer on a reference_wrapper. Previously, this would fail if using arguments which were convertible to the correct type, but did not exactly match. - invoke now correctly forwards arguments when invoking a member data pointer. - invoke now correctly uses decay_t instead of remove_reference_t in a number of places. - invoke_result_t no longer uses decay_t on the type being invoked. - invoke is now constexpr. - eastl::variant fixes: - Fixed incorrect results from some relational operators when valueless_by_exception() is true. - Fixed incorrect index when an exception is thrown during emplace(). - Removed assertions from some eastl::array functions in order to ensure usability in constexpr contexts. - eastl::make_signed and eastl::make_unsigned now work correctly for enum types and volatile-qualified types. - Containers which support find_as now support using it with keys of the same type as the container's key. - Disallowed use of smart pointer default deleter on incomplete types. - Fixed an issue where nodes for some data structures could be under-aligned. - Properly supported arrays in eastl::cbegin() and eastl::cend(). - Fixed creation of zero-length spans and subspans. - eastl::is_reference now returns true for rvalue references. Optimizations: - eastl::variant optimizations: - Avoided unnecessary double index checks in variant relational operators. - Avoided unnecessary work in valueless_by_exception() when exceptions are disabled. - Optimized visit() for the common case of visiting a single variant. - Removed unnecessary copies during visit(). --- doc/EASTL.natvis | 70 ++ include/EASTL/allocator_malloc.h | 2 +- include/EASTL/array.h | 35 - include/EASTL/bit.h | 65 ++ include/EASTL/bitset.h | 2 +- include/EASTL/chrono.h | 3 +- include/EASTL/fixed_hash_map.h | 36 +- include/EASTL/fixed_hash_set.h | 54 +- include/EASTL/fixed_list.h | 8 +- include/EASTL/fixed_slist.h | 8 +- include/EASTL/functional.h | 27 +- .../atomic/arch/arm/arch_arm_memory_barrier.h | 4 +- .../EASTL/internal/atomic/arch/x86/arch_x86.h | 17 +- .../atomic/arch/x86/arch_x86_add_fetch.h | 2 +- .../atomic/arch/x86/arch_x86_and_fetch.h | 2 +- .../atomic/arch/x86/arch_x86_cmpxchg_strong.h | 2 +- .../atomic/arch/x86/arch_x86_cmpxchg_weak.h | 2 +- .../atomic/arch/x86/arch_x86_exchange.h | 2 +- .../atomic/arch/x86/arch_x86_fetch_add.h | 2 +- .../atomic/arch/x86/arch_x86_fetch_and.h | 2 +- .../atomic/arch/x86/arch_x86_fetch_or.h | 2 +- .../atomic/arch/x86/arch_x86_fetch_sub.h | 2 +- .../atomic/arch/x86/arch_x86_fetch_xor.h | 2 +- .../internal/atomic/arch/x86/arch_x86_load.h | 84 +- .../atomic/arch/x86/arch_x86_memory_barrier.h | 2 +- .../atomic/arch/x86/arch_x86_or_fetch.h | 2 +- .../internal/atomic/arch/x86/arch_x86_store.h | 2 +- .../atomic/arch/x86/arch_x86_sub_fetch.h | 2 +- .../atomic/arch/x86/arch_x86_thread_fence.h | 2 +- .../atomic/arch/x86/arch_x86_xor_fetch.h | 2 +- include/EASTL/internal/atomic/atomic.h | 6 +- include/EASTL/internal/atomic/atomic_flag.h | 12 +- .../EASTL/internal/atomic/atomic_integral.h | 8 +- .../internal/atomic/atomic_memory_order.h | 12 +- .../EASTL/internal/atomic/atomic_pointer.h | 8 +- .../internal/atomic/atomic_size_aligned.h | 40 +- .../EASTL/internal/atomic/compiler/compiler.h | 2 +- .../compiler/msvc/compiler_msvc_barrier.h | 4 +- .../msvc/compiler_msvc_cmpxchg_strong.h | 1 - include/EASTL/internal/config.h | 30 +- include/EASTL/internal/copy_help.h | 57 +- include/EASTL/internal/fill_help.h | 4 +- include/EASTL/internal/fixed_pool.h | 11 +- include/EASTL/internal/function.h | 2 + include/EASTL/internal/function_detail.h | 2 +- include/EASTL/internal/functional_base.h | 90 +- include/EASTL/internal/hashtable.h | 12 +- include/EASTL/internal/integer_sequence.h | 30 + include/EASTL/internal/red_black_tree.h | 8 + include/EASTL/internal/smart_ptr.h | 5 +- include/EASTL/internal/thread_support.h | 18 +- include/EASTL/internal/type_compound.h | 59 +- include/EASTL/internal/type_fundamental.h | 55 +- include/EASTL/internal/type_pod.h | 46 +- include/EASTL/internal/type_properties.h | 61 +- include/EASTL/internal/type_transformations.h | 304 ++++-- include/EASTL/intrusive_list.h | 8 + include/EASTL/iterator.h | 43 +- include/EASTL/list.h | 2 +- include/EASTL/meta.h | 57 +- include/EASTL/numeric_limits.h | 10 +- include/EASTL/slist.h | 2 +- include/EASTL/sort.h | 4 +- include/EASTL/span.h | 44 +- include/EASTL/string.h | 14 +- include/EASTL/type_traits.h | 38 +- include/EASTL/unique_ptr.h | 13 +- include/EASTL/utility.h | 2 +- include/EASTL/variant.h | 758 ++++++++++----- source/numeric_limits.cpp | 6 +- source/thread_support.cpp | 6 +- test/source/EASTLTest.h | 1 + test/source/TestBitcast.cpp | 52 + test/source/TestFunctional.cpp | 177 +++- test/source/TestHash.cpp | 10 + test/source/TestIntrusiveHash.cpp | 6 + test/source/TestIterator.cpp | 83 ++ test/source/TestMap.cpp | 13 + test/source/TestOptional.cpp | 16 +- test/source/TestSpan.cpp | 20 +- test/source/TestTypeTraits.cpp | 177 +++- test/source/TestVariant.cpp | 900 +++++++++++++++++- test/source/main.cpp | 1 + 83 files changed, 2975 insertions(+), 822 deletions(-) create mode 100644 include/EASTL/bit.h create mode 100644 test/source/TestBitcast.cpp diff --git a/doc/EASTL.natvis b/doc/EASTL.natvis index 30986d5e..2fb311b1 100644 --- a/doc/EASTL.natvis +++ b/doc/EASTL.natvis @@ -558,6 +558,76 @@ {mFlag.mAtomic} + + + [valueless_by_exception] + {{ index=0, value={($T1*)mStorage.mBuffer.mCharData}} + {{ index=1, value={($T2*)mStorage.mBuffer.mCharData}} + {{ index=2, value={($T3*)mStorage.mBuffer.mCharData}} + {{ index=3, value={($T4*)mStorage.mBuffer.mCharData}} + {{ index=4, value={($T5*)mStorage.mBuffer.mCharData}} + {{ index=5, value={($T6*)mStorage.mBuffer.mCharData}} + {{ index=6, value={($T7*)mStorage.mBuffer.mCharData}} + {{ index=7, value={($T8*)mStorage.mBuffer.mCharData}} + {{ index=8, value={($T9*)mStorage.mBuffer.mCharData}} + {{ index=9, value={($T10*)mStorage.mBuffer.mCharData}} + {{ index=10, value={($T11*)mStorage.mBuffer.mCharData}} + {{ index=11, value={($T12*)mStorage.mBuffer.mCharData}} + {{ index=12, value={($T13*)mStorage.mBuffer.mCharData}} + {{ index=13, value={($T14*)mStorage.mBuffer.mCharData}} + {{ index=14, value={($T15*)mStorage.mBuffer.mCharData}} + {{ index=15, value={($T16*)mStorage.mBuffer.mCharData}} + {{ index=16, value={($T17*)mStorage.mBuffer.mCharData}} + {{ index=17, value={($T18*)mStorage.mBuffer.mCharData}} + {{ index=18, value={($T19*)mStorage.mBuffer.mCharData}} + {{ index=19, value={($T20*)mStorage.mBuffer.mCharData}} + {{ index=20, value={($T21*)mStorage.mBuffer.mCharData}} + {{ index=21, value={($T22*)mStorage.mBuffer.mCharData}} + {{ index=22, value={($T23*)mStorage.mBuffer.mCharData}} + {{ index=23, value={($T24*)mStorage.mBuffer.mCharData}} + {{ index=24, value={($T25*)mStorage.mBuffer.mCharData}} + {{ index=25, value={($T26*)mStorage.mBuffer.mCharData}} + {{ index=26, value={($T27*)mStorage.mBuffer.mCharData}} + {{ index=27, value={($T28*)mStorage.mBuffer.mCharData}} + {{ index=28, value={($T29*)mStorage.mBuffer.mCharData}} + {{ index=29, value={($T30*)mStorage.mBuffer.mCharData}} + {{ index=30, value={($T31*)mStorage.mBuffer.mCharData}} + + index() + ($T1*)mStorage.mBuffer.mCharData + ($T2*)mStorage.mBuffer.mCharData + ($T3*)mStorage.mBuffer.mCharData + ($T4*)mStorage.mBuffer.mCharData + ($T5*)mStorage.mBuffer.mCharData + ($T6*)mStorage.mBuffer.mCharData + ($T7*)mStorage.mBuffer.mCharData + ($T8*)mStorage.mBuffer.mCharData + ($T9*)mStorage.mBuffer.mCharData + ($T10*)mStorage.mBuffer.mCharData + ($T11*)mStorage.mBuffer.mCharData + ($T12*)mStorage.mBuffer.mCharData + ($T13*)mStorage.mBuffer.mCharData + ($T14*)mStorage.mBuffer.mCharData + ($T15*)mStorage.mBuffer.mCharData + ($T16*)mStorage.mBuffer.mCharData + ($T17*)mStorage.mBuffer.mCharData + ($T18*)mStorage.mBuffer.mCharData + ($T19*)mStorage.mBuffer.mCharData + ($T20*)mStorage.mBuffer.mCharData + ($T21*)mStorage.mBuffer.mCharData + ($T22*)mStorage.mBuffer.mCharData + ($T23*)mStorage.mBuffer.mCharData + ($T24*)mStorage.mBuffer.mCharData + ($T25*)mStorage.mBuffer.mCharData + ($T26*)mStorage.mBuffer.mCharData + ($T27*)mStorage.mBuffer.mCharData + ($T28*)mStorage.mBuffer.mCharData + ($T29*)mStorage.mBuffer.mCharData + ($T30*)mStorage.mBuffer.mCharData + ($T31*)mStorage.mBuffer.mCharData + + + diff --git a/include/EASTL/allocator_malloc.h b/include/EASTL/allocator_malloc.h index 31f8deca..78f4f69d 100644 --- a/include/EASTL/allocator_malloc.h +++ b/include/EASTL/allocator_malloc.h @@ -40,7 +40,7 @@ #endif #elif defined(EA_PLATFORM_BSD) #include - #elif defined(EA_COMPILER_CLANG) + #elif defined(__clang__) #if __has_include() #include #elif __has_include() diff --git a/include/EASTL/array.h b/include/EASTL/array.h index 590aa94b..05d5d32f 100644 --- a/include/EASTL/array.h +++ b/include/EASTL/array.h @@ -279,12 +279,6 @@ namespace eastl EA_CPP14_CONSTEXPR inline typename array::reference array::operator[](size_type i) { - #if EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY(i >= N)) - EASTL_FAIL_MSG("array::operator[] -- out of range"); - #endif - - EA_ANALYSIS_ASSUME(i < N); return mValue[i]; } @@ -293,13 +287,6 @@ namespace eastl EA_CPP14_CONSTEXPR inline typename array::const_reference array::operator[](size_type i) const { - #if EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY(i >= N)) - EASTL_FAIL_MSG("array::operator[] -- out of range"); - - #endif - - EA_ANALYSIS_ASSUME(i < N); return mValue[i]; } @@ -308,11 +295,6 @@ namespace eastl EA_CPP14_CONSTEXPR inline typename array::reference array::front() { - #if EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY(empty())) // We don't allow the user to reference an empty container. - EASTL_FAIL_MSG("array::front -- empty array"); - #endif - return mValue[0]; } @@ -321,11 +303,6 @@ namespace eastl EA_CPP14_CONSTEXPR inline typename array::const_reference array::front() const { - #if EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY(empty())) // We don't allow the user to reference an empty container. - EASTL_FAIL_MSG("array::front -- empty array"); - #endif - return mValue[0]; } @@ -334,11 +311,6 @@ namespace eastl EA_CPP14_CONSTEXPR inline typename array::reference array::back() { - #if EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY(empty())) // We don't allow the user to reference an empty container. - EASTL_FAIL_MSG("array::back -- empty array"); - #endif - return mValue[N - 1]; } @@ -347,11 +319,6 @@ namespace eastl EA_CPP14_CONSTEXPR inline typename array::const_reference array::back() const { - #if EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY(empty())) // We don't allow the user to reference an empty container. - EASTL_FAIL_MSG("array::back -- empty array"); - #endif - return mValue[N - 1]; } @@ -381,7 +348,6 @@ namespace eastl EASTL_FAIL_MSG("array::at -- out of range"); #endif - EA_ANALYSIS_ASSUME(i < N); return static_cast(mValue[i]); } @@ -397,7 +363,6 @@ namespace eastl EASTL_FAIL_MSG("array::at -- out of range"); #endif - EA_ANALYSIS_ASSUME(i < N); return static_cast(mValue[i]); } diff --git a/include/EASTL/bit.h b/include/EASTL/bit.h new file mode 100644 index 00000000..64efe487 --- /dev/null +++ b/include/EASTL/bit.h @@ -0,0 +1,65 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_BIT_H +#define EASTL_BIT_H + +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + +#include +#include +#include // memcpy + +namespace eastl +{ + // eastl::bit_cast + // Obtains a value of type To by reinterpreting the object representation of 'from'. + // Every bit in the value representation of the returned To object is equal to the + // corresponding bit in the object representation of 'from'. + // + // In order for bit_cast to be constexpr, the compiler needs to explicitly support + // it by providing the __builtin_bit_cast builtin. If that builtin is not available, + // then we memcpy into aligned storage at runtime and return that instead. + // + // Both types To and From must be equal in size, and must be trivially copyable. + + #if defined(EASTL_CONSTEXPR_BIT_CAST_SUPPORTED) && EASTL_CONSTEXPR_BIT_CAST_SUPPORTED + + template::value + && eastl::is_trivially_copyable::value + > + > + EA_CONSTEXPR To bit_cast(const From& from) EA_NOEXCEPT + { + return __builtin_bit_cast(To, from); + } + + #else + + template::value + && eastl::is_trivially_copyable::value + > + > + inline To bit_cast(const From& from) EA_NOEXCEPT + { + typename eastl::aligned_storage::type to; + ::memcpy(eastl::addressof(to), eastl::addressof(from), sizeof(To)); + return reinterpret_cast(to); + } + + #endif // EASTL_CONSTEXPR_BIT_CAST_SUPPORTED + +} // namespace eastl + +#endif // EASTL_BIT_H diff --git a/include/EASTL/bitset.h b/include/EASTL/bitset.h index d9261050..8778372f 100644 --- a/include/EASTL/bitset.h +++ b/include/EASTL/bitset.h @@ -1505,7 +1505,7 @@ EA_RESTORE_GCC_WARNING() inline typename BitsetBase<2, WordType>::size_type BitsetBase<2, WordType>::count() const { - #if defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 304) // GCC 3.4 or later + #if (defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 304)) || defined(__clang__) // GCC 3.4 or later #if(EA_PLATFORM_WORD_SIZE == 4) return (size_type)__builtin_popcountl(mWord[0]) + (size_type)__builtin_popcountl(mWord[1]); #else diff --git a/include/EASTL/chrono.h b/include/EASTL/chrono.h index 453ab0f4..5d8ca425 100644 --- a/include/EASTL/chrono.h +++ b/include/EASTL/chrono.h @@ -597,8 +597,7 @@ namespace chrono timespec ts; int result = clock_gettime(CLOCK_MONOTONIC, &ts); - if(result == EINVAL - ) + if (result == -1 && errno == EINVAL) result = clock_gettime(CLOCK_REALTIME, &ts); const uint64_t nNanoseconds = (uint64_t)ts.tv_nsec + ((uint64_t)ts.tv_sec * UINT64_C(1000000000)); diff --git a/include/EASTL/fixed_hash_map.h b/include/EASTL/fixed_hash_map.h index af6663dd..b94ea541 100644 --- a/include/EASTL/fixed_hash_map.h +++ b/include/EASTL/fixed_hash_map.h @@ -251,7 +251,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -267,11 +267,13 @@ namespace eastl { EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); - if(!bEnableOverflow) + if (!bEnableOverflow) + { base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + } #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -288,11 +290,13 @@ namespace eastl { EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); - if(!bEnableOverflow) + if (!bEnableOverflow) + { base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + } #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -314,7 +318,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -377,7 +381,7 @@ namespace eastl mAllocator.copy_overflow_allocator(x.mAllocator); #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); + mAllocator.set_name(x.mAllocator.get_name()); #endif EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); @@ -402,7 +406,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -532,8 +536,10 @@ namespace eastl { EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); - if(!bEnableOverflow) + if (!bEnableOverflow) + { base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + } #if EASTL_NAME_ENABLED mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); @@ -556,7 +562,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -577,7 +583,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -599,7 +605,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -616,7 +622,7 @@ namespace eastl mAllocator.copy_overflow_allocator(x.mAllocator); #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); + mAllocator.set_name(x.mAllocator.get_name()); #endif EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); @@ -662,7 +668,7 @@ namespace eastl mAllocator.copy_overflow_allocator(x.mAllocator); #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); + mAllocator.set_name(x.mAllocator.get_name()); #endif EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); @@ -687,7 +693,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); diff --git a/include/EASTL/fixed_hash_set.h b/include/EASTL/fixed_hash_set.h index 0db9f49f..fa2783ad 100644 --- a/include/EASTL/fixed_hash_set.h +++ b/include/EASTL/fixed_hash_set.h @@ -75,7 +75,7 @@ namespace eastl bucketCount + 1, sizeof(typename hash_set::node_type), nodeCount, - EASTL_ALIGN_OF(Value), + EASTL_ALIGN_OF(typename hash_set::node_type), 0, bEnableOverflow, OverflowAllocator>, @@ -83,8 +83,9 @@ namespace eastl { public: typedef fixed_hashtable_allocator::node_type), nodeCount, EASTL_ALIGN_OF(Value), 0, - bEnableOverflow, OverflowAllocator> fixed_allocator_type; + OverflowAllocator, bCacheHashCode>::node_type), nodeCount, + EASTL_ALIGN_OF(typename hash_set::node_type), + 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type; typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type; typedef fixed_hash_set this_type; typedef hash_set base_type; @@ -162,7 +163,7 @@ namespace eastl bucketCount + 1, sizeof(typename hash_multiset::node_type), nodeCount, - EASTL_ALIGN_OF(Value), + EASTL_ALIGN_OF(typename hash_multiset::node_type), 0, bEnableOverflow, OverflowAllocator>, @@ -170,7 +171,8 @@ namespace eastl { public: typedef fixed_hashtable_allocator::node_type), nodeCount, EASTL_ALIGN_OF(Value), 0, + OverflowAllocator, bCacheHashCode>::node_type), nodeCount, EASTL_ALIGN_OF(typename hash_multiset::node_type), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type; typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type; typedef hash_multiset base_type; @@ -238,11 +240,13 @@ namespace eastl { EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); - if(!bEnableOverflow) + if (!bEnableOverflow) + { base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + } #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -262,7 +266,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -279,11 +283,13 @@ namespace eastl { EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); - if(!bEnableOverflow) + if (!bEnableOverflow) + { base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + } #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -302,10 +308,12 @@ namespace eastl EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); if(!bEnableOverflow) + { base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + } #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -322,7 +330,7 @@ namespace eastl mAllocator.copy_overflow_allocator(x.mAllocator); #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); + mAllocator.set_name(x.mAllocator.get_name()); #endif EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); @@ -344,7 +352,7 @@ namespace eastl mAllocator.copy_overflow_allocator(x.mAllocator); #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); + mAllocator.set_name(x.mAllocator.get_name()); #endif EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); @@ -366,7 +374,7 @@ namespace eastl mAllocator.copy_overflow_allocator(x.mAllocator); #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); + mAllocator.set_name(x.mAllocator.get_name()); #endif EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); @@ -391,7 +399,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -515,7 +523,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -535,7 +543,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -556,7 +564,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -578,7 +586,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -595,7 +603,7 @@ namespace eastl mAllocator.copy_overflow_allocator(x.mAllocator); #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); + mAllocator.set_name(x.mAllocator.get_name()); #endif EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); @@ -617,7 +625,7 @@ namespace eastl mAllocator.copy_overflow_allocator(x.mAllocator); #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); + mAllocator.set_name(x.mAllocator.get_name()); #endif EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); @@ -639,7 +647,7 @@ namespace eastl mAllocator.copy_overflow_allocator(x.mAllocator); #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); + mAllocator.set_name(x.mAllocator.get_name()); #endif EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); @@ -664,7 +672,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); diff --git a/include/EASTL/fixed_list.h b/include/EASTL/fixed_list.h index 9e48089c..e57c08bf 100644 --- a/include/EASTL/fixed_list.h +++ b/include/EASTL/fixed_list.h @@ -63,12 +63,12 @@ namespace eastl /// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap. /// template - class fixed_list : public list::node_type), - nodeCount, EASTL_ALIGN_OF(T), 0, bEnableOverflow, OverflowAllocator> > + class fixed_list : public list::node_type), + nodeCount, EASTL_ALIGN_OF(typename list::node_type), 0, bEnableOverflow, OverflowAllocator> > { public: - typedef fixed_node_allocator::node_type), nodeCount, - EASTL_ALIGN_OF(T), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type; + typedef fixed_node_allocator::node_type), nodeCount, + EASTL_ALIGN_OF(typename list::node_type), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type; typedef OverflowAllocator overflow_allocator_type; typedef list base_type; typedef fixed_list this_type; diff --git a/include/EASTL/fixed_slist.h b/include/EASTL/fixed_slist.h index 85a7a7b3..abad7ad9 100644 --- a/include/EASTL/fixed_slist.h +++ b/include/EASTL/fixed_slist.h @@ -63,12 +63,12 @@ namespace eastl /// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap. /// template - class fixed_slist : public slist::node_type), - nodeCount, EASTL_ALIGN_OF(T), 0, bEnableOverflow, OverflowAllocator> > + class fixed_slist : public slist::node_type), + nodeCount, EASTL_ALIGN_OF(typename slist::node_type), 0, bEnableOverflow, OverflowAllocator> > { public: - typedef fixed_node_allocator::node_type), nodeCount, - EASTL_ALIGN_OF(T), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type; + typedef fixed_node_allocator::node_type), nodeCount, + EASTL_ALIGN_OF(typename slist::node_type), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type; typedef OverflowAllocator overflow_allocator_type; typedef slist base_type; typedef fixed_slist this_type; diff --git a/include/EASTL/functional.h b/include/EASTL/functional.h index 556bf020..6fa34893 100644 --- a/include/EASTL/functional.h +++ b/include/EASTL/functional.h @@ -389,52 +389,41 @@ namespace eastl // Dual type functions /////////////////////////////////////////////////////////////////////// + template struct equal_to_2 : public binary_function { EA_CPP14_CONSTEXPR bool operator()(const T& a, const U& b) const { return a == b; } - EA_CPP14_CONSTEXPR bool operator()(const U& b, const T& a) const // If you are getting a 'operator() already defined' error related to on this line while compiling a - { return b == a; } // hashtable class (e.g. hash_map), it's likely that you are using hashtable::find_as when you should - }; // be using hashtable::find instead. The problem is that (const T, U) collide. To do: make this work. - template - struct equal_to_2 : public equal_to - { + template , eastl::remove_const_t>>> + EA_CPP14_CONSTEXPR bool operator()(const U& b, const T& a) const + { return b == a; } }; - template struct not_equal_to_2 : public binary_function { EA_CPP14_CONSTEXPR bool operator()(const T& a, const U& b) const { return a != b; } + + template , eastl::remove_const_t>>> EA_CPP14_CONSTEXPR bool operator()(const U& b, const T& a) const { return b != a; } }; - template - struct not_equal_to_2 : public not_equal_to - { - }; - template struct less_2 : public binary_function { EA_CPP14_CONSTEXPR bool operator()(const T& a, const U& b) const { return a < b; } + + template , eastl::remove_const_t>>> EA_CPP14_CONSTEXPR bool operator()(const U& b, const T& a) const { return b < a; } }; - template - struct less_2 : public less - { - }; - - - /// unary_negate /// diff --git a/include/EASTL/internal/atomic/arch/arm/arch_arm_memory_barrier.h b/include/EASTL/internal/atomic/arch/arm/arch_arm_memory_barrier.h index c52962eb..44dc991d 100644 --- a/include/EASTL/internal/atomic/arch/arm/arch_arm_memory_barrier.h +++ b/include/EASTL/internal/atomic/arch/arm/arch_arm_memory_barrier.h @@ -11,7 +11,7 @@ #endif -#if defined(EA_COMPILER_MSVC) +#if defined(EA_COMPILER_MSVC) && !defined(EA_COMPILER_CLANG_CL) #if defined(EA_PROCESSOR_ARM32) @@ -46,7 +46,7 @@ EASTL_ATOMIC_COMPILER_BARRIER() -#elif defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG) +#elif defined(EA_COMPILER_GNUC) || defined(__clang__) #define EASTL_ARM_DMB_ISH ish diff --git a/include/EASTL/internal/atomic/arch/x86/arch_x86.h b/include/EASTL/internal/atomic/arch/x86/arch_x86.h index 5087c133..142a5143 100644 --- a/include/EASTL/internal/atomic/arch/x86/arch_x86.h +++ b/include/EASTL/internal/atomic/arch/x86/arch_x86.h @@ -32,23 +32,14 @@ ///////////////////////////////////////////////////////////////////////////////// - -#if defined(EA_COMPILER_MSVC) - +#if (defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64) + #define EASTL_ARCH_ATOMIC_HAS_128BIT +#elif defined(EA_COMPILER_MSVC) #if EA_PLATFORM_PTR_SIZE == 8 #define EASTL_ARCH_ATOMIC_HAS_128BIT #endif - #endif - -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) - - #define EASTL_ARCH_ATOMIC_HAS_128BIT - -#endif - - ///////////////////////////////////////////////////////////////////////////////// @@ -104,7 +95,7 @@ * SSE 128-bit loads are not guaranteed to be atomic even though some CPUs * make them atomic such as AMD Ryzen or Intel SandyBridge. */ -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_NOP_PRE_COMPUTE_DESIRED(ret, observed, val) \ diff --git a/include/EASTL/internal/atomic/arch/x86/arch_x86_add_fetch.h b/include/EASTL/internal/atomic/arch/x86/arch_x86_add_fetch.h index 4534806d..7b77528e 100644 --- a/include/EASTL/internal/atomic/arch/x86/arch_x86_add_fetch.h +++ b/include/EASTL/internal/atomic/arch/x86/arch_x86_add_fetch.h @@ -54,7 +54,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_ADD_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \ diff --git a/include/EASTL/internal/atomic/arch/x86/arch_x86_and_fetch.h b/include/EASTL/internal/atomic/arch/x86/arch_x86_and_fetch.h index c38ba414..05831636 100644 --- a/include/EASTL/internal/atomic/arch/x86/arch_x86_and_fetch.h +++ b/include/EASTL/internal/atomic/arch/x86/arch_x86_and_fetch.h @@ -54,7 +54,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_AND_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \ diff --git a/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_strong.h b/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_strong.h index e028398a..1968e9ab 100644 --- a/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_strong.h +++ b/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_strong.h @@ -15,7 +15,7 @@ // // void EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_*_*_N(type, bool ret, type * ptr, type * expected, type desired) // -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_CMPXCHG_STRONG_128_IMPL(type, ret, ptr, expected, desired) \ diff --git a/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_weak.h b/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_weak.h index f8b956a3..61a126c1 100644 --- a/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_weak.h +++ b/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_weak.h @@ -15,7 +15,7 @@ // // void EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_*_*_N(type, bool ret, type * ptr, type * expected, type desired) // -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_128(type, ret, ptr, expected, desired) \ diff --git a/include/EASTL/internal/atomic/arch/x86/arch_x86_exchange.h b/include/EASTL/internal/atomic/arch/x86/arch_x86_exchange.h index 0f058004..624d2f55 100644 --- a/include/EASTL/internal/atomic/arch/x86/arch_x86_exchange.h +++ b/include/EASTL/internal/atomic/arch/x86/arch_x86_exchange.h @@ -51,7 +51,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_EXCHANGE_128(type, ret, ptr, val, MemoryOrder) \ diff --git a/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_add.h b/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_add.h index d78b3334..e816af9b 100644 --- a/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_add.h +++ b/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_add.h @@ -51,7 +51,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_FETCH_ADD_PRE_COMPUTE_DESIRED(ret, observed, val) \ diff --git a/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_and.h b/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_and.h index fd7dbb9c..ff27b1a2 100644 --- a/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_and.h +++ b/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_and.h @@ -51,7 +51,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_FETCH_AND_PRE_COMPUTE_DESIRED(ret, observed, val) \ diff --git a/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_or.h b/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_or.h index 50da6db7..8627d3a2 100644 --- a/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_or.h +++ b/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_or.h @@ -51,7 +51,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_FETCH_OR_PRE_COMPUTE_DESIRED(ret, observed, val) \ diff --git a/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_sub.h b/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_sub.h index 77bee83b..14b43f90 100644 --- a/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_sub.h +++ b/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_sub.h @@ -51,7 +51,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_FETCH_SUB_PRE_COMPUTE_DESIRED(ret, observed, val) \ diff --git a/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_xor.h b/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_xor.h index 2e76b0c5..666df8bf 100644 --- a/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_xor.h +++ b/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_xor.h @@ -51,7 +51,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_FETCH_XOR_PRE_COMPUTE_DESIRED(ret, observed, val) \ diff --git a/include/EASTL/internal/atomic/arch/x86/arch_x86_load.h b/include/EASTL/internal/atomic/arch/x86/arch_x86_load.h index b0441903..644a2a17 100644 --- a/include/EASTL/internal/atomic/arch/x86/arch_x86_load.h +++ b/include/EASTL/internal/atomic/arch/x86/arch_x86_load.h @@ -15,7 +15,46 @@ // // void EASTL_ARCH_ATOMIC_LOAD_*_N(type, type ret, type * ptr) // -#if defined(EA_COMPILER_MSVC) + +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) + + + /** + * NOTE: + * + * Since the cmpxchg 128-bit inline assembly does a sete in the asm to set the return boolean, + * it doesn't get dead-store removed even though we don't care about the success of the + * cmpxchg since the compiler cannot reason about what is inside asm blocks. + * Thus this variant just does the minimum required to do an atomic load. + */ +#define EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, MemoryOrder) \ + { \ + EASTL_ATOMIC_FIXED_WIDTH_TYPE_128 expected = 0; \ + ret = EASTL_ATOMIC_TYPE_PUN_CAST(type, expected); \ + \ + /* Compare RDX:RAX with m128. If equal, set ZF and load RCX:RBX into m128. Else, clear ZF and load m128 into RDX:RAX. */ \ + __asm__ __volatile__ ("lock; cmpxchg16b %2" /* cmpxchg16b sets/clears ZF */ \ + /* Output Operands */ \ + : "=a"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[0]), "=d"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[1]), \ + "+m"(*(EASTL_ATOMIC_VOLATILE_INTEGRAL_CAST(__uint128_t, (ptr)))) \ + /* Input Operands */ \ + : "b"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[0]), "c"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[1]), \ + "a"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[0]), "d"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[1]) \ + /* Clobbers */ \ + : "memory", "cc"); \ + } + + +#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_128(type, ret, ptr) \ + EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, RELAXED) + +#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_128(type, ret, ptr) \ + EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, ACQUIRE) + +#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_128(type, ret, ptr) \ + EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, SEQ_CST) + +#elif defined(EA_COMPILER_MSVC) #if defined(EA_COMPILER_MSVC) && (EA_COMPILER_VERSION >= 1920) // >= VS2019 @@ -119,49 +158,6 @@ #define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_128(type, ret, ptr) \ EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, SEQ_CST) - -#endif - - -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) - - - /** - * NOTE: - * - * Since the cmpxchg 128-bit inline assembly does a sete in the asm to set the return boolean, - * it doesn't get dead-store removed even though we don't care about the success of the - * cmpxchg since the compiler cannot reason about what is inside asm blocks. - * Thus this variant just does the minimum required to do an atomic load. - */ - #define EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, MemoryOrder) \ - { \ - EASTL_ATOMIC_FIXED_WIDTH_TYPE_128 expected = 0; \ - ret = EASTL_ATOMIC_TYPE_PUN_CAST(type, expected); \ - \ - /* Compare RDX:RAX with m128. If equal, set ZF and load RCX:RBX into m128. Else, clear ZF and load m128 into RDX:RAX. */ \ - __asm__ __volatile__ ("lock; cmpxchg16b %2" /* cmpxchg16b sets/clears ZF */ \ - /* Output Operands */ \ - : "=a"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[0]), "=d"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[1]), \ - "+m"(*(EASTL_ATOMIC_VOLATILE_INTEGRAL_CAST(__uint128_t, (ptr)))) \ - /* Input Operands */ \ - : "b"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[0]), "c"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[1]), \ - "a"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[0]), "d"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[1]) \ - /* Clobbers */ \ - : "memory", "cc"); \ - } - - - #define EASTL_ARCH_ATOMIC_LOAD_RELAXED_128(type, ret, ptr) \ - EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, RELAXED) - - #define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_128(type, ret, ptr) \ - EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, ACQUIRE) - - #define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_128(type, ret, ptr) \ - EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, SEQ_CST) - - #endif diff --git a/include/EASTL/internal/atomic/arch/x86/arch_x86_memory_barrier.h b/include/EASTL/internal/atomic/arch/x86/arch_x86_memory_barrier.h index 1d1c8fca..7bad141f 100644 --- a/include/EASTL/internal/atomic/arch/x86/arch_x86_memory_barrier.h +++ b/include/EASTL/internal/atomic/arch/x86/arch_x86_memory_barrier.h @@ -46,7 +46,7 @@ #endif -#elif defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG) +#elif defined(__clang__) || defined(EA_COMPILER_GNUC) /** * NOTE: diff --git a/include/EASTL/internal/atomic/arch/x86/arch_x86_or_fetch.h b/include/EASTL/internal/atomic/arch/x86/arch_x86_or_fetch.h index 751cc2a3..42f7d61f 100644 --- a/include/EASTL/internal/atomic/arch/x86/arch_x86_or_fetch.h +++ b/include/EASTL/internal/atomic/arch/x86/arch_x86_or_fetch.h @@ -54,7 +54,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_OR_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \ diff --git a/include/EASTL/internal/atomic/arch/x86/arch_x86_store.h b/include/EASTL/internal/atomic/arch/x86/arch_x86_store.h index 397ff5f8..31655c3b 100644 --- a/include/EASTL/internal/atomic/arch/x86/arch_x86_store.h +++ b/include/EASTL/internal/atomic/arch/x86/arch_x86_store.h @@ -145,7 +145,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_STORE_128(type, ptr, val, MemoryOrder) \ diff --git a/include/EASTL/internal/atomic/arch/x86/arch_x86_sub_fetch.h b/include/EASTL/internal/atomic/arch/x86/arch_x86_sub_fetch.h index 124b586d..a1d09329 100644 --- a/include/EASTL/internal/atomic/arch/x86/arch_x86_sub_fetch.h +++ b/include/EASTL/internal/atomic/arch/x86/arch_x86_sub_fetch.h @@ -54,7 +54,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_SUB_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \ diff --git a/include/EASTL/internal/atomic/arch/x86/arch_x86_thread_fence.h b/include/EASTL/internal/atomic/arch/x86/arch_x86_thread_fence.h index fe3bd58c..183c7f3a 100644 --- a/include/EASTL/internal/atomic/arch/x86/arch_x86_thread_fence.h +++ b/include/EASTL/internal/atomic/arch/x86/arch_x86_thread_fence.h @@ -31,7 +31,7 @@ #endif -#if defined(EA_COMPILER_MSVC) || defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC) +#if defined(EA_COMPILER_MSVC) || defined(__clang__) || defined(EA_COMPILER_GNUC) #define EASTL_ARCH_ATOMIC_THREAD_FENCE_SEQ_CST() \ EASTL_ATOMIC_CPU_MB() diff --git a/include/EASTL/internal/atomic/arch/x86/arch_x86_xor_fetch.h b/include/EASTL/internal/atomic/arch/x86/arch_x86_xor_fetch.h index 28cb9587..a5b62c3b 100644 --- a/include/EASTL/internal/atomic/arch/x86/arch_x86_xor_fetch.h +++ b/include/EASTL/internal/atomic/arch/x86/arch_x86_xor_fetch.h @@ -54,7 +54,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_XOR_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \ diff --git a/include/EASTL/internal/atomic/atomic.h b/include/EASTL/internal/atomic/atomic.h index e1c5286e..eb27d2d9 100644 --- a/include/EASTL/internal/atomic/atomic.h +++ b/include/EASTL/internal/atomic/atomic.h @@ -62,7 +62,7 @@ namespace internal template struct is_atomic_lockfree_size { - static EASTL_CPP17_INLINE_VARIABLE constexpr bool value = false || + static EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR_OR_CONST bool value = false || #if defined(EASTL_ATOMIC_HAS_8BIT) sizeof(T) == 1 || #endif @@ -85,7 +85,7 @@ namespace internal template struct is_user_type_suitable_for_primary_template { - static EASTL_CPP17_INLINE_VARIABLE constexpr bool value = eastl::internal::is_atomic_lockfree_size::value; + static EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR_OR_CONST bool value = eastl::internal::is_atomic_lockfree_size::value; }; @@ -116,7 +116,7 @@ namespace internal \ public: \ \ - static EASTL_CPP17_INLINE_VARIABLE constexpr bool is_always_lock_free = eastl::internal::is_atomic_lockfree_size::value; \ + static EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR_OR_CONST bool is_always_lock_free = eastl::internal::is_atomic_lockfree_size::value; \ \ public: /* deleted ctors && assignment operators */ \ \ diff --git a/include/EASTL/internal/atomic/atomic_flag.h b/include/EASTL/internal/atomic/atomic_flag.h index e135d612..eed448ae 100644 --- a/include/EASTL/internal/atomic/atomic_flag.h +++ b/include/EASTL/internal/atomic/atomic_flag.h @@ -42,13 +42,13 @@ class atomic_flag public: /* clear */ template - void clear(Order order) volatile EA_NOEXCEPT + void clear(Order /*order*/) volatile EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(Order); } template - void clear(Order order) EA_NOEXCEPT + void clear(Order /*order*/) EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(Order); } @@ -76,14 +76,14 @@ class atomic_flag public: /* test_and_set */ template - bool test_and_set(Order order) volatile EA_NOEXCEPT + bool test_and_set(Order /*order*/) volatile EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(Order); return false; } template - bool test_and_set(Order order) EA_NOEXCEPT + bool test_and_set(Order /*order*/) EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(Order); return false; @@ -122,14 +122,14 @@ class atomic_flag public: /* test */ template - bool test(Order order) const volatile EA_NOEXCEPT + bool test(Order /*order*/) const volatile EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(Order); return false; } template - bool test(Order order) const EA_NOEXCEPT + bool test(Order /*order*/) const EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(Order); return false; diff --git a/include/EASTL/internal/atomic/atomic_integral.h b/include/EASTL/internal/atomic/atomic_integral.h index 7c94db32..bcf7c178 100644 --- a/include/EASTL/internal/atomic/atomic_integral.h +++ b/include/EASTL/internal/atomic/atomic_integral.h @@ -24,18 +24,18 @@ namespace internal #define EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_FUNCS_IMPL(funcName) \ template \ - T funcName(T arg, Order order) EA_NOEXCEPT \ + T funcName(T /*arg*/, Order /*order*/) EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(T); \ } \ \ template \ - T funcName(T arg, Order order) volatile EA_NOEXCEPT \ + T funcName(T /*arg*/, Order /*order*/) volatile EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \ } \ \ - T funcName(T arg) volatile EA_NOEXCEPT \ + T funcName(T /*arg*/) volatile EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \ } @@ -54,7 +54,7 @@ namespace internal #define EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_ASSIGNMENT_OPERATOR_IMPL(operatorOp) \ - T operator operatorOp(T arg) volatile EA_NOEXCEPT \ + T operator operatorOp(T /*arg*/) volatile EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \ } diff --git a/include/EASTL/internal/atomic/atomic_memory_order.h b/include/EASTL/internal/atomic/atomic_memory_order.h index b1c14035..1564d87d 100644 --- a/include/EASTL/internal/atomic/atomic_memory_order.h +++ b/include/EASTL/internal/atomic/atomic_memory_order.h @@ -30,12 +30,12 @@ struct memory_order_seq_cst_s {}; } // namespace internal -EASTL_CPP17_INLINE_VARIABLE constexpr auto memory_order_relaxed = internal::memory_order_relaxed_s{}; -EASTL_CPP17_INLINE_VARIABLE constexpr auto memory_order_read_depends = internal::memory_order_read_depends_s{}; -EASTL_CPP17_INLINE_VARIABLE constexpr auto memory_order_acquire = internal::memory_order_acquire_s{}; -EASTL_CPP17_INLINE_VARIABLE constexpr auto memory_order_release = internal::memory_order_release_s{}; -EASTL_CPP17_INLINE_VARIABLE constexpr auto memory_order_acq_rel = internal::memory_order_acq_rel_s{}; -EASTL_CPP17_INLINE_VARIABLE constexpr auto memory_order_seq_cst = internal::memory_order_seq_cst_s{}; +EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR auto memory_order_relaxed = internal::memory_order_relaxed_s{}; +EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR auto memory_order_read_depends = internal::memory_order_read_depends_s{}; +EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR auto memory_order_acquire = internal::memory_order_acquire_s{}; +EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR auto memory_order_release = internal::memory_order_release_s{}; +EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR auto memory_order_acq_rel = internal::memory_order_acq_rel_s{}; +EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR auto memory_order_seq_cst = internal::memory_order_seq_cst_s{}; } // namespace eastl diff --git a/include/EASTL/internal/atomic/atomic_pointer.h b/include/EASTL/internal/atomic/atomic_pointer.h index 18f6691c..c0b19e66 100644 --- a/include/EASTL/internal/atomic/atomic_pointer.h +++ b/include/EASTL/internal/atomic/atomic_pointer.h @@ -27,18 +27,18 @@ namespace internal #define EASTL_ATOMIC_POINTER_STATIC_ASSERT_FUNCS_IMPL(funcName) \ template \ - T* funcName(ptrdiff_t arg, Order order) EA_NOEXCEPT \ + T* funcName(ptrdiff_t /*arg*/, Order /*order*/) EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(T); \ } \ \ template \ - T* funcName(ptrdiff_t arg, Order order) volatile EA_NOEXCEPT \ + T* funcName(ptrdiff_t /*arg*/, Order /*order*/) volatile EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \ } \ \ - T* funcName(ptrdiff_t arg) volatile EA_NOEXCEPT \ + T* funcName(ptrdiff_t /*arg*/) volatile EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \ } @@ -55,7 +55,7 @@ namespace internal } #define EASTL_ATOMIC_POINTER_STATIC_ASSERT_ASSIGNMENT_OPERATOR_IMPL(operatorOp) \ - T* operator operatorOp(ptrdiff_t arg) volatile EA_NOEXCEPT \ + T* operator operatorOp(ptrdiff_t /*arg*/) volatile EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \ } diff --git a/include/EASTL/internal/atomic/atomic_size_aligned.h b/include/EASTL/internal/atomic/atomic_size_aligned.h index db23e478..f5033758 100644 --- a/include/EASTL/internal/atomic/atomic_size_aligned.h +++ b/include/EASTL/internal/atomic/atomic_size_aligned.h @@ -24,40 +24,40 @@ namespace internal #define EASTL_ATOMIC_SIZE_ALIGNED_STATIC_ASSERT_CMPXCHG_IMPL(funcName) \ template \ - bool funcName(T& expected, T desired, \ - OrderSuccess orderSuccess, \ - OrderFailure orderFailure) EA_NOEXCEPT \ + bool funcName(T& /*expected*/, T /*desired*/, \ + OrderSuccess /*orderSuccess*/, \ + OrderFailure /*orderFailure*/) EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(T); \ return false; \ } \ \ template \ - bool funcName(T& expected, T desired, \ - OrderSuccess orderSuccess, \ - OrderFailure orderFailure) volatile EA_NOEXCEPT \ + bool funcName(T& /*expected*/, T /*desired*/, \ + OrderSuccess /*orderSuccess*/, \ + OrderFailure /*orderFailure*/) volatile EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \ return false; \ } \ \ template \ - bool funcName(T& expected, T desired, \ - Order order) EA_NOEXCEPT \ + bool funcName(T& /*expected*/, T /*desired*/, \ + Order /*order*/) EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(T); \ return false; \ } \ \ template \ - bool funcName(T& expected, T desired, \ - Order order) volatile EA_NOEXCEPT \ + bool funcName(T& /*expected*/, T /*desired*/, \ + Order /*order*/) volatile EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \ return false; \ } \ \ - bool funcName(T& expected, T desired) volatile EA_NOEXCEPT \ + bool funcName(T& /*expected*/, T /*desired*/) volatile EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \ return false; \ @@ -90,18 +90,18 @@ namespace internal public: /* store */ template - void store(T desired, Order order) EA_NOEXCEPT + void store(T /*desired*/, Order /*order*/) EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(T); } template - void store(T desired, Order order) volatile EA_NOEXCEPT + void store(T /*desired*/, Order /*order*/) volatile EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); } - void store(T desired) volatile EA_NOEXCEPT + void store(T /*desired*/) volatile EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); } @@ -109,13 +109,13 @@ namespace internal public: /* load */ template - T load(Order order) const EA_NOEXCEPT + T load(Order /*order*/) const EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(T); } template - T load(Order order) const volatile EA_NOEXCEPT + T load(Order /*order*/) const volatile EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); } @@ -128,18 +128,18 @@ namespace internal public: /* exchange */ template - T exchange(T desired, Order order) EA_NOEXCEPT + T exchange(T /*desired*/, Order /*order*/) EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(T); } template - T exchange(T desired, Order order) volatile EA_NOEXCEPT + T exchange(T /*desired*/, Order /*order*/) volatile EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); } - T exchange(T desired) volatile EA_NOEXCEPT + T exchange(T /*desired*/) volatile EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); } @@ -154,7 +154,7 @@ namespace internal public: /* assignment operator */ - T operator=(T desired) volatile EA_NOEXCEPT + T operator=(T /*desired*/) volatile EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); } diff --git a/include/EASTL/internal/atomic/compiler/compiler.h b/include/EASTL/internal/atomic/compiler/compiler.h index 65a4cd00..fc128795 100644 --- a/include/EASTL/internal/atomic/compiler/compiler.h +++ b/include/EASTL/internal/atomic/compiler/compiler.h @@ -15,7 +15,7 @@ // // Include the compiler specific implementations // -#if defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG) +#if defined(EA_COMPILER_GNUC) || defined(__clang__) #include "gcc/compiler_gcc.h" diff --git a/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_barrier.h b/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_barrier.h index 02e2d03a..90b78a65 100644 --- a/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_barrier.h +++ b/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_barrier.h @@ -16,7 +16,9 @@ // void EASTL_COMPILER_ATOMIC_COMPILER_BARRIER() // #define EASTL_COMPILER_ATOMIC_COMPILER_BARRIER() \ - _ReadWriteBarrier() + EA_DISABLE_CLANG_WARNING(-Wdeprecated-declarations) \ + _ReadWriteBarrier() \ + EA_RESTORE_CLANG_WARNING() ///////////////////////////////////////////////////////////////////////////////// diff --git a/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cmpxchg_strong.h b/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cmpxchg_strong.h index 42117a1a..8217f232 100644 --- a/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cmpxchg_strong.h +++ b/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cmpxchg_strong.h @@ -10,7 +10,6 @@ #pragma once #endif - #if defined(EA_PROCESSOR_X86_64) #define EASTL_MSVC_ATOMIC_CMPXCHG_STRONG_INTRIN_8 _InterlockedCompareExchange8 diff --git a/include/EASTL/internal/config.h b/include/EASTL/internal/config.h index 530bbc87..8dc14202 100644 --- a/include/EASTL/internal/config.h +++ b/include/EASTL/internal/config.h @@ -89,8 +89,8 @@ /////////////////////////////////////////////////////////////////////////////// #ifndef EASTL_VERSION - #define EASTL_VERSION "3.17.06" - #define EASTL_VERSION_N 31706 + #define EASTL_VERSION "3.18.00" + #define EASTL_VERSION_N 31800 #endif @@ -864,7 +864,7 @@ namespace eastl #if EASTL_INT128_SUPPORTED #define EASTL_INT128_DEFINED 1 - #if defined(__SIZEOF_INT128__) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG) + #if defined(__SIZEOF_INT128__) || defined(EA_COMPILER_GNUC) || defined(__clang__) typedef __int128_t eastl_int128_t; typedef __uint128_t eastl_uint128_t; #else @@ -1274,7 +1274,7 @@ namespace eastl // useful macro identifier for our type traits implementation. // #ifndef EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE - #if defined(_MSC_VER) && (_MSC_VER >= 1500) // VS2008 or later + #if defined(_MSC_VER) && (_MSC_VER >= 1500) && !defined(EA_COMPILER_CLANG_CL) // VS2008 or later #pragma warning(push, 0) #include #pragma warning(pop) @@ -1283,9 +1283,9 @@ namespace eastl #else #define EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE 0 #endif - #elif defined(EA_COMPILER_CLANG) && defined(__APPLE__) && defined(_CXXCONFIG) // Apple clang but with GCC's libstdc++. + #elif defined(__clang__) && defined(__APPLE__) && defined(_CXXCONFIG) // Apple clang but with GCC's libstdc++. #define EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE 0 - #elif defined(EA_COMPILER_CLANG) + #elif defined(__clang__) #define EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE 1 #elif defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003) && !defined(__GCCXML__) #define EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE 1 @@ -1836,14 +1836,14 @@ typedef EASTL_SSIZE_T eastl_ssize_t; // Signed version of eastl_size_t. Concept /// EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE -#if defined(_MSC_VER) && (_MSC_VER >= 1913) // VS2017+ - #define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 1 -#elif defined(EA_COMPILER_CLANG) +#if defined(__clang__) #if !__is_identifier(__has_unique_object_representations) #define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 1 #else #define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 0 #endif +#elif defined(_MSC_VER) && (_MSC_VER >= 1913) // VS2017+ + #define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 1 #else #define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 0 #endif @@ -1873,5 +1873,17 @@ typedef EASTL_SSIZE_T eastl_ssize_t; // Signed version of eastl_size_t. Concept #define EASTL_SYSTEM_LITTLE_ENDIAN_STATEMENT(...) #endif +/// EASTL_CONSTEXPR_BIT_CAST_SUPPORTED +/// eastl::bit_cast, in order to be implemented as constexpr, requires explicit compiler support. +/// This macro defines whether it's possible for bit_cast to be constexpr. +/// +#if (defined(EA_COMPILER_MSVC) && defined(EA_COMPILER_MSVC_VERSION_14_26) && EA_COMPILER_VERSION >= EA_COMPILER_MSVC_VERSION_14_26) \ + || EA_COMPILER_HAS_BUILTIN(__builtin_bit_cast) + #define EASTL_CONSTEXPR_BIT_CAST_SUPPORTED 1 +#else + #define EASTL_CONSTEXPR_BIT_CAST_SUPPORTED 0 +#endif + + #endif // Header include guard diff --git a/include/EASTL/internal/copy_help.h b/include/EASTL/internal/copy_help.h index e5fb2abd..67b5d876 100644 --- a/include/EASTL/internal/copy_help.h +++ b/include/EASTL/internal/copy_help.h @@ -6,12 +6,12 @@ #ifndef EASTL_INTERNAL_COPY_HELP_H #define EASTL_INTERNAL_COPY_HELP_H +#include #if defined(EA_PRAGMA_ONCE_SUPPORTED) #pragma once #endif -#include #include #include #include // memcpy, memcmp, memmove @@ -19,15 +19,15 @@ namespace eastl { - /// move / move_n / move_backward + /// move / move_n / move_backward /// copy / copy_n / copy_backward /// /// We want to optimize move, move_n, move_backward, copy, copy_backward, copy_n to do memmove operations - /// when possible. + /// when possible. /// - /// We could possibly use memcpy, though it has stricter overlap requirements than the move and copy - /// algorithms and would require a runtime if/else to choose it over memmove. In particular, memcpy - /// allows no range overlap at all, whereas move/copy allow output end overlap and move_backward/copy_backward + /// We could possibly use memcpy, though it has stricter overlap requirements than the move and copy + /// algorithms and would require a runtime if/else to choose it over memmove. In particular, memcpy + /// allows no range overlap at all, whereas move/copy allow output end overlap and move_backward/copy_backward /// allow output begin overlap. Despite this it might be useful to use memcpy for any platforms where /// memcpy is significantly faster than memmove, and since in most cases the copy/move operation in fact /// doesn't target overlapping memory and so memcpy would be usable. @@ -36,13 +36,13 @@ namespace eastl /// InputIterator and OutputIterator are of the same type. /// InputIterator and OutputIterator are of type contiguous_iterator_tag or simply are pointers (the two are virtually synonymous). /// is_trivially_copyable::value is true. i.e. the constructor T(const T& t) (or T(T&& t) if present) can be replaced by memmove(this, &t, sizeof(T)) - /// - /// copy normally differs from move, but there is a case where copy is the same as move: when copy is - /// used with a move_iterator. We handle that case here by detecting that copy is being done with a + /// + /// copy normally differs from move, but there is a case where copy is the same as move: when copy is + /// used with a move_iterator. We handle that case here by detecting that copy is being done with a /// move_iterator and redirect it to move (which can take advantage of memmove/memcpy). /// - /// The generic_iterator class is typically used for wrapping raw memory pointers so they can act like - /// formal iterators. Since pointers provide an opportunity for memmove/memcpy operations, we can + /// The generic_iterator class is typically used for wrapping raw memory pointers so they can act like + /// formal iterators. Since pointers provide an opportunity for memmove/memcpy operations, we can /// detect a generic iterator and use it's wrapped type as a pointer if it happens to be one. // Implementation moving copying both trivial and non-trivial data via a lesser iterator than random-access. @@ -61,7 +61,7 @@ namespace eastl // Specialization for copying non-trivial data via a random-access iterator. It's theoretically faster because the compiler can see the count when its a compile-time const. // This specialization converts the random access InputIterator last-first to an integral type. There's simple way for us to take advantage of a random access output iterator, // as the range is specified by the input instead of the output, and distance(first, last) for a non-random-access iterator is potentially slow. - template <> + template <> struct move_and_copy_helper { template @@ -88,7 +88,7 @@ namespace eastl return result; } }; - + // Specialization for moving non-trivial data via a random-access iterator. It's theoretically faster because the compiler can see the count when its a compile-time const. template <> struct move_and_copy_helper @@ -130,9 +130,9 @@ namespace eastl typedef typename eastl::iterator_traits::value_type value_type_input; typedef typename eastl::iterator_traits::value_type value_type_output; - const bool canBeMemmoved = eastl::is_trivially_copyable::value && - eastl::is_same::value && - (eastl::is_pointer::value || eastl::is_same::value) && + const bool canBeMemmoved = eastl::is_trivially_copyable::value && + eastl::is_same::value && + (eastl::is_pointer::value || eastl::is_same::value) && (eastl::is_pointer::value || eastl::is_same::value); return eastl::move_and_copy_helper::move_or_copy(first, last, result); // Need to chose based on the input iterator tag and not the output iterator tag, because containers accept input ranges of iterator types different than self. @@ -149,11 +149,11 @@ namespace eastl /// move /// - /// After this operation the elements in the moved-from range will still contain valid values of the - /// appropriate type, but not necessarily the same values as before the move. + /// After this operation the elements in the moved-from range will still contain valid values of the + /// appropriate type, but not necessarily the same values as before the move. /// Returns the end of the result range. /// Note: When moving between containers, the dest range must be valid; this function doesn't resize containers. - /// Note: if result is within [first, last), move_backward must be used instead of move. + /// Note: if result is within [first, last), move_backward must be used instead of move. /// /// Example usage: /// eastl::move(myArray.begin(), myArray.end(), myDestArray.begin()); @@ -180,7 +180,7 @@ namespace eastl /// starting from first and proceeding to last. For each nonnegative integer n < (last - first), /// performs *(result + n) = *(first + n). /// - /// Returns: result + (last - first). That is, returns the end of the result. Note that this + /// Returns: result + (last - first). That is, returns the end of the result. Note that this /// is different from how memmove/memcpy work, as they return the beginning of the result. /// /// Requires: result shall not be in the range [first, last). But the end of the result range @@ -197,19 +197,4 @@ namespace eastl } } // namespace eastl -#endif // Header include guard - - - - - - - - - - - - - - - +#endif // EASTL_INTERNAL_COPY_HELP_H diff --git a/include/EASTL/internal/fill_help.h b/include/EASTL/internal/fill_help.h index 235a24ee..07e3b62d 100644 --- a/include/EASTL/internal/fill_help.h +++ b/include/EASTL/internal/fill_help.h @@ -85,7 +85,7 @@ namespace eastl } - #if(defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) && (defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64)) + #if (defined(EA_COMPILER_GNUC) || defined(__clang__)) && (defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64)) #if defined(EA_PROCESSOR_X86_64) template inline void fill(uint64_t* first, uint64_t* last, Value c) @@ -327,7 +327,7 @@ namespace eastl } #endif - #if(defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) && (defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64)) + #if (defined(EA_COMPILER_GNUC) || defined(__clang__)) && (defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64)) #if defined(EA_PROCESSOR_X86_64) template inline uint64_t* fill_n(uint64_t* first, Size n, Value c) diff --git a/include/EASTL/internal/fixed_pool.h b/include/EASTL/internal/fixed_pool.h index 5a380046..4d710354 100644 --- a/include/EASTL/internal/fixed_pool.h +++ b/include/EASTL/internal/fixed_pool.h @@ -1362,12 +1362,11 @@ namespace eastl { } - // Disabled because the default is sufficient. - //fixed_vector_allocator(const fixed_vector_allocator& x) - //{ - // mpPoolBegin = x.mpPoolBegin; - // mOverflowAllocator = x.mOverflowAllocator; - //} + fixed_vector_allocator(const fixed_vector_allocator& x) + { + mpPoolBegin = x.mpPoolBegin; + mOverflowAllocator = x.mOverflowAllocator; + } fixed_vector_allocator& operator=(const fixed_vector_allocator& x) { diff --git a/include/EASTL/internal/function.h b/include/EASTL/internal/function.h index 6e857f0b..785969d2 100644 --- a/include/EASTL/internal/function.h +++ b/include/EASTL/internal/function.h @@ -5,6 +5,8 @@ #ifndef EASTL_FUNCTION_H #define EASTL_FUNCTION_H +#include + #if defined(EA_PRAGMA_ONCE_SUPPORTED) #pragma once #endif diff --git a/include/EASTL/internal/function_detail.h b/include/EASTL/internal/function_detail.h index dc18b631..3ee36677 100644 --- a/include/EASTL/internal/function_detail.h +++ b/include/EASTL/internal/function_detail.h @@ -95,7 +95,7 @@ namespace eastl template struct is_functor_inplace_allocatable { - static constexpr bool value = + static EA_CONSTEXPR bool value = sizeof(Functor) <= sizeof(functor_storage) && (eastl::alignment_of_v> % eastl::alignment_of_v) == 0; }; diff --git a/include/EASTL/internal/functional_base.h b/include/EASTL/internal/functional_base.h index a7d2dc91..ef27800b 100644 --- a/include/EASTL/internal/functional_base.h +++ b/include/EASTL/internal/functional_base.h @@ -6,21 +6,23 @@ #ifndef EASTL_INTERNAL_FUNCTIONAL_BASE_H #define EASTL_INTERNAL_FUNCTIONAL_BASE_H +#include + #if defined(EA_PRAGMA_ONCE_SUPPORTED) #pragma once #endif -#include #include #include #include + namespace eastl { // foward declaration for swap template inline void swap(T& a, T& b) - EA_NOEXCEPT_IF(eastl::is_nothrow_move_constructible::value&& eastl::is_nothrow_move_assignable::value); + EA_NOEXCEPT_IF(eastl::is_nothrow_move_constructible::value && eastl::is_nothrow_move_assignable::value); /// invoke @@ -39,44 +41,47 @@ namespace eastl /// http://en.cppreference.com/w/cpp/utility/functional/invoke /// template - auto invoke_impl(R C::*func, T&& obj, Args&&... args) -> - typename enable_if>::value, + EA_CONSTEXPR auto invoke_impl(R C::*func, T&& obj, Args&&... args) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR((eastl::forward(obj).*func)(eastl::forward(args)...))) + -> typename enable_if>::value, decltype((eastl::forward(obj).*func)(eastl::forward(args)...))>::type { return (eastl::forward(obj).*func)(eastl::forward(args)...); } template - auto invoke_impl(F&& func, Args&&... args) -> decltype(eastl::forward(func)(eastl::forward(args)...)) + EA_CONSTEXPR auto invoke_impl(F&& func, Args&&... args) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(eastl::forward(func)(eastl::forward(args)...))) + -> decltype(eastl::forward(func)(eastl::forward(args)...)) { return eastl::forward(func)(eastl::forward(args)...); } template - auto invoke_impl(R C::*func, T&& obj, Args&&... args) -> decltype(((*eastl::forward(obj)).*func)(eastl::forward(args)...)) + EA_CONSTEXPR auto invoke_impl(R C::*func, T&& obj, Args&&... args) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(((*eastl::forward(obj)).*func)(eastl::forward(args)...))) + -> decltype(((*eastl::forward(obj)).*func)(eastl::forward(args)...)) { return ((*eastl::forward(obj)).*func)(eastl::forward(args)...); } template - auto invoke_impl(M C::*member, T&& obj) -> - typename enable_if< - is_base_of>::value, - decltype(obj.*member) + EA_CONSTEXPR auto invoke_impl(M C::*member, T&& obj) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(eastl::forward(obj).*member)) + -> typename enable_if< + is_base_of>::value, + decltype(eastl::forward(obj).*member) >::type { - return obj.*member; + return eastl::forward(obj).*member; } template - auto invoke_impl(M C::*member, T&& obj) -> decltype((*eastl::forward(obj)).*member) + EA_CONSTEXPR auto invoke_impl(M C::*member, T&& obj) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR((*eastl::forward(obj)).*member)) + -> decltype((*eastl::forward(obj)).*member) { return (*eastl::forward(obj)).*member; } template - inline decltype(auto) invoke(F&& func, Args&&... args) + EA_CONSTEXPR decltype(auto) invoke(F&& func, Args&&... args) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(invoke_impl(eastl::forward(func), eastl::forward(args)...))) { return invoke_impl(eastl::forward(func), eastl::forward(args)...); } @@ -86,9 +91,9 @@ namespace eastl }; template - struct invoke_result_impl>(), eastl::declval()...))>, Args...> + struct invoke_result_impl(), eastl::declval()...))>, Args...> { - typedef decltype(invoke_impl(eastl::declval>(), eastl::declval()...)) type; + typedef decltype(invoke_impl(eastl::declval(), eastl::declval()...)) type; }; template @@ -118,13 +123,40 @@ namespace eastl template struct is_invocable_r : public is_invocable_r_impl {}; - #if EASTL_VARIABLE_TEMPLATES_ENABLED - template - EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool is_invocable_v = is_invocable::value; + template + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool is_invocable_v = is_invocable::value; - template - EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool is_invocable_r_v = is_invocable_r::value; - #endif + template + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool is_invocable_r_v = is_invocable_r::value; + + template + struct is_nothrow_invocable_impl : public eastl::false_type {}; + + template + struct is_nothrow_invocable_impl::type>, Args...> + : public eastl::bool_constant(), eastl::declval()...))> {}; + + template + struct is_nothrow_invocable : public is_nothrow_invocable_impl {}; + + template + struct is_nothrow_invocable_r_impl : public eastl::false_type {}; + + template + struct is_nothrow_invocable_r_impl::type>, Args...> + { + static EA_CONSTEXPR_OR_CONST bool value = eastl::is_convertible::type, R>::value + && eastl::is_nothrow_invocable::value; + }; + + template + struct is_nothrow_invocable_r : public is_nothrow_invocable_r_impl {}; + + template + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool is_no_throw_invocable_v = is_nothrow_invocable::value; + + template + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool is_nothrow_invocable_r_v = is_nothrow_invocable_r::value; /// allocator_arg_t /// @@ -144,9 +176,7 @@ namespace eastl /// such as tuple, function, promise, and packaged_task. /// http://en.cppreference.com/w/cpp/memory/allocator_arg /// - #if !defined(EA_COMPILER_NO_CONSTEXPR) - EA_CONSTEXPR allocator_arg_t allocator_arg = allocator_arg_t(); - #endif + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR allocator_arg_t allocator_arg = allocator_arg_t(); template @@ -248,7 +278,7 @@ namespace eastl template reference_wrapper ref(T& t) EA_NOEXCEPT { - return eastl::reference_wrapper(t); + return eastl::reference_wrapper(t); } template @@ -307,16 +337,16 @@ namespace eastl // These have to come after reference_wrapper is defined, but reference_wrapper needs to have a // definition of invoke, so these specializations need to come after everything else has been defined. template - auto invoke_impl(R (C::*func)(Args...), T&& obj, Args&&... args) -> - typename enable_if::type>::value, + EA_CONSTEXPR auto invoke_impl(R C::*func, T&& obj, Args&&... args) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR((obj.get().*func)(eastl::forward(args)...))) + -> typename enable_if>::value, decltype((obj.get().*func)(eastl::forward(args)...))>::type { return (obj.get().*func)(eastl::forward(args)...); } template - auto invoke_impl(M(C::*member), T&& obj) -> - typename enable_if::type>::value, + EA_CONSTEXPR auto invoke_impl(M C::*member, T&& obj) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(obj.get().*member)) + -> typename enable_if>::value, decltype(obj.get().*member)>::type { return obj.get().*member; @@ -386,4 +416,4 @@ namespace eastl } // namespace eastl -#endif // Header include guard +#endif // EASTL_INTERNAL_FUNCTIONAL_BASE_H diff --git a/include/EASTL/internal/hashtable.h b/include/EASTL/internal/hashtable.h index bb6d27eb..a9347b18 100644 --- a/include/EASTL/internal/hashtable.h +++ b/include/EASTL/internal/hashtable.h @@ -1572,7 +1572,7 @@ namespace eastl typename hashtable::node_type* hashtable::DoAllocateNodeFromKey(const key_type& key) { - node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0); + node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); #if EASTL_EXCEPTIONS_ENABLED @@ -1598,7 +1598,7 @@ namespace eastl typename hashtable::node_type* hashtable::DoAllocateNodeFromKey(key_type&& key) { - node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0); + node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); #if EASTL_EXCEPTIONS_ENABLED @@ -2105,7 +2105,7 @@ namespace eastl typename hashtable::node_type* hashtable::DoAllocateNode(Args&&... args) { - node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0); + node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); #if EASTL_EXCEPTIONS_ENABLED @@ -2283,7 +2283,7 @@ namespace eastl typename hashtable::node_type* hashtable::DoAllocateNode(value_type&& value) { - node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0); + node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); #if EASTL_EXCEPTIONS_ENABLED @@ -2453,7 +2453,7 @@ namespace eastl typename hashtable::node_type* hashtable::DoAllocateNode(const value_type& value) { - node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0); + node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); #if EASTL_EXCEPTIONS_ENABLED @@ -2480,7 +2480,7 @@ namespace eastl hashtable::allocate_uninitialized_node() { // We don't wrap this in try/catch because users of this function are expected to do that themselves as needed. - node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0); + node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); // Leave pNode->mValue uninitialized. pNode->mpNext = NULL; diff --git a/include/EASTL/internal/integer_sequence.h b/include/EASTL/internal/integer_sequence.h index 88cf1b1b..2a5539dd 100644 --- a/include/EASTL/internal/integer_sequence.h +++ b/include/EASTL/internal/integer_sequence.h @@ -67,6 +67,36 @@ using make_integer_sequence = typename make_integer_sequence_impl::type; template using index_sequence_for = make_index_sequence; +namespace internal +{ + +template +struct integer_sequence_size_helper; + +template +struct integer_sequence_size_helper> : public integral_constant +{ +}; + +template +struct integer_sequence_size : public integer_sequence_size_helper> +{ +}; + +template +struct index_sequence_size : public integer_sequence_size_helper> +{ +}; + +template +EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR size_t integer_sequence_size_v = integer_sequence_size::value; + +template +EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR size_t index_sequence_size_v = index_sequence_size::value; + + +} // namespace internal + #endif // EASTL_VARIADIC_TEMPLATES_ENABLED } // namespace eastl diff --git a/include/EASTL/internal/red_black_tree.h b/include/EASTL/internal/red_black_tree.h index 7448bd42..111fbb42 100644 --- a/include/EASTL/internal/red_black_tree.h +++ b/include/EASTL/internal/red_black_tree.h @@ -169,6 +169,7 @@ namespace eastl rbtree_iterator(); explicit rbtree_iterator(const node_type* pNode); rbtree_iterator(const iterator& x); + rbtree_iterator& operator=(const iterator& x); reference operator*() const; pointer operator->() const; @@ -662,6 +663,13 @@ namespace eastl rbtree_iterator::rbtree_iterator(const iterator& x) : mpNode(x.mpNode) { } + template + typename rbtree_iterator::this_type& + rbtree_iterator::operator=(const iterator& x) + { + mpNode = x.mpNode; + return *this; + } template typename rbtree_iterator::reference diff --git a/include/EASTL/internal/smart_ptr.h b/include/EASTL/internal/smart_ptr.h index f1d52e1b..8a37950f 100644 --- a/include/EASTL/internal/smart_ptr.h +++ b/include/EASTL/internal/smart_ptr.h @@ -162,7 +162,10 @@ namespace eastl default_delete(const default_delete&, typename eastl::enable_if::value>::type* = 0) EA_NOEXCEPT {} void operator()(T* p) const EA_NOEXCEPT - { delete p; } + { + static_assert(eastl::internal::is_complete_type_v, "Attempting to call the destructor of an incomplete type"); + delete p; + } }; diff --git a/include/EASTL/internal/thread_support.h b/include/EASTL/internal/thread_support.h index 80386d20..60272a98 100644 --- a/include/EASTL/internal/thread_support.h +++ b/include/EASTL/internal/thread_support.h @@ -19,10 +19,12 @@ // // fatal error C1189: is not supported when compiling with /clr or /clr:pure ///////////////////////////////////////////////////////////////////////////////////////////////////// -#if defined(EA_HAVE_CPP11_MUTEX) && !defined(EA_COMPILER_MANAGED_CPP) - #define EASTL_CPP11_MUTEX_ENABLED 1 -#else - #define EASTL_CPP11_MUTEX_ENABLED 0 +#if !defined(EASTL_CPP11_MUTEX_ENABLED) + #if defined(EA_HAVE_CPP11_MUTEX) && !defined(EA_COMPILER_MANAGED_CPP) + #define EASTL_CPP11_MUTEX_ENABLED 1 + #else + #define EASTL_CPP11_MUTEX_ENABLED 0 + #endif #endif #if EASTL_CPP11_MUTEX_ENABLED @@ -77,7 +79,7 @@ EA_DISABLE_VC_WARNING(4625 4626 4275); /////////////////////////////////////////////////////////////////////////////// #if !defined(EASTL_THREAD_SUPPORT_AVAILABLE) - #if defined(EA_COMPILER_CLANG) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)) + #if defined(__clang__) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)) #define EASTL_THREAD_SUPPORT_AVAILABLE 1 #elif defined(EA_COMPILER_MSVC) #define EASTL_THREAD_SUPPORT_AVAILABLE 1 @@ -95,7 +97,7 @@ namespace eastl /// Returns the new value. inline int32_t atomic_increment(int32_t* p32) EA_NOEXCEPT { - #if defined(EA_COMPILER_CLANG) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)) + #if defined(__clang__) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)) return __sync_add_and_fetch(p32, 1); #elif defined(EA_COMPILER_MSVC) static_assert(sizeof(long) == sizeof(int32_t), "unexpected size"); @@ -118,7 +120,7 @@ namespace eastl /// Returns the new value. inline int32_t atomic_decrement(int32_t* p32) EA_NOEXCEPT { - #if defined(EA_COMPILER_CLANG) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)) + #if defined(__clang__) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)) return __sync_add_and_fetch(p32, -1); #elif defined(EA_COMPILER_MSVC) return _InterlockedDecrement((volatile long*)p32); // volatile long cast is OK because int32_t == long on Microsoft platforms. @@ -145,7 +147,7 @@ namespace eastl /// the two as would be the case with simple C code. inline bool atomic_compare_and_swap(int32_t* p32, int32_t newValue, int32_t condition) { - #if defined(EA_COMPILER_CLANG) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)) + #if defined(__clang__) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)) return __sync_bool_compare_and_swap(p32, condition, newValue); #elif defined(EA_COMPILER_MSVC) return ((int32_t)_InterlockedCompareExchange((volatile long*)p32, (long)newValue, (long)condition) == condition); diff --git a/include/EASTL/internal/type_compound.h b/include/EASTL/internal/type_compound.h index 178a7342..1f852509 100644 --- a/include/EASTL/internal/type_compound.h +++ b/include/EASTL/internal/type_compound.h @@ -290,7 +290,7 @@ namespace eastl // is_convertible::value; // Generates compiler error. /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_convertible_to))) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_convertible_to))) #define EASTL_TYPE_TRAIT_is_convertible_CONFORMANCE 1 // is_convertible is conforming. // Problem: VC++ reports that int is convertible to short, yet if you construct a short from an int then VC++ generates a warning: @@ -371,7 +371,7 @@ namespace eastl // via 'msl::is_union::value'. The user can force something to be // evaluated as a union via EASTL_DECLARE_UNION. /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_union))) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_union))) #define EASTL_TYPE_TRAIT_is_union_CONFORMANCE 1 // is_union is conforming. template @@ -401,7 +401,7 @@ namespace eastl // distinguish between unions and classes. As a result, is_class // will erroneously evaluate to true for union types. /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_class))) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_class))) #define EASTL_TYPE_TRAIT_is_class_CONFORMANCE 1 // is_class is conforming. template @@ -442,57 +442,6 @@ namespace eastl #endif - /////////////////////////////////////////////////////////////////////// - // is_enum - // - // is_enum::value == true if and only if T is an enumeration type. - // - /////////////////////////////////////////////////////////////////////// - - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_enum))) - #define EASTL_TYPE_TRAIT_is_enum_CONFORMANCE 1 // is_enum is conforming. - - template - struct is_enum : public integral_constant{}; - #else - #define EASTL_TYPE_TRAIT_is_enum_CONFORMANCE 1 // is_enum is conforming. - - struct int_convertible{ int_convertible(int); }; - - template - struct is_enum_helper { template struct nest : public is_convertible{}; }; - - template <> - struct is_enum_helper { template struct nest : public false_type {}; }; - - template - struct is_enum_helper2 - { - typedef type_or::value, is_reference::value, is_class::value> selector; - typedef is_enum_helper helper_t; - typedef typename add_reference::type ref_t; - typedef typename helper_t::template nest result; - }; - - template - struct is_enum : public integral_constant::result::value>{}; - - template <> struct is_enum : public false_type {}; - template <> struct is_enum : public false_type {}; - template <> struct is_enum : public false_type {}; - template <> struct is_enum : public false_type {}; - #endif - - #if EASTL_VARIABLE_TEMPLATES_ENABLED - template - EA_CONSTEXPR bool is_enum_v = is_enum::value; - #endif - - #define EASTL_DECLARE_ENUM(T) namespace eastl{ template <> struct is_enum : public true_type{}; template <> struct is_enum : public true_type{}; } - - - - /////////////////////////////////////////////////////////////////////// // is_polymorphic @@ -503,7 +452,7 @@ namespace eastl // /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_polymorphic))) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_polymorphic))) #define EASTL_TYPE_TRAIT_is_polymorphic_CONFORMANCE 1 // is_polymorphic is conforming. template diff --git a/include/EASTL/internal/type_fundamental.h b/include/EASTL/internal/type_fundamental.h index 950d15e3..5ff9259e 100644 --- a/include/EASTL/internal/type_fundamental.h +++ b/include/EASTL/internal/type_fundamental.h @@ -139,7 +139,7 @@ namespace eastl #ifndef EA_WCHAR_T_NON_NATIVE // If wchar_t is a native type instead of simply a define to an existing type which is already handled above... template <> struct is_integral_helper : public true_type{}; #endif - #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(__clang__)) template <> struct is_integral_helper<__int128_t> : public true_type{}; template <> struct is_integral_helper<__uint128_t> : public true_type{}; #endif @@ -262,6 +262,59 @@ namespace eastl EA_CONSTEXPR bool is_hat_type_v = is_hat_type::value; #endif + + + /////////////////////////////////////////////////////////////////////// + // is_enum + // + // is_enum::value == true if and only if T is an enumeration type. + // + /////////////////////////////////////////////////////////////////////// + + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_enum))) + #define EASTL_TYPE_TRAIT_is_enum_CONFORMANCE 1 // is_enum is conforming. + + template + struct is_enum : public integral_constant{}; + #else + #define EASTL_TYPE_TRAIT_is_enum_CONFORMANCE 1 // is_enum is conforming. + + struct int_convertible{ int_convertible(int); }; + + template + struct is_enum_helper { template struct nest : public is_convertible{}; }; + + template <> + struct is_enum_helper { template struct nest : public false_type {}; }; + + template + struct is_enum_helper2 + { + typedef type_or::value, is_reference::value, is_class::value> selector; + typedef is_enum_helper helper_t; + typedef typename add_reference::type ref_t; + typedef typename helper_t::template nest result; + }; + + template + struct is_enum : public integral_constant::result::value>{}; + + template <> struct is_enum : public false_type {}; + template <> struct is_enum : public false_type {}; + template <> struct is_enum : public false_type {}; + template <> struct is_enum : public false_type {}; + #endif + + #if EASTL_VARIABLE_TEMPLATES_ENABLED + template + EA_CONSTEXPR bool is_enum_v = is_enum::value; + #endif + + #define EASTL_DECLARE_ENUM(T) namespace eastl{ template <> struct is_enum : public true_type{}; template <> struct is_enum : public true_type{}; } + + + + } // namespace eastl diff --git a/include/EASTL/internal/type_pod.h b/include/EASTL/internal/type_pod.h index 8726a7e6..998e9574 100644 --- a/include/EASTL/internal/type_pod.h +++ b/include/EASTL/internal/type_pod.h @@ -25,7 +25,7 @@ namespace eastl // // is_empty cannot be used with union types until is_union can be made to work. /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_empty))) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_empty))) #define EASTL_TYPE_TRAIT_is_empty_CONFORMANCE 1 // is_empty is conforming. template @@ -90,7 +90,7 @@ namespace eastl struct is_pod : public eastl::integral_constant::value) || eastl::is_void::value || eastl::is_scalar::value>{}; EA_RESTORE_VC_WARNING() - #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_pod))) + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_pod))) #define EASTL_TYPE_TRAIT_is_pod_CONFORMANCE 1 // is_pod is conforming. template @@ -128,7 +128,7 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // is_standard_layout // - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(EA_COMPILER_MSVC) && (_MSC_VER >= 1700)) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4006)) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_standard_layout))) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(EA_COMPILER_MSVC) && (_MSC_VER >= 1700)) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4006)) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_standard_layout))) #define EASTL_TYPE_TRAIT_is_standard_layout_CONFORMANCE 1 // is_standard_layout is conforming. template @@ -182,12 +182,12 @@ namespace eastl // can be called without an argument. /////////////////////////////////////////////////////////////////////// - #if defined(_MSC_VER) && (_MSC_VER >= 1600) // VS2010+ + #if defined(_MSC_VER) && (_MSC_VER >= 1600) && !defined(EA_COMPILER_CLANG_CL) // VS2010+ #define EASTL_TYPE_TRAIT_has_trivial_constructor_CONFORMANCE 1 // has_trivial_constructor is conforming. template struct has_trivial_constructor : public eastl::integral_constant::value) && !eastl::is_hat_type::value>{}; - #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_has_trivial_constructor_CONFORMANCE 1 // has_trivial_constructor is conforming. template @@ -242,12 +242,12 @@ namespace eastl // use EASTL_DECLARE_TRIVIAL_COPY to help the compiler. /////////////////////////////////////////////////////////////////////// - #if defined(_MSC_VER) + #if defined(_MSC_VER) && !defined(EA_COMPILER_CLANG_CL) #define EASTL_TYPE_TRAIT_has_trivial_copy_CONFORMANCE 1 // has_trivial_copy is conforming. template struct has_trivial_copy : public eastl::integral_constant::value) && !eastl::is_volatile::value && !eastl::is_hat_type::value>{}; - #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_has_trivial_copy_CONFORMANCE 1 // has_trivial_copy is conforming. template @@ -292,12 +292,12 @@ namespace eastl // can use EASTL_DECLARE_TRIVIAL_ASSIGN to help the compiler. /////////////////////////////////////////////////////////////////////// - #if defined(_MSC_VER) && (_MSC_VER >= 1600) + #if defined(_MSC_VER) && (_MSC_VER >= 1600) && !defined(EA_COMPILER_CLANG_CL) #define EASTL_TYPE_TRAIT_has_trivial_assign_CONFORMANCE 1 // has_trivial_assign is conforming. template struct has_trivial_assign : public integral_constant::value) && !eastl::is_const::value && !eastl::is_volatile::value && !eastl::is_hat_type::value>{}; - #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_has_trivial_assign_CONFORMANCE 1 // has_trivial_assign is conforming. template @@ -341,12 +341,12 @@ namespace eastl // The user can use EASTL_DECLARE_TRIVIAL_DESTRUCTOR to help the compiler. /////////////////////////////////////////////////////////////////////// - #if defined(_MSC_VER) && (_MSC_VER >= 1600) + #if defined(_MSC_VER) && (_MSC_VER >= 1600) && !defined(EA_COMPILER_CLANG_CL) #define EASTL_TYPE_TRAIT_has_trivial_destructor_CONFORMANCE 1 // has_trivial_destructor is conforming. template struct has_trivial_destructor : public eastl::integral_constant::value) && !eastl::is_hat_type::value>{}; - #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_has_trivial_destructor_CONFORMANCE 1 // has_trivial_destructor is conforming. template @@ -412,7 +412,7 @@ namespace eastl // /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_has_nothrow_constructor_CONFORMANCE 1 template @@ -452,7 +452,7 @@ namespace eastl // /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_has_nothrow_copy_CONFORMANCE 1 template @@ -491,7 +491,7 @@ namespace eastl // /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_has_nothrow_assign_CONFORMANCE 1 template @@ -529,7 +529,7 @@ namespace eastl // /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_has_virtual_destructor_CONFORMANCE 1 template @@ -571,7 +571,7 @@ namespace eastl // /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_literal)) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_literal)) #define EASTL_TYPE_TRAIT_is_literal_type_CONFORMANCE 1 template @@ -615,7 +615,7 @@ namespace eastl // /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_abstract))) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_abstract))) #define EASTL_TYPE_TRAIT_is_abstract_CONFORMANCE 1 // is_abstract is conforming. template @@ -672,7 +672,7 @@ namespace eastl // up obj1 are copied into obj2, obj2 shall subsequently hold the // same value as obj1. In other words, you can memcpy/memmove it. /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(_MSC_VER) && (_MSC_VER >= 1700)) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 5003)) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_trivially_copyable))) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(_MSC_VER) && (_MSC_VER >= 1700)) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 5003)) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_trivially_copyable))) #define EASTL_TYPE_TRAIT_is_trivially_copyable_CONFORMANCE 1 // https://connect.microsoft.com/VisualStudio/feedback/details/808827/c-std-is-trivially-copyable-produces-wrong-result-for-arrays @@ -731,7 +731,7 @@ namespace eastl #define EASTL_TYPE_TRAIT_is_constructible_CONFORMANCE 1 - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_constructible))) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_constructible))) template struct is_constructible : public bool_constant<__is_constructible(T, Args...) > {}; #else @@ -850,7 +850,7 @@ namespace eastl // whether the __is_trivially_constructible compiler intrinsic is available. // If the compiler has this trait built-in (which ideally all compilers would have since it's necessary for full conformance) use it. - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_trivially_constructible)) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_trivially_constructible)) template struct is_trivially_constructible @@ -915,7 +915,7 @@ namespace eastl #else // If the compiler has this trait built-in (which ideally all compilers would have since it's necessary for full conformance) use it. - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_trivially_constructible)) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_trivially_constructible)) #define EASTL_TYPE_TRAIT_is_trivially_constructible_CONFORMANCE 1 // We have a problem with clang here as of clang 3.4: __is_trivially_constructible(int[]) is false, yet I believe it should be true. @@ -1380,7 +1380,7 @@ namespace eastl // arrays of unknown bound /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_trivially_assignable)) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_trivially_assignable)) #define EASTL_TYPE_TRAIT_is_trivially_assignable_CONFORMANCE 1 template @@ -1778,7 +1778,7 @@ namespace eastl struct is_trivially_destructible : integral_constant {}; - #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_is_trivially_destructible_CONFORMANCE EASTL_TYPE_TRAIT_is_destructible_CONFORMANCE template diff --git a/include/EASTL/internal/type_properties.h b/include/EASTL/internal/type_properties.h index 5276f878..df90fcbf 100644 --- a/include/EASTL/internal/type_properties.h +++ b/include/EASTL/internal/type_properties.h @@ -28,7 +28,7 @@ namespace eastl // /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(_MSC_VER) && (_MSC_VER >= 1700)) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4007)) || defined(EA_COMPILER_CLANG)) // VS2012+ + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(_MSC_VER) && (_MSC_VER >= 1700)) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4007)) || defined(__clang__)) // VS2012+ #define EASTL_TYPE_TRAIT_underlying_type_CONFORMANCE 1 // underlying_type is conforming. template @@ -46,6 +46,25 @@ namespace eastl using underlying_type_t = typename underlying_type::type; #endif + /////////////////////////////////////////////////////////////////////// + // to_underlying + // + // Cast a enum value to its underlying type. + // For example: + // + // enum class MyEnum : uint8_t { Value = 0; } + // auto x = MyEnum::Value; + // std::cout << to_underlying(x); // equivalent to sts::cout << static_cast(x); + /////////////////////////////////////////////////////////////////////// + + #if EASTL_VARIABLE_TEMPLATES_ENABLED && !defined(EA_COMPILER_NO_TEMPLATE_ALIASES) + template + constexpr underlying_type_t to_underlying(T value) noexcept + { + return static_cast>(value); + } + #endif + /////////////////////////////////////////////////////////////////////// // has_unique_object_representations @@ -281,7 +300,7 @@ namespace eastl // /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_base_of))) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || ((defined(__clang__)) && EA_COMPILER_HAS_FEATURE(is_base_of))) #define EASTL_TYPE_TRAIT_is_base_of_CONFORMANCE 1 // is_base_of is conforming. template @@ -374,6 +393,44 @@ namespace eastl EA_CONSTEXPR auto has_equality_v = has_equality::value; #endif + namespace internal + { + /////////////////////////////////////////////////////////////////////// + // is_complete_type + // + // Determines if the specified type is complete + // + // Warning: Be careful when using is_complete_type since the value is fixed at first instantiation. + // Consider the following: + // + // struct Foo; + // is_complete_type_v // false + // struct Foo {}; + // is_complete_type_v // still false + /////////////////////////////////////////////////////////////////////// + + template + struct is_complete_type : public false_type {}; + + template + struct is_complete_type> : public true_type {}; + + template<> + struct is_complete_type : public false_type {}; + template<> + struct is_complete_type : public false_type {}; + template<> + struct is_complete_type : public false_type {}; + template<> + struct is_complete_type : public false_type {}; + + template + struct is_complete_type>> : public true_type {}; + + template + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool is_complete_type_v = is_complete_type::value; + } + } // namespace eastl diff --git a/include/EASTL/internal/type_transformations.h b/include/EASTL/internal/type_transformations.h index cffa65e5..0853181d 100644 --- a/include/EASTL/internal/type_transformations.h +++ b/include/EASTL/internal/type_transformations.h @@ -111,54 +111,148 @@ namespace eastl // make_signed // // Used to convert an integral type to its signed equivalent, if not already. - // T shall be a (possibly const and/or volatile-qualified) integral type + // T shall be a (possibly const and/or volatile-qualified) integral type // or enumeration but not a bool type.; // - // The user can define their own make_signed overrides for their own + // The user can define their own make_signed overrides for their own // types by making a template specialization like done below and adding // it to the user's code. /////////////////////////////////////////////////////////////////////// - // To do: This implementation needs to be updated to support C++11 conformance (recognition of enums) and - // to support volatile-qualified types. It will probably be useful to have it fail for unsupported types. - #define EASTL_TYPE_TRAIT_make_signed_CONFORMANCE 0 // make_signed is only partially conforming. + #define EASTL_TYPE_TRAIT_make_signed_CONFORMANCE 1 - template struct make_signed { typedef T type; }; + namespace internal + { + template || eastl::is_integral_v> + struct make_signed_helper_0 + { + struct char_helper + { + typedef signed char type; + }; + + struct short_helper + { + typedef signed short type; + }; + + struct int_helper + { + typedef signed int type; + }; + + struct long_helper + { + typedef signed long type; + }; + + struct longlong_helper + { + typedef signed long long type; + }; + struct int128_helper + { + #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(__clang__)) + typedef __int128_t type; + #endif + }; + + struct no_type_helper + { + }; + + typedef typename + eastl::conditional + #else + no_type_helper + #endif + > + > + > + > + >::type type; + }; + + template + struct make_signed_helper_0 + { + struct no_type_helper + { + }; + + typedef no_type_helper type; + }; + + template + struct make_signed_helper_1 + { + typedef typename T::type type; + }; + + template + struct make_signed_helper + { + typedef typename eastl::internal::make_signed_helper_1::type>::type type; + }; + + } // namespace internal + + template + struct make_signed + { + typedef typename eastl::internal::make_signed_helper::type type; + }; + + template <> struct make_signed {}; + template <> struct make_signed { typedef signed char type; }; template <> struct make_signed { typedef signed char type; }; - template <> struct make_signed { typedef const signed char type; }; + template <> struct make_signed { typedef signed short type; }; template <> struct make_signed { typedef signed short type; }; - template <> struct make_signed { typedef const signed short type; }; + template <> struct make_signed { typedef signed int type; }; template <> struct make_signed { typedef signed int type; }; - template <> struct make_signed { typedef const signed int type; }; + template <> struct make_signed { typedef signed long type; }; template <> struct make_signed { typedef signed long type; }; - template <> struct make_signed { typedef const signed long type; }; + template <> struct make_signed { typedef signed long long type; }; template <> struct make_signed { typedef signed long long type; }; - template <> struct make_signed { typedef const signed long long type; }; + #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(__clang__)) + template <> struct make_signed<__int128_t> { typedef __int128_t type; }; + template <> struct make_signed<__uint128_t> { typedef __int128_t type; }; + #endif + #if (defined(CHAR_MAX) && defined(UCHAR_MAX) && (CHAR_MAX == UCHAR_MAX)) // If char is unsigned, we convert char to signed char. However, if char is signed then make_signed returns char itself and not signed char. template <> struct make_signed { typedef signed char type; }; - template <> struct make_signed { typedef signed char type; }; #endif - #ifndef EA_WCHAR_T_NON_NATIVE // If wchar_t is a native type instead of simply a define to an existing type... - #if (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ == 4294967295U)) // If wchar_t is a 32 bit unsigned value... - template<> - struct make_signed - { typedef int32_t type; }; - #elif (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ == 65535)) // If wchar_t is a 16 bit unsigned value... - template<> - struct make_signed - { typedef int16_t type; }; - #elif (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ == 255)) // If wchar_t is an 8 bit unsigned value... - template<> - struct make_signed - { typedef int8_t type; }; - #endif - #endif + template + struct make_signed + { + typedef eastl::add_const_t::type> type; + }; + + template + struct make_signed + { + typedef eastl::add_volatile_t::type> type; + }; + + template + struct make_signed + { + typedef eastl::add_cv_t::type> type; + }; #if EASTL_VARIABLE_TEMPLATES_ENABLED - template + template using make_signed_t = typename make_signed::type; #endif @@ -180,55 +274,151 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // make_unsigned // - // Used to convert an integral type to its signed equivalent, if not already. - // T shall be a (possibly const and/or volatile-qualified) integral type + // Used to convert an integral type to its unsigned equivalent, if not already. + // T shall be a (possibly const and/or volatile-qualified) integral type // or enumeration but not a bool type.; // - // The user can define their own make_signed overrides for their own + // The user can define their own make_unsigned overrides for their own // types by making a template specialization like done below and adding // it to the user's code. /////////////////////////////////////////////////////////////////////// - // To do: This implementation needs to be updated to support C++11 conformance (recognition of enums) and - // to support volatile-qualified types. It will probably be useful to have it fail for unsupported types. - #define EASTL_TYPE_TRAIT_make_unsigned_CONFORMANCE 0 // make_unsigned is only partially conforming. + #define EASTL_TYPE_TRAIT_make_unsigned_CONFORMANCE 1 - template struct make_unsigned { typedef T type; }; + namespace internal + { + template ::value || eastl::is_integral::value> + struct make_unsigned_helper_0 + { + struct char_helper + { + typedef unsigned char type; + }; + + struct short_helper + { + typedef unsigned short type; + }; + + struct int_helper + { + typedef unsigned int type; + }; + + struct long_helper + { + typedef unsigned long type; + }; + + struct longlong_helper + { + typedef unsigned long long type; + }; + + struct int128_helper + { + #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(__clang__)) + typedef __uint128_t type; + #endif + }; + + struct no_type_helper + { + }; + + + typedef typename + eastl::conditional + #else + no_type_helper + #endif + > + > + > + > + >::type type; + }; + + + template + struct make_unsigned_helper_0 + { + struct no_type_helper + { + }; + + typedef no_type_helper type; + }; + + template + struct make_unsigned_helper_1 + { + typedef typename T::type type; + }; + + template + struct make_unsigned_helper + { + typedef typename eastl::internal::make_unsigned_helper_1::type>::type type; + }; + + } // namespace internal + + template + struct make_unsigned + { + typedef typename eastl::internal::make_unsigned_helper::type type; + }; + + template <> struct make_unsigned {}; template <> struct make_unsigned { typedef unsigned char type; }; - template <> struct make_unsigned { typedef const unsigned char type; }; + template <> struct make_unsigned { typedef unsigned char type; }; template <> struct make_unsigned { typedef unsigned short type; }; - template <> struct make_unsigned { typedef const unsigned short type; }; + template <> struct make_unsigned { typedef unsigned short type; }; template <> struct make_unsigned { typedef unsigned int type; }; - template <> struct make_unsigned { typedef const unsigned int type; }; + template <> struct make_unsigned { typedef unsigned int type; }; template <> struct make_unsigned { typedef unsigned long type; }; - template <> struct make_unsigned { typedef const unsigned long type; }; + template <> struct make_unsigned { typedef unsigned long type; }; template <> struct make_unsigned { typedef unsigned long long type; }; - template <> struct make_unsigned { typedef const unsigned long long type; }; + template <> struct make_unsigned { typedef unsigned long long type; }; + #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(__clang__)) + template <> struct make_unsigned<__int128_t> { typedef __uint128_t type; }; + template <> struct make_unsigned<__uint128_t> { typedef __uint128_t type; }; + #endif #if (CHAR_MIN < 0) // If char is signed, we convert char to unsigned char. However, if char is unsigned then make_unsigned returns char itself and not unsigned char. template <> struct make_unsigned { typedef unsigned char type; }; - template <> struct make_unsigned { typedef unsigned char type; }; #endif - #ifndef EA_WCHAR_T_NON_NATIVE // If wchar_t is a native type instead of simply a define to an existing type... - #if (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ != 4294967295U)) // If wchar_t is a 32 bit signed value... - template<> - struct make_unsigned - { typedef uint32_t type; }; - #elif (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ != 65535)) // If wchar_t is a 16 bit signed value... - template<> - struct make_unsigned - { typedef uint16_t type; }; - #elif (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ != 255)) // If wchar_t is an 8 bit signed value... - template<> - struct make_unsigned - { typedef uint8_t type; }; - #endif - #endif + template + struct make_unsigned + { + typedef eastl::add_const_t::type> type; + }; + + template + struct make_unsigned + { + typedef eastl::add_volatile_t::type> type; + }; + + template + struct make_unsigned + { + typedef eastl::add_cv_t::type> type; + }; #if EASTL_VARIABLE_TEMPLATES_ENABLED - template + template using make_unsigned_t = typename make_unsigned::type; #endif diff --git a/include/EASTL/intrusive_list.h b/include/EASTL/intrusive_list.h index 18d7e93a..dc0129f3 100644 --- a/include/EASTL/intrusive_list.h +++ b/include/EASTL/intrusive_list.h @@ -146,6 +146,7 @@ namespace eastl intrusive_list_iterator(); explicit intrusive_list_iterator(pointer pNode); // Note that you can also construct an iterator from T via this, since value_type == node_type. intrusive_list_iterator(const iterator& x); + intrusive_list_iterator& operator=(const iterator& x); reference operator*() const; pointer operator->() const; @@ -368,6 +369,13 @@ namespace eastl // Empty } + template + inline typename intrusive_list_iterator::this_type& + intrusive_list_iterator::operator=(const iterator& x) + { + mpNode = x.mpNode; + return *this; + } template inline typename intrusive_list_iterator::reference diff --git a/include/EASTL/iterator.h b/include/EASTL/iterator.h index d2dc8993..67603487 100644 --- a/include/EASTL/iterator.h +++ b/include/EASTL/iterator.h @@ -409,6 +409,9 @@ namespace eastl template class move_iterator // Don't inherit from iterator. { + private: + using WrappedIteratorReference = typename iterator_traits::reference; + public: typedef Iterator iterator_type; typedef iterator_type wrapped_iterator_type; // This is not in the C++ Standard; it's used by use to identify it as a wrapping iterator type. @@ -417,7 +420,9 @@ namespace eastl typedef typename traits_type::value_type value_type; typedef typename traits_type::difference_type difference_type; typedef Iterator pointer; - typedef value_type&& reference; + using reference = conditional_t::value, + remove_reference_t&&, + WrappedIteratorReference>; protected: iterator_type mIterator; @@ -440,8 +445,7 @@ namespace eastl iterator_type base() const { return mIterator; } - reference operator*() const - { return eastl::move(*mIterator); } + reference operator*() const { return static_cast(*mIterator); } pointer operator->() const { return mIterator; } @@ -1070,10 +1074,16 @@ namespace eastl return container.begin(); } + template + EA_CPP14_CONSTEXPR inline T* begin(T (&arrayObject)[arraySize]) EA_NOEXCEPT + { + return arrayObject; + } + template - EA_CPP14_CONSTEXPR inline auto cbegin(const Container& container) -> decltype(container.begin()) + EA_CPP14_CONSTEXPR inline auto cbegin(const Container& container) -> decltype(eastl::begin(container)) { - return container.begin(); + return eastl::begin(container); } template @@ -1088,10 +1098,16 @@ namespace eastl return container.end(); } + template + EA_CPP14_CONSTEXPR inline T* end(T (&arrayObject)[arraySize]) EA_NOEXCEPT + { + return (arrayObject + arraySize); + } + template - EA_CPP14_CONSTEXPR inline auto cend(const Container& container) -> decltype(container.end()) + EA_CPP14_CONSTEXPR inline auto cend(const Container& container) -> decltype(eastl::end(container)) { - return container.end(); + return eastl::end(container); } template @@ -1130,17 +1146,6 @@ namespace eastl return container.rend(); } - template - EA_CPP14_CONSTEXPR inline T* begin(T (&arrayObject)[arraySize]) - { - return arrayObject; - } - - template - EA_CPP14_CONSTEXPR inline T* end(T (&arrayObject)[arraySize]) - { - return (arrayObject + arraySize); - } template EA_CPP14_CONSTEXPR inline reverse_iterator rbegin(T (&arrayObject)[arraySize]) @@ -1179,7 +1184,7 @@ namespace eastl // Some compilers (e.g. GCC 4.6) support range-based for loops, but have a bug with // respect to argument-dependent lookup which results on them unilaterally using std::begin/end // with range-based for loops. To work around this we #include for this case in -// order to make std::begin/end visible to users of , for portability. +// order to make std::begin/end visible to users of , for portability. #if !EASTL_BEGIN_END_ENABLED && !defined(EA_COMPILER_NO_RANGE_BASED_FOR_LOOP) #include #endif diff --git a/include/EASTL/list.h b/include/EASTL/list.h index 680dcad7..5e794379 100644 --- a/include/EASTL/list.h +++ b/include/EASTL/list.h @@ -771,7 +771,7 @@ namespace eastl inline typename ListBase::node_type* ListBase::DoAllocateNode() { - node_type* pNode = (node_type*)allocate_memory(internalAllocator(), sizeof(node_type), EASTL_ALIGN_OF(T), 0); + node_type* pNode = (node_type*)allocate_memory(internalAllocator(), sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); EASTL_ASSERT(pNode != nullptr); return pNode; } diff --git a/include/EASTL/meta.h b/include/EASTL/meta.h index 09880b7a..545354d4 100644 --- a/include/EASTL/meta.h +++ b/include/EASTL/meta.h @@ -36,24 +36,24 @@ namespace eastl template struct get_type_index { - static const int value = is_same_v ? I : get_type_index::value; + static EA_CONSTEXPR_OR_CONST int value = is_same_v ? I : get_type_index::value; }; template struct get_type_index { - static const int value = -1; + static EA_CONSTEXPR_OR_CONST int value = -1; }; } template struct get_type_index { - static const int value = Internal::get_type_index<0, T, Types...>::value; + static EA_CONSTEXPR_OR_CONST int value = Internal::get_type_index<0, T, Types...>::value; }; template - constexpr int get_type_index_v = get_type_index::value; + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR int get_type_index_v = get_type_index::value; //////////////////////////////////////////////////////////////////////////////////////////// @@ -77,7 +77,7 @@ namespace eastl //////////////////////////////////////////////////////////////////////////////////////////// - // type_count_v + // type_count_v // // Returns the number of occurrences of type T in a typelist. // @@ -87,33 +87,37 @@ namespace eastl template struct type_count { - static const int value = (is_same_v ? 1 : 0) + type_count::value; + static EA_CONSTEXPR_OR_CONST int value = (is_same_v ? 1 : 0) + type_count::value; }; - template struct type_count { static const int value = 0; }; + template + struct type_count + { + static EA_CONSTEXPR_OR_CONST int value = 0; + }; template - constexpr int type_count_v = type_count::value; + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR int type_count_v = type_count::value; //////////////////////////////////////////////////////////////////////////////////////////// // duplicate_type_check_v - // + // // Checks if a type T occurs in a typelist more than once. // template struct duplicate_type_check { - static const bool value = (type_count::value == 1); + static EA_CONSTEXPR_OR_CONST bool value = (type_count::value == 1); }; template - constexpr bool duplicate_type_check_v = duplicate_type_check::value; + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool duplicate_type_check_v = duplicate_type_check::value; ////////////////////////////////////////////////////////////////////////////////// - // type_list + // type_list // // type_list is a simple struct that allows us to pass template parameter packs // around in a single struct, and deduce parameter packs from function arguments @@ -170,8 +174,8 @@ namespace eastl //////////////////////////////////////////////////////////////////////////////////////////// - // overload_resolution_t - // + // overload_resolution_t + // // Given an input type and a typelist (which is a stand-in for alternative // function overloads) this traits will return the same type chosen as if // overload_resolution has selected a function to run. @@ -215,8 +219,29 @@ namespace eastl template using overload_resolution_t = typename overload_resolution, OverloadSet>::type; - } // namespace meta + + //////////////////////////////////////////////////////////////////////////////////////////// + // double_pack_expansion + // + // MSVC 2017 has a hard time expanding two packs of different lengths. + // This is a helper meant to coerce MSVC 2017 into doing the expansion by adding another level + // of indirection. + // + + template + struct double_pack_expansion; + + template + struct double_pack_expansion, I> + { + using type = index_sequence; + }; + + template + using double_pack_expansion_t = typename double_pack_expansion::type; + + + } // namespace meta } // namespace eastl #endif // EASTL_META_H - diff --git a/include/EASTL/numeric_limits.h b/include/EASTL/numeric_limits.h index c2770c9e..e991e7e9 100644 --- a/include/EASTL/numeric_limits.h +++ b/include/EASTL/numeric_limits.h @@ -57,7 +57,7 @@ EA_DISABLE_VC_WARNING(4310 4296) // Indicates whether we need to define our own implementations of inf, nan, snan, denorm floating point constants. // #if !defined(EASTL_CUSTOM_FLOAT_CONSTANTS_REQUIRED) - #if (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG) && defined(__FLT_MIN__)) || defined(_CPPLIB_VER) // __FLT_MIN__ detects if it's really GCC/clang and not a mimic. _CPPLIB_VER (Dinkumware) covers VC++, and Microsoft platforms. + #if (defined(EA_COMPILER_GNUC) || defined(__clang__) && defined(__FLT_MIN__)) || defined(_CPPLIB_VER) // __FLT_MIN__ detects if it's really GCC/clang and not a mimic. _CPPLIB_VER (Dinkumware) covers VC++, and Microsoft platforms. #define EASTL_CUSTOM_FLOAT_CONSTANTS_REQUIRED 0 #else #define EASTL_CUSTOM_FLOAT_CONSTANTS_REQUIRED 1 @@ -1213,7 +1213,7 @@ namespace eastl }; - #if (EA_COMPILER_INTMAX_SIZE >= 16) && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) // If __int128_t/__uint128_t is supported... + #if (EA_COMPILER_INTMAX_SIZE >= 16) && (defined(EA_COMPILER_GNUC) || defined(__clang__)) // If __int128_t/__uint128_t is supported... // numeric_limits<__uint128_t> template<> struct numeric_limits<__uint128_t> @@ -1391,7 +1391,7 @@ namespace eastl static value_type denorm_min() { return Internal::gFloatDenorm; } - #elif (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) && defined(__FLT_MIN__) + #elif (defined(EA_COMPILER_GNUC) || defined(__clang__)) && defined(__FLT_MIN__) static EA_CONSTEXPR value_type min() { return __FLT_MIN__; } @@ -1509,7 +1509,7 @@ namespace eastl static value_type denorm_min() { return Internal::gDoubleDenorm; } - #elif (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) && defined(__DBL_MIN__) + #elif (defined(EA_COMPILER_GNUC) || defined(__clang__)) && defined(__DBL_MIN__) static EA_CONSTEXPR value_type min() { return __DBL_MIN__; } @@ -1627,7 +1627,7 @@ namespace eastl static value_type denorm_min() { return Internal::gLongDoubleDenorm; } - #elif (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) && defined(__LDBL_MIN__) + #elif (defined(EA_COMPILER_GNUC) || defined(__clang__)) && defined(__LDBL_MIN__) static EA_CONSTEXPR value_type min() { return __LDBL_MIN__; } diff --git a/include/EASTL/slist.h b/include/EASTL/slist.h index 27966928..1dbb44fc 100644 --- a/include/EASTL/slist.h +++ b/include/EASTL/slist.h @@ -679,7 +679,7 @@ namespace eastl template inline SListNode* SListBase::DoAllocateNode() { - return (node_type*)allocate_memory(internalAllocator(), sizeof(node_type), EASTL_ALIGN_OF(T), 0); + return (node_type*)allocate_memory(internalAllocator(), sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); } diff --git a/include/EASTL/sort.h b/include/EASTL/sort.h index 35d105d7..60cfcd8b 100644 --- a/include/EASTL/sort.h +++ b/include/EASTL/sort.h @@ -1653,8 +1653,8 @@ namespace eastl IntegerType) { RandomAccessIterator srcFirst = first; - constexpr size_t numBuckets = 1 << DigitBits; - constexpr IntegerType bucketMask = numBuckets - 1; + EA_CONSTEXPR_OR_CONST size_t numBuckets = 1 << DigitBits; + EA_CONSTEXPR_OR_CONST IntegerType bucketMask = numBuckets - 1; // The alignment of this variable isn't required; it merely allows the code below to be faster on some platforms. uint32_t EA_PREFIX_ALIGN(EASTL_PLATFORM_PREFERRED_ALIGNMENT) bucketSize[numBuckets]; diff --git a/include/EASTL/span.h b/include/EASTL/span.h index 1f3b9b42..9c47f5b3 100644 --- a/include/EASTL/span.h +++ b/include/EASTL/span.h @@ -76,7 +76,7 @@ namespace eastl static EA_CONSTEXPR size_t extent = Extent; // constructors / destructor - EA_CONSTEXPR span() EA_NOEXCEPT = default; + EA_CONSTEXPR span() EA_NOEXCEPT; EA_CONSTEXPR span(const span& other) EA_NOEXCEPT = default; EA_CONSTEXPR span(pointer ptr, index_type count); EA_CONSTEXPR span(pointer pBegin, pointer pEnd); @@ -86,9 +86,14 @@ namespace eastl EA_CPP14_CONSTEXPR span& operator=(const span& other) EA_NOEXCEPT = default; // conversion constructors for c-array and eastl::array - template EA_CONSTEXPR span(element_type (&arr)[N]) EA_NOEXCEPT; - template EA_CONSTEXPR span(eastl::array& arr) EA_NOEXCEPT; - template EA_CONSTEXPR span(const eastl::array& arr) EA_NOEXCEPT; + template > + EA_CONSTEXPR span(element_type (&arr)[N]) EA_NOEXCEPT; + + template > + EA_CONSTEXPR span(eastl::array& arr) EA_NOEXCEPT; + + template > + EA_CONSTEXPR span(const eastl::array& arr) EA_NOEXCEPT; // SfinaeForGenericContainers // @@ -198,34 +203,43 @@ namespace eastl // ctor implementations /////////////////////////////////////////////////////////////////////////// + + template + EA_CONSTEXPR span::span() EA_NOEXCEPT + { + static_assert(Extent == dynamic_extent || Extent == 0, "impossible to default construct a span with a fixed Extent different than 0"); + } + template EA_CONSTEXPR span::span(pointer ptr, index_type size) : mpData(ptr), mnSize(size) { + EASTL_ASSERT_MSG(Extent == dynamic_extent || Extent == mnSize, "impossible to create a span with a fixed Extent different than the size of the supplied buffer"); } template EA_CONSTEXPR span::span(pointer pBegin, pointer pEnd) : mpData(pBegin), mnSize(static_cast(pEnd - pBegin)) { + EASTL_ASSERT_MSG(Extent == dynamic_extent || Extent == mnSize, "impossible to create a span with a fixed Extent different than the size of the supplied buffer"); } template - template + template EA_CONSTEXPR span::span(element_type(&arr)[N]) EA_NOEXCEPT : span(arr, static_cast(N)) { } template - template + template EA_CONSTEXPR span::span(eastl::array &arr) EA_NOEXCEPT : span(arr.data(), arr.size()) { } template - template + template EA_CONSTEXPR span::span(const eastl::array& arr) EA_NOEXCEPT : span(arr.data(), arr.size()) { @@ -368,7 +382,7 @@ namespace eastl template EA_CPP14_CONSTEXPR span::element_type, Count> span::first() const { - EASTL_ASSERT_MSG(bounds_check(Count), "undefined behavior accessing out of bounds"); + EASTL_ASSERT_MSG(Count <= size(), "undefined behavior accessing out of bounds"); return {data(), static_cast(Count)}; } @@ -376,7 +390,7 @@ namespace eastl EA_CPP14_CONSTEXPR span::element_type, dynamic_extent> span::first(size_t sz) const { - EASTL_ASSERT_MSG(bounds_check(sz), "undefined behavior accessing out of bounds"); + EASTL_ASSERT_MSG(sz <= size(), "undefined behavior accessing out of bounds"); return {data(), static_cast(sz)}; } @@ -384,7 +398,7 @@ namespace eastl template EA_CPP14_CONSTEXPR span::element_type, Count> span::last() const { - EASTL_ASSERT_MSG(bounds_check(Count), "undefined behavior accessing out of bounds"); + EASTL_ASSERT_MSG(Count <= size(), "undefined behavior accessing out of bounds"); return {data() + size() - Count, static_cast(Count)}; } @@ -392,7 +406,7 @@ namespace eastl EA_CPP14_CONSTEXPR span::element_type, dynamic_extent> span::last(size_t sz) const { - EASTL_ASSERT_MSG(bounds_check(sz), "undefined behavior accessing out of bounds"); + EASTL_ASSERT_MSG(sz <= size(), "undefined behavior accessing out of bounds"); return {data() + size() - sz, static_cast(sz)}; } @@ -401,7 +415,7 @@ namespace eastl EA_CONSTEXPR span::element_type, Internal::SubspanExtent::value> span::subspan() const { - EASTL_ASSERT_MSG(bounds_check(Offset), "undefined behaviour accessing out of bounds"); + EASTL_ASSERT_MSG(Offset <= size(), "undefined behaviour accessing out of bounds"); EASTL_ASSERT_MSG(Count == dynamic_extent || Count <= (size() - Offset), "undefined behaviour exceeding size of span"); return {data() + Offset, eastl_size_t(Count == dynamic_extent ? size() - Offset : Count)}; @@ -411,16 +425,16 @@ namespace eastl EA_CONSTEXPR span::element_type, dynamic_extent> span::subspan(size_t offset, size_t count) const { - EASTL_ASSERT_MSG(bounds_check(offset), "undefined behaviour accessing out of bounds"); + EASTL_ASSERT_MSG(offset <= size(), "undefined behaviour accessing out of bounds"); EASTL_ASSERT_MSG(count == dynamic_extent || count <= (size() - offset), "undefined behaviour exceeding size of span"); return {data() + offset, eastl_size_t(count == dynamic_extent ? size() - offset : count)}; } template - EA_CONSTEXPR bool span::bounds_check(size_t sz) const + EA_CONSTEXPR bool span::bounds_check(size_t offset) const { - return (sz >= 0 && sz < size()); + return offset < size(); } } diff --git a/include/EASTL/string.h b/include/EASTL/string.h index 82816a42..18c2e7cd 100644 --- a/include/EASTL/string.h +++ b/include/EASTL/string.h @@ -313,19 +313,19 @@ namespace eastl // Masks used to determine if we are in SSO or Heap #ifdef EA_SYSTEM_BIG_ENDIAN // Big Endian use LSB, unless we want to reorder struct layouts on endianness, Bit is set when we are in Heap - static constexpr size_type kHeapMask = 0x1; - static constexpr size_type kSSOMask = 0x1; + static EA_CONSTEXPR_OR_CONST size_type kHeapMask = 0x1; + static EA_CONSTEXPR_OR_CONST size_type kSSOMask = 0x1; #else // Little Endian use MSB - static constexpr size_type kHeapMask = ~(size_type(~size_type(0)) >> 1); - static constexpr size_type kSSOMask = 0x80; + static EA_CONSTEXPR_OR_CONST size_type kHeapMask = ~(size_type(~size_type(0)) >> 1); + static EA_CONSTEXPR_OR_CONST size_type kSSOMask = 0x80; #endif public: #ifdef EA_SYSTEM_BIG_ENDIAN - static constexpr size_type kMaxSize = (~kHeapMask) >> 1; + static EA_CONSTEXPR_OR_CONST size_type kMaxSize = (~kHeapMask) >> 1; #else - static constexpr size_type kMaxSize = ~kHeapMask; + static EA_CONSTEXPR_OR_CONST size_type kMaxSize = ~kHeapMask; #endif protected: @@ -353,7 +353,7 @@ namespace eastl // The view of memory when the string data is able to store the string data locally (without a heap allocation). struct SSOLayout { - static constexpr size_type SSO_CAPACITY = (sizeof(HeapLayout) - sizeof(char)) / sizeof(value_type); + static EA_CONSTEXPR_OR_CONST size_type SSO_CAPACITY = (sizeof(HeapLayout) - sizeof(char)) / sizeof(value_type); // mnSize must correspond to the last byte of HeapLayout.mnCapacity, so we don't want the compiler to insert // padding after mnSize if sizeof(value_type) != 1; Also ensures both layouts are the same size. diff --git a/include/EASTL/type_traits.h b/include/EASTL/type_traits.h index 68a388d5..2cf5d7a7 100644 --- a/include/EASTL/type_traits.h +++ b/include/EASTL/type_traits.h @@ -500,13 +500,8 @@ namespace eastl struct conjunction : conditional, B>::type {}; #if EASTL_VARIABLE_TEMPLATES_ENABLED - #if EASTL_INLINE_VARIABLE_ENABLED - template - inline constexpr bool conjunction_v = conjunction::value; - #else - template - static const constexpr bool conjunction_v = conjunction::value; - #endif + template + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool conjunction_v = conjunction::value; #endif @@ -529,13 +524,8 @@ namespace eastl struct disjunction : conditional>::type {}; #if EASTL_VARIABLE_TEMPLATES_ENABLED - #if EASTL_INLINE_VARIABLE_ENABLED - template - inline constexpr bool disjunction_v = disjunction::value; - #else - template - static const constexpr bool disjunction_v = disjunction::value; - #endif + template + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool disjunction_v = disjunction::value; #endif @@ -552,13 +542,8 @@ namespace eastl struct negation : eastl::bool_constant {}; #if EASTL_VARIABLE_TEMPLATES_ENABLED - #if EASTL_INLINE_VARIABLE_ENABLED - template - inline constexpr bool negation_v = negation::value; - #else - template - static const constexpr bool negation_v = negation::value; - #endif + template + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool negation_v = negation::value; #endif @@ -674,15 +659,16 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // is_reference // - // is_reference::value == true if and only if T is a reference type. + // is_reference::value == true if and only if T is a reference type (l-value reference or r-value reference). // This category includes reference to function types. // /////////////////////////////////////////////////////////////////////// #define EASTL_TYPE_TRAIT_is_reference_CONFORMANCE 1 // is_reference is conforming; doesn't make mistakes. - template struct is_reference : public eastl::false_type{}; - template struct is_reference : public eastl::true_type{}; + template struct is_reference : public eastl::false_type{}; + template struct is_reference : public eastl::true_type{}; + template struct is_reference : public eastl::true_type{}; #if EASTL_VARIABLE_TEMPLATES_ENABLED template @@ -831,9 +817,11 @@ namespace eastl // // The add_reference transformation trait adds a level of indirection // by reference to the type to which it is applied. For a given type T, - // add_reference::type is equivalent to T& if is_reference::value == false, + // add_reference::type is equivalent to T& if is_lvalue_reference::value == false, // and T otherwise. // + // Note: due to the reference collapsing rules, if you supply an r-value reference such as T&&, it will collapse to T&. + // /////////////////////////////////////////////////////////////////////// #define EASTL_TYPE_TRAIT_add_reference_CONFORMANCE 1 // add_reference is conforming. diff --git a/include/EASTL/unique_ptr.h b/include/EASTL/unique_ptr.h index 562e2c4d..c5d2480b 100644 --- a/include/EASTL/unique_ptr.h +++ b/include/EASTL/unique_ptr.h @@ -88,6 +88,7 @@ namespace eastl template > class unique_ptr { + static_assert(!is_rvalue_reference::value, "The supplied Deleter cannot be a r-value reference."); public: typedef Deleter deleter_type; typedef T element_type; @@ -130,7 +131,7 @@ namespace eastl /// Example usage: /// eastl::smart_ptr_deleter del; /// unique_ptr ptr(new int(3), del); - unique_ptr(pointer pValue, typename eastl::conditional::value, deleter_type, typename eastl::add_lvalue_reference::type>::type deleter) EA_NOEXCEPT + unique_ptr(pointer pValue, typename eastl::conditional::value, deleter_type, typename eastl::add_lvalue_reference::type>::type deleter) EA_NOEXCEPT : mPair(pValue, deleter) {} /// unique_ptr @@ -140,7 +141,7 @@ namespace eastl unique_ptr(pointer pValue, typename eastl::remove_reference::type&& deleter) EA_NOEXCEPT : mPair(pValue, eastl::move(deleter)) { - static_assert(!eastl::is_reference::value, "deleter_type reference refers to an rvalue deleter. The reference will probably become invalid before used. Change the deleter_type to not be a reference or construct with permanent deleter."); + static_assert(!eastl::is_lvalue_reference::value, "deleter_type reference refers to an rvalue deleter. The reference will probably become invalid before used. Change the deleter_type to not be a reference or construct with permanent deleter."); } /// unique_ptr @@ -157,7 +158,7 @@ namespace eastl /// unique_ptr ptr(new int(3)); /// unique_ptr newPtr = eastl::move(ptr); template - unique_ptr(unique_ptr&& u, typename enable_if::value && is_convertible::pointer, pointer>::value && is_convertible::value && (is_same::value || !is_reference::value)>::type* = 0) EA_NOEXCEPT + unique_ptr(unique_ptr&& u, typename enable_if::value && is_convertible::pointer, pointer>::value && is_convertible::value && (is_same::value || !is_lvalue_reference::value)>::type* = 0) EA_NOEXCEPT : mPair(u.release(), eastl::forward(u.get_deleter())) {} /// unique_ptr @@ -383,7 +384,7 @@ namespace eastl } template - unique_ptr(P pArray, typename eastl::conditional::value, deleter_type, + unique_ptr(P pArray, typename eastl::conditional::value, deleter_type, typename eastl::add_lvalue_reference::type>::type deleter, typename eastl::enable_if::value>::type* = 0) EA_NOEXCEPT : mPair(pArray, deleter) {} @@ -392,7 +393,7 @@ namespace eastl unique_ptr(P pArray, typename eastl::remove_reference::type&& deleter, eastl::enable_if_t::value>* = 0) EA_NOEXCEPT : mPair(pArray, eastl::move(deleter)) { - static_assert(!eastl::is_reference::value, "deleter_type reference refers to an rvalue deleter. The reference will probably become invalid before used. Change the deleter_type to not be a reference or construct with permanent deleter."); + static_assert(!eastl::is_lvalue_reference::value, "deleter_type reference refers to an rvalue deleter. The reference will probably become invalid before used. Change the deleter_type to not be a reference or construct with permanent deleter."); } unique_ptr(this_type&& x) EA_NOEXCEPT @@ -401,7 +402,7 @@ namespace eastl template unique_ptr(unique_ptr&& u, typename enable_if::pointer>::value && eastl::is_convertible::value && - (!eastl::is_reference::value || eastl::is_same::value)>::type* = 0) EA_NOEXCEPT + (!eastl::is_lvalue_reference::value || eastl::is_same::value)>::type* = 0) EA_NOEXCEPT : mPair(u.release(), eastl::forward(u.get_deleter())) {} this_type& operator=(this_type&& x) EA_NOEXCEPT diff --git a/include/EASTL/utility.h b/include/EASTL/utility.h index cc546fb0..a91ce8c1 100644 --- a/include/EASTL/utility.h +++ b/include/EASTL/utility.h @@ -413,7 +413,7 @@ namespace eastl // // See bug submitted to LLVM for more details. // https://bugs.llvm.org/show_bug.cgi?id=38374 - #if !defined(EA_COMPILER_CLANG) + #if !defined(__clang__) template using single_pair_ctor_sfinae = eastl::enable_if_t>; #else diff --git a/include/EASTL/variant.h b/include/EASTL/variant.h index e59c3007..e351629a 100644 --- a/include/EASTL/variant.h +++ b/include/EASTL/variant.h @@ -10,12 +10,12 @@ // // As with unions, if a variant holds a value of some object type T, the object // representation of T is allocated directly within the object representation of -// the variant itself. +// the variant itself. // // Variant is not allowed to allocate additional (dynamic) memory. // // A variant is not permitted to hold references, arrays, or the type void. -// Empty variants are also ill-formed (variant can be used instead). +// Empty variants are also ill-formed (variant can be used instead). // // A variant is permitted to hold the same type more than once, and to hold // differently cv-qualified versions of the same type. As with unions, the @@ -48,7 +48,7 @@ // * strong exception guarantees as specified (we punted on the assignment problem). // if an exception is thrown during assignment its undefined behaviour in our implementation. // -// Reference: +// Reference: // * http://en.cppreference.com/w/cpp/utility/variant // * https://thenewcpp.wordpress.com/2012/02/15/variadic-templates-part-3-or-how-i-wrote-a-variant-class/ /////////////////////////////////////////////////////////////////////////// @@ -65,6 +65,13 @@ #include #include #include +#include + +#if EASTL_EXCEPTIONS_ENABLED + #include + #include +#endif + #if defined(EA_PRAGMA_ONCE_SUPPORTED) #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. @@ -83,7 +90,7 @@ namespace eastl /////////////////////////////////////////////////////////////////////////// // default_construct_if_supported // - // Utility class to remove default constructor calls for types that + // Utility class to remove default constructor calls for types that // do not support default construction. // // We can remove these utilities when C++17 'constexpr if' is available. @@ -106,7 +113,7 @@ namespace eastl /////////////////////////////////////////////////////////////////////////// // destroy_if_supported // - // Utility class to remove default constructor calls for types that + // Utility class to remove default constructor calls for types that // do not support default construction. // // We can remove these utilities when C++17 'constexpr if' is available. @@ -129,7 +136,7 @@ namespace eastl /////////////////////////////////////////////////////////////////////////// // copy_if_supported // - // Utility class to remove copy constructor calls for types that + // Utility class to remove copy constructor calls for types that // do not support copying. // // We can remove these utilities when C++17 'constexpr if' is available. @@ -152,7 +159,7 @@ namespace eastl /////////////////////////////////////////////////////////////////////////// // move_if_supported // - // Utility class to remove move constructor calls for types that + // Utility class to remove move constructor calls for types that // do not support moves. // // We can remove these utilities when C++17 'constexpr if' is available. @@ -171,7 +178,7 @@ namespace eastl { static void call(T* pThis, T* pOther) {} // intentionally blank }; - } // namespace internal + } // namespace internal /////////////////////////////////////////////////////////////////////////// @@ -229,10 +236,10 @@ namespace eastl template <> struct hash { size_t operator()(monostate) const { return static_cast(-0x42); } }; - + /////////////////////////////////////////////////////////////////////////// // variant_storage - // + // // This is a utility class to simplify the implementation of a storage type // for a distriminted union. This utility handles the alignment, size // requirements, and data access required by the variant type. @@ -318,33 +325,33 @@ namespace eastl public: variant_storage() { - DoOp(StorageOp::DEFAULT_CONSTRUCT); + DoOp(StorageOp::DEFAULT_CONSTRUCT); } ~variant_storage() { - DoOp(StorageOp::DESTROY); + DoOp(StorageOp::DESTROY); } variant_storage(const variant_storage& other) { - DoOp(StorageOp::COPY, other); + DoOp(StorageOp::COPY, other); } variant_storage(variant_storage&& other) { - DoOp(StorageOp::MOVE, other); + DoOp(StorageOp::MOVE, other); } variant_storage& operator=(const variant_storage& other) { - DoOp(StorageOp::COPY, other); + DoOp(StorageOp::COPY, other); return *this; } variant_storage& operator=(variant_storage&& other) { - DoOp(StorageOp::MOVE, eastl::move(other)); + DoOp(StorageOp::MOVE, eastl::move(other)); return *this; } @@ -353,7 +360,7 @@ namespace eastl { // NOTE(rparolin): If this assert fires there is an EASTL problem picking the size of the local buffer which // variant_storage used to store types. The size selected should be large enough to hold the largest type in - // the user provided variant type-list. + // the user provided variant type-list. static_assert(sizeof(aligned_storage_impl_t) >= sizeof(T), "T is larger than local buffer size"); using RT = remove_reference_t; @@ -368,7 +375,7 @@ namespace eastl { // NOTE(rparolin): If this assert fires there is an EASTL problem picking the size of the local buffer which // variant_storage used to store types. The size selected should be large enough to hold the largest type in - // the user provided variant type-list. + // the user provided variant type-list. static_assert(sizeof(aligned_storage_impl_t) >= sizeof(T), "T is larger than local buffer size"); using RT = remove_reference_t; @@ -394,7 +401,7 @@ namespace eastl void destroy() { - DoOp(StorageOp::DESTROY); + DoOp(StorageOp::DESTROY); } }; @@ -426,7 +433,7 @@ namespace eastl { // NOTE(rparolin): If this assert fires there is an EASTL problem picking the size of the local buffer which // variant_storage used to store types. The size selected should be large enough to hold the largest type in - // the user provided variant type-list. + // the user provided variant type-list. static_assert(sizeof(aligned_storage_impl_t) >= sizeof(T), "T is larger than local buffer size"); new (&mBuffer) remove_reference_t(eastl::forward(args)...); @@ -438,7 +445,7 @@ namespace eastl { // NOTE(rparolin): If this assert fires there is an EASTL problem picking the size of the local buffer which // variant_storage used to store types. The size selected should be large enough to hold the largest type in - // the user provided variant type-list. + // the user provided variant type-list. static_assert(sizeof(aligned_storage_impl_t) >= sizeof(T), "T is larger than local buffer size"); new (&mBuffer) remove_reference_t(il, eastl::forward(args)...); @@ -464,7 +471,7 @@ namespace eastl /////////////////////////////////////////////////////////////////////////// - // 20.7.2, forward-declaration for types that depend on the variant + // 20.7.2, forward-declaration for types that depend on the variant // template class variant; @@ -473,18 +480,19 @@ namespace eastl /////////////////////////////////////////////////////////////////////////// // 20.7.3, variant_size, variant_size_v helper classes // - template struct variant_size; + template struct variant_size; template struct variant_size : integral_constant::value> {}; template struct variant_size : integral_constant::value> {}; template struct variant_size : integral_constant::value> {}; template struct variant_size> : integral_constant {}; // variant_size_v template alias - template EA_CONSTEXPR size_t variant_size_v = variant_size::value; + template + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR size_t variant_size_v = variant_size::value; /////////////////////////////////////////////////////////////////////////// - // variant_alternative_helper + // variant_alternative_helper // // This helper does the heavy lifting of traversing the variadic type list // and retrieving the type at the user provided index. @@ -508,9 +516,9 @@ namespace eastl template struct variant_alternative> : variant_alternative_helper {}; // ISO required cv-qualifer specializations - template struct variant_alternative : add_cv_t> {}; - template struct variant_alternative : add_volatile_t> {}; - template struct variant_alternative : add_cv_t> {}; + template struct variant_alternative : add_const::type> {}; + template struct variant_alternative : add_volatile::type> {}; + template struct variant_alternative : add_cv::type> {}; // variant_alternative_t template alias template using variant_alternative_t = typename variant_alternative::type; @@ -525,7 +533,7 @@ namespace eastl /////////////////////////////////////////////////////////////////////////// - // get_if + // get_if // template EA_CONSTEXPR add_pointer_t>> get_if(variant* pv) EA_NOEXCEPT @@ -559,15 +567,14 @@ namespace eastl /////////////////////////////////////////////////////////////////////////// - // get + // get // template EA_CONSTEXPR variant_alternative_t>& get(variant& v) { static_assert(I < sizeof...(Types), "get is ill-formed if I is not a valid index in the variant typelist"); using return_type = add_pointer_t>>; - - EASTL_ASSERT(v.index() == I); + return *v.mStorage.template get_as(); } @@ -576,8 +583,7 @@ namespace eastl { static_assert(I < sizeof...(Types), "get is ill-formed if I is not a valid index in the variant typelist"); using return_type = add_pointer_t>>; - - EASTL_ASSERT(v.index() == I); + return eastl::move(*v.mStorage.template get_as()); } @@ -586,8 +592,7 @@ namespace eastl { static_assert(I < sizeof...(Types), "get is ill-formed if I is not a valid index in the variant typelist"); using return_type = add_pointer_t>>; - - EASTL_ASSERT(v.index() == I); + return *v.mStorage.template get_as(); } @@ -596,8 +601,7 @@ namespace eastl { static_assert(I < sizeof...(Types), "get is ill-formed if I is not a valid index in the variant typelist"); using return_type = add_pointer_t>>; - - EASTL_ASSERT(v.index() == I); + return eastl::move(*v.mStorage.template get_as()); } @@ -645,7 +649,7 @@ namespace eastl // 20.7.2, variant // template - class variant + class variant { static_assert(sizeof...(Types) > 0, "variant must have at least 1 type (empty variants are ill-formed)"); static_assert(disjunction_v...> == false, "variant does not allow void as an alternative type"); @@ -661,7 +665,7 @@ namespace eastl // variant_index_t mIndex; variant_storage_t mStorage; - + public: /////////////////////////////////////////////////////////////////////////// // 20.7.2.1, constructors @@ -808,10 +812,16 @@ namespace eastl variant_alternative_t& emplace(Args&&... args) { if (!valueless_by_exception()) + { mStorage.destroy(); - mIndex = static_cast(I); + #if EASTL_EXCEPTIONS_ENABLED + mIndex = static_cast(variant_npos); + #endif + } + mStorage.template set_as(eastl::forward(args)...); + mIndex = static_cast(I); return *reinterpret_cast(&mStorage.mBuffer); } @@ -829,10 +839,16 @@ namespace eastl variant_alternative_t& emplace(std::initializer_list il, Args&&... args) { if (!valueless_by_exception()) + { mStorage.destroy(); - mIndex = static_cast(I); + #if EASTL_EXCEPTIONS_ENABLED + mIndex = static_cast(variant_npos); + #endif + } + mStorage.template set_as(il, eastl::forward(args)...); + mIndex = static_cast(I); return *reinterpret_cast(&mStorage.mBuffer); } @@ -896,14 +912,29 @@ namespace eastl /////////////////////////////////////////////////////////////////////////// // 20.7.2.5, value status // - EA_CONSTEXPR size_t index() const EA_NOEXCEPT { return valueless_by_exception() ? variant_npos : mIndex; } - EA_CONSTEXPR bool valueless_by_exception() const EA_NOEXCEPT { return mIndex == variant_npos; } + EA_CONSTEXPR size_t index() const EA_NOEXCEPT + { + #if EASTL_EXCEPTIONS_ENABLED + return valueless_by_exception() ? variant_npos : mIndex; + #else + return mIndex; + #endif + } + + EA_CONSTEXPR bool valueless_by_exception() const EA_NOEXCEPT + { + #if EASTL_EXCEPTIONS_ENABLED + return mIndex == variant_npos; + #else + return false; + #endif + } /////////////////////////////////////////////////////////////////////////// // 20.7.2.6, swap // - void swap(variant& other) + void swap(variant& other) EA_NOEXCEPT(conjunction_v..., is_nothrow_swappable...>) { eastl::swap(mIndex, other.mIndex); @@ -926,12 +957,13 @@ namespace eastl // 20.7.9, swap // template - void swap(variant& lhs, variant& rhs) + void swap(variant& lhs, variant& rhs) EA_NOEXCEPT(EA_NOEXCEPT(lhs.swap(rhs))) { lhs.swap(rhs); } + // visit is a bit convoluted, in order to fulfill a few requirements: // - It must support visiting multiple variants using a single visitor and a single function call. The // visitor in this case should have one function for each possible combination of types: @@ -949,149 +981,355 @@ namespace eastl // // - It must be declared constexpr // - It must be constant-time for the case of visiting a single variant - // - It must allow different return types in the visitor, as long as they are all convertible // - // visitor_caller is responsible for the mechanics of visit. Each visitor_caller creates an array of - // functions which call get() on the variant (where I is the array index), then add the returned reference - // to a tuple of arguments. The final visitor_caller calls invoke() with the visitor and the unpacked - // arguments. + // - 20.7.7 states that variant visitation requires all combinations of visitors to return the same type. + // + // NOTE(mwinkler): + // Visit creates an N-Dimensional matrix whereby each dimension is M wide. + // Where N == sizeof...(Variants) and M == variant_size_v + // + // variant v; + // visit(Visitor{}, v, v); + // + // This creates a 3x3 matrix of potential visitors. + // The argument indices into the variants are as follows. + // [0, 0], [0, 1], [0, 2] + // [1, 0], [1, 1], [1, 2] + // [2, 0], [2, 1], [2, 2] + // + // These indices are compile-time constants but the variants have a runtime index. + // Therefore we must instantiate an NxNxN... matrix of function pointers who are + // templated on the indices based on their position in the matrix and then + // at runtime index into the array to call the correct function pointer that can + // get the correct alternatives in the variants. + // + // There are a couple of ways to do this. We can construct the matrix bottom up or top down. + // + // Constructing a matrix bottom up would look something as follows. + // + // make_visitor_matrix_recurse(eastl::index_sequence<>{}, eastl::make_index_sequence>>{}...); + // + // make_visitor_matrix_recurse(eastl::index_sequence) { return templated function pointer on Is... } + // + // make_visitor_matrix_recurse(eastl::index_sequence, eastl::index_sequence, RestIndex... rest) + // return make_array(make_visitor_matrix_recurse(eastl::index_sequence{}, rest...)...); + // + // Essentially we construct the matrix bottom up, row by row of indices and return an array of function pointers. + // The end result is a NxNxN... array on the stack which can be indexed by each variant in order as follows, + // array[v0.index()][v1.index()][vn.index()](); + // + // The downside with this approach is the massive NxNxN... array that is created on the stack. + // + // The other approach is to build the matrix top down and use tail recursion to ensure there is only one + // N sized array on the stack. The downside here is the extra function calls, but we feel this approach provides + // a good balance between performance and memory usage. + // + // We construct the matrix top down by first creating an N sized array that is indexed by the first variant. + // This calls a function that recursively creates another N sized array that is indexed by the second variant. + // The recursion continues until we reach the base case which is the last variant. At this point we know + // the compile-time value of the N indices needed to get each alternative from each variant to invoke the visitor upon. + // Essentially we create a tree of function pointers like so. + // // - // This allows us to look up each appropriate get() function in constant time using the variant's index. - template - struct visitor_caller + // +------------------------------------------------------------------+ + // | | + // | 0 1 N | + // | | + // | | + // +----+---------------------------+---------------------------------+ + // | | + // | | + // | | + // | | + // | | + // +--------------------------+-----------------+ +----+------------------------------------+ + // | | | | + // |0,0 0,1 0,N| |1,0 1,1 1,N| + // | | | | + // | | | | + // +--------------------------------------------+ +-----------------------------------------+ + // + // Essentially each call creates a N sized array of function pointers that is the concatention of the indices known so far + // and the index of itself in the array whereby the leaf function pointer does the final invoke of the visitor. + // + + // Since decltype() is not one of the contexts where an overloaded function can be used without arguments; + // We use this function to deduce the function pointer types. + // We also return an eastl::array<> since we cannot return C-style arrays as value types. + template + static EA_CONSTEXPR array, 1> make_visitor_array(T&& t) { - // @visitor, @variant and @variants are all the arguments to the initial visit() function. - // @args is the tuple of arguments which have been retrieved by any previous visitor_callers. - // - // The two unnamed index_sequence parameters let us deduce two different sets of indices - // as parameter packs - one for the arguments and one for the array of call_next functions. - // This is necessary so we can create the constexpr array of functions which call - // get(variant) based on the array index, and so we can unpack the final of arguments by - // calling get(args) for each index in args. - template - static decltype(auto) EA_CONSTEXPR call_next(Visitor&& visitor, - index_sequence, - index_sequence, - ArgsTuple&& args, - Variant&& variant, - Variants&&... variants) - { - // Call the appropriate get() function on the variant, and pack the result into a new tuple along with - // all of the previous arguments. Then call the next visitor_caller with the new argument added, - // and the current variant removed. - return visitor_caller::call( - eastl::forward(visitor), - index_sequence(), - index_sequence(), - eastl::make_tuple(get(eastl::forward(args))..., get(eastl::forward(variant))), - eastl::forward(variants)... - ); + return { { eastl::forward(t) } }; + } + + template + static EA_CONSTEXPR array, sizeof...(Ts) + 1> make_visitor_array(T&& t, Ts&&... ts) + { + static_assert(conjunction_v, decay_t>...>, "`visit` variant visitation requires that all visitors have the same return type!"); + + return { { eastl::forward(t), eastl::forward(ts)... } }; + } + + + template = 0> + static EA_CONSTEXPR decltype(auto) get_variant_n(Variant&& variant, Variants&&... variants) + { + return eastl::forward(variant); + } + + template = 0> + static EA_CONSTEXPR decltype(auto) get_variant_n(Variant&& variant, Variants&&... variants) + { + return get_variant_n(eastl::forward(variants)...); + } + + + template + static EA_CONSTEXPR decltype(auto) call_visitor_at_index(Array&& array, Index index, Visitor&& visitor, Variants&&... variants) + { + return array[static_cast(index)](eastl::forward(visitor), eastl::forward(variants)...); + } + + template + static EA_CONSTEXPR decltype(auto) call_visitor_at(Array&& array, Visitor&& visitor, Variants&&... variants) + { + return call_visitor_at_index(eastl::forward(array), + get_variant_n(eastl::forward(variants)...).index(), + eastl::forward(visitor), + eastl::forward(variants)...); + } + + + // abstracts calling visit on 2 or more variants + template + struct visitor_caller_n; + + template + struct visitor_caller_n, Visitor, Variants...> + { + using return_type = invoke_result_t>...>; + + template + static EA_CONSTEXPR return_type invoke_visitor_leaf(Visitor&& visitor, Variants&&... variants) + { + return eastl::invoke(eastl::forward(visitor), + eastl::get(eastl::forward(variants))...); + } + + template + static EA_CONSTEXPR auto make_invoke_visitor_leaf(index_sequence) + { + return &invoke_visitor_leaf; + } + + + template + static EA_CONSTEXPR return_type invoke_visitor_recurse(Visitor&& visitor, Variants&&... variants) + { + return call(index_sequence{}, + eastl::forward(visitor), + eastl::forward(variants)...); } - // Arguments are the same as for call_next (see above). - template - static decltype(auto) EA_CPP14_CONSTEXPR call(Visitor&& visitor, - index_sequence, - index_sequence, - ArgsTuple&& args, - Variant&& variant, - Variants&&... variants) - { - // Deduce the type of the inner array of call_next functions - using return_type = decltype(call_next<0>( - eastl::forward(visitor), - index_sequence(), - index_sequence(), - eastl::forward(args), - eastl::forward(variant), - eastl::forward(variants)...) - ); - - using next_type = return_type (*)( - Visitor&&, - index_sequence, - index_sequence, - ArgsTuple&&, - Variant&&, - Variants&&... - ); - - // Create an array of call_next<0>, call_next<1>, ... , call_next - // where N = variant_size. - EA_CPP14_CONSTEXPR next_type next[] = { static_cast(call_next)... }; - - // call_next() with the correct index for the variant. - return next[variant.index()]( - eastl::forward(visitor), - index_sequence(), - index_sequence(), - eastl::forward(args), - eastl::forward(variant), - eastl::forward(variants)... - ); + template + static EA_CONSTEXPR auto make_invoke_visitor_recurse(index_sequence) + { + return &invoke_visitor_recurse; + } + + + template + 1 == sizeof...(Variants), int> = 0> + static EA_CPP14_CONSTEXPR decltype(auto) call(VariantArgIndexSequence, Visitor&& visitor, Variants&&... variants) + { + EA_CPP14_CONSTEXPR auto callers = make_visitor_array(make_invoke_visitor_leaf(meta::double_pack_expansion_t{})...); + + return call_visitor_at>(eastl::move(callers), + eastl::forward(visitor), + eastl::forward(variants)...); + } + + template + 1 != sizeof...(Variants), int> = 0> + static EA_CPP14_CONSTEXPR decltype(auto) call(VariantArgIndexSequence, Visitor&& visitor, Variants&&... variants) + { + EA_CPP14_CONSTEXPR auto callers = make_visitor_array(make_invoke_visitor_recurse(meta::double_pack_expansion_t{})...); + + return call_visitor_at>(eastl::move(callers), + eastl::forward(visitor), + eastl::forward(variants)...); } + }; - template - struct visitor_caller + template + static EA_CONSTEXPR decltype(auto) call_initial_n(VariantIndexSequence, Visitor&& visitor, Variants&&... variants) + { + return visitor_caller_n::call(index_sequence<>{}, eastl::forward(visitor), eastl::forward(variants)...); + } + + + // abstracts calling visit on 2 or more variants with return types convertible to R + template + struct visitor_caller_n_r; + + template + struct visitor_caller_n_r, Visitor, Variants...> { - // Invoke the correct visitor for a given variant index, and call the correct get() function to retrieve - // the argument. Unpack any additional arguments from earlier visitor_callers (see above). - template - static decltype(auto) EA_CONSTEXPR invoke_visitor(Visitor&& visitor, index_sequence, ArgsTuple&& args, Variant&& variant) - { - return static_cast(invoke( - eastl::forward(visitor), - get(eastl::forward(args))..., - get(eastl::forward(variant)) - )); + template + struct visitor_leaf_r + { + static EA_CONSTEXPR R_ invoke_visitor_leaf_r(Visitor&& visitor, Variants&&... variants) + { + return eastl::invoke(eastl::forward(visitor), + eastl::get(eastl::forward(variants))...); + } + }; + + // void return type must discard the return values of the visitor even if the visitor returns a value. + template + struct visitor_leaf_r + { + static EA_CONSTEXPR void invoke_visitor_leaf_r(Visitor&& visitor, Variants&&... variants) + { + eastl::invoke(eastl::forward(visitor), + eastl::get(eastl::forward(variants))...); + } + }; + template struct visitor_leaf_r : public visitor_leaf_r {}; + template struct visitor_leaf_r : public visitor_leaf_r {}; + template struct visitor_leaf_r : public visitor_leaf_r {}; + + template + static EA_CONSTEXPR auto make_invoke_visitor_leaf_r(index_sequence) + { + return &visitor_leaf_r::invoke_visitor_leaf_r; } - // The final call() in the recursion. - // - // By this point, expands to <0 .. N - 2> where N is the number of arguments to the - // final invoke() call. This corresponds to each element in @args, so `get(args)...` - // expands to `get<0>(args), get<1>(args), ... , get(args)`. The final argument is selected - // based on the final array index, leaving us with a sequence of arguments from 0 .. N - 1. - // - // is the same as in earlier calls - it expands to <0 .. I - 1> where I is the - // number of alternatives in the variant. This lets us call the correct `get` based on the - // final variant index, as we did for all earlier calls. - template - static decltype(auto) EA_CPP14_CONSTEXPR call(Visitor&& visitor, index_sequence, index_sequence, ArgsTuple&& args, Variant&& variant) - { - // MSVC isn't able to handle the nested pack expansion required here, so we have to just use the - // return type of the first visitor function instead of the common_type of all possible visitor - // functions. This means we can't handle the case where visitor functions return different (but - // compatible) types. This is unlikely to be a common case, but we might be able to get around it - // if it's a big issue. - // - // TODO: we should reevaluate this on future compiler releases - #if defined(EA_COMPILER_MSVC) - using return_type = invoke_result_t(args))..., decltype(get<0>(variant))>; - #else - // If we're on a compiler that can take it, determine the common_type between all possible visitor - // invocations. - using return_type = common_type_t< - invoke_result_t(args))..., decltype(get(variant))>... - >; - #endif - using caller_type = return_type (*)(Visitor&&, index_sequence, ArgsTuple&&, Variant&&); + template + struct visitor_recurse_r + { + static EA_CONSTEXPR R_ invoke_visitor_recurse_r(Visitor&& visitor, Variants&&... variants) + { + return call_r(index_sequence{}, + eastl::forward(visitor), + eastl::forward(variants)...); + } + }; + + template + static EA_CONSTEXPR auto make_invoke_visitor_recurse_r(index_sequence) + { + return &visitor_recurse_r::invoke_visitor_recurse_r; + } - // Create the final array of invoke_visitor<0>, invoke_visitor<1>, ... , invoke_visitor - // where N = variant_size - EA_CPP14_CONSTEXPR caller_type callers[] = { invoke_visitor... }; - return callers[eastl::forward(variant).index()]( - eastl::forward(visitor), - index_sequence(), - eastl::forward(args), - eastl::forward(variant) - ); + template + 1 == sizeof...(Variants), int> = 0> + static EA_CPP14_CONSTEXPR decltype(auto) call_r(VariantArgIndexSequence, Visitor&& visitor, Variants&&... variants) + { + EA_CPP14_CONSTEXPR auto callers = make_visitor_array(make_invoke_visitor_leaf_r(meta::double_pack_expansion_t{})...); + + return call_visitor_at>(eastl::move(callers), + eastl::forward(visitor), + eastl::forward(variants)...); + } + + template + 1 != sizeof...(Variants), int> = 0> + static EA_CPP14_CONSTEXPR decltype(auto) call_r(VariantArgIndexSequence, Visitor&& visitor, Variants&&... variants) + { + EA_CPP14_CONSTEXPR auto callers = make_visitor_array(make_invoke_visitor_recurse_r(meta::double_pack_expansion_t{})...); + + return call_visitor_at>(eastl::move(callers), + eastl::forward(visitor), + eastl::forward(variants)...); + } + + }; + + template + static EA_CONSTEXPR decltype(auto) call_initial_n_r(VariantIndexSequence, Visitor&& visitor, Variants&&... variants) + { + return visitor_caller_n_r::call_r(index_sequence<>{}, eastl::forward(visitor), eastl::forward(variants)...); + } + + + // abstracts calling visit on a single variant + struct visitor_caller_one + { + + template + static EA_CONSTEXPR decltype(auto) invoke_visitor(Visitor&& visitor, Variant&& variant) + { + return eastl::invoke(eastl::forward(visitor), + eastl::get(eastl::forward(variant))); + } + + template + static EA_CPP14_CONSTEXPR decltype(auto) call_index(Visitor&& visitor, Variant&& variant, index_sequence) + { + EA_CPP14_CONSTEXPR auto callers = make_visitor_array((&invoke_visitor)...); + + return call_visitor_at_index(eastl::move(callers), eastl::forward(variant).index(), + eastl::forward(visitor), eastl::forward(variant)); + } + + template + static EA_CONSTEXPR decltype(auto) call(Visitor&& visitor, Variant&& variant) + { + return call_index(eastl::forward(visitor), + eastl::forward(variant), + make_index_sequence>>{}); + } + + }; + + + // abstracts calling visit on a single variant with return types convertible to R + struct visitor_caller_one_r + { + template + struct visitor_r + { + template + static EA_CONSTEXPR R invoke_visitor_r(Visitor&& visitor, Variant&& variant) + { + return eastl::invoke(eastl::forward(visitor), + eastl::get(eastl::forward(variant))); + } + }; + + // void return type must discard the return values of the visitor even if the visitor returns a value. + template <> + struct visitor_r + { + template + static EA_CONSTEXPR void invoke_visitor_r(Visitor&& visitor, Variant&& variant) + { + eastl::invoke(eastl::forward(visitor), + eastl::get(eastl::forward(variant))); + } + }; + template<> struct visitor_r : public visitor_r {}; + template<> struct visitor_r : public visitor_r {}; + template<> struct visitor_r : public visitor_r {}; + + template + static EA_CPP14_CONSTEXPR decltype(auto) call_index_r(Visitor&& visitor, Variant&& variant, eastl::index_sequence) + { + EA_CPP14_CONSTEXPR auto callers = make_visitor_array(&visitor_r::template invoke_visitor_r...); + + return callers[static_cast(eastl::forward(variant).index())](eastl::forward(visitor), + eastl::forward(variant)); + } + + template + static EA_CONSTEXPR decltype(auto) call_r(Visitor&& visitor, Variant&& variant) + { + return call_index_r(eastl::forward(visitor), eastl::forward(variant), eastl::make_index_sequence>>()); } + }; + /////////////////////////////////////////////////////////////////////////// // 20.7.6, visitation // @@ -1107,24 +1345,80 @@ namespace eastl // visit(MyVisitor{}, v); // calls MyVisitor::operator()(string) {} // + template + static EA_CPP14_CONSTEXPR void visit_throw_bad_variant_access(Variants&&... variants) + { + #if EASTL_EXCEPTIONS_ENABLED + using bool_array_type = bool[]; + bool badAccess = false; + + (void)bool_array_type{ (badAccess |= eastl::forward(variants).valueless_by_exception(), false)... }; + + if (badAccess) + { + throw bad_variant_access(); + } + #endif + } + + template + static EA_CONSTEXPR void visit_static_assert_check(Variants&&... variants) + { + static_assert(sizeof...(Variants) > 0, "`visit` at least one variant instance must be passed as an argument to the visit function"); + + using variant_type = decay_t>; + static_assert(conjunction_v>...>, + "`visit` all variants passed to eastl::visit() must have the same type"); + } + + // visit // - template - EA_CONSTEXPR decltype(auto) visit(Visitor&& visitor, Variants&&... variants) + template + EA_CPP14_CONSTEXPR decltype(auto) visit(Visitor&& visitor, Variant&& variant) + { + visit_static_assert_check(eastl::forward(variant)); + + visit_throw_bad_variant_access(eastl::forward(variant)); + + return visitor_caller_one::call(eastl::forward(visitor), + eastl::forward(variant)); + } + + template + EA_CPP14_CONSTEXPR decltype(auto) visit(Visitor&& visitor, Variants&&... variants) + { + visit_static_assert_check(eastl::forward(variants)...); + + visit_throw_bad_variant_access(eastl::forward(variants)...); + + return call_initial_n(make_index_sequence>>>{}, + eastl::forward(visitor), + eastl::forward(variants)...); + + } + + template , int> = 0> + EA_CPP14_CONSTEXPR R visit(Visitor&& visitor, Variant&& variant) + { + visit_static_assert_check(eastl::forward(variant)); + + visit_throw_bad_variant_access(eastl::forward(variant)); + + return visitor_caller_one_r::call_r(eastl::forward(visitor), + eastl::forward(variant)); + } + + template , int> = 0> + EA_CPP14_CONSTEXPR R visit(Visitor&& visitor, Variants&&... variants) { - static_assert(sizeof...(Variants) > 0, "at least one variant instance must be passed as an argument to the visit function"); - - using variant_type = remove_reference_t>; - static_assert(conjunction_v>...>, - "all variants passed to eastl::visit() must have the same type"); - - return visitor_caller::call( - eastl::forward(visitor), - index_sequence<>(), - make_index_sequence>(), - tuple<>(), - eastl::forward(variants)... - ); + visit_static_assert_check(eastl::forward(variants)...); + + visit_throw_bad_variant_access(eastl::forward(variants)...); + + return call_initial_n_r(make_index_sequence>>>{}, + eastl::forward(visitor), + eastl::forward(variants)...); } @@ -1134,42 +1428,46 @@ namespace eastl namespace internal { - template - EA_CPP14_CONSTEXPR bool Compare(const variant& lhs, const variant& rhs, Predicate predicate) + // For relational operators we do not need to create the NxN matrix of comparisons since we know already + // that both the lhs and rhs variants have the same index. We just need to compare the value of the types at that + // index for equality. Therefore the visitation is simpler than visit() for relational operators. + // + struct variant_relational_comparison { - return visit(predicate, lhs, rhs); - } - // For variant visitation, we need to have a comparison function for all possible combinations of types, - // eg. for variant, our comparator needs: - // - // bool operator()(int, int); - // bool operator()(int, string); - // bool operator()(string, int); - // bool operator()(string, string); - // - // Even though we never call the mixed-type versions of these functions when comparing variants, we - // need them in order to compile visit(). So this struct forwards the good comparisons to the appropriate - // comparison, and asserts that we never call the bad comparisons. - template - struct variant_comparison : public C - { - template , eastl::decay_t>>> - auto operator()(const A& a, const B& b) + template + static EA_CONSTEXPR bool invoke_relational_visitor(const Variant& lhs, const Variant& rhs) { - return C::operator()(a, b); + return eastl::invoke(Compare{}, eastl::get(lhs), eastl::get(rhs)); } - template , eastl::decay_t>>> - bool operator()(const A&, const B&) + template + static EA_CPP14_CONSTEXPR bool call_index(const Variant& lhs, const Variant& rhs, eastl::index_sequence) { - EASTL_ASSERT_MSG(false, "eastl::variant<> comparison function called on two different types at different indices! This is a library bug! Please file bug report."); - return false; + using invoke_relational_visitor_func_ptr = bool (*)(const Variant&, const Variant&); + + EA_CPP14_CONSTEXPR invoke_relational_visitor_func_ptr visitors[] = { static_cast(&invoke_relational_visitor)... }; + + return visitors[lhs.index()](lhs, rhs); + } + + template + static EA_CONSTEXPR bool call(const Variant& lhs, const Variant& rhs) + { + return call_index(lhs, rhs, eastl::make_index_sequence>>()); } + }; + template + static EA_CONSTEXPR bool CompareVariantRelational(const Variant& lhs, const Variant& rhs) + { + return variant_relational_comparison::call(lhs, rhs); + } + } // namespace internal + /////////////////////////////////////////////////////////////////////////// // 20.7.5, relational operators // @@ -1178,7 +1476,17 @@ namespace eastl { if (lhs.index() != rhs.index()) return false; if (lhs.valueless_by_exception()) return true; - return internal::Compare(lhs, rhs, internal::variant_comparison>{}); + + return internal::CompareVariantRelational>(lhs, rhs); + } + + template + EA_CPP14_CONSTEXPR bool operator!=(const variant& lhs, const variant& rhs) + { + if (lhs.index() != rhs.index()) return true; + if (lhs.valueless_by_exception()) return false; + + return internal::CompareVariantRelational>(lhs, rhs); } template @@ -1188,15 +1496,8 @@ namespace eastl if (lhs.valueless_by_exception()) return true; if (lhs.index() < rhs.index()) return true; if (lhs.index() > rhs.index()) return false; - return internal::Compare(lhs, rhs, internal::variant_comparison>{}); - } - template - EA_CPP14_CONSTEXPR bool operator!=(const variant& lhs, const variant& rhs) - { - if (lhs.index() != rhs.index()) return true; - if (lhs.valueless_by_exception()) return false; - return internal::Compare(lhs, rhs, internal::variant_comparison>{}); + return internal::CompareVariantRelational>(lhs, rhs); } template @@ -1206,17 +1507,19 @@ namespace eastl if (rhs.valueless_by_exception()) return true; if (lhs.index() > rhs.index()) return true; if (lhs.index() < rhs.index()) return false; - return internal::Compare(lhs, rhs, internal::variant_comparison>{}); + + return internal::CompareVariantRelational>(lhs, rhs); } template EA_CPP14_CONSTEXPR bool operator<=(const variant& lhs, const variant& rhs) { - if (rhs.valueless_by_exception()) return true; - if (lhs.valueless_by_exception()) return false; + if (lhs.valueless_by_exception()) return true; + if (rhs.valueless_by_exception()) return false; if (lhs.index() < rhs.index()) return true; if (lhs.index() > rhs.index()) return false; - return internal::Compare(lhs, rhs, internal::variant_comparison>{}); + + return internal::CompareVariantRelational>(lhs, rhs); } template @@ -1226,11 +1529,12 @@ namespace eastl if (lhs.valueless_by_exception()) return false; if (lhs.index() > rhs.index()) return true; if (lhs.index() < rhs.index()) return false; - return internal::Compare(lhs, rhs, internal::variant_comparison>{}); + + return internal::CompareVariantRelational>(lhs, rhs); } + } // namespace eastl EA_RESTORE_VC_WARNING() #endif // EASTL_VARIANT_H - diff --git a/source/numeric_limits.cpp b/source/numeric_limits.cpp index 7b7bf2f8..4eed54e8 100644 --- a/source/numeric_limits.cpp +++ b/source/numeric_limits.cpp @@ -39,7 +39,7 @@ #endif -#if defined(_MSC_VER) +#if defined(_MSC_VER) && !defined(EA_COMPILER_CLANG_CL) // VC++ has a long-standing bug: it fails to allow the definition of static const member variables // outside the declaration within the class. The C++ Standard actually requires that they be defined // and some other compilers fail to link if they aren't. So we simply don't define the members for VC++. @@ -442,7 +442,7 @@ EA_CONSTEXPR_OR_CONST bool numeric_limits::is_iec559; // __uint128_t - #if (EA_COMPILER_INTMAX_SIZE >= 16) && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) // If __int128_t/__uint128_t is supported... + #if (EA_COMPILER_INTMAX_SIZE >= 16) && (defined(EA_COMPILER_GNUC) || defined(__clang__)) // If __int128_t/__uint128_t is supported... EA_CONSTEXPR_OR_CONST bool numeric_limits<__uint128_t>::is_specialized; EA_CONSTEXPR_OR_CONST int numeric_limits<__uint128_t>::digits; EA_CONSTEXPR_OR_CONST int numeric_limits<__uint128_t>::digits10; @@ -468,7 +468,7 @@ #endif // __int128_t - #if (EA_COMPILER_INTMAX_SIZE >= 16) && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) // If __int128_t/__uint128_t is supported... + #if (EA_COMPILER_INTMAX_SIZE >= 16) && (defined(EA_COMPILER_GNUC) || defined(__clang__)) // If __int128_t/__uint128_t is supported... EA_CONSTEXPR_OR_CONST bool numeric_limits<__int128_t>::is_specialized; EA_CONSTEXPR_OR_CONST int numeric_limits<__int128_t>::digits; EA_CONSTEXPR_OR_CONST int numeric_limits<__int128_t>::digits10; diff --git a/source/thread_support.cpp b/source/thread_support.cpp index 1b036295..547e5886 100644 --- a/source/thread_support.cpp +++ b/source/thread_support.cpp @@ -49,7 +49,11 @@ namespace eastl pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); - pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE); + + #if defined(EA_HAVE_pthread_mutexattr_setpshared_DECL) + pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE); + #endif + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&mMutex, &attr); pthread_mutexattr_destroy(&attr); diff --git a/test/source/EASTLTest.h b/test/source/EASTLTest.h index 1cb298b1..1908f5f9 100644 --- a/test/source/EASTLTest.h +++ b/test/source/EASTLTest.h @@ -82,6 +82,7 @@ int TestVectorMap(); int TestVectorSet(); int TestAtomicBasic(); int TestAtomicAsm(); +int TestBitcast(); // Now enable warnings as desired. diff --git a/test/source/TestBitcast.cpp b/test/source/TestBitcast.cpp new file mode 100644 index 00000000..d6f0840b --- /dev/null +++ b/test/source/TestBitcast.cpp @@ -0,0 +1,52 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#include "EASTLTest.h" +#include + +using namespace eastl; + + +int TestBitcast() +{ + int nErrorCount = 0; + + { + uint32_t int32Value = 0x12345678; + float floatValue = eastl::bit_cast(int32Value); + VERIFY(memcmp(&int32Value, &floatValue, sizeof(float)) == 0); + } + + { + struct IntFloatStruct + { + uint32_t i = 0x87654321; + float f = 10.f; + }; + struct CharIntStruct + { + char c1; + char c2; + char c3; + char c4; + uint32_t i; + }; + + IntFloatStruct ifStruct; + CharIntStruct ciStruct = eastl::bit_cast(ifStruct); + VERIFY(memcmp(&ifStruct, &ciStruct, sizeof(IntFloatStruct)) == 0); + } + +#if EASTL_CONSTEXPR_BIT_CAST_SUPPORTED + { + constexpr uint32_t int32Value = 40; + constexpr float floatValue = eastl::bit_cast(int32Value); + VERIFY(memcmp(&int32Value, &floatValue, sizeof(float)) == 0); + } +#endif + + + return nErrorCount; +} diff --git a/test/source/TestFunctional.cpp b/test/source/TestFunctional.cpp index 88f4c2cf..63b35163 100644 --- a/test/source/TestFunctional.cpp +++ b/test/source/TestFunctional.cpp @@ -68,14 +68,17 @@ namespace bool operator==(const N1& n1, const N1& n1a){ return (n1.mX == n1a.mX); } bool operator==(const N1& n1, const N2& n2) { return (n1.mX == n2.mX); } bool operator==(const N2& n2, const N1& n1) { return (n2.mX == n1.mX); } + bool operator==(const volatile N1& n1, const volatile N1& n1a) { return (n1.mX == n1a.mX); } bool operator!=(const N1& n1, const N1& n1a){ return (n1.mX != n1a.mX); } bool operator!=(const N1& n1, const N2& n2) { return (n1.mX != n2.mX); } bool operator!=(const N2& n2, const N1& n1) { return (n2.mX != n1.mX); } + bool operator!=(const volatile N1& n1, const volatile N1& n1a) { return (n1.mX != n1a.mX); } bool operator< (const N1& n1, const N1& n1a){ return (n1.mX < n1a.mX); } bool operator< (const N1& n1, const N2& n2) { return (n1.mX < n2.mX); } bool operator< (const N2& n2, const N1& n1) { return (n2.mX < n1.mX); } + bool operator< (const volatile N1& n1, const volatile N1& n1a) { return (n1.mX < n1a.mX); } // Used for mem_fun tests below. @@ -260,8 +263,12 @@ int TestFunctional() N1 n13(3); N2 n21(1); N2 n22(2); - //const N1 cn11(1); - //const N1 cn13(3); + const N1 cn11(1); + const N1 cn13(3); + volatile N1 vn11(1); + volatile N1 vn13(3); + const volatile N1 cvn11(1); + const volatile N1 cvn13(3); equal_to_2 e; EATEST_VERIFY(e(n11, n21)); @@ -269,9 +276,40 @@ int TestFunctional() equal_to_2 es; EATEST_VERIFY(es(n11, n11)); + EATEST_VERIFY(!es(n11, n13)); - //equal_to_2 ec; // To do: Make this case work. - //EATEST_VERIFY(e(cn11, n11)); + equal_to_2 ec; + EATEST_VERIFY(ec(cn11, n11)); + EATEST_VERIFY(ec(n11, cn11)); + + equal_to_2 ec2; + EATEST_VERIFY(ec2(n11, cn11)); + EATEST_VERIFY(ec2(cn11, n11)); + + equal_to_2 ecc; + EATEST_VERIFY(ecc(cn11, cn11)); + + equal_to_2 ev; + EATEST_VERIFY(ev(vn11, n11)); + EATEST_VERIFY(ev(n11, vn11)); + + equal_to_2 ev2; + EATEST_VERIFY(ev2(n11, vn11)); + EATEST_VERIFY(ev2(vn11, n11)); + + equal_to_2 evv; + EATEST_VERIFY(evv(vn11, vn11)); + + equal_to_2 ecv; + EATEST_VERIFY(ecv(cvn11, n11)); + EATEST_VERIFY(ecv(n11, cvn11)); + + equal_to_2 ecv2; + EATEST_VERIFY(ecv2(n11, cvn11)); + EATEST_VERIFY(ecv2(cvn11, n11)); + + equal_to_2 ecvcv; + EATEST_VERIFY(ecvcv(cvn11, cvn11)); // not_equal_to_2 not_equal_to_2 n; @@ -280,6 +318,40 @@ int TestFunctional() not_equal_to_2 ns; EATEST_VERIFY(ns(n11, n13)); + EATEST_VERIFY(!ns(n11, n11)); + + not_equal_to_2 nc; + EATEST_VERIFY(nc(cn11, n13)); + EATEST_VERIFY(nc(n13, cn11)); + + not_equal_to_2 nc2; + EATEST_VERIFY(nc2(n13, cn11)); + EATEST_VERIFY(nc2(cn11, n13)); + + not_equal_to_2 ncc; + EATEST_VERIFY(ncc(cn11, cn13)); + + not_equal_to_2 nv; + EATEST_VERIFY(nv(vn11, n13)); + EATEST_VERIFY(nv(n11, vn13)); + + not_equal_to_2 nv2; + EATEST_VERIFY(nv2(n11, vn13)); + EATEST_VERIFY(nv2(vn11, n13)); + + not_equal_to_2 nvv; + EATEST_VERIFY(nvv(vn11, vn13)); + + not_equal_to_2 ncv; + EATEST_VERIFY(ncv(cvn11, n13)); + EATEST_VERIFY(ncv(n11, cvn13)); + + not_equal_to_2 ncv2; + EATEST_VERIFY(ncv2(n11, cvn13)); + EATEST_VERIFY(ncv2(cvn11, n13)); + + not_equal_to_2 ncvcv; + EATEST_VERIFY(ncvcv(cvn11, cvn13)); // less_2 less_2 le; @@ -288,6 +360,39 @@ int TestFunctional() less_2 les; EATEST_VERIFY(les(n11, n13)); + + less_2 lec; + EATEST_VERIFY(lec(cn11, n13)); + EATEST_VERIFY(lec(n11, cn13)); + + less_2 lec2; + EATEST_VERIFY(lec2(n11, cn13)); + EATEST_VERIFY(lec2(cn11, n13)); + + less_2 lecc; + EATEST_VERIFY(lecc(cn11, cn13)); + + less_2 lev; + EATEST_VERIFY(lev(vn11, n13)); + EATEST_VERIFY(lev(n11, vn13)); + + less_2 lev2; + EATEST_VERIFY(lev2(n11, vn13)); + EATEST_VERIFY(lev2(vn11, n13)); + + less_2 levv; + EATEST_VERIFY(levv(vn11, vn13)); + + less_2 lecv; + EATEST_VERIFY(lecv(cvn11, n13)); + EATEST_VERIFY(lecv(n11, cvn13)); + + less_2 lecv2; + EATEST_VERIFY(lecv2(n11, cvn13)); + EATEST_VERIFY(lecv2(cvn11, n13)); + + less_2 lecvcv; + EATEST_VERIFY(lecvcv(cvn11, cvn13)); } @@ -435,6 +540,7 @@ int TestFunctional() void Add(int addAmount) { value += addAmount; } int GetValue() { return value; } int& GetValueReference() { return value; } + void NoThrow(int inValue) EA_NOEXCEPT {} int value; }; @@ -444,6 +550,12 @@ int TestFunctional() bool called = false; }; + struct TestFunctorNoThrow + { + void operator()() EA_NOEXCEPT { called = true; } + bool called = false; + }; + struct TestFunctorArguments { void operator()(int i) { value = i; } @@ -457,6 +569,8 @@ int TestFunctional() static_assert(eastl::is_same::type, void>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); + static_assert(eastl::is_nothrow_invocable::value, "incorrect value for is_nothrow_invocable"); + static_assert(!eastl::is_nothrow_invocable::value, "incorrect value for is_nothrow_invocable"); } { TestStruct a(42); @@ -465,6 +579,8 @@ int TestFunctional() static_assert(eastl::is_same::type, void>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); + static_assert(eastl::is_nothrow_invocable::value, "incorrect value for is_nothrow_invocable"); + static_assert(!eastl::is_nothrow_invocable::value, "incorrect value for is_nothrow_invocable"); } { TestStruct a(42); @@ -474,6 +590,8 @@ int TestFunctional() static_assert(eastl::is_same, int>::type, void>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable, int>::value, "incorrect value for is_invocable"); + static_assert(eastl::is_nothrow_invocable, int>::value, "incorrect value for is_nothrow_invocable"); + static_assert(!eastl::is_nothrow_invocable, int>::value, "incorrect value for is_nothrow_invocable"); } { TestStruct a(42); @@ -535,6 +653,16 @@ int TestFunctional() static_assert(eastl::is_same::type, void>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); + static_assert(!eastl::is_nothrow_invocable::value, "incorrect value for is_nothrow_invocable"); + } + { + TestFunctorNoThrow f; + eastl::invoke(f); + EATEST_VERIFY(f.called); + + static_assert(eastl::is_same::type, void>::value, "incorrect type for invoke_result"); + static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); + static_assert(eastl::is_nothrow_invocable::value, "incorrect value for is_nothrow_invocable"); } { TestFunctorArguments f; @@ -544,6 +672,43 @@ int TestFunctional() static_assert(eastl::is_same::type, void>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); } + { + struct TestInvokeConstAccess + { + void ConstMemberFunc(int i) const {} + void ConstVolatileMemberFunc(int i) const volatile {} + + int mI; + }; + + static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); + static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); + } + { + struct TestReferenceWrapperInvoke + { + int NonConstMemberFunc(int i) { return i; } + int ConstMemberFunc(int i) const { return i; } + + int mI = 1; + const int mIC = 1; + }; + + TestReferenceWrapperInvoke testStruct; + int ret; + + ret = eastl::invoke(&TestReferenceWrapperInvoke::NonConstMemberFunc, eastl::ref(testStruct), 1); + EATEST_VERIFY(ret == 1); + + ret = eastl::invoke(&TestReferenceWrapperInvoke::ConstMemberFunc, eastl::ref(testStruct), 1); + EATEST_VERIFY(ret == 1); + + ret = eastl::invoke(&TestReferenceWrapperInvoke::mI, eastl::ref(testStruct)); + EATEST_VERIFY(ret == 1); + + ret = eastl::invoke(&TestReferenceWrapperInvoke::mIC, eastl::ref(testStruct)); + EATEST_VERIFY(ret == 1); + } { static bool called = false; auto f = [] {called = true;}; @@ -565,16 +730,20 @@ int TestFunctional() { struct A {}; struct B : public A {}; + struct C : public A {}; struct TestStruct { A a() { return A(); }; B b() { return B(); }; + C c() EA_NOEXCEPT { return C(); }; }; static_assert(!eastl::is_invocable_r::value, "incorrect value for is_invocable_r"); static_assert(eastl::is_invocable_r::value, "incorrect value for is_invocable_r"); static_assert(eastl::is_invocable_r::value, "incorrect value for is_invocable_r"); + static_assert(!eastl::is_nothrow_invocable_r::value, "incorrect value for is_nothrow_invocable_r"); + static_assert(eastl::is_nothrow_invocable_r::value, "incorrect value for is_nothrow_invocable_r"); } } diff --git a/test/source/TestHash.cpp b/test/source/TestHash.cpp index eff6156b..9c9bf9d7 100644 --- a/test/source/TestHash.cpp +++ b/test/source/TestHash.cpp @@ -994,9 +994,19 @@ int TestHash() EATEST_VERIFY(it != hashSet.end()); else EATEST_VERIFY(it == hashSet.end()); + + string::CtorSprintf cs; + string s(cs, "%d", i); + + it = hashSet.find_as(s); + if (i < kCount) + EATEST_VERIFY(it != hashSet.end()); + else + EATEST_VERIFY(it == hashSet.end()); } } + { // Test const containers. const hash_set constHashSet; diff --git a/test/source/TestIntrusiveHash.cpp b/test/source/TestIntrusiveHash.cpp index 4fd8215c..f089aabe 100644 --- a/test/source/TestIntrusiveHash.cpp +++ b/test/source/TestIntrusiveHash.cpp @@ -617,6 +617,12 @@ int TestIntrusiveHash() itfc = ihmMW1Const.find_as(7.f); VERIFY(itfc->mKey == 7); + + itf = ihmMW1.find_as(8); + VERIFY(itf->mKey == 8); + + itfc = ihmMW1Const.find_as(8); + VERIFY(itfc->mKey == 8); // iterator find_as(const U& u, UHash uhash, BinaryPredicate predicate); diff --git a/test/source/TestIterator.cpp b/test/source/TestIterator.cpp index e1681182..02aa1d40 100644 --- a/test/source/TestIterator.cpp +++ b/test/source/TestIterator.cpp @@ -14,6 +14,7 @@ #include #include #include +#include EA_DISABLE_ALL_VC_WARNINGS() #include @@ -139,6 +140,77 @@ int TestIterator_moveIterator() EATEST_VERIFY(*moveIter != *(constBeginMoveIter + 2)); } + { + // Ensure that move_iterator indeed move yielded value whenever possible. + auto x = eastl::make_unique(42); + auto* pX = &x; + auto moveIter = eastl::make_move_iterator(pX); + + constexpr bool isCorrectReferenceType = eastl::is_same_v&&>; + constexpr bool isCorrectReturnType = eastl::is_same_v&&>; + + static_assert(isCorrectReferenceType, "move_iterator::reference has wrong type."); + static_assert(isCorrectReturnType, "move_iterator::operator*() has wrong return type."); + EATEST_VERIFY(isCorrectReferenceType); + EATEST_VERIFY(isCorrectReturnType); + + auto pMoveX = *moveIter; + EATEST_VERIFY(*pMoveX == 42); + } + + // Bellow are regression tests that ensure we are covering the defect LWG 2106: http://cplusplus.github.io/LWG/lwg-defects.html#2106 + { + // Check that we support iterators yielding const references. + const int x = 42; + const int* pX = &x; + auto moveIter = eastl::make_move_iterator(pX); + + constexpr bool isCorrectReferenceType = eastl::is_same_v; + constexpr bool isCorrectReturnType = eastl::is_same_v; + + static_assert(isCorrectReferenceType, "move_iterator::reference has wrong type."); + static_assert(isCorrectReturnType, "move_iterator::operator*() has wrong return type."); + EATEST_VERIFY(isCorrectReferenceType); + EATEST_VERIFY(isCorrectReturnType); + + auto pCopiedX = *moveIter; + EATEST_VERIFY(pCopiedX == 42); + } + + { + // Check that we support iterators yielding plain value (typically a proxy-iterator). + struct FakeProxyIterator + { + using iterator_category = eastl::forward_iterator_tag; + using difference_type = ptrdiff_t; + using value_type = int; + using pointer = int; // Note that we are yielding by value. + using reference = int; // Note that we are yielding by value. + + reference operator*() const { return 42; } + pointer operator->() { return 42; } + FakeProxyIterator& operator++() { return *this; } + FakeProxyIterator operator++(int) { return {}; } + + bool operator==(const FakeProxyIterator& rhs) { return true; }; + bool operator!=(const FakeProxyIterator& rhs) { return false; }; + }; + + FakeProxyIterator it = {}; + auto moveIter = eastl::make_move_iterator(it); + + constexpr bool isCorrectReferenceType = eastl::is_same_v; + constexpr bool isCorrectReturnType = eastl::is_same_v; + + static_assert(isCorrectReferenceType, "move_iterator::reference has wrong type."); + static_assert(isCorrectReturnType, "move_iterator::operator*() has wrong return type."); + EATEST_VERIFY(isCorrectReferenceType); + EATEST_VERIFY(isCorrectReturnType); + + auto pCopiedX = *moveIter; + EATEST_VERIFY(pCopiedX == 42); + } + return nErrorCount; } @@ -385,6 +457,17 @@ int TestIterator() static_assert((eastl::is_same::iterator>::value == true), "unwrap_iterator failure"); } + { + // array cbegin - cend + int arr[3]{ 1, 2, 3 }; + auto b = eastl::cbegin(arr); + auto e = eastl::cend(arr); + EATEST_VERIFY(*b == 1); + + auto dist = eastl::distance(b,e); + EATEST_VERIFY(dist == 3); + } + return nErrorCount; } diff --git a/test/source/TestMap.cpp b/test/source/TestMap.cpp index df4a195e..e2eef2f4 100644 --- a/test/source/TestMap.cpp +++ b/test/source/TestMap.cpp @@ -119,6 +119,19 @@ int TestMap() m.find_as(EA_CHAR8("some string"), eastl::equal_to_2()); } + { + eastl::map m; + int* ip = (int*)(uintptr_t)0xDEADC0DE; + + m[ip] = 0; + + auto it = m.find_as(ip, eastl::less_2{}); + EATEST_VERIFY(it != m.end()); + + it = m.find_as((int*)(uintptr_t)0xDEADC0DE, eastl::less_2{}); + EATEST_VERIFY(it != m.end()); + } + { // User reports that vector> is crashing after the recent changes to add rvalue move and emplace support to rbtree. typedef eastl::map IntIntMap; diff --git a/test/source/TestOptional.cpp b/test/source/TestOptional.cpp index 6c1fa4fc..b4934a71 100644 --- a/test/source/TestOptional.cpp +++ b/test/source/TestOptional.cpp @@ -536,13 +536,13 @@ int TestOptional() // optional rvalue tests { - VERIFY(*optional(1) == 1); - VERIFY( optional(1).value() == 1); - VERIFY( optional(1).value_or(0xdeadf00d) == 1); - VERIFY( optional().value_or(0xdeadf00d) == 0xdeadf00d); - VERIFY( optional(1).has_value() == true); - VERIFY( optional().has_value() == false); - VERIFY( optional(in_place, 10)->data == 10); + VERIFY(*optional(1u) == 1u); + VERIFY(optional(1u).value() == 1u); + VERIFY(optional(1u).value_or(0xdeadf00d) == 1u); + VERIFY(optional().value_or(0xdeadf00d) == 0xdeadf00d); + VERIFY(optional(1u).has_value() == true); + VERIFY(optional().has_value() == false); + VERIFY( optional(in_place, 10)->data == 10); } @@ -611,7 +611,7 @@ int TestOptional() copyCtorCalledWithUninitializedValue = moveCtorCalledWithUninitializedValue = false; struct local { - int val; + uint32_t val; local() : val(0xabcdabcd) {} diff --git a/test/source/TestSpan.cpp b/test/source/TestSpan.cpp index 060950d0..5a0ec077 100644 --- a/test/source/TestSpan.cpp +++ b/test/source/TestSpan.cpp @@ -295,7 +295,7 @@ void TestSpanContainerConversion(int& nErrorCount) { vector v = {0, 1, 2, 3, 4, 5}; - span s1(v); + span s1(v); span s2(s1); VERIFY(s2.size() == (span::index_type)v.size()); @@ -391,6 +391,24 @@ void TestSpanSubViews(int& nErrorCount) VERIFY(first_span[3] == 9); } + { // empty range + span s{}; + + auto fixed_span = s.subspan<0, 0>(); + VERIFY(fixed_span.empty()); + fixed_span = s.first<0>(); + VERIFY(fixed_span.empty()); + fixed_span = s.last<0>(); + VERIFY(fixed_span.empty()); + + span dynamic_span; + VERIFY(dynamic_span.empty()); + dynamic_span = s.first(0); + VERIFY(dynamic_span.empty()); + dynamic_span = s.last(0); + VERIFY(dynamic_span.empty()); + } + { // subspan: full range span s = arr1; diff --git a/test/source/TestTypeTraits.cpp b/test/source/TestTypeTraits.cpp index 0fb6280f..0353be91 100644 --- a/test/source/TestTypeTraits.cpp +++ b/test/source/TestTypeTraits.cpp @@ -620,9 +620,15 @@ int TestTypeTraits() static_assert(is_reference::value == true, "is_reference failure"); EATEST_VERIFY(GetType(is_reference()) == true); + static_assert(is_reference::value == true, "is_reference failure"); + EATEST_VERIFY(GetType(is_reference()) == true); + static_assert(is_reference::value == true, "is_reference failure"); EATEST_VERIFY(GetType(is_reference()) == true); + static_assert(is_reference::value == true, "is_reference failure"); + EATEST_VERIFY(GetType(is_reference()) == true); + static_assert(is_reference::value == false, "is_reference failure"); EATEST_VERIFY(GetType(is_reference()) == false); @@ -674,6 +680,14 @@ int TestTypeTraits() static_assert(is_enum_v == false, "is_enum failure "); EATEST_VERIFY(GetType(is_enum()) == false); + static_assert(is_enum::value == false, "is_enum failure "); + static_assert(is_enum_v == false, "is_enum failure "); + EATEST_VERIFY(GetType(is_enum()) == false); + + static_assert(is_enum::value == false, "is_enum failure "); + static_assert(is_enum_v == false, "is_enum failure "); + EATEST_VERIFY(GetType(is_enum()) == false); + // is_union static_assert(is_union::value == true, "is_union failure"); @@ -747,6 +761,9 @@ int TestTypeTraits() static_assert(is_object::value == false, "is_object failure"); EATEST_VERIFY(GetType(is_object()) == false); + static_assert(is_object::value == false, "is_object failure"); + EATEST_VERIFY(GetType(is_object()) == false); + // is_scalar static_assert(is_scalar::value == true, "is_scalar failure"); @@ -827,10 +844,22 @@ int TestTypeTraits() EATEST_VERIFY(GetType(is_volatile()) == false); - // underlying_type + // underlying_type and to_underlying #if EASTL_TYPE_TRAIT_underlying_type_CONFORMANCE && !defined(EA_COMPILER_NO_STRONGLY_TYPED_ENUMS) // If we can execute this test... enum UnderlyingTypeTest : uint16_t { firstVal = 0, secondVal = 1 }; - static_assert(sizeof(underlying_type::type) == sizeof(uint16_t), "underlying_type failure"); + + constexpr bool isUnderlyingTypeCorrect = is_same_v, uint16_t>; + static_assert(isUnderlyingTypeCorrect, "Wrong type for underlying_type_t."); + EATEST_VERIFY(isUnderlyingTypeCorrect); + + auto v1 = to_underlying(UnderlyingTypeTest::firstVal); + auto v2 = to_underlying(UnderlyingTypeTest::secondVal); + + constexpr bool isToUnderlyingReturnTypeCorrect = is_same_v; + static_assert(isToUnderlyingReturnTypeCorrect, "Wrong return type for to_underlying."); + EATEST_VERIFY(isToUnderlyingReturnTypeCorrect); + + EATEST_VERIFY(v1 == 0 && v2 == 1); #endif @@ -1276,6 +1305,7 @@ int TestTypeTraits() static_assert(is_constructible::value == false, "is_constructible failure"); static_assert(is_constructible::value == true, "is_constructible failure"); static_assert(is_constructible::value == false, "is_constructible failure"); + static_assert(is_constructible::value == false, "is_constructible failure"); static_assert(is_constructible::value == true, "is_constructible failure"); static_assert(is_constructible::value == false, "is_constructible failure"); static_assert(is_constructible::value == true, "is_constructible failure"); @@ -1381,6 +1411,8 @@ int TestTypeTraits() // is_trivially_destructible static_assert(is_trivially_destructible::value == true, "is_trivially_destructible failure"); + static_assert(is_trivially_destructible::value == true, "is_trivially_destructible failure"); + static_assert(is_trivially_destructible::value == true, "is_trivially_destructible failure"); static_assert(is_trivially_destructible::value == true, "is_trivially_destructible failure"); static_assert(is_trivially_destructible::value == true, "is_trivially_destructible failure"); static_assert(is_trivially_destructible::value == false, "is_trivially_destructible failure"); @@ -1397,6 +1429,8 @@ int TestTypeTraits() // is_nothrow_destructible static_assert(is_nothrow_destructible::value == true, "is_nothrow_destructible failure"); + static_assert(is_nothrow_destructible::value == true, "is_nothrow_destructible failure"); + static_assert(is_nothrow_destructible::value == true, "is_nothrow_destructible failure"); static_assert(is_nothrow_destructible::value == false, "is_nothrow_destructible failure"); #if EASTL_TYPE_TRAIT_is_nothrow_destructible_CONFORMANCE static_assert(is_nothrow_destructible::value == true, "is_nothrow_destructible failure"); // NonPod2 is nothrow destructible because it has an empty destructor (makes no calls) which has no exception specification. Thus its exception specification defaults to noexcept(true) [C++11 Standard, 15.4 paragraph 14] @@ -1573,6 +1607,120 @@ int TestTypeTraits() EATEST_VERIFY(u64 == UINT64_C(0xffffffffffffffff)); i64 = static_cast::type>(u64); EATEST_VERIFY(i64 == -1); + + + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + + #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + static_assert(eastl::is_same_v<__uint128_t, eastl::make_unsigned<__int128_t>::type>); + static_assert(eastl::is_same_v<__uint128_t, eastl::make_unsigned<__uint128_t>::type>); + + static_assert(eastl::is_same_v<__int128_t, eastl::make_signed<__int128_t>::type>); + static_assert(eastl::is_same_v<__int128_t, eastl::make_signed<__uint128_t>::type>); + #endif + + // Char tests + static_assert(sizeof(char) == sizeof(eastl::make_signed::type)); + static_assert(sizeof(wchar_t) == sizeof(eastl::make_signed::type)); + static_assert(sizeof(char16_t) == sizeof(eastl::make_signed::type)); + static_assert(sizeof(char32_t) == sizeof(eastl::make_signed::type)); + static_assert(sizeof(char) == sizeof(eastl::make_unsigned::type)); + static_assert(sizeof(wchar_t) == sizeof(eastl::make_unsigned::type)); + static_assert(sizeof(char16_t) == sizeof(eastl::make_unsigned::type)); + static_assert(sizeof(char32_t) == sizeof(eastl::make_unsigned::type)); + + // Enum tests + enum EnumUCharSize : unsigned char {}; + enum EnumUShortSize : unsigned short {}; + enum EnumUIntSize : unsigned int {}; + enum EnumULongSize : unsigned long {}; + enum EnumULongLongSize : unsigned long long {}; + + static_assert(eastl::is_signed_v::type>); + static_assert(eastl::is_signed_v::type>); + static_assert(eastl::is_signed_v::type>); + static_assert(eastl::is_signed_v::type>); + static_assert(eastl::is_signed_v::type>); + static_assert(sizeof(EnumUCharSize) == sizeof(eastl::make_signed::type)); + static_assert(sizeof(EnumUShortSize) == sizeof(eastl::make_signed::type)); + static_assert(sizeof(EnumUIntSize) == sizeof(eastl::make_signed::type)); + static_assert(sizeof(EnumULongSize) == sizeof(eastl::make_signed::type)); + static_assert(sizeof(EnumULongLongSize) == sizeof(eastl::make_signed::type)); + + enum EnumCharSize : signed char {}; + enum EnumShortSize : short {}; + enum EnumIntSize : int {}; + enum EnumLongSize : long {}; + enum EnumLongLongSize : long long {}; + + static_assert(eastl::is_unsigned_v::type>); + static_assert(eastl::is_unsigned_v::type>); + static_assert(eastl::is_unsigned_v::type>); + static_assert(eastl::is_unsigned_v::type>); + static_assert(eastl::is_unsigned_v::type>); + static_assert(sizeof(EnumCharSize) == sizeof(eastl::make_unsigned::type)); + static_assert(sizeof(EnumShortSize) == sizeof(eastl::make_unsigned::type)); + static_assert(sizeof(EnumIntSize) == sizeof(eastl::make_unsigned::type)); + static_assert(sizeof(EnumLongSize) == sizeof(eastl::make_unsigned::type)); + static_assert(sizeof(EnumLongLongSize) == sizeof(eastl::make_unsigned::type)); } // remove_const @@ -2027,12 +2175,31 @@ int TestTypeTraits() } #endif - return nErrorCount; -} - + // is_complete_type + { + struct Foo + { + int x; + }; + struct FooEmpty + { + }; + struct Bar; + void FooFunc(); + static_assert(eastl::internal::is_complete_type_v, "is_complete_type failure"); + static_assert(eastl::internal::is_complete_type_v, "is_complete_type failure"); + static_assert(!eastl::internal::is_complete_type_v, "is_complete_type failure"); + static_assert(!eastl::internal::is_complete_type_v, "is_complete_type failure"); + static_assert(!eastl::internal::is_complete_type_v, "is_complete_type failure"); + static_assert(!eastl::internal::is_complete_type_v, "is_complete_type failure"); + static_assert(!eastl::internal::is_complete_type_v, "is_complete_type failure"); + static_assert(eastl::internal::is_complete_type_v, "is_complete_type failure"); + } + return nErrorCount; +} diff --git a/test/source/TestVariant.cpp b/test/source/TestVariant.cpp index 8c71eda5..164c28c2 100644 --- a/test/source/TestVariant.cpp +++ b/test/source/TestVariant.cpp @@ -13,6 +13,27 @@ #include +#if EASTL_EXCEPTIONS_ENABLED + +// Intentionally Non-Trivial. +// There are optimizations we can make in variant if the types are trivial that we don't currently do but can do. +template +struct valueless_struct +{ + valueless_struct() {} + + valueless_struct(const valueless_struct&) {} + + ~valueless_struct() {} + + struct exception_tag {}; + + operator T() const { throw exception_tag{}; } +}; + +#endif + + int TestVariantAlternative() { using namespace eastl; @@ -625,6 +646,86 @@ int TestVariantInplaceCtors() return nErrorCount; } +// Many Compilers are smart and will fully inline the visitor in our unittests, +// Thereby not actually testing the recursive call. +EA_NO_INLINE int TestVariantVisitNoInline(const eastl::variant& v) +{ + int nErrorCount = 0; + + bool bVisited = false; + + struct MyVisitor + { + MyVisitor() = delete; + + void operator()(int) { mVisited = true; } + void operator()(bool) { mVisited = true; } + void operator()(unsigned) { mVisited = true; } + + bool& mVisited; + }; + + eastl::visit(MyVisitor{bVisited}, v); + + EATEST_VERIFY(bVisited); + + return nErrorCount; +} + +EA_NO_INLINE int TestVariantVisit2NoInline(const eastl::variant& v0, const eastl::variant& v1) +{ + int nErrorCount = 0; + + bool bVisited = false; + + struct MyVisitor + { + MyVisitor() = delete; + + void operator()(int, int) { mVisited = true; } + void operator()(bool, int) { mVisited = true; } + void operator()(int, bool) { mVisited = true; } + void operator()(bool, bool) { mVisited = true; } + + bool& mVisited; + }; + + eastl::visit(MyVisitor{bVisited}, v0, v1); + + EATEST_VERIFY(bVisited); + + return nErrorCount; +} + +EA_NO_INLINE int TestVariantVisit3tNoInline(const eastl::variant& v0, const eastl::variant& v1, const eastl::variant& v2) +{ + int nErrorCount = 0; + + bool bVisited = false; + + struct MyVisitor + { + MyVisitor() = delete; + + void operator()(int, int, int) { mVisited = true; } + void operator()(bool, int, int) { mVisited = true; } + void operator()(int, bool, int) { mVisited = true; } + void operator()(bool, bool, int) { mVisited = true; } + + void operator()(int, int, bool) { mVisited = true; } + void operator()(bool, int, bool) { mVisited = true; } + void operator()(int, bool, bool) { mVisited = true; } + void operator()(bool, bool, bool) { mVisited = true; } + + bool& mVisited; + }; + + eastl::visit(MyVisitor{bVisited}, v0, v1, v2); + + EATEST_VERIFY(bVisited); + + return nErrorCount; +} int TestVariantVisitor() { @@ -662,6 +763,14 @@ int TestVariantVisitor() } VERIFY(count == EAArrayCount(arr)); + + count = 0; + for (auto& e : arr) + { + eastl::visit([&](auto){ count++; }, e); + } + + VERIFY(count == EAArrayCount(arr)); } { @@ -671,14 +780,171 @@ int TestVariantVisitor() struct MyVisitor { - MyVisitor& operator()(int) { bVisited = true; return *this; }; - MyVisitor& operator()(long) { return *this; }; - MyVisitor& operator()(string) { return *this; }; - MyVisitor& operator()(unsigned) { return *this; }; // not in variant + void operator()(int) { bVisited = true; }; + void operator()(long) { }; + void operator()(string) { }; + void operator()(unsigned) { }; // not in variant }; visit(MyVisitor{}, v); VERIFY(bVisited); + + bVisited = false; + + visit(MyVisitor{}, v); + VERIFY(bVisited); + } + + { + static bool bVisited = false; + + variant v = (int)1; + + struct MyVisitor + { + bool& operator()(int) { return bVisited; } + bool& operator()(bool) { return bVisited; } + bool& operator()(unsigned) { return bVisited; } + }; + + bool& ret = visit(MyVisitor{}, v); + ret = true; + VERIFY(bVisited); + + bVisited = false; + bool& ret2 = visit(MyVisitor{}, v); + ret2 = true; + VERIFY(bVisited); + } + + { + variant v = (int)1; + + struct MyVisitor + { + void operator()(int& i) { i = 2; } + void operator()(bool&) {} + void operator()(unsigned&) {} + }; + + visit(MyVisitor{}, v); + EATEST_VERIFY(get<0>(v) == (int)2); + + v = (int)1; + visit(MyVisitor{}, v); + EATEST_VERIFY(get<0>(v) == (int)2); + } + + { + static bool bVisited = false; + + variant v =(int)1; + + struct MyVisitor + { + void operator()(const int&) { bVisited = true; } + void operator()(const bool&) {} + void operator()(const unsigned&) {} + }; + + visit(MyVisitor{}, v); + EATEST_VERIFY(bVisited); + + bVisited = false; + visit(MyVisitor{}, v); + EATEST_VERIFY(bVisited); + } + + { + static bool bVisited = false; + + const variant v =(int)1; + + struct MyVisitor + { + void operator()(const int&) { bVisited = true; } + void operator()(const bool&) {} + void operator()(const unsigned&) {} + }; + + visit(MyVisitor{}, v); + EATEST_VERIFY(bVisited); + + bVisited = false; + visit(MyVisitor{}, v); + EATEST_VERIFY(bVisited); + } + + { + static bool bVisited = false; + + struct MyVisitor + { + void operator()(int&&) { bVisited = true; } + void operator()(bool&&) {} + void operator()(unsigned&&) {} + }; + + visit(MyVisitor{}, variant{(int)1}); + EATEST_VERIFY(bVisited); + + visit(MyVisitor{}, variant{(int)1}); + EATEST_VERIFY(bVisited); + } + + { + static bool bVisited = false; + + variant v = (int)1; + + struct MyVisitor + { + bool&& operator()(int) { return eastl::move(bVisited); } + bool&& operator()(bool) { return eastl::move(bVisited); } + bool&& operator()(unsigned) { return eastl::move(bVisited); } + }; + + bool&& ret = visit(MyVisitor{}, v); + ret = true; + VERIFY(bVisited); + + bVisited = false; + bool&& ret2 = visit(MyVisitor{}, v); + ret2 = true; + VERIFY(bVisited); + } + + { + variant v = (int)1; + + TestVariantVisitNoInline(v); + v = (bool)true; + TestVariantVisitNoInline(v); + v = (int)3; + TestVariantVisitNoInline(v); + } + + { + variant v0 = (int)1; + variant v1 = (bool)true; + + TestVariantVisit2NoInline(v0, v1); + v0 = (bool)false; + TestVariantVisit2NoInline(v0, v1); + v1 = (int)2; + TestVariantVisit2NoInline(v0, v1); + } + + { + variant v0 = (int)1; + variant v1 = (int)2; + variant v2 = (int)3; + + TestVariantVisit3tNoInline(v0, v1, v2); + v2 = (bool)false; + TestVariantVisit3tNoInline(v0, v1, v2); + v0 = (bool)true; + TestVariantVisit3tNoInline(v0, v1, v2); } { @@ -695,10 +961,41 @@ int TestVariantVisitor() MultipleVisitor& operator()(string, string) { return *this; } }; - visit(MultipleVisitor{}, i, s); + MultipleVisitor& ret = visit(MultipleVisitor{}, i, s); + EA_UNUSED(ret); + VERIFY(bVisited); + + MultipleVisitor& ret2 = visit(MultipleVisitor{}, i, s); + EA_UNUSED(ret2); VERIFY(bVisited); } + { + bool bVisited = false; + + variant v0 = 0; + variant v1 = 1; + + struct MultipleVisitor + { + MultipleVisitor() = delete; + + void operator()(int, int) { mVisited = true; } + void operator()(int, bool) {} + void operator()(bool, int) {} + void operator()(bool, bool) {} + + bool& mVisited; + }; + + visit(MultipleVisitor{bVisited}, v0, v1); + EATEST_VERIFY(bVisited); + + bVisited = false; + visit(MultipleVisitor{bVisited}, v0, v1); + EATEST_VERIFY(bVisited); + } + { variant v = 42; @@ -724,24 +1021,128 @@ int TestVariantVisitor() VERIFY(visit(ReturningVisitor{}, v) == 42); } -#if !defined(EA_COMPILER_MSVC) + return nErrorCount; +} + +int TestVariantVisitorReturn() +{ + int nErrorCount = 0; + { - variant v = 42; + static bool bVisited = false; + + eastl::variant v = (int)1; - struct ReturningDifferentTypesVisitor + struct MyVisitor { - int operator()(int i) {return i;} - size_t operator()(string s) {return s.size();} + bool operator()(int) { bVisited = true; return true; } + bool operator()(bool) { return false; } }; - VERIFY(visit(ReturningDifferentTypesVisitor{}, v) == 42); + eastl::visit(MyVisitor{}, v); + EATEST_VERIFY(bVisited); + } + + { + static bool bVisited = false; + + eastl::variant v = (int)1; + + struct MyVisitor + { + bool operator()(int) { bVisited = true; return true; } + bool operator()(bool) { return false; } + }; + + eastl::visit(MyVisitor{}, v); + EATEST_VERIFY(bVisited); + } + + { + static bool bVisited = false; + + eastl::variant v = (int)1; + + struct MyVisitor + { + bool operator()(int) { bVisited = true; return true; } + bool operator()(bool) { return false; } + }; + + eastl::visit(MyVisitor{}, v); + EATEST_VERIFY(bVisited); + } + + { + static bool bVisited = false; + + eastl::variant v = (int)1; + + struct MyVisitor + { + bool operator()(int) { bVisited = true; return true; } + bool operator()(bool) { return false; } + }; + + eastl::visit(MyVisitor{}, v); + EATEST_VERIFY(bVisited); + } + + { + static bool bVisited = false; + + eastl::variant v = (int)1; + + struct MyVisitor + { + bool operator()(int) { bVisited = true; return true; } + bool operator()(bool) { return false; } + }; + + int ret = eastl::visit(MyVisitor{}, v); + EATEST_VERIFY(bVisited); + EATEST_VERIFY(ret); + } + + { + static bool bVisited = false; + + struct A {}; + struct B : public A {}; + struct C : public A {}; + + eastl::variant v = (int)1; + + struct MyVisitor + { + B operator()(int) { bVisited = true; return B{}; } + C operator()(bool) { return C{}; } + }; + + A ret = eastl::visit(MyVisitor{}, v); + EA_UNUSED(ret); + EATEST_VERIFY(bVisited); + } + + { + static bool bVisited = false; + + eastl::variant v = (int)1; + + struct MyVisitor + { + MyVisitor operator()(int) { bVisited = true; return MyVisitor{}; } + MyVisitor operator()(bool) { return MyVisitor{}; } + }; + + MyVisitor ret = eastl::visit(MyVisitor{}, v); + EA_UNUSED(ret); + EATEST_VERIFY(bVisited); } -#endif return nErrorCount; } - int TestVariantAssignment() { using namespace eastl; @@ -825,6 +1226,328 @@ int TestVariantUserRegressionCopyMoveAssignmentOperatorLeak() return nErrorCount; } +int TestVariantRelationalOperators() +{ + int nErrorCount = 0; + + using VariantNoThrow = eastl::variant; + + // Equality + { + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ true }; + + EATEST_VERIFY((v1 == v2) == false); + } + + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 == v2) == true); + } + + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ (int)0 }; + + EATEST_VERIFY((v1 == v2) == false); + } + } + + // Inequality + { + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ true }; + + EATEST_VERIFY((v1 != v2) == true); + } + + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 != v2) == false); + } + + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ (int)0 }; + + EATEST_VERIFY((v1 != v2) == true); + } + } + + // Less Than + { + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ true }; + + EATEST_VERIFY((v1 < v2) == true); + } + + { + VariantNoThrow v1{ true }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 < v2) == false); + } + + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 < v2) == false); + } + + { + VariantNoThrow v1{ (int)0 }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 < v2) == true); + } + } + + // Greater Than + { + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ true }; + + EATEST_VERIFY((v1 > v2) == false); + } + + { + VariantNoThrow v1{ true }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 > v2) == true); + } + + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 > v2) == false); + } + + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ (int)0 }; + + EATEST_VERIFY((v1 > v2) == true); + } + } + + // Less Equal + { + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ true }; + + EATEST_VERIFY((v1 <= v2) == true); + } + + { + VariantNoThrow v1{ true }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 <= v2) == false); + } + + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 <= v2) == true); + } + + { + VariantNoThrow v1{ (int)0 }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 <= v2) == true); + } + + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ (int)0 }; + + EATEST_VERIFY((v1 <= v2) == false); + } + } + + // Greater Equal + { + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ true }; + + EATEST_VERIFY((v1 >= v2) == false); + } + + { + VariantNoThrow v1{ true }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 >= v2) == true); + } + + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 >= v2) == true); + } + + { + VariantNoThrow v1{ (int)0 }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 >= v2) == false); + } + + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ (int)0 }; + + EATEST_VERIFY((v1 >= v2) == true); + } + } + +#if EASTL_EXCEPTIONS_ENABLED + + using VariantThrow = eastl::variant; + + auto make_variant_valueless = [](VariantThrow& v) + { + try + { + v.emplace<0>(valueless_struct{}); + } + catch(const typename valueless_struct::exception_tag &) + { + } + }; + + // Equality + { + { + VariantThrow v0{ (int)0 }; + VariantThrow v1{ (int)1 }; + + make_variant_valueless(v0); + make_variant_valueless(v1); + + EATEST_VERIFY((v0 == v1) == true); + } + } + + // Inequality + { + { + VariantThrow v0{ (int)0 }; + VariantThrow v1{ (int)1 }; + + make_variant_valueless(v0); + make_variant_valueless(v1); + + EATEST_VERIFY((v0 != v1) == false); + } + } + + // Less Than + { + { + VariantThrow v0{ (int)0 }; + VariantThrow v1{ (int)1 }; + + make_variant_valueless(v0); + + EATEST_VERIFY((v0 < v1) == true); + } + + { + VariantThrow v0{ (int)0 }; + VariantThrow v1{ (int)1 }; + + make_variant_valueless(v1); + + EATEST_VERIFY((v0 < v1) == false); + } + } + + // Greater Than + { + { + VariantThrow v0{ (int)1 }; + VariantThrow v1{ (int)0 }; + + make_variant_valueless(v0); + + EATEST_VERIFY((v0 > v1) == false); + } + + { + VariantThrow v0{ (int)1 }; + VariantThrow v1{ (int)0 }; + + make_variant_valueless(v1); + + EATEST_VERIFY((v0 > v1) == true); + } + } + + // Less Equal + { + { + VariantThrow v0{ (int)1 }; + VariantThrow v1{ (int)1 }; + + make_variant_valueless(v0); + + EATEST_VERIFY((v0 <= v1) == true); + } + + { + VariantThrow v0{ (int)1 }; + VariantThrow v1{ (int)0 }; + + make_variant_valueless(v1); + + EATEST_VERIFY((v0 <= v1) == false); + } + } + + // Greater Equal + { + { + VariantThrow v0{ (int)1 }; + VariantThrow v1{ (int)1 }; + + make_variant_valueless(v0); + + EATEST_VERIFY((v0 >= v1) == false); + } + + { + VariantThrow v0{ (int)1 }; + VariantThrow v1{ (int)0 }; + + make_variant_valueless(v1); + + EATEST_VERIFY((v0 >= v1) == true); + } + } + +#endif + + return nErrorCount; +} + int TestVariantUserRegressionIncompleteType() { @@ -848,6 +1571,155 @@ int TestVariantUserRegressionIncompleteType() return nErrorCount; } +#define EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(Type, VarName) \ + bool operator==(const Type & rhs) const { return VarName == rhs.VarName; } \ + bool operator!=(const Type & rhs) const { return VarName != rhs.VarName; } \ + bool operator<(const Type & rhs) const { return VarName < rhs.VarName; } \ + bool operator>(const Type & rhs) const { return VarName > rhs.VarName; } \ + bool operator<=(const Type & rhs) const { return VarName <= rhs.VarName; } \ + bool operator>=(const Type & rhs) const { return VarName >= rhs.VarName; } + +int TestBigVariantComparison() +{ + int nErrorCount = 0; + + struct A; + struct B; + struct C; + struct D; + struct E; + struct F; + struct G; + struct H; + struct I; + struct J; + struct K; + struct L; + struct M; + struct N; + struct O; + struct P; + struct Q; + struct R; + struct S; + struct T; + struct U; + struct V; + struct W; + struct X; + struct Y; + struct Z; + + using BigVariant = eastl::variant; + + struct A { int a; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(A, a) }; + struct B { int b; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(B, b) }; + struct C { int c; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(C, c) }; + struct D { int d; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(D, d) }; + struct E { int e; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(E, e) }; + struct F { int f; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(F, f) }; + struct G { int g; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(G, g) }; + struct H { int h; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(H, h) }; + struct I { int i; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(I, i) }; + struct J { int j; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(J, j) }; + struct K { int k; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(K, k) }; + struct L { int l; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(L, l) }; + struct M { int m; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(M, m) }; + struct N { int n; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(N, n) }; + struct O { int o; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(O, o) }; + struct P { int p; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(P, p) }; + struct Q { int q; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(Q, q) }; + struct R { int r; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(R, r) }; + struct S { int s; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(S, s) }; + struct T { int t; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(T, t) }; + struct U { int u; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(U, u) }; + struct V { int v; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(V, v) }; + struct W { int w; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(W, w) }; + struct X { int x; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(X, x) }; + struct Y { int y; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(Y, y) }; + struct Z { int z; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(Z, z) }; + + { + BigVariant v0{ A{0} }; + BigVariant v1{ A{1} }; + + VERIFY(v0 != v1); + } + + { + BigVariant v0{ A{0} }; + BigVariant v1{ A{1} }; + + VERIFY(v0 < v1); + } + + { + BigVariant v0{ A{0} }; + BigVariant v1{ A{0} }; + + VERIFY(v0 == v1); + } + + { + BigVariant v0{ A{1} }; + BigVariant v1{ A{0} }; + + VERIFY(v0 > v1); + } + + { + BigVariant v0{ A{0} }; + BigVariant v1{ A{1} }; + + VERIFY(v0 <= v1); + } + + { + BigVariant v0{ A{0} }; + BigVariant v1{ A{0} }; + + VERIFY(v0 <= v1); + } + + { + BigVariant v0{ A{0} }; + BigVariant v1{ A{0} }; + + VERIFY(v0 >= v1); + } + + { + BigVariant v0{ A{1} }; + BigVariant v1{ A{0} }; + + VERIFY(v0 >= v1); + } + + { + BigVariant v0{ A{0} }; + BigVariant v1{ B{0} }; + + VERIFY(v0 != v1); + } + + { + BigVariant v0{ A{0} }; + BigVariant v1{ B{0} }; + + VERIFY(v0 < v1); + } + + { + BigVariant v0{ A{0} }; + BigVariant v1{ B{0} }; + + VERIFY(v1 > v0); + } + + return nErrorCount; +} + int TestVariantGeneratingComparisonOverloads(); int TestVariant() @@ -872,6 +1744,8 @@ int TestVariant() nErrorCount += TestVariantUserRegressionCopyMoveAssignmentOperatorLeak(); nErrorCount += TestVariantUserRegressionIncompleteType(); nErrorCount += TestVariantGeneratingComparisonOverloads(); + nErrorCount += TestBigVariantComparison(); + nErrorCount += TestVariantRelationalOperators(); return nErrorCount; } diff --git a/test/source/main.cpp b/test/source/main.cpp index 962d2c4b..8ce7c1bd 100644 --- a/test/source/main.cpp +++ b/test/source/main.cpp @@ -145,6 +145,7 @@ int EAMain(int argc, char* argv[]) testSuite.AddTest("VectorSet", TestVectorSet); testSuite.AddTest("AtomicBasic", TestAtomicBasic); testSuite.AddTest("AtomicAsm", TestAtomicAsm); + testSuite.AddTest("TestBitcast", TestBitcast); nErrorCount += testSuite.Run(); From 20ca24356ad03438e54c7e0b3328135c37c192bd Mon Sep 17 00:00:00 2001 From: Liam Mitchell Date: Wed, 20 Oct 2021 15:46:27 -0700 Subject: [PATCH 2/3] Open-source CI fixes --- include/EASTL/internal/type_transformations.h | 4 ++++ test/source/TestVariant.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/include/EASTL/internal/type_transformations.h b/include/EASTL/internal/type_transformations.h index 0853181d..2d77a556 100644 --- a/include/EASTL/internal/type_transformations.h +++ b/include/EASTL/internal/type_transformations.h @@ -399,6 +399,10 @@ namespace eastl template <> struct make_unsigned { typedef unsigned char type; }; #endif + #if defined(EA_CHAR8_UNIQUE) && EA_CHAR8_UNIQUE + template <> struct make_unsigned { typedef unsigned char type; }; + #endif + template struct make_unsigned { diff --git a/test/source/TestVariant.cpp b/test/source/TestVariant.cpp index 164c28c2..a8197e50 100644 --- a/test/source/TestVariant.cpp +++ b/test/source/TestVariant.cpp @@ -657,6 +657,7 @@ EA_NO_INLINE int TestVariantVisitNoInline(const eastl::variant& v0, struct MyVisitor { MyVisitor() = delete; + MyVisitor(bool& b) : mVisited(b) {} void operator()(int, int) { mVisited = true; } void operator()(bool, int) { mVisited = true; } @@ -706,6 +708,7 @@ EA_NO_INLINE int TestVariantVisit3tNoInline(const eastl::variant& v0, struct MyVisitor { MyVisitor() = delete; + MyVisitor(bool& b) : mVisited(b) {} void operator()(int, int, int) { mVisited = true; } void operator()(bool, int, int) { mVisited = true; } @@ -979,6 +982,7 @@ int TestVariantVisitor() struct MultipleVisitor { MultipleVisitor() = delete; + MultipleVisitor(bool& b) : mVisited(b) {} void operator()(int, int) { mVisited = true; } void operator()(int, bool) {} From 7c299378e93cbe1fe9b87ce965f6e70b92965437 Mon Sep 17 00:00:00 2001 From: Liam Mitchell Date: Wed, 20 Oct 2021 16:19:51 -0700 Subject: [PATCH 3/3] Avoid specializing templates within an outer class --- include/EASTL/variant.h | 50 ++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/include/EASTL/variant.h b/include/EASTL/variant.h index e351629a..6e779283 100644 --- a/include/EASTL/variant.h +++ b/include/EASTL/variant.h @@ -1282,36 +1282,36 @@ namespace eastl }; - - // abstracts calling visit on a single variant with return types convertible to R - struct visitor_caller_one_r + template + struct visitor_r { - template - struct visitor_r + template + static EA_CONSTEXPR R invoke_visitor_r(Visitor&& visitor, Variant&& variant) { - template - static EA_CONSTEXPR R invoke_visitor_r(Visitor&& visitor, Variant&& variant) - { - return eastl::invoke(eastl::forward(visitor), - eastl::get(eastl::forward(variant))); - } - }; + return eastl::invoke(eastl::forward(visitor), + eastl::get(eastl::forward(variant))); + } + }; - // void return type must discard the return values of the visitor even if the visitor returns a value. - template <> - struct visitor_r + // void return type must discard the return values of the visitor even if the visitor returns a value. + template <> + struct visitor_r + { + template + static EA_CONSTEXPR void invoke_visitor_r(Visitor&& visitor, Variant&& variant) { - template - static EA_CONSTEXPR void invoke_visitor_r(Visitor&& visitor, Variant&& variant) - { - eastl::invoke(eastl::forward(visitor), - eastl::get(eastl::forward(variant))); - } - }; - template<> struct visitor_r : public visitor_r {}; - template<> struct visitor_r : public visitor_r {}; - template<> struct visitor_r : public visitor_r {}; + eastl::invoke(eastl::forward(visitor), + eastl::get(eastl::forward(variant))); + } + }; + + template<> struct visitor_r : public visitor_r {}; + template<> struct visitor_r : public visitor_r {}; + template<> struct visitor_r : public visitor_r {}; + // abstracts calling visit on a single variant with return types convertible to R + struct visitor_caller_one_r + { template static EA_CPP14_CONSTEXPR decltype(auto) call_index_r(Visitor&& visitor, Variant&& variant, eastl::index_sequence) {