aboutsummaryrefslogtreecommitdiff
path: root/EASTL
diff options
context:
space:
mode:
Diffstat (limited to 'EASTL')
-rw-r--r--EASTL/.github/workflows/c-cpp.yml11
-rw-r--r--EASTL/.gitignore1
-rw-r--r--EASTL/CMakeLists.txt4
-rw-r--r--EASTL/benchmark/CMakeLists.txt3
-rw-r--r--EASTL/doc/EASTL.natvis124
-rw-r--r--EASTL/include/EASTL/algorithm.h151
-rw-r--r--EASTL/include/EASTL/allocator.h10
-rw-r--r--EASTL/include/EASTL/array.h96
-rw-r--r--EASTL/include/EASTL/bit.h107
-rw-r--r--EASTL/include/EASTL/bitset.h6
-rw-r--r--EASTL/include/EASTL/bonus/lru_cache.h2
-rw-r--r--EASTL/include/EASTL/bonus/overloaded.h81
-rw-r--r--EASTL/include/EASTL/bonus/tuple_vector.h12
-rw-r--r--EASTL/include/EASTL/chrono.h110
-rw-r--r--EASTL/include/EASTL/compare.h45
-rw-r--r--EASTL/include/EASTL/deque.h45
-rw-r--r--EASTL/include/EASTL/fixed_substring.h10
-rw-r--r--EASTL/include/EASTL/hash_map.h186
-rw-r--r--EASTL/include/EASTL/hash_set.h28
-rw-r--r--EASTL/include/EASTL/heap.h4
-rw-r--r--EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86.h4
-rw-r--r--EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_exchange.h2
-rw-r--r--EASTL/include/EASTL/internal/atomic/atomic_base_width.h2
-rw-r--r--EASTL/include/EASTL/internal/atomic/atomic_integral.h2
-rw-r--r--EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros.h11
-rw-r--r--EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros_base.h7
-rw-r--r--EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc.h1
-rw-r--r--EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cpu_pause.h19
-rw-r--r--EASTL/include/EASTL/internal/config.h81
-rw-r--r--EASTL/include/EASTL/internal/copy_help.h37
-rw-r--r--EASTL/include/EASTL/internal/fixed_pool.h7
-rw-r--r--EASTL/include/EASTL/internal/function.h4
-rw-r--r--EASTL/include/EASTL/internal/functional_base.h7
-rw-r--r--EASTL/include/EASTL/internal/generic_iterator.h17
-rw-r--r--EASTL/include/EASTL/internal/hashtable.h299
-rw-r--r--EASTL/include/EASTL/internal/integer_sequence.h32
-rw-r--r--EASTL/include/EASTL/internal/red_black_tree.h42
-rw-r--r--EASTL/include/EASTL/internal/thread_support.h86
-rw-r--r--EASTL/include/EASTL/internal/type_compound.h84
-rw-r--r--EASTL/include/EASTL/internal/type_detected.h180
-rw-r--r--EASTL/include/EASTL/internal/type_fundamental.h6
-rw-r--r--EASTL/include/EASTL/internal/type_pod.h31
-rw-r--r--EASTL/include/EASTL/internal/type_properties.h134
-rw-r--r--EASTL/include/EASTL/internal/type_transformations.h66
-rw-r--r--EASTL/include/EASTL/internal/type_void_t.h43
-rw-r--r--EASTL/include/EASTL/iterator.h157
-rw-r--r--EASTL/include/EASTL/list.h33
-rw-r--r--EASTL/include/EASTL/map.h142
-rw-r--r--EASTL/include/EASTL/memory.h35
-rw-r--r--EASTL/include/EASTL/numeric.h97
-rw-r--r--EASTL/include/EASTL/numeric_limits.h101
-rw-r--r--EASTL/include/EASTL/optional.h24
-rw-r--r--EASTL/include/EASTL/queue.h9
-rw-r--r--EASTL/include/EASTL/set.h24
-rw-r--r--EASTL/include/EASTL/shared_ptr.h61
-rw-r--r--EASTL/include/EASTL/slist.h40
-rw-r--r--EASTL/include/EASTL/sort.h19
-rw-r--r--EASTL/include/EASTL/stack.h8
-rw-r--r--EASTL/include/EASTL/string.h211
-rw-r--r--EASTL/include/EASTL/string_view.h248
-rw-r--r--EASTL/include/EASTL/tuple.h67
-rw-r--r--EASTL/include/EASTL/type_traits.h105
-rw-r--r--EASTL/include/EASTL/unique_ptr.h40
-rw-r--r--EASTL/include/EASTL/utility.h102
-rw-r--r--EASTL/include/EASTL/variant.h50
-rw-r--r--EASTL/include/EASTL/vector.h45
-rw-r--r--EASTL/source/assert.cpp8
-rw-r--r--EASTL/source/numeric_limits.cpp26
-rw-r--r--EASTL/test/CMakeLists.txt3
-rw-r--r--EASTL/test/source/EASTLTest.h2
-rw-r--r--EASTL/test/source/TestAlgorithm.cpp235
-rw-r--r--EASTL/test/source/TestAllocator.cpp2
-rw-r--r--EASTL/test/source/TestArray.cpp47
-rw-r--r--EASTL/test/source/TestChrono.cpp11
-rw-r--r--EASTL/test/source/TestDeque.cpp44
-rw-r--r--EASTL/test/source/TestExtra.cpp610
-rw-r--r--EASTL/test/source/TestFixedString.cpp52
-rw-r--r--EASTL/test/source/TestFunctional.cpp34
-rw-r--r--EASTL/test/source/TestHash.cpp12
-rw-r--r--EASTL/test/source/TestIterator.cpp111
-rw-r--r--EASTL/test/source/TestList.cpp103
-rw-r--r--EASTL/test/source/TestMap.cpp65
-rw-r--r--EASTL/test/source/TestMap.h30
-rw-r--r--EASTL/test/source/TestMemory.cpp44
-rw-r--r--EASTL/test/source/TestNumericLimits.cpp5
-rw-r--r--EASTL/test/source/TestOptional.cpp42
-rw-r--r--EASTL/test/source/TestSList.cpp114
-rw-r--r--EASTL/test/source/TestSet.cpp48
-rw-r--r--EASTL/test/source/TestSmartPtr.cpp39
-rw-r--r--EASTL/test/source/TestSort.cpp42
-rw-r--r--EASTL/test/source/TestString.inl40
-rw-r--r--EASTL/test/source/TestStringView.cpp19
-rw-r--r--EASTL/test/source/TestStringView.inl80
-rw-r--r--EASTL/test/source/TestTuple.cpp51
-rw-r--r--EASTL/test/source/TestTypeTraits.cpp304
-rw-r--r--EASTL/test/source/TestUtility.cpp293
-rw-r--r--EASTL/test/source/TestVariant.cpp139
-rw-r--r--EASTL/test/source/TestVector.cpp94
-rw-r--r--EASTL/test/source/main.cpp2
99 files changed, 5444 insertions, 1165 deletions
diff --git a/EASTL/.github/workflows/c-cpp.yml b/EASTL/.github/workflows/c-cpp.yml
index 1537c9c..0be723e 100644
--- a/EASTL/.github/workflows/c-cpp.yml
+++ b/EASTL/.github/workflows/c-cpp.yml
@@ -30,6 +30,7 @@ jobs:
os: [ windows-latest, ubuntu-latest ]
compiler: [ clang, gcc, msvc ]
configuration: [ Debug, Release ]
+ std_iter_compatibility: [ std_iter_category_disabled, std_iter_category_enabled ]
exclude:
- os: windows-latest
compiler: gcc
@@ -43,13 +44,13 @@ jobs:
cxxflags: '/std:c++20 /Zc:char8_t'
- os: ubuntu-latest
compiler: clang
- cc: 'clang-11'
- cxx: 'clang++-11'
+ cc: 'clang-14'
+ cxx: 'clang++-14'
cxxflags: '-std=c++20'
- os: ubuntu-latest
compiler: gcc
- cc: 'gcc-10'
- cxx: 'g++-10'
+ cc: 'gcc-12'
+ cxx: 'g++-12'
cxxflags: '-std=c++2a'
name: Build EASTL
@@ -63,7 +64,7 @@ jobs:
path: Code/
- run: mkdir build
- - run: cd build && cmake ../Code -DEASTL_BUILD_BENCHMARK:BOOL=ON -DEASTL_BUILD_TESTS:BOOL=ON
+ - run: cd build && cmake ../Code -DEASTL_BUILD_BENCHMARK:BOOL=ON -DEASTL_BUILD_TESTS:BOOL=ON -DEASTL_STD_ITERATOR_CATEGORY_ENABLED:BOOL=${{ contains(matrix.std_iter_compatibility, 'enabled') && 'ON' || 'OFF' }}
env:
CXXFLAGS: ${{ matrix.cxxflags }}
CXX: ${{ matrix.cxx }}
diff --git a/EASTL/.gitignore b/EASTL/.gitignore
index 8d148cd..92749f4 100644
--- a/EASTL/.gitignore
+++ b/EASTL/.gitignore
@@ -47,3 +47,4 @@ Testing/*
/buckaroo/
.buckconfig.local
BUCKAROO_DEPS
+.vscode/settings.json
diff --git a/EASTL/CMakeLists.txt b/EASTL/CMakeLists.txt
index e8700dc..25e7373 100644
--- a/EASTL/CMakeLists.txt
+++ b/EASTL/CMakeLists.txt
@@ -9,6 +9,7 @@ project(EASTL CXX)
#-------------------------------------------------------------------------------------------
option(EASTL_BUILD_BENCHMARK "Enable generation of build files for benchmark" OFF)
option(EASTL_BUILD_TESTS "Enable generation of build files for tests" OFF)
+option(EASTL_STD_ITERATOR_CATEGORY_ENABLED "Enable compatibility with std:: iterator categories" OFF)
#-------------------------------------------------------------------------------------------
# Compiler Flags
@@ -37,6 +38,9 @@ add_definitions(-D_CHAR16T)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
add_definitions(-DEASTL_OPENSOURCE=1)
+if (EASTL_STD_ITERATOR_CATEGORY_ENABLED)
+ add_definitions(-DEASTL_STD_ITERATOR_CATEGORY_ENABLED=1)
+endif()
#-------------------------------------------------------------------------------------------
# Include dirs
diff --git a/EASTL/benchmark/CMakeLists.txt b/EASTL/benchmark/CMakeLists.txt
index 94bc971..9ef8c66 100644
--- a/EASTL/benchmark/CMakeLists.txt
+++ b/EASTL/benchmark/CMakeLists.txt
@@ -58,6 +58,9 @@ add_definitions(-D_SCL_SECURE_NO_WARNINGS)
add_definitions(-DEASTL_THREAD_SUPPORT_AVAILABLE=0)
add_definitions(-DEASTL_OPENSOURCE=1)
add_definitions(-D_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS) # silence std::hash_map deprecation warnings
+if (EASTL_STD_ITERATOR_CATEGORY_ENABLED)
+ add_definitions(-DEASTL_STD_ITERATOR_CATEGORY_ENABLED=1)
+endif()
if(NOT EASTL_BUILD_TESTS)
add_subdirectory(../test/packages/EAStdC ../test/EAStdC)
diff --git a/EASTL/doc/EASTL.natvis b/EASTL/doc/EASTL.natvis
index 2fb311b..c3e94db 100644
--- a/EASTL/doc/EASTL.natvis
+++ b/EASTL/doc/EASTL.natvis
@@ -70,7 +70,7 @@
<Item Name="[capacity]" Condition="!!(mPair.mFirst.sso.mRemainingSizeField.mnRemainingSize &amp; kSSOMask)">(mPair.mFirst.heap.mnCapacity &amp; ~kHeapMask)</Item>
<Item Name="[value]" Condition="!!(mPair.mFirst.sso.mRemainingSizeField.mnRemainingSize &amp; kSSOMask)">mPair.mFirst.heap.mpBegin,sb</Item>
- <Item Name="[length]" Condition="!(mPair.mFirst.sso.mRemainingSizeField.mnRemainingSize &amp; kSSOMask)">mPair.mFirst.sso.mRemainingSizeField.mnRemainingSize</Item>
+ <Item Name="[length]" Condition="!(mPair.mFirst.sso.mRemainingSizeField.mnRemainingSize &amp; kSSOMask)">(SSOLayout::SSO_CAPACITY - mPair.mFirst.sso.mRemainingSizeField.mnRemainingSize)</Item>
<Item Name="[capacity]" Condition="!(mPair.mFirst.sso.mRemainingSizeField.mnRemainingSize &amp; kSSOMask)">SSOLayout::SSO_CAPACITY</Item>
<Item Name="[value]" Condition="!(mPair.mFirst.sso.mRemainingSizeField.mnRemainingSize &amp; kSSOMask)">mPair.mFirst.sso.mData,sb</Item>
@@ -87,7 +87,7 @@
<Item Name="[capacity]" Condition="!!(mPair.mFirst.sso.mRemainingSizeField.mnRemainingSize &amp; kSSOMask)">(mPair.mFirst.heap.mnCapacity &amp; ~kHeapMask)</Item>
<Item Name="[value]" Condition="!!(mPair.mFirst.sso.mRemainingSizeField.mnRemainingSize &amp; kSSOMask)">mPair.mFirst.heap.mpBegin,su</Item>
- <Item Name="[length]" Condition="!(mPair.mFirst.sso.mRemainingSizeField.mnRemainingSize &amp; kSSOMask)">mPair.mFirst.sso.mRemainingSizeField.mnRemainingSize</Item>
+ <Item Name="[length]" Condition="!(mPair.mFirst.sso.mRemainingSizeField.mnRemainingSize &amp; kSSOMask)">(SSOLayout::SSO_CAPACITY - mPair.mFirst.sso.mRemainingSizeField.mnRemainingSize)</Item>
<Item Name="[capacity]" Condition="!(mPair.mFirst.sso.mRemainingSizeField.mnRemainingSize &amp; kSSOMask)">SSOLayout::SSO_CAPACITY</Item>
<Item Name="[value]" Condition="!(mPair.mFirst.sso.mRemainingSizeField.mnRemainingSize &amp; kSSOMask)">mPair.mFirst.sso.mData,su</Item>
@@ -392,9 +392,9 @@
<Synthetic Name="NOTE!">
<DisplayString>It is possible to expand parents that do not exist.</DisplayString>
</Synthetic>
- <Item Name="Parent">*(eastl::rbtree_node&lt;$T2&gt;*)(mpNodeParent.value &amp; (~uintptr_t(1)))</Item>
- <Item Name="Left">*(eastl::rbtree_node&lt;$T2&gt;*)mpNodeLeft</Item>
- <Item Name="Right">*(eastl::rbtree_node&lt;$T2&gt;*)mpNodeRight</Item>
+ <Item Name="Parent">*(eastl::rbtree_node&lt;$T1&gt;*)mpNodeParent</Item>
+ <Item Name="Left">*(eastl::rbtree_node&lt;$T1&gt;*)mpNodeLeft</Item>
+ <Item Name="Right">*(eastl::rbtree_node&lt;$T1&gt;*)mpNodeRight</Item>
</Expand>
</Type>
@@ -407,14 +407,29 @@
<Type Name="eastl::hashtable&lt;*&gt;">
- <DisplayString Condition="mnElementCount == 0">[{mnElementCount}] {{}}</DisplayString>
- <DisplayString Condition="mnElementCount != 0">[{mnElementCount}] {{ ... }}</DisplayString>
- <Expand>
- <ArrayItems>
- <Size>mnBucketCount</Size>
- <ValuePointer>mpBucketArray</ValuePointer>
- </ArrayItems>
- </Expand>
+ <DisplayString Condition="mnElementCount == 0">[{mnElementCount}] {{}}</DisplayString>
+ <DisplayString Condition="mnElementCount != 0">[{mnElementCount}] {{ ... }}</DisplayString>
+ <Expand>
+ <ArrayItems IncludeView="detailed">
+ <Size>mnBucketCount</Size>
+ <ValuePointer>mpBucketArray</ValuePointer>
+ </ArrayItems>
+ <CustomListItems ExcludeView="detailed">
+ <Variable Name="bucketIndex" InitialValue="0"/>
+ <Variable Name="entry" InitialValue ="mpBucketArray[bucketIndex]"/>
+ <Loop>
+ <Item Condition="entry != nullptr">entry->mValue</Item>
+ <If Condition="entry != nullptr">
+ <Exec>entry = entry->mpNext</Exec>
+ </If>
+ <If Condition="entry == nullptr">
+ <Exec>bucketIndex++</Exec>
+ <Break Condition="bucketIndex == mnBucketCount"/>
+ <Exec>entry = mpBucketArray[bucketIndex]</Exec>
+ </If>
+ </Loop>
+ </CustomListItems>
+ </Expand>
</Type>
<Type Name="eastl::hash_node&lt;*&gt;">
@@ -629,7 +644,88 @@
</Type>
-<!-- TODO eastl::tuple -->
+<Type Name="eastl::tuple&lt;&gt;">
+ <DisplayString IncludeView="noparens"></DisplayString>
+ <DisplayString ExcludeView="noparens">({*this,view(noparens)})</DisplayString>
+ <Expand/>
+</Type>
+
+<Type Name="eastl::tuple&lt;*&gt;">
+ <DisplayString IncludeView="noparens">{(*((eastl::Internal::TupleLeaf&lt;0,$T1,0&gt;*)&amp;mImpl)).mValue}</DisplayString>
+ <DisplayString ExcludeView="noparens">({*this,view(noparens)})</DisplayString>
+ <Expand>
+ <Item Name="[0]">(*((eastl::Internal::TupleLeaf&lt;0,$T1,0&gt;*)&amp;mImpl)).mValue</Item>
+ </Expand>
+</Type>
+
+<Type Name="eastl::tuple&lt;*,*&gt;">
+ <DisplayString IncludeView="noparens">{(*((eastl::Internal::TupleLeaf&lt;0,$T1,0&gt;*)&amp;mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf&lt;1,$T2,0&gt;*)&amp;mImpl)).mValue}</DisplayString>
+ <DisplayString ExcludeView="noparens">({*this,view(noparens)})</DisplayString>
+ <Expand>
+ <Item Name="[0]">(*((eastl::Internal::TupleLeaf&lt;0,$T1,0&gt;*)&amp;mImpl)).mValue</Item>
+ <Item Name="[1]">(*((eastl::Internal::TupleLeaf&lt;1,$T2,0&gt;*)&amp;mImpl)).mValue</Item>
+ </Expand>
+</Type>
+
+<Type Name="eastl::tuple&lt;*,*,*&gt;">
+ <DisplayString IncludeView="noparens">{(*((eastl::Internal::TupleLeaf&lt;0,$T1,0&gt;*)&amp;mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf&lt;1,$T2,0&gt;*)&amp;mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf&lt;2,$T3,0&gt;*)&amp;mImpl)).mValue}</DisplayString>
+ <DisplayString ExcludeView="noparens">({*this,view(noparens)})</DisplayString>
+ <Expand>
+ <Item Name="[0]">(*((eastl::Internal::TupleLeaf&lt;0,$T1,0&gt;*)&amp;mImpl)).mValue</Item>
+ <Item Name="[1]">(*((eastl::Internal::TupleLeaf&lt;1,$T2,0&gt;*)&amp;mImpl)).mValue</Item>
+ <Item Name="[2]">(*((eastl::Internal::TupleLeaf&lt;2,$T3,0&gt;*)&amp;mImpl)).mValue</Item>
+ </Expand>
+</Type>
+
+<Type Name="eastl::tuple&lt;*,*,*,*&gt;">
+ <DisplayString IncludeView="noparens">{(*((eastl::Internal::TupleLeaf&lt;0,$T1,0&gt;*)&amp;mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf&lt;1,$T2,0&gt;*)&amp;mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf&lt;2,$T3,0&gt;*)&amp;mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf&lt;3,$T4,0&gt;*)&amp;mImpl)).mValue}</DisplayString>
+ <DisplayString ExcludeView="noparens">({*this,view(noparens)})</DisplayString>
+ <Expand>
+ <Item Name="[0]">(*((eastl::Internal::TupleLeaf&lt;0,$T1,0&gt;*)&amp;mImpl)).mValue</Item>
+ <Item Name="[1]">(*((eastl::Internal::TupleLeaf&lt;1,$T2,0&gt;*)&amp;mImpl)).mValue</Item>
+ <Item Name="[2]">(*((eastl::Internal::TupleLeaf&lt;2,$T3,0&gt;*)&amp;mImpl)).mValue</Item>
+ <Item Name="[3]">(*((eastl::Internal::TupleLeaf&lt;3,$T4,0&gt;*)&amp;mImpl)).mValue</Item>
+ </Expand>
+</Type>
+
+<Type Name="eastl::tuple&lt;*,*,*,*,*&gt;">
+ <DisplayString IncludeView="noparens">{(*((eastl::Internal::TupleLeaf&lt;0,$T1,0&gt;*)&amp;mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf&lt;1,$T2,0&gt;*)&amp;mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf&lt;2,$T3,0&gt;*)&amp;mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf&lt;3,$T4,0&gt;*)&amp;mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf&lt;4,$T5,0&gt;*)&amp;mImpl)).mValue}</DisplayString>
+ <DisplayString ExcludeView="noparens">({*this,view(noparens)})</DisplayString>
+ <Expand>
+ <Item Name="[0]">(*((eastl::Internal::TupleLeaf&lt;0,$T1,0&gt;*)&amp;mImpl)).mValue</Item>
+ <Item Name="[1]">(*((eastl::Internal::TupleLeaf&lt;1,$T2,0&gt;*)&amp;mImpl)).mValue</Item>
+ <Item Name="[2]">(*((eastl::Internal::TupleLeaf&lt;2,$T3,0&gt;*)&amp;mImpl)).mValue</Item>
+ <Item Name="[3]">(*((eastl::Internal::TupleLeaf&lt;3,$T4,0&gt;*)&amp;mImpl)).mValue</Item>
+ <Item Name="[4]">(*((eastl::Internal::TupleLeaf&lt;4,$T5,0&gt;*)&amp;mImpl)).mValue</Item>
+ </Expand>
+</Type>
+
+<Type Name="eastl::tuple&lt;*,*,*,*,*,*&gt;">
+ <DisplayString IncludeView="noparens">{(*((eastl::Internal::TupleLeaf&lt;0,$T1,0&gt;*)&amp;mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf&lt;1,$T2,0&gt;*)&amp;mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf&lt;2,$T3,0&gt;*)&amp;mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf&lt;3,$T4,0&gt;*)&amp;mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf&lt;4,$T5,0&gt;*)&amp;mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf&lt;5,$T6,0&gt;*)&amp;mImpl)).mValue}</DisplayString>
+ <DisplayString ExcludeView="noparens">({*this,view(noparens)})</DisplayString>
+ <Expand>
+ <Item Name="[0]">(*((eastl::Internal::TupleLeaf&lt;0,$T1,0&gt;*)&amp;mImpl)).mValue</Item>
+ <Item Name="[1]">(*((eastl::Internal::TupleLeaf&lt;1,$T2,0&gt;*)&amp;mImpl)).mValue</Item>
+ <Item Name="[2]">(*((eastl::Internal::TupleLeaf&lt;2,$T3,0&gt;*)&amp;mImpl)).mValue</Item>
+ <Item Name="[3]">(*((eastl::Internal::TupleLeaf&lt;3,$T4,0&gt;*)&amp;mImpl)).mValue</Item>
+ <Item Name="[4]">(*((eastl::Internal::TupleLeaf&lt;4,$T5,0&gt;*)&amp;mImpl)).mValue</Item>
+ <Item Name="[5]">(*((eastl::Internal::TupleLeaf&lt;5,$T6,0&gt;*)&amp;mImpl)).mValue</Item>
+ </Expand>
+</Type>
+
+<Type Name="eastl::tuple&lt;*,*,*,*,*,*,*&gt;">
+ <DisplayString IncludeView="noparens">{(*((eastl::Internal::TupleLeaf&lt;0,$T1,0&gt;*)&amp;mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf&lt;1,$T2,0&gt;*)&amp;mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf&lt;2,$T3,0&gt;*)&amp;mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf&lt;3,$T4,0&gt;*)&amp;mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf&lt;4,$T5,0&gt;*)&amp;mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf&lt;5,$T6,0&gt;*)&amp;mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf&lt;6,$T7,0&gt;*)&amp;mImpl)).mValue}</DisplayString>
+ <DisplayString ExcludeView="noparens">({*this,view(noparens)})</DisplayString>
+ <Expand>
+ <Item Name="[0]">(*((eastl::Internal::TupleLeaf&lt;0,$T1,0&gt;*)&amp;mImpl)).mValue</Item>
+ <Item Name="[1]">(*((eastl::Internal::TupleLeaf&lt;1,$T2,0&gt;*)&amp;mImpl)).mValue</Item>
+ <Item Name="[2]">(*((eastl::Internal::TupleLeaf&lt;2,$T3,0&gt;*)&amp;mImpl)).mValue</Item>
+ <Item Name="[3]">(*((eastl::Internal::TupleLeaf&lt;3,$T4,0&gt;*)&amp;mImpl)).mValue</Item>
+ <Item Name="[4]">(*((eastl::Internal::TupleLeaf&lt;4,$T5,0&gt;*)&amp;mImpl)).mValue</Item>
+ <Item Name="[5]">(*((eastl::Internal::TupleLeaf&lt;5,$T6,0&gt;*)&amp;mImpl)).mValue</Item>
+ <Item Name="[6]">(*((eastl::Internal::TupleLeaf&lt;6,$T7,0&gt;*)&amp;mImpl)).mValue</Item>
+ </Expand>
+</Type>
</AutoVisualizer>
diff --git a/EASTL/include/EASTL/algorithm.h b/EASTL/include/EASTL/algorithm.h
index da35c2e..6257514 100644
--- a/EASTL/include/EASTL/algorithm.h
+++ b/EASTL/include/EASTL/algorithm.h
@@ -128,6 +128,7 @@
// iter_swap
// lexicographical_compare
// lexicographical_compare<Compare>
+// lexicographical_compare_three_way
// lower_bound
// lower_bound<Compare>
// make_heap Found in heap.h
@@ -163,6 +164,8 @@
// random_shuffle<Random>
// remove
// remove_if
+// +apply_and_remove
+// +apply_and_remove_if
// remove_copy
// remove_copy_if
// +remove_heap Found in heap.h
@@ -247,6 +250,7 @@
#include <EASTL/utility.h>
#include <EASTL/internal/generic_iterator.h>
#include <EASTL/random.h>
+#include <EASTL/compare.h>
EA_DISABLE_ALL_VC_WARNINGS();
@@ -806,18 +810,18 @@ namespace eastl
template <typename T>
inline T&& median_impl(T&& a, T&& b, T&& c)
{
- if(a < b)
+ if(eastl::less<T>()(a, b))
{
- if(b < c)
+ if(eastl::less<T>()(b, c))
return eastl::forward<T>(b);
- else if(a < c)
+ else if(eastl::less<T>()(a, c))
return eastl::forward<T>(c);
else
return eastl::forward<T>(a);
}
- else if(a < c)
+ else if(eastl::less<T>()(a, c))
return eastl::forward<T>(a);
- else if(b < c)
+ else if(eastl::less<T>()(b, c))
return eastl::forward<T>(c);
return eastl::forward<T>(b);
}
@@ -1259,14 +1263,8 @@ namespace eastl
inline BidirectionalIterator2 move_and_copy_backward_chooser(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 resultEnd)
{
typedef typename eastl::iterator_traits<BidirectionalIterator1>::iterator_category IIC;
- typedef typename eastl::iterator_traits<BidirectionalIterator2>::iterator_category OIC;
- typedef typename eastl::iterator_traits<BidirectionalIterator1>::value_type value_type_input;
- typedef typename eastl::iterator_traits<BidirectionalIterator2>::value_type value_type_output;
- const bool canBeMemmoved = eastl::is_trivially_copyable<value_type_output>::value &&
- eastl::is_same<value_type_input, value_type_output>::value &&
- (eastl::is_pointer<BidirectionalIterator1>::value || eastl::is_same<IIC, eastl::contiguous_iterator_tag>::value) &&
- (eastl::is_pointer<BidirectionalIterator2>::value || eastl::is_same<OIC, eastl::contiguous_iterator_tag>::value);
+ const bool canBeMemmoved = internal::can_be_memmoved_helper<BidirectionalIterator1, BidirectionalIterator2>::value;
return eastl::move_and_copy_backward_helper<IIC, isMove, canBeMemmoved>::move_or_copy_backward(first, last, resultEnd); // 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.
}
@@ -2114,6 +2112,42 @@ namespace eastl
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+
+ /// lexicographical_compare_three_way
+ ///
+ /// Returns: The comparison category ordering between both ranges. For the first non-equivalent pair in the ranges,
+ /// the comparison will be returned. Else if the first range is a subset (superset) of the second range, then the
+ /// less (greater) ordering will be returned.
+ ///
+ /// Complexity: At most N iterations, where N = min(last1-first1, last2-first2) of the applications
+ /// of the corresponding comparison.
+ ///
+ /// Note: If two sequences have the same number of elements and their
+ /// corresponding elements are equivalent, then neither sequence is
+ /// lexicographically less than the other. If one sequence is a prefix
+ /// of the other, then the shorter sequence is lexicographically less
+ /// than the longer sequence. Otherwise, the lexicographical comparison
+ /// of the sequences yields the same result as the comparison of the first
+ /// corresponding pair of elements that are not equivalent.
+ ///
+ template <typename InputIterator1, typename InputIterator2, typename Compare>
+ constexpr auto lexicographical_compare_three_way(InputIterator1 first1, InputIterator1 last1,
+ InputIterator2 first2, InputIterator2 last2,
+ Compare compare) -> decltype(compare(*first1, *first2))
+ {
+ for (; (first1 != last1) && (first2 != last2); ++first1, ++first2)
+ {
+ if (auto c = compare(*first1, *first2); c != 0)
+ return c;
+ }
+
+ return (first1 != last1) ? std::strong_ordering::greater :
+ (first2 != last2) ? std::strong_ordering::less :
+ std::strong_ordering::equal;
+ }
+#endif
+
/// mismatch
///
/// Finds the first position where the two ranges [first1, last1) and
@@ -2628,6 +2662,94 @@ namespace eastl
}
+ /// apply_and_remove_if
+ ///
+ /// Calls the Function function for all elements referred to my iterator i in the range
+ /// [first, last) for which the following corresponding condition holds:
+ /// predicate(*i) == true
+ /// and then left shift moves potential non-matching elements over it.
+ ///
+ /// Returns: a past-the-end iterator for the new end of the range.
+ ///
+ /// Complexity: Exactly 'last - first' applications of the corresponding predicate + applies
+ /// function once for every time the condition holds.
+ ///
+ /// Note: Since removing is done by shifting (by means of copy move assignment) the elements
+ /// in the range in such a way that the elements that are not to be removed appear in the
+ /// beginning of the range doesn't actually remove it from the given container, the user must call
+ /// the container erase function if the user wants to erase the element
+ /// from the container. I.e. in the same they as for remove_if the excess elements
+ /// are left in a valid but possibly moved from state.
+ ///
+ template <typename ForwardIterator, typename Function, typename Predicate>
+ inline ForwardIterator apply_and_remove_if(ForwardIterator first,
+ ForwardIterator last,
+ Function function,
+ Predicate predicate)
+ {
+ first = eastl::find_if(first, last, predicate);
+ if (first != last)
+ {
+ function(*first);
+ for (auto i = next(first); i != last; ++i)
+ {
+ if (predicate(*i))
+ {
+ function(*i);
+ continue;
+ }
+ *first = eastl::move(*i);
+ ++first;
+ }
+ }
+ return first;
+ }
+
+
+ /// apply_and_remove
+ ///
+ /// Calls the Function function for all elements referred to my iterator i in the range
+ /// [first, last) for which the following corresponding condition holds:
+ /// value == *i
+ /// and then left shift moves potential non-matching elements over it.
+ ///
+ /// Returns: a past-the-end iterator for the new end of the range.
+ ///
+ /// Complexity: Exactly 'last - first' applications of the corresponding equality test
+ /// + applies function once for every time the condition holds.
+ ///
+ /// Note: Since removing is done by shifting (by means of copy move assignment) the elements
+ /// in the range in such a way that the elements that are not to be removed appear in the
+ /// beginning of the range doesn't actually remove it from the given container, the user must call
+ /// the container erase function if the user wants to erase the element
+ /// from the container. I.e. in the same they as for remove_if the excess elements
+ /// are left in a valid but possibly moved from state.
+ ///
+ template <typename ForwardIterator, typename Function, typename T>
+ inline ForwardIterator apply_and_remove(ForwardIterator first,
+ ForwardIterator last,
+ Function function,
+ const T& value)
+ {
+ first = eastl::find(first, last, value);
+ if (first != last)
+ {
+ function(*first);
+ for (auto i = next(first); i != last; ++i)
+ {
+ if (value == *i)
+ {
+ function(*i);
+ continue;
+ }
+ *first = eastl::move(*i);
+ ++first;
+ }
+ }
+ return first;
+ }
+
+
/// replace_copy
///
/// Effects: Assigns to every iterator i in the range [result, result + (last - first))
@@ -4187,9 +4309,8 @@ namespace eastl
template <class T, class Compare>
EA_CONSTEXPR const T& clamp(const T& v, const T& lo, const T& hi, Compare comp)
{
- // code collapsed to a single line due to constexpr requirements
- return [&] { EASTL_ASSERT(!comp(hi, lo)); }(),
- comp(v, lo) ? lo : comp(hi, v) ? hi : v;
+ EASTL_ASSERT(!comp(hi, lo));
+ return comp(v, lo) ? lo : comp(hi, v) ? hi : v;
}
template <class T>
diff --git a/EASTL/include/EASTL/allocator.h b/EASTL/include/EASTL/allocator.h
index ad20e4d..d645466 100644
--- a/EASTL/include/EASTL/allocator.h
+++ b/EASTL/include/EASTL/allocator.h
@@ -71,8 +71,9 @@ namespace eastl
};
bool operator==(const allocator& a, const allocator& b);
+#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
bool operator!=(const allocator& a, const allocator& b);
-
+#endif
/// dummy_allocator
@@ -97,8 +98,9 @@ namespace eastl
};
inline bool operator==(const dummy_allocator&, const dummy_allocator&) { return true; }
+#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
inline bool operator!=(const dummy_allocator&, const dummy_allocator&) { return false; }
-
+#endif
/// Defines a static default allocator which is constant across all types.
@@ -299,12 +301,12 @@ namespace eastl
return true; // All allocators are considered equal, as they merely use global new/delete.
}
-
+#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
inline bool operator!=(const allocator&, const allocator&)
{
return false; // All allocators are considered equal, as they merely use global new/delete.
}
-
+#endif
} // namespace eastl
diff --git a/EASTL/include/EASTL/array.h b/EASTL/include/EASTL/array.h
index 05d5d32..34ad07d 100644
--- a/EASTL/include/EASTL/array.h
+++ b/EASTL/include/EASTL/array.h
@@ -401,6 +401,13 @@ namespace eastl
return eastl::equal(&a.mValue[0], &a.mValue[N], &b.mValue[0]);
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T, size_t N>
+ inline synth_three_way_result<T> operator<=>(const array<T, N>& a, const array<T,N>& b)
+ {
+ return eastl::lexicographical_compare_three_way(&a.mValue[0], &a.mValue[N], &b.mValue[0], &b.mValue[N], synth_three_way{});
+ }
+#else
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline bool operator<(const array<T, N>& a, const array<T, N>& b)
@@ -435,7 +442,7 @@ namespace eastl
{
return !eastl::lexicographical_compare(&a.mValue[0], &a.mValue[N], &b.mValue[0], &b.mValue[N]);
}
-
+#endif
template <typename T, size_t N>
inline void swap(array<T, N>& a, array<T, N>& b)
@@ -478,9 +485,96 @@ namespace eastl
return internal::to_array(eastl::move(a), eastl::make_index_sequence<N>{});
}
+#if EASTL_TUPLE_ENABLED
+
+ template <typename T, size_t N>
+ class tuple_size<array<T, N>> : public integral_constant<size_t, N>
+ {
+ };
+
+ template <typename T, size_t N>
+ class tuple_size<const array<T, N>> : public integral_constant<size_t, N>
+ {
+ };
+
+ template <size_t I, typename T, size_t N>
+ class tuple_element<I, array<T, N>>
+ {
+ public:
+ using type = T;
+ };
+
+ template <size_t I, typename T, size_t N>
+ class tuple_element<I, const array<T, N>>
+ {
+ public:
+ using type = const T;
+ };
+
+ template <size_t I>
+ struct GetArray
+ {
+ template <typename T, size_t N>
+ static EA_CONSTEXPR T& getInternal(array<T, N>& a)
+ {
+ return a[I];
+ }
+
+ template <typename T, size_t N>
+ static EA_CONSTEXPR const T& getInternal(const array<T, N>& a)
+ {
+ return a[I];
+ }
+
+ template <typename T, size_t N>
+ static EA_CONSTEXPR T&& getInternal(array<T, N>&& a)
+ {
+ return eastl::forward<T>(a[I]);
+ }
+ };
+
+ template <size_t I, typename T, size_t N>
+ EA_CONSTEXPR tuple_element_t<I, array<T, N>>& get(array<T, N>& p)
+ {
+ return GetArray<I>::getInternal(p);
+ }
+
+ template <size_t I, typename T, size_t N>
+ EA_CONSTEXPR const tuple_element_t<I, array<T, N>>& get(const array<T, N>& p)
+ {
+ return GetArray<I>::getInternal(p);
+ }
+
+ template <size_t I, typename T, size_t N>
+ EA_CONSTEXPR tuple_element_t<I, array<T, N>>&& get(array<T, N>&& p)
+ {
+ return GetArray<I>::getInternal(eastl::move(p));
+ }
+
+#endif // EASTL_TUPLE_ENABLED
+
} // namespace eastl
+///////////////////////////////////////////////////////////////
+// C++17 structured binding support for eastl::array
+//
+#ifndef EA_COMPILER_NO_STRUCTURED_BINDING
+ #include <tuple>
+
+ template <typename T, size_t N>
+ class std::tuple_size<::eastl::array<T, N>> : public ::eastl::integral_constant<size_t, N>
+ {
+ };
+
+ template <size_t I, typename T, size_t N>
+ struct std::tuple_element<I, ::eastl::array<T, N>>
+ {
+ static_assert(I < N, "index is out of bounds");
+ using type = T;
+ };
+#endif // EA_COMPILER_NO_STRUCTURED_BINDING
+
#endif // Header include guard
diff --git a/EASTL/include/EASTL/bit.h b/EASTL/include/EASTL/bit.h
index 64efe48..0eeeed0 100644
--- a/EASTL/include/EASTL/bit.h
+++ b/EASTL/include/EASTL/bit.h
@@ -60,6 +60,113 @@ namespace eastl
#endif // EASTL_CONSTEXPR_BIT_CAST_SUPPORTED
+ #if defined(EA_COMPILER_CPP20_ENABLED)
+ #ifndef EASTL_COUNT_LEADING_ZEROES
+ #if defined(__GNUC__)
+ #if (EA_PLATFORM_PTR_SIZE == 8)
+ #define EASTL_COUNT_LEADING_ZEROES __builtin_clzll
+ #else
+ #define EASTL_COUNT_LEADING_ZEROES __builtin_clz
+ #endif
+ #endif
+
+ #ifndef EASTL_COUNT_LEADING_ZEROES
+ static inline int eastl_count_leading_zeroes(uint64_t x)
+ {
+ if(x)
+ {
+ int n = 0;
+ if(x & UINT64_C(0xFFFFFFFF00000000)) { n += 32; x >>= 32; }
+ if(x & 0xFFFF0000) { n += 16; x >>= 16; }
+ if(x & 0xFFFFFF00) { n += 8; x >>= 8; }
+ if(x & 0xFFFFFFF0) { n += 4; x >>= 4; }
+ if(x & 0xFFFFFFFC) { n += 2; x >>= 2; }
+ if(x & 0xFFFFFFFE) { n += 1; }
+ return 63 - n;
+ }
+ return 64;
+ }
+
+ static inline int eastl_count_leading_zeroes(uint32_t x)
+ {
+ if(x)
+ {
+ int n = 0;
+ if(x <= 0x0000FFFF) { n += 16; x <<= 16; }
+ if(x <= 0x00FFFFFF) { n += 8; x <<= 8; }
+ if(x <= 0x0FFFFFFF) { n += 4; x <<= 4; }
+ if(x <= 0x3FFFFFFF) { n += 2; x <<= 2; }
+ if(x <= 0x7FFFFFFF) { n += 1; }
+ return n;
+ }
+ return 32;
+ }
+
+ #define EASTL_COUNT_LEADING_ZEROES eastl_count_leading_zeroes
+ #endif
+ #endif
+
+ template <typename T, typename = eastl::enable_if_t<eastl::is_unsigned_v<T>>>
+ EA_CONSTEXPR int countl_zero(const T num) EA_NOEXCEPT
+ {
+ EA_CONSTEXPR auto DIGITS = eastl::numeric_limits<T>::digits;
+ EA_CONSTEXPR auto DIGITS_U = eastl::numeric_limits<unsigned>::digits;
+ EA_CONSTEXPR auto DIGITS_ULL = eastl::numeric_limits<unsigned long long>::digits;
+
+ if (num == 0)
+ {
+ return DIGITS;
+ }
+
+ if constexpr (DIGITS <= DIGITS_U)
+ {
+ EA_CONSTEXPR auto DIFF = DIGITS_U - DIGITS;
+ return EASTL_COUNT_LEADING_ZEROES(static_cast<uint32_t>(num)) - DIFF;
+ }
+ else
+ {
+ EA_CONSTEXPR auto DIFF = DIGITS_ULL - DIGITS;
+ return EASTL_COUNT_LEADING_ZEROES(static_cast<uint64_t>(num)) - DIFF;
+ }
+ }
+
+ template <typename T, typename = eastl::enable_if_t<eastl::is_unsigned_v<T>>>
+ EA_CONSTEXPR bool has_single_bit(const T num) EA_NOEXCEPT
+ {
+ return num != 0 && (num & (num - 1)) == 0;
+ }
+
+ template <typename T, typename = eastl::enable_if_t<eastl::is_unsigned_v<T>>>
+ EA_CONSTEXPR T bit_ceil(const T num) EA_NOEXCEPT
+ {
+ if (num <= 1U)
+ {
+ return T(1);
+ }
+
+ const auto shift = eastl::numeric_limits<T>::digits - eastl::countl_zero(static_cast<T>(num - 1));
+ return static_cast<T>(T(1) << shift);
+ }
+
+ template <typename T, typename = eastl::enable_if_t<eastl::is_unsigned_v<T>>>
+ EA_CONSTEXPR T bit_floor(const T num) EA_NOEXCEPT
+ {
+ if (num == 0)
+ {
+ return T(0);
+ }
+
+ const auto shift = eastl::numeric_limits<T>::digits - eastl::countl_zero(num) - 1;
+ return static_cast<T>(T(1) << shift);
+ }
+
+ template <typename T, typename = eastl::enable_if_t<eastl::is_unsigned_v<T>>>
+ EA_CONSTEXPR T bit_width(const T num) EA_NOEXCEPT
+ {
+ return static_cast<T>(eastl::numeric_limits<T>::digits - eastl::countl_zero(num));
+ }
+ #endif
+
} // namespace eastl
#endif // EASTL_BIT_H
diff --git a/EASTL/include/EASTL/bitset.h b/EASTL/include/EASTL/bitset.h
index 8778372..c31831a 100644
--- a/EASTL/include/EASTL/bitset.h
+++ b/EASTL/include/EASTL/bitset.h
@@ -405,7 +405,9 @@ namespace eastl
size_type size() const;
bool operator==(const this_type& x) const;
+#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
bool operator!=(const this_type& x) const;
+#endif
bool test(size_type i) const;
//bool any() const; // We inherit this from the base class.
@@ -2078,13 +2080,13 @@ EA_RESTORE_GCC_WARNING()
return base_type::operator==(x);
}
-
+#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <size_t N, typename WordType>
inline bool bitset<N, WordType>::operator!=(const this_type& x) const
{
return !base_type::operator==(x);
}
-
+#endif
template <size_t N, typename WordType>
inline bool bitset<N, WordType>::test(size_type i) const
diff --git a/EASTL/include/EASTL/bonus/lru_cache.h b/EASTL/include/EASTL/bonus/lru_cache.h
index 46d053d..a8d7c33 100644
--- a/EASTL/include/EASTL/bonus/lru_cache.h
+++ b/EASTL/include/EASTL/bonus/lru_cache.h
@@ -122,7 +122,7 @@ namespace eastl
}
lru_cache(std::initializer_list<eastl::pair<Key, Value>> il)
- : lru_cache(il.size())
+ : lru_cache(static_cast<size_type>(il.size()))
{
for(auto& p : il)
insert_or_assign(p.first, p.second);
diff --git a/EASTL/include/EASTL/bonus/overloaded.h b/EASTL/include/EASTL/bonus/overloaded.h
new file mode 100644
index 0000000..55ca158
--- /dev/null
+++ b/EASTL/include/EASTL/bonus/overloaded.h
@@ -0,0 +1,81 @@
+/////////////////////////////////////////////////////////////////////////////
+// Copyright (c) Electronic Arts Inc. All rights reserved.
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef EASTL_OVERLOADED_H
+#define EASTL_OVERLOADED_H
+
+#include <EASTL/internal/move_help.h>
+#include <EASTL/type_traits.h>
+
+
+#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.
+#endif
+
+namespace eastl
+{
+ ///////////////////////////////////////////////////////////////////////////
+ /// overloaded
+ ///
+ /// A helper class that permits you to combine multiple function objects into one.
+ /// Typically, this helper is really handy when visiting an eastl::variant with multiple lambdas.
+ /// Example:
+ ///
+ /// eastl::variant<int, string> v{42};
+ ///
+ /// eastl::visit(
+ /// eastl::overloaded{
+ /// [](const int& x) { std::cout << "Visited an integer: " << x << "\n"; }, // Will reach that lambda with x == 42.
+ /// [](const string& s) { std::cout << "Visited an string: " << s << "\n"; }
+ /// },
+ /// v
+ /// );
+ ///////////////////////////////////////////////////////////////////////////
+ template <class... T>
+ struct overloaded;
+
+ template <class T>
+ struct overloaded<T> : T
+ {
+ template <class U>
+ EA_CPP14_CONSTEXPR overloaded(U&& u) : T(eastl::forward<U>(u))
+ {
+ }
+
+ using T::operator();
+ };
+
+ template <class T, class... R>
+ struct overloaded<T, R...> : T, overloaded<R...>
+ {
+ template <class U, class... V>
+ EA_CPP14_CONSTEXPR overloaded(U&& u, V&&... v) : T(eastl::forward<U>(u)), overloaded<R...>(eastl::forward<V>(v)...)
+ {
+ }
+
+ using T::operator();
+ using overloaded<R...>::operator();
+ };
+
+ #ifdef __cpp_deduction_guides
+ template <class... T>
+ overloaded(T...) -> overloaded<T...>;
+ #endif
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// make_overloaded
+ ///
+ /// Helper function to create an overloaded instance when lacking deduction guides.
+ /// make_overloaded(f1, f2, f3) == overloaded{f1, f2, f3}
+ ///////////////////////////////////////////////////////////////////////////
+ template <class... T>
+ EA_CPP14_CONSTEXPR overloaded<typename eastl::remove_cvref<T>::type...> make_overloaded(T&&... t)
+ {
+ return overloaded<typename eastl::remove_cvref<T>::type...>{eastl::forward<T>(t)...};
+ }
+
+} // namespace eastl
+
+#endif // EASTL_OVERLOADED_H \ No newline at end of file
diff --git a/EASTL/include/EASTL/bonus/tuple_vector.h b/EASTL/include/EASTL/bonus/tuple_vector.h
index 7123c57..6ade75a 100644
--- a/EASTL/include/EASTL/bonus/tuple_vector.h
+++ b/EASTL/include/EASTL/bonus/tuple_vector.h
@@ -340,13 +340,13 @@ struct TupleVecIterCompatible<TupleTypes<Us...>, TupleTypes<Ts...>> :
// storing - and harmoniously updating on each modification - a full tuple of pointers to the tupleVec's data
template <eastl_size_t... Indices, typename... Ts>
struct TupleVecIter<index_sequence<Indices...>, Ts...>
- : public iterator<random_access_iterator_tag, tuple<Ts...>, eastl_size_t, tuple<Ts*...>, tuple<Ts&...>>
+ : public iterator<EASTL_ITC_NS::random_access_iterator_tag, tuple<Ts...>, eastl_size_t, tuple<Ts*...>, tuple<Ts&...>>
{
private:
typedef TupleVecIter<index_sequence<Indices...>, Ts...> this_type;
typedef eastl_size_t size_type;
- typedef iterator<random_access_iterator_tag, tuple<Ts...>, eastl_size_t, tuple<Ts*...>, tuple<Ts&...>> iter_type;
+ typedef iterator<EASTL_ITC_NS::random_access_iterator_tag, tuple<Ts...>, eastl_size_t, tuple<Ts*...>, tuple<Ts&...>> iter_type;
template<typename U, typename... Us>
friend struct TupleVecIter;
@@ -1411,7 +1411,6 @@ class move_iterator<TupleVecInternal::TupleVecIter<index_sequence<Indices...>, T
{
public:
typedef TupleVecInternal::TupleVecIter<index_sequence<Indices...>, Ts...> 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.
typedef iterator_traits<iterator_type> traits_type;
typedef typename traits_type::iterator_category iterator_category;
@@ -1477,6 +1476,13 @@ private:
{
return reference(eastl::move(((Ts*)mIterator.mpData[Indices])[mIterator.mIndex])...);
}
+
+ // Unwrapping interface, not part of the public API.
+ iterator_type unwrap() const { return mIterator; }
+
+ // The unwrapper helpers need access to unwrap().
+ friend is_iterator_wrapper_helper<this_type, true>;
+ friend is_iterator_wrapper<this_type>;
};
template <typename AllocatorA, typename AllocatorB, typename Indices, typename... Ts>
diff --git a/EASTL/include/EASTL/chrono.h b/EASTL/include/EASTL/chrono.h
index 5d8ca42..4b94fe4 100644
--- a/EASTL/include/EASTL/chrono.h
+++ b/EASTL/include/EASTL/chrono.h
@@ -16,7 +16,7 @@
#define EASTL_CHRONO_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
- #pragma once
+ #pragma once
#endif
#include <EASTL/internal/config.h>
@@ -50,12 +50,9 @@
#if defined(EA_PLATFORM_MICROSOFT) && !defined(EA_PLATFORM_MINGW)
// Nothing to do
-#elif defined(EA_PLATFORM_SONY)
- #include <Dinkum/threads/xtimec.h>
- #include <kernel.h>
#elif defined(EA_PLATFORM_APPLE)
#include <mach/mach_time.h>
-#elif defined(EA_PLATFORM_POSIX) || defined(EA_PLATFORM_MINGW) || defined(EA_PLATFORM_ANDROID)
+#elif defined(EA_PLATFORM_POSIX) || defined(EA_PLATFORM_MINGW) || defined(EA_PLATFORM_ANDROID)
// Posix means Linux, Unix, and Macintosh OSX, among others (including Linux-based mobile platforms).
#if defined(EA_PLATFORM_MINGW)
#include <pthread_time.h>
@@ -104,7 +101,7 @@ namespace chrono
namespace Internal
{
///////////////////////////////////////////////////////////////////////////////
- // IsRatio
+ // IsRatio
///////////////////////////////////////////////////////////////////////////////
template <typename> struct IsRatio : eastl::false_type {};
template <intmax_t N, intmax_t D> struct IsRatio<ratio<N, D>> : eastl::true_type {};
@@ -114,7 +111,7 @@ namespace chrono
///////////////////////////////////////////////////////////////////////////////
- // IsDuration
+ // IsDuration
///////////////////////////////////////////////////////////////////////////////
template<typename> struct IsDuration : eastl::false_type{};
template<typename Rep, typename Period> struct IsDuration<duration<Rep, Period>> : eastl::true_type{};
@@ -124,7 +121,7 @@ namespace chrono
///////////////////////////////////////////////////////////////////////////////
- // RatioGCD
+ // RatioGCD
///////////////////////////////////////////////////////////////////////////////
template <class Period1, class Period2>
struct RatioGCD
@@ -197,10 +194,10 @@ namespace chrono
///////////////////////////////////////////////////////////////////////////////
- // duration_cast
+ // duration_cast
///////////////////////////////////////////////////////////////////////////////
template <typename ToDuration, typename Rep, typename Period>
- inline typename eastl::enable_if<Internal::IsDuration<ToDuration>::value, ToDuration>::type
+ inline typename eastl::enable_if<Internal::IsDuration<ToDuration>::value, ToDuration>::type
duration_cast(const duration<Rep, Period>& d)
{
typedef typename duration<Rep, Period>::this_type FromDuration;
@@ -209,12 +206,12 @@ namespace chrono
///////////////////////////////////////////////////////////////////////////////
- // duration
+ // duration
///////////////////////////////////////////////////////////////////////////////
template <class Rep, class Period>
class duration
{
- Rep mRep;
+ Rep mRep;
public:
typedef Rep rep;
@@ -222,7 +219,7 @@ namespace chrono
typedef duration<Rep, Period> this_type;
#if defined(EA_COMPILER_NO_DEFAULTED_FUNCTIONS)
- EA_CONSTEXPR duration()
+ EA_CONSTEXPR duration()
: mRep() {}
duration(const duration& other)
@@ -238,7 +235,7 @@ namespace chrono
///////////////////////////////////////////////////////////////////////////////
- // conversion constructors
+ // conversion constructors
///////////////////////////////////////////////////////////////////////////////
template <class Rep2>
inline EA_CONSTEXPR explicit duration(
@@ -258,12 +255,12 @@ namespace chrono
: mRep(duration_cast<duration>(d2).count()) {}
///////////////////////////////////////////////////////////////////////////////
- // returns the count of ticks
+ // returns the count of ticks
///////////////////////////////////////////////////////////////////////////////
EA_CONSTEXPR Rep count() const { return mRep; }
///////////////////////////////////////////////////////////////////////////////
- // static accessors of special duration values
+ // static accessors of special duration values
///////////////////////////////////////////////////////////////////////////////
EA_CONSTEXPR inline static duration zero() { return duration(duration_values<Rep>::zero()); }
EA_CONSTEXPR inline static duration min() { return duration(duration_values<Rep>::min()); }
@@ -314,7 +311,7 @@ namespace chrono
duration<typename eastl::common_type<Rep1, Rep2>::type, Period1> EASTL_FORCE_INLINE
operator*(const duration<Rep1, Period1>& lhs, const Rep2& rhs)
{
- typedef typename duration<eastl::common_type<Rep1, Rep2>, Period1>::type common_duration_t;
+ typedef duration<typename eastl::common_type<Rep1, Rep2>::type, Period1> common_duration_t;
return common_duration_t(common_duration_t(lhs).count() * rhs);
}
@@ -421,7 +418,7 @@ namespace chrono
///////////////////////////////////////////////////////////////////////////////
// 20.12.6, time_point
///////////////////////////////////////////////////////////////////////////////
- template <typename Clock, typename Duration = typename Clock::duration>
+ template <typename Clock, typename Duration = typename Clock::duration>
class time_point
{
Duration mDuration;
@@ -443,7 +440,7 @@ namespace chrono
EA_CONSTEXPR Duration time_since_epoch() const { return mDuration; }
- time_point& operator+=(const Duration& d) { mDuration += d; return *this; }
+ time_point& operator+=(const Duration& d) { mDuration += d; return *this; }
time_point& operator-=(const Duration& d) { mDuration -= d; return *this; }
static EA_CONSTEXPR time_point min() { return time_point(Duration::min()); }
@@ -546,26 +543,26 @@ namespace chrono
namespace Internal
{
#if defined(EA_PLATFORM_MICROSOFT) && !defined(EA_PLATFORM_MINGW)
- #define EASTL_NS_PER_TICK 1
+ #define EASTL_NS_PER_TICK 1
#elif defined EA_PLATFORM_SONY
- #define EASTL_NS_PER_TICK _XTIME_NSECS_PER_TICK
+ #define EASTL_NS_PER_TICK 1
#elif defined EA_PLATFORM_POSIX
#define EASTL_NS_PER_TICK _XTIME_NSECS_PER_TICK
#else
- #define EASTL_NS_PER_TICK 100
+ #define EASTL_NS_PER_TICK 100
#endif
- #if defined(EA_PLATFORM_POSIX)
+ #if defined(EA_PLATFORM_POSIX)
typedef chrono::nanoseconds::period SystemClock_Period;
typedef chrono::nanoseconds::period SteadyClock_Period;
#else
- typedef eastl::ratio_multiply<eastl::ratio<EASTL_NS_PER_TICK, 1>, nano>::type SystemClock_Period;
- typedef eastl::ratio_multiply<eastl::ratio<EASTL_NS_PER_TICK, 1>, nano>::type SteadyClock_Period;
+ typedef eastl::ratio_multiply<eastl::ratio<EASTL_NS_PER_TICK, 1>, nano>::type SystemClock_Period;
+ typedef eastl::ratio_multiply<eastl::ratio<EASTL_NS_PER_TICK, 1>, nano>::type SteadyClock_Period;
#endif
///////////////////////////////////////////////////////////////////////////////
- // Internal::GetTicks
+ // Internal::GetTicks
///////////////////////////////////////////////////////////////////////////////
inline uint64_t GetTicks()
{
@@ -574,7 +571,7 @@ namespace chrono
{
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
- return double(1000000000.0L / frequency.QuadPart); // nanoseconds per tick
+ return double(1000000000.0L / (long double)frequency.QuadPart); // nanoseconds per tick
};
auto queryCounter = []
@@ -587,11 +584,23 @@ namespace chrono
EA_DISABLE_VC_WARNING(4640) // warning C4640: construction of local static object is not thread-safe (VS2013)
static auto frequency = queryFrequency(); // cache cpu frequency on first call
EA_RESTORE_VC_WARNING()
- return uint64_t(frequency * queryCounter());
- #elif defined EA_PLATFORM_SONY
- return sceKernelGetProcessTimeCounter();
+ return uint64_t(frequency * (double)queryCounter());
+ #elif defined EA_PLATFORM_SONY
+ static_assert(false, "Implementing GetTicks() requires first party support");
+ return 0;
#elif defined(EA_PLATFORM_APPLE)
- return mach_absolute_time();
+ auto queryTimeInfo = []
+ {
+ mach_timebase_info_data_t info;
+ mach_timebase_info(&info);
+ return info;
+ };
+
+ static auto timeInfo = queryTimeInfo();
+ uint64_t t = mach_absolute_time();
+ t *= timeInfo.numer;
+ t /= timeInfo.denom;
+ return t;
#elif defined(EA_PLATFORM_POSIX) // Posix means Linux, Unix, and Macintosh OSX, among others (including Linux-based mobile platforms).
#if (defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC))
timespec ts;
@@ -616,7 +625,7 @@ namespace chrono
///////////////////////////////////////////////////////////////////////////////
- // system_clock
+ // system_clock
///////////////////////////////////////////////////////////////////////////////
class system_clock
{
@@ -630,15 +639,15 @@ namespace chrono
EA_CONSTEXPR_OR_CONST static bool is_steady = false;
// returns a time point representing the current point in time.
- static time_point now() EA_NOEXCEPT
- {
- return time_point(duration(Internal::GetTicks()));
+ static time_point now() EA_NOEXCEPT
+ {
+ return time_point(duration(Internal::GetTicks()));
}
};
///////////////////////////////////////////////////////////////////////////////
- // steady_clock
+ // steady_clock
///////////////////////////////////////////////////////////////////////////////
class steady_clock
{
@@ -652,24 +661,24 @@ namespace chrono
EA_CONSTEXPR_OR_CONST static bool is_steady = true;
// returns a time point representing the current point in time.
- static time_point now() EA_NOEXCEPT
- {
- return time_point(duration(Internal::GetTicks()));
+ static time_point now() EA_NOEXCEPT
+ {
+ return time_point(duration(Internal::GetTicks()));
}
};
///////////////////////////////////////////////////////////////////////////////
- // high_resolution_clock
+ // high_resolution_clock
///////////////////////////////////////////////////////////////////////////////
typedef system_clock high_resolution_clock;
-} // namespace chrono
+} // namespace chrono
///////////////////////////////////////////////////////////////////////////////
- // duration common_type specialization
+ // duration common_type specialization
///////////////////////////////////////////////////////////////////////////////
template <typename Rep1, typename Period1, typename Rep2, typename Period2>
struct common_type<chrono::duration<Rep1, Period1>, chrono::duration<Rep2, Period2>>
@@ -680,7 +689,7 @@ namespace chrono
///////////////////////////////////////////////////////////////////////////////
- // time_point common_type specialization
+ // time_point common_type specialization
///////////////////////////////////////////////////////////////////////////////
template <typename Clock, typename Duration1, typename Duration2>
struct common_type<chrono::time_point<Clock, Duration1>, chrono::time_point<Clock, Duration2>>
@@ -690,10 +699,15 @@ namespace chrono
///////////////////////////////////////////////////////////////////////////////
- // chrono_literals
+ // chrono_literals
///////////////////////////////////////////////////////////////////////////////
#if EASTL_USER_LITERALS_ENABLED && EASTL_INLINE_NAMESPACES_ENABLED
- EA_DISABLE_VC_WARNING(4455) // disable warning C4455: literal suffix identifiers that do not start with an underscore are reserved
+ // Disabling the Clang/GCC/MSVC warning about using user
+ // defined literals without a leading '_' as they are reserved
+ // for standard libary usage.
+ EA_DISABLE_VC_WARNING(4455)
+ EA_DISABLE_CLANG_WARNING(-Wuser-defined-literals)
+ EA_DISABLE_GCC_WARNING(-Wliteral-suffix)
inline namespace literals
{
inline namespace chrono_literals
@@ -726,7 +740,9 @@ namespace chrono
} // namespace chrono_literals
}// namespace literals
- EA_RESTORE_VC_WARNING() // warning: 4455
+ EA_RESTORE_GCC_WARNING() // -Wliteral-suffix
+ EA_RESTORE_CLANG_WARNING() // -Wuser-defined-literals
+ EA_RESTORE_VC_WARNING() // warning: 4455
#endif
} // namespace eastl
@@ -740,4 +756,4 @@ namespace chrono
#endif
-#endif
+#endif
diff --git a/EASTL/include/EASTL/compare.h b/EASTL/include/EASTL/compare.h
new file mode 100644
index 0000000..9bc3bd6
--- /dev/null
+++ b/EASTL/include/EASTL/compare.h
@@ -0,0 +1,45 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) Electronic Arts Inc. All rights reserved.
+///////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef EASTL_COMPARE_H
+#define EASTL_COMPARE_H
+
+
+#include <EABase/eabase.h>
+
+namespace eastl
+{
+
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ struct synth_three_way
+ {
+ template <typename T, typename U>
+ constexpr auto operator()(const T& t, const U& u) const requires requires
+ {
+ {t < u}->std::convertible_to<bool>;
+ {u < t}->std::convertible_to<bool>;
+ }
+ {
+ if constexpr (std::three_way_comparable_with<T, U>)
+ {
+ return t <=> u;
+ }
+ else
+ {
+ return (t < u) ? std::weak_ordering::less :
+ (u < t) ? std::weak_ordering::greater :
+ std::weak_ordering::equivalent;
+ }
+ }
+ };
+
+ template <typename T, typename U=T>
+ using synth_three_way_result = decltype(synth_three_way{}(declval<T&>(), declval<U&>()));
+#endif
+
+} // namespace eastl
+
+
+#endif // Header include guard \ No newline at end of file
diff --git a/EASTL/include/EASTL/deque.h b/EASTL/include/EASTL/deque.h
index c2d55b1..9a812c9 100644
--- a/EASTL/include/EASTL/deque.h
+++ b/EASTL/include/EASTL/deque.h
@@ -2619,6 +2619,14 @@ namespace eastl
return ((a.size() == b.size()) && eastl::equal(a.begin(), a.end(), b.begin()));
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T, typename Allocator, unsigned kDequeSubarraySize>
+ inline synth_three_way_result<T> operator<=>(const deque<T, Allocator, kDequeSubarraySize>& a, const deque<T, Allocator, kDequeSubarraySize>& b)
+ {
+ return eastl::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end(), synth_three_way{});
+ }
+
+#else
template <typename T, typename Allocator, unsigned kDequeSubarraySize>
inline bool operator!=(const deque<T, Allocator, kDequeSubarraySize>& a, const deque<T, Allocator, kDequeSubarraySize>& b)
{
@@ -2648,6 +2656,7 @@ namespace eastl
{
return !(a < b);
}
+#endif
template <typename T, typename Allocator, unsigned kDequeSubarraySize>
inline void swap(deque<T, Allocator, kDequeSubarraySize>& a, deque<T, Allocator, kDequeSubarraySize>& b)
@@ -2661,17 +2670,39 @@ namespace eastl
// https://en.cppreference.com/w/cpp/container/deque/erase2
///////////////////////////////////////////////////////////////////////
template <class T, class Allocator, class U>
- void erase(deque<T, Allocator>& c, const U& value)
+ typename deque<T, Allocator>::size_type erase(deque<T, Allocator>& c, const U& value)
{
- // Erases all elements that compare equal to value from the container.
- c.erase(eastl::remove(c.begin(), c.end(), value), c.end());
+ // Erases all elements that compare equal to value from the container.
+ auto origEnd = c.end();
+ auto newEnd = eastl::remove(c.begin(), origEnd, value);
+ auto numRemoved = eastl::distance(newEnd, origEnd);
+ c.erase(newEnd, origEnd);
+
+ // Note: This is technically a lossy conversion when size_type
+ // is 32bits and ptrdiff_t is 64bits (could happen on 64bit
+ // systems when EASTL_SIZE_T_32BIT is set). In practice this
+ // is fine because if EASTL_SIZE_T_32BIT is set then the deque
+ // should not have more elements than fit in a uint32_t and so
+ // the distance here should fit in a size_type.
+ return static_cast<typename deque<T, Allocator>::size_type>(numRemoved);
}
template <class T, class Allocator, class Predicate>
- void erase_if(deque<T, Allocator>& c, Predicate predicate)
- {
- // Erases all elements that satisfy the predicate pred from the container.
- c.erase(eastl::remove_if(c.begin(), c.end(), predicate), c.end());
+ typename deque<T, Allocator>::size_type erase_if(deque<T, Allocator>& c, Predicate predicate)
+ {
+ // Erases all elements that satisfy the predicate pred from the container.
+ auto origEnd = c.end();
+ auto newEnd = eastl::remove_if(c.begin(), origEnd, predicate);
+ auto numRemoved = eastl::distance(newEnd, origEnd);
+ c.erase(newEnd, origEnd);
+
+ // Note: This is technically a lossy conversion when size_type
+ // is 32bits and ptrdiff_t is 64bits (could happen on 64bit
+ // systems when EASTL_SIZE_T_32BIT is set). In practice this
+ // is fine because if EASTL_SIZE_T_32BIT is set then the deque
+ // should not have more elements than fit in a uint32_t and so
+ // the distance here should fit in a size_type.
+ return static_cast<typename deque<T, Allocator>::size_type>(numRemoved);
}
diff --git a/EASTL/include/EASTL/fixed_substring.h b/EASTL/include/EASTL/fixed_substring.h
index 033052f..e186cfc 100644
--- a/EASTL/include/EASTL/fixed_substring.h
+++ b/EASTL/include/EASTL/fixed_substring.h
@@ -108,6 +108,10 @@ namespace eastl
{
}
+ fixed_substring(const fixed_substring& x)
+ : fixed_substring(static_cast<const base_type&>(x))
+ {}
+
fixed_substring(const base_type& x)
: base_type()
{
@@ -156,6 +160,12 @@ namespace eastl
AllocateSelf();
}
+ this_type& operator=(const this_type& x)
+ {
+ assign(x);
+ return *this;
+ }
+
this_type& operator=(const base_type& x)
{
assign(x);
diff --git a/EASTL/include/EASTL/hash_map.h b/EASTL/include/EASTL/hash_map.h
index c363597..e7cad7b 100644
--- a/EASTL/include/EASTL/hash_map.h
+++ b/EASTL/include/EASTL/hash_map.h
@@ -5,9 +5,9 @@
///////////////////////////////////////////////////////////////////////////////
// This file is based on the TR1 (technical report 1) reference implementation
// of the unordered_set/unordered_map C++ classes as of about 4/2005. Most likely
-// many or all C++ library vendors' implementations of this classes will be
+// many or all C++ library vendors' implementations of this classes will be
// based off of the reference version and so will look pretty similar to this
-// file as well as other vendors' versions.
+// file as well as other vendors' versions.
///////////////////////////////////////////////////////////////////////////////
@@ -64,7 +64,7 @@ namespace eastl
/// hash_map
///
/// Implements a hash_map, which is a hashed associative container.
- /// Lookups are O(1) (that is, they are fast) but the container is
+ /// Lookups are O(1) (that is, they are fast) but the container is
/// not sorted. Note that lookups are only O(1) if the hash table
/// is well-distributed (non-colliding). The lookup approaches
/// O(n) behavior as the table becomes increasingly poorly distributed.
@@ -74,17 +74,17 @@ namespace eastl
/// call set_max_load_factor with a very high value such as 100000.f.
///
/// bCacheHashCode
- /// We provide the boolean bCacheHashCode template parameter in order
- /// to allow the storing of the hash code of the key within the map.
- /// When this option is disabled, the rehashing of the table will
- /// call the hash function on the key. Setting bCacheHashCode to true
+ /// We provide the boolean bCacheHashCode template parameter in order
+ /// to allow the storing of the hash code of the key within the map.
+ /// When this option is disabled, the rehashing of the table will
+ /// call the hash function on the key. Setting bCacheHashCode to true
/// is useful for cases whereby the calculation of the hash value for
/// a contained object is very expensive.
///
/// find_as
/// In order to support the ability to have a hashtable of strings but
- /// be able to do efficiently lookups via char pointers (i.e. so they
- /// aren't converted to string objects), we provide the find_as
+ /// be able to do efficiently lookups via char pointers (i.e. so they
+ /// aren't converted to string objects), we provide the find_as
/// function. This function allows you to do a find with a key of a
/// type other than the hashtable key type.
///
@@ -96,16 +96,16 @@ namespace eastl
/// hash_map<string, int> hashMap;
/// i = hashMap.find_as("hello", hash<char*>(), equal_to_2<string, char*>());
///
- template <typename Key, typename T, typename Hash = eastl::hash<Key>, typename Predicate = eastl::equal_to<Key>,
+ template <typename Key, typename T, typename Hash = eastl::hash<Key>, typename Predicate = eastl::equal_to<Key>,
typename Allocator = EASTLAllocatorType, bool bCacheHashCode = false>
class hash_map
: public hashtable<Key, eastl::pair<const Key, T>, Allocator, eastl::use_first<eastl::pair<const Key, T> >, Predicate,
Hash, mod_range_hashing, default_ranged_hash, prime_rehash_policy, bCacheHashCode, true, true>
{
public:
- typedef hashtable<Key, eastl::pair<const Key, T>, Allocator,
- eastl::use_first<eastl::pair<const Key, T> >,
- Predicate, Hash, mod_range_hashing, default_ranged_hash,
+ typedef hashtable<Key, eastl::pair<const Key, T>, Allocator,
+ eastl::use_first<eastl::pair<const Key, T> >,
+ Predicate, Hash, mod_range_hashing, default_ranged_hash,
prime_rehash_policy, bCacheHashCode, true, true> base_type;
typedef hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode> this_type;
typedef typename base_type::size_type size_type;
@@ -125,8 +125,19 @@ namespace eastl
///
/// Default constructor.
///
- explicit hash_map(const allocator_type& allocator = EASTL_HASH_MAP_DEFAULT_ALLOCATOR)
- : base_type(0, Hash(), mod_range_hashing(), default_ranged_hash(),
+ hash_map()
+ : this_type(EASTL_HASH_MAP_DEFAULT_ALLOCATOR)
+ {
+ // Empty
+ }
+
+
+ /// hash_map
+ ///
+ /// Constructor which creates an empty container with allocator.
+ ///
+ explicit hash_map(const allocator_type& allocator)
+ : base_type(0, Hash(), mod_range_hashing(), default_ranged_hash(),
Predicate(), eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
@@ -136,12 +147,12 @@ namespace eastl
/// hash_map
///
/// Constructor which creates an empty container, but start with nBucketCount buckets.
- /// We default to a small nBucketCount value, though the user really should manually
+ /// We default to a small nBucketCount value, though the user really should manually
/// specify an appropriate value in order to prevent memory from being reallocated.
///
- explicit hash_map(size_type nBucketCount, const Hash& hashFunction = Hash(),
+ explicit hash_map(size_type nBucketCount, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MAP_DEFAULT_ALLOCATOR)
- : base_type(nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
+ : base_type(nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
@@ -168,12 +179,12 @@ namespace eastl
/// hash_map
///
- /// initializer_list-based constructor.
+ /// initializer_list-based constructor.
/// Allows for initializing with brace values (e.g. hash_map<int, char*> hm = { {3,"c"}, {4,"d"}, {5,"e"} }; )
- ///
- hash_map(std::initializer_list<value_type> ilist, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
+ ///
+ hash_map(std::initializer_list<value_type> ilist, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MAP_DEFAULT_ALLOCATOR)
- : base_type(ilist.begin(), ilist.end(), nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
+ : base_type(ilist.begin(), ilist.end(), nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
@@ -182,13 +193,13 @@ namespace eastl
/// hash_map
///
- /// An input bucket count of <= 1 causes the bucket count to be equal to the number of
+ /// An input bucket count of <= 1 causes the bucket count to be equal to the number of
/// elements in the input range.
///
template <typename ForwardIterator>
- hash_map(ForwardIterator first, ForwardIterator last, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
+ hash_map(ForwardIterator first, ForwardIterator last, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MAP_DEFAULT_ALLOCATOR)
- : base_type(first, last, nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
+ : base_type(first, last, nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
@@ -215,8 +226,8 @@ namespace eastl
/// insert
///
- /// This is an extension to the C++ standard. We insert a default-constructed
- /// element with the given key. The reason for this is that we can avoid the
+ /// This is an extension to the C++ standard. We insert a default-constructed
+ /// element with the given key. The reason for this is that we can avoid the
/// potentially expensive operation of creating and/or copying a mapped_type
/// object on the stack.
insert_return_type insert(const key_type& key)
@@ -285,15 +296,61 @@ namespace eastl
return (*base_type::DoInsertKey(true_type(), eastl::move(key)).first).second;
}
+ // try_emplace API added in C++17
+ template <class... Args>
+ inline insert_return_type try_emplace(const key_type& k, Args&&... args)
+ {
+ return try_emplace_forwarding(k, eastl::forward<Args>(args)...);
+ }
+
+ template <class... Args>
+ inline insert_return_type try_emplace(key_type&& k, Args&&... args) {
+ return try_emplace_forwarding(eastl::move(k), eastl::forward<Args>(args)...);
+ }
+
+ template <class... Args>
+ inline iterator try_emplace(const_iterator, const key_type& k, Args&&... args) {
+ // Currently, the first parameter is ignored.
+ insert_return_type result = try_emplace(k, eastl::forward<Args>(args)...);
+ return base_type::DoGetResultIterator(true_type(), result);
+ }
+
+ template <class... Args>
+ inline iterator try_emplace(const_iterator, key_type&& k, Args&&... args) {
+ // Currently, the first parameter is ignored.
+ insert_return_type result = try_emplace(eastl::move(k), eastl::forward<Args>(args)...);
+ return base_type::DoGetResultIterator(true_type(), result);
+ }
+ private:
+ template <class K, class... Args>
+ insert_return_type try_emplace_forwarding(K&& k, Args&&... args)
+ {
+ const auto key_data = base_type::DoFindKeyData(k);
+ if (key_data.node)
+ { // Node exists, no insertion needed.
+ return eastl::pair<iterator, bool>(
+ iterator(key_data.node, base_type::mpBucketArray + key_data.bucket_index), false);
+ }
+ else
+ {
+ node_type* const pNodeNew =
+ base_type::DoAllocateNode(piecewise_construct, eastl::forward_as_tuple(eastl::forward<K>(k)),
+ forward_as_tuple(eastl::forward<Args>(args)...));
+ // the key might have been moved from above, so we can't use `k` anymore.
+ const auto& key = base_type::mExtractKey(pNodeNew->mValue);
+ return base_type::template DoInsertUniqueNode<true>(key, key_data.code, key_data.bucket_index, pNodeNew);
+ }
+ }
}; // hash_map
/// hash_map erase_if
///
/// https://en.cppreference.com/w/cpp/container/unordered_map/erase_if
template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode, typename UserPredicate>
- void erase_if(eastl::hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& c, UserPredicate predicate)
+ typename eastl::hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>::size_type erase_if(eastl::hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& c, UserPredicate predicate)
{
+ auto oldSize = c.size();
// Erases all elements that satisfy the predicate from the container.
for (auto i = c.begin(), last = c.end(); i != last;)
{
@@ -306,13 +363,14 @@ namespace eastl
++i;
}
}
+ return oldSize - c.size();
}
/// hash_multimap
///
- /// Implements a hash_multimap, which is the same thing as a hash_map
- /// except that contained elements need not be unique. See the
+ /// Implements a hash_multimap, which is the same thing as a hash_map
+ /// except that contained elements need not be unique. See the
/// documentation for hash_set for details.
///
template <typename Key, typename T, typename Hash = eastl::hash<Key>, typename Predicate = eastl::equal_to<Key>,
@@ -322,9 +380,9 @@ namespace eastl
Hash, mod_range_hashing, default_ranged_hash, prime_rehash_policy, bCacheHashCode, true, false>
{
public:
- typedef hashtable<Key, eastl::pair<const Key, T>, Allocator,
- eastl::use_first<eastl::pair<const Key, T> >,
- Predicate, Hash, mod_range_hashing, default_ranged_hash,
+ typedef hashtable<Key, eastl::pair<const Key, T>, Allocator,
+ eastl::use_first<eastl::pair<const Key, T> >,
+ Predicate, Hash, mod_range_hashing, default_ranged_hash,
prime_rehash_policy, bCacheHashCode, true, false> base_type;
typedef hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode> this_type;
typedef typename base_type::size_type size_type;
@@ -339,7 +397,6 @@ namespace eastl
using base_type::insert;
private:
- using base_type::try_emplace;
using base_type::insert_or_assign;
public:
@@ -348,7 +405,7 @@ namespace eastl
/// Default constructor.
///
explicit hash_multimap(const allocator_type& allocator = EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR)
- : base_type(0, Hash(), mod_range_hashing(), default_ranged_hash(),
+ : base_type(0, Hash(), mod_range_hashing(), default_ranged_hash(),
Predicate(), eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
@@ -358,12 +415,12 @@ namespace eastl
/// hash_multimap
///
/// Constructor which creates an empty container, but start with nBucketCount buckets.
- /// We default to a small nBucketCount value, though the user really should manually
+ /// We default to a small nBucketCount value, though the user really should manually
/// specify an appropriate value in order to prevent memory from being reallocated.
///
- explicit hash_multimap(size_type nBucketCount, const Hash& hashFunction = Hash(),
+ explicit hash_multimap(size_type nBucketCount, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR)
- : base_type(nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
+ : base_type(nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
@@ -390,12 +447,12 @@ namespace eastl
/// hash_multimap
///
- /// initializer_list-based constructor.
+ /// initializer_list-based constructor.
/// Allows for initializing with brace values (e.g. hash_multimap<int, char*> hm = { {3,"c"}, {3,"C"}, {4,"d"} }; )
- ///
- hash_multimap(std::initializer_list<value_type> ilist, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
+ ///
+ hash_multimap(std::initializer_list<value_type> ilist, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR)
- : base_type(ilist.begin(), ilist.end(), nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
+ : base_type(ilist.begin(), ilist.end(), nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
@@ -404,13 +461,13 @@ namespace eastl
/// hash_multimap
///
- /// An input bucket count of <= 1 causes the bucket count to be equal to the number of
+ /// An input bucket count of <= 1 causes the bucket count to be equal to the number of
/// elements in the input range.
///
template <typename ForwardIterator>
- hash_multimap(ForwardIterator first, ForwardIterator last, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
+ hash_multimap(ForwardIterator first, ForwardIterator last, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR)
- : base_type(first, last, nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
+ : base_type(first, last, nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
@@ -437,8 +494,8 @@ namespace eastl
/// insert
///
- /// This is an extension to the C++ standard. We insert a default-constructed
- /// element with the given key. The reason for this is that we can avoid the
+ /// This is an extension to the C++ standard. We insert a default-constructed
+ /// element with the given key. The reason for this is that we can avoid the
/// potentially expensive operation of creating and/or copying a mapped_type
/// object on the stack.
insert_return_type insert(const key_type& key)
@@ -458,8 +515,9 @@ namespace eastl
///
/// https://en.cppreference.com/w/cpp/container/unordered_multimap/erase_if
template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode, typename UserPredicate>
- void erase_if(eastl::hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& c, UserPredicate predicate)
+ typename eastl::hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>::size_type erase_if(eastl::hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& c, UserPredicate predicate)
{
+ auto oldSize = c.size();
// Erases all elements that satisfy the predicate from the container.
for (auto i = c.begin(), last = c.end(); i != last;)
{
@@ -472,6 +530,7 @@ namespace eastl
++i;
}
}
+ return oldSize - c.size();
}
@@ -481,7 +540,7 @@ namespace eastl
///////////////////////////////////////////////////////////////////////
template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
- inline bool operator==(const hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
+ inline bool operator==(const hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
const hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& b)
{
typedef typename hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>::const_iterator const_iterator;
@@ -496,23 +555,24 @@ namespace eastl
{
const_iterator bi = b.find(ai->first);
- if((bi == biEnd) || !(*ai == *bi)) // We have to compare the values, because lookups are done by keys alone but the full value_type of a map is a key/value pair.
+ if((bi == biEnd) || !(*ai == *bi)) // We have to compare the values, because lookups are done by keys alone but the full value_type of a map is a key/value pair.
return false; // It's possible that two elements in the two containers have identical keys but different values.
}
return true;
}
+#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
- inline bool operator!=(const hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
+ inline bool operator!=(const hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
const hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& b)
{
return !(a == b);
}
-
+#endif
template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
- inline bool operator==(const hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
+ inline bool operator==(const hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
const hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& b)
{
typedef typename hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>::const_iterator const_iterator;
@@ -522,9 +582,9 @@ namespace eastl
if(a.size() != b.size())
return false;
- // We can't simply search for each element of a in b, as it may be that the bucket for
- // two elements in a has those same two elements in b but in different order (which should
- // still result in equality). Also it's possible that one bucket in a has two elements which
+ // We can't simply search for each element of a in b, as it may be that the bucket for
+ // two elements in a has those same two elements in b but in different order (which should
+ // still result in equality). Also it's possible that one bucket in a has two elements which
// both match a solitary element in the equivalent bucket in b (which shouldn't result in equality).
eastl::pair<const_iterator, const_iterator> aRange;
eastl::pair<const_iterator, const_iterator> bRange;
@@ -545,12 +605,12 @@ namespace eastl
// Implement a fast pathway for the case that there's just a single element.
if(aDistance == 1)
{
- if(!(*aRange.first == *bRange.first)) // We have to compare the values, because lookups are done by keys alone but the full value_type of a map is a key/value pair.
+ if(!(*aRange.first == *bRange.first)) // We have to compare the values, because lookups are done by keys alone but the full value_type of a map is a key/value pair.
return false; // It's possible that two elements in the two containers have identical keys but different values. Ditto for the permutation case below.
}
else
{
- // Check to see if these aRange and bRange are any permutation of each other.
+ // Check to see if these aRange and bRange are any permutation of each other.
// This check gets slower as there are more elements in the range.
if(!eastl::is_permutation(aRange.first, aRange.second, bRange.first))
return false;
@@ -560,21 +620,17 @@ namespace eastl
return true;
}
+#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
- inline bool operator!=(const hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
+ inline bool operator!=(const hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
const hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& b)
{
return !(a == b);
}
+#endif
} // namespace eastl
#endif // Header include guard
-
-
-
-
-
-
diff --git a/EASTL/include/EASTL/hash_set.h b/EASTL/include/EASTL/hash_set.h
index c075975..3215d36 100644
--- a/EASTL/include/EASTL/hash_set.h
+++ b/EASTL/include/EASTL/hash_set.h
@@ -117,8 +117,19 @@ namespace eastl
/// hash_set
///
/// Default constructor.
- ///
- explicit hash_set(const allocator_type& allocator = EASTL_HASH_SET_DEFAULT_ALLOCATOR)
+ ///
+ hash_set()
+ : this_type(EASTL_HASH_SET_DEFAULT_ALLOCATOR)
+ {
+ // Empty
+ }
+
+
+ /// hash_set
+ ///
+ /// Constructor which creates an empty container with allocator.
+ ///
+ explicit hash_set(const allocator_type& allocator)
: base_type(0, Hash(), mod_range_hashing(), default_ranged_hash(), Predicate(), eastl::use_self<Value>(), allocator)
{
// Empty
@@ -207,8 +218,9 @@ namespace eastl
///
/// https://en.cppreference.com/w/cpp/container/unordered_set/erase_if
template <typename Value, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode, typename UserPredicate>
- void erase_if(eastl::hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode>& c, UserPredicate predicate)
+ typename eastl::hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode>::size_type erase_if(eastl::hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode>& c, UserPredicate predicate)
{
+ auto oldSize = c.size();
// Erases all elements that satisfy the predicate pred from the container.
for (auto i = c.begin(), last = c.end(); i != last;)
{
@@ -221,6 +233,7 @@ namespace eastl
++i;
}
}
+ return oldSize - c.size();
}
@@ -341,8 +354,9 @@ namespace eastl
///
/// https://en.cppreference.com/w/cpp/container/unordered_multiset/erase_if
template <typename Value, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode, typename UserPredicate>
- void erase_if(eastl::hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>& c, UserPredicate predicate)
+ typename eastl::hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>::size_type erase_if(eastl::hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>& c, UserPredicate predicate)
{
+ auto oldSize = c.size();
// Erases all elements that satisfy the predicate pred from the container.
for (auto i = c.begin(), last = c.end(); i != last;)
{
@@ -355,6 +369,7 @@ namespace eastl
++i;
}
}
+ return oldSize - c.size();
}
@@ -386,13 +401,14 @@ namespace eastl
return true;
}
+#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <typename Value, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
inline bool operator!=(const hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode>& a,
const hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode>& b)
{
return !(a == b);
}
-
+#endif
template <typename Value, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
inline bool operator==(const hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>& a,
@@ -443,12 +459,14 @@ namespace eastl
return true;
}
+#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <typename Value, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
inline bool operator!=(const hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>& a,
const hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>& b)
{
return !(a == b);
}
+#endif
} // namespace eastl
diff --git a/EASTL/include/EASTL/heap.h b/EASTL/include/EASTL/heap.h
index f0e770b..a8e4260 100644
--- a/EASTL/include/EASTL/heap.h
+++ b/EASTL/include/EASTL/heap.h
@@ -55,7 +55,7 @@ namespace eastl
inline void promote_heap_impl(RandomAccessIterator first, Distance topPosition, Distance position, T value)
{
for(Distance parentPosition = (position - 1) >> 1; // This formula assumes that (position > 0). // We use '>> 1' instead of '/ 2' because we have seen VC++ generate better code with >>.
- (position > topPosition) && (*(first + parentPosition) < value);
+ (position > topPosition) && eastl::less<ValueType>()(*(first + parentPosition), value);
parentPosition = (position - 1) >> 1)
{
*(first + position) = eastl::forward<ValueType>(*(first + parentPosition)); // Swap the node with its parent.
@@ -170,7 +170,7 @@ namespace eastl
for(; childPosition < heapSize; childPosition = (2 * childPosition) + 2)
{
- if(*(first + childPosition) < *(first + (childPosition - 1))) // Choose the larger of the two children.
+ if(eastl::less<ValueType>()(*(first + childPosition), *(first + (childPosition - 1)))) // Choose the larger of the two children.
--childPosition;
*(first + position) = eastl::forward<ValueType>(*(first + childPosition)); // Swap positions with this child.
position = childPosition;
diff --git a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86.h b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86.h
index 142a514..77c383a 100644
--- a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86.h
+++ b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86.h
@@ -68,7 +68,7 @@
#define EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, MemoryOrder, PRE_COMPUTE_DESIRED, POST_COMPUTE_RET) \
{ \
- bool cmpxchgRet; \
+ EASTL_ATOMIC_DEFAULT_INIT(bool, cmpxchgRet); \
EASTL_ATOMIC_LOAD_RELAXED_64(type, ret, ptr); \
do \
{ \
@@ -106,7 +106,7 @@
#define EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, MemoryOrder, PRE_COMPUTE_DESIRED, POST_COMPUTE_RET) \
{ \
- bool cmpxchgRet; \
+ EASTL_ATOMIC_DEFAULT_INIT(bool, cmpxchgRet); \
/* This is intentionally a non-atomic 128-bit load which may observe shearing. */ \
/* Either we do not observe *(ptr) but then the cmpxchg will fail and the observed */ \
/* atomic load will be returned. Or the non-atomic load got lucky and the cmpxchg succeeds */ \
diff --git a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_exchange.h b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_exchange.h
index 624d2f5..b1de7d8 100644
--- a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_exchange.h
+++ b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_exchange.h
@@ -56,7 +56,7 @@
#define EASTL_ARCH_ATOMIC_X86_EXCHANGE_128(type, ret, ptr, val, MemoryOrder) \
{ \
- bool cmpxchgRet; \
+ EASTL_ATOMIC_DEFAULT_INIT(bool, cmpxchgRet); \
/* This is intentionally a non-atomic 128-bit load which may observe shearing. */ \
/* Either we do not observe *(ptr) but then the cmpxchg will fail and the observed */ \
/* atomic load will be returned. Or the non-atomic load got lucky and the cmpxchg succeeds */ \
diff --git a/EASTL/include/EASTL/internal/atomic/atomic_base_width.h b/EASTL/include/EASTL/internal/atomic/atomic_base_width.h
index ca47618..ac76097 100644
--- a/EASTL/include/EASTL/internal/atomic/atomic_base_width.h
+++ b/EASTL/include/EASTL/internal/atomic/atomic_base_width.h
@@ -64,7 +64,7 @@ namespace internal
#define EASTL_ATOMIC_CMPXCHG_FUNC_IMPL(op, bits) \
- bool retVal; \
+ EASTL_ATOMIC_DEFAULT_INIT(bool, retVal); \
EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits) fixedWidthDesired = EASTL_ATOMIC_TYPE_PUN_CAST(EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits), desired); \
EA_PREPROCESSOR_JOIN(op, bits)(EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits), \
retVal, \
diff --git a/EASTL/include/EASTL/internal/atomic/atomic_integral.h b/EASTL/include/EASTL/internal/atomic/atomic_integral.h
index bcf7c17..a9c96c7 100644
--- a/EASTL/include/EASTL/internal/atomic/atomic_integral.h
+++ b/EASTL/include/EASTL/internal/atomic/atomic_integral.h
@@ -156,7 +156,7 @@ namespace internal
struct atomic_integral_width;
#define EASTL_ATOMIC_INTEGRAL_FUNC_IMPL(op, bits) \
- T retVal; \
+ EASTL_ATOMIC_DEFAULT_INIT(T, retVal); \
EA_PREPROCESSOR_JOIN(op, bits)(T, retVal, this->GetAtomicAddress(), arg); \
return retVal;
diff --git a/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros.h b/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros.h
index 941ac51..437b221 100644
--- a/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros.h
+++ b/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros.h
@@ -10,6 +10,7 @@
#pragma once
#endif
+#include <EABase/eabase.h>
#include "atomic_macros_base.h"
@@ -141,5 +142,15 @@
#endif
+// We write some of our variables in inline assembly, which MSAN
+// doesn't understand. This macro forces initialization of those
+// variables when MSAN is enabled and doesn't pay the initialization
+// cost when it's not enabled.
+#if EA_MSAN_ENABLED
+ #define EASTL_ATOMIC_DEFAULT_INIT(type, var) type var{}
+#else
+ #define EASTL_ATOMIC_DEFAULT_INIT(type, var) type var
+#endif // EA_MSAN_ENABLED
+
#endif /* EASTL_ATOMIC_INTERNAL_ATOMIC_MACROS_H */
diff --git a/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros_base.h b/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros_base.h
index f03720d..486e137 100644
--- a/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros_base.h
+++ b/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros_base.h
@@ -17,8 +17,13 @@
#define EASTL_ATOMIC_INTERNAL_ARCH_AVAILABLE(op) \
EA_PREPROCESSOR_JOIN(EA_PREPROCESSOR_JOIN(EASTL_ARCH_, op), _AVAILABLE)
+
+// We can't just use static_assert(false, ...) here, since on MSVC 17.10
+// the /Zc:static_assert flag makes non-dependent static_asserts in the body of a template
+// be evaluated at template-parse time, rather than at template instantion time.
+// So instead we just make the assert dependent on the type.
#define EASTL_ATOMIC_INTERNAL_NOT_IMPLEMENTED_ERROR(...) \
- static_assert(false, "eastl::atomic<T> atomic macro not implemented!")
+ static_assert(!eastl::is_same_v<T,T>, "eastl::atomic<T> atomic macro not implemented!")
/* Compiler && Arch Not Implemented */
diff --git a/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc.h b/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc.h
index 6df8c05..90901ee 100644
--- a/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc.h
+++ b/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc.h
@@ -12,7 +12,6 @@
EA_DISABLE_ALL_VC_WARNINGS();
-#include <Windows.h>
#include <intrin.h>
EA_RESTORE_ALL_VC_WARNINGS();
diff --git a/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cpu_pause.h b/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cpu_pause.h
index 720701a..5f436b8 100644
--- a/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cpu_pause.h
+++ b/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cpu_pause.h
@@ -10,18 +10,13 @@
#pragma once
#endif
-
-/////////////////////////////////////////////////////////////////////////////////
-//
-// void EASTL_COMPILER_ATOMIC_CPU_PAUSE()
-//
-// NOTE:
-// Rather obscure macro in Windows.h that expands to pause or rep; nop on
-// compatible x86 cpus or the arm yield on compatible arm processors.
-// This is nicer than switching on platform specific intrinsics.
-//
-#define EASTL_COMPILER_ATOMIC_CPU_PAUSE() \
- YieldProcessor()
+#if defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64)
+ #define EASTL_COMPILER_ATOMIC_CPU_PAUSE() _mm_pause()
+#elif defined(EA_PROCESSOR_ARM32) || defined(EA_PROCESSOR_ARM64)
+ #define EASTL_COMPILER_ATOMIC_CPU_PAUSE() __yield()
+#else
+ #error Unsupported CPU architecture for EASTL_COMPILER_ATOMIC_CPU_PAUSE
+#endif
#endif /* EASTL_ATOMIC_INTERNAL_COMPILER_MSVC_CPU_PAUSE_H */
diff --git a/EASTL/include/EASTL/internal/config.h b/EASTL/include/EASTL/internal/config.h
index 8dc1420..0564e18 100644
--- a/EASTL/include/EASTL/internal/config.h
+++ b/EASTL/include/EASTL/internal/config.h
@@ -89,8 +89,8 @@
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_VERSION
- #define EASTL_VERSION "3.18.00"
- #define EASTL_VERSION_N 31800
+ #define EASTL_VERSION "3.20.02"
+ #define EASTL_VERSION_N 32002
#endif
@@ -670,6 +670,17 @@ namespace eastl
///////////////////////////////////////////////////////////////////////////////
+// EASTL_CRASH
+//
+// Executes an invalid memory write, which should result in an exception
+// on most platforms.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#define EASTL_CRASH() *((volatile int*)0) = 0xDEADC0DE;
+
+
+///////////////////////////////////////////////////////////////////////////////
// EASTL_ALLOCATOR_COPY_ENABLED
//
// Defined as 0 or 1. Default is 0 (disabled) until some future date.
@@ -825,7 +836,7 @@ namespace eastl
// Defined as 0 or 1.
//
#ifndef EASTL_INT128_SUPPORTED
- #if defined(__SIZEOF_INT128__) || (defined(EA_COMPILER_INTMAX_SIZE) && (EA_COMPILER_INTMAX_SIZE >= 16))
+ #if defined(EA_COMPILER_INTMAX_SIZE) && (EA_COMPILER_INTMAX_SIZE >= 16)
#define EASTL_INT128_SUPPORTED 1
#else
#define EASTL_INT128_SUPPORTED 0
@@ -833,6 +844,21 @@ namespace eastl
#endif
+///////////////////////////////////////////////////////////////////////////////
+// EASTL_GCC_STYLE_INT128_SUPPORTED
+//
+// Defined as 0 or 1.
+// Specifies whether __int128_t/__uint128_t are defined.
+//
+#ifndef EASTL_GCC_STYLE_INT128_SUPPORTED
+#if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(__clang__))
+#define EASTL_GCC_STYLE_INT128_SUPPORTED 1
+#else
+#define EASTL_GCC_STYLE_INT128_SUPPORTED 0
+#endif
+#endif
+
+
///////////////////////////////////////////////////////////////////////////////
// EASTL_DEFAULT_ALLOCATOR_ALIGNED_ALLOCATIONS_SUPPORTED
@@ -859,12 +885,15 @@ namespace eastl
//
// Defined as 0 or 1.
// Specifies whether eastl_int128_t/eastl_uint128_t have been typedef'd yet.
+// NB: these types are not considered fundamental, arithmetic or integral when using the EAStdC implementation.
+// this changes the compiler type traits defined in type_traits.h.
+// eg. is_signed<eastl_int128_t>::value may be false, because it is not arithmetic.
//
#ifndef EASTL_INT128_DEFINED
#if EASTL_INT128_SUPPORTED
#define EASTL_INT128_DEFINED 1
- #if defined(__SIZEOF_INT128__) || defined(EA_COMPILER_GNUC) || defined(__clang__)
+ #if EASTL_GCC_STYLE_INT128_SUPPORTED
typedef __int128_t eastl_int128_t;
typedef __uint128_t eastl_uint128_t;
#else
@@ -875,7 +904,6 @@ namespace eastl
#endif
-
///////////////////////////////////////////////////////////////////////////////
// EASTL_BITSET_WORD_TYPE_DEFAULT / EASTL_BITSET_WORD_SIZE_DEFAULT
//
@@ -1779,16 +1807,6 @@ typedef EASTL_SSIZE_T eastl_ssize_t; // Signed version of eastl_size_t. Concept
#ifndef EASTL_USER_LITERALS_ENABLED
#if defined(EA_COMPILER_CPP14_ENABLED)
#define EASTL_USER_LITERALS_ENABLED 1
-
- // Disabling the Clang/GCC/MSVC warning about using user defined literals without a leading '_' as they are
- // reserved for standard libary usage.
- EA_DISABLE_CLANG_WARNING(-Wuser-defined-literals)
- EA_DISABLE_CLANG_WARNING(-Wreserved-user-defined-literal)
- EA_DISABLE_GCC_WARNING(-Wliteral-suffix)
- #ifdef _MSC_VER
- #pragma warning(disable: 4455) // disable warning C4455: literal suffix identifiers that do not start with an underscore are reserved
- #endif
-
#else
#define EASTL_USER_LITERALS_ENABLED 0
#endif
@@ -1837,17 +1855,48 @@ typedef EASTL_SSIZE_T eastl_ssize_t; // Signed version of eastl_size_t. Concept
/// EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE
#if defined(__clang__)
+ // NB: !__is_identifier() is correct: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66970#c11
#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+
+#elif defined(_MSC_VER) && (_MSC_VER >= 1913) // VS2017 15.6+
#define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 1
#else
#define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 0
#endif
+#if defined(__clang__)
+ // NB: !__is_identifier() is correct: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66970#c11
+ #if !__is_identifier(__is_final)
+ #define EASTL_IS_FINAL_AVAILABLE 1
+ #else
+ #define EASTL_IS_FINAL_AVAILABLE 0
+ #endif
+#elif defined(_MSC_VER) && (_MSC_VER >= 1914) // VS2017 15.7+
+ #define EASTL_IS_FINAL_AVAILABLE 1
+#elif defined(EA_COMPILER_GNUC)
+ #define EASTL_IS_FINAL_AVAILABLE 1
+#else
+ #define EASTL_IS_FINAL_AVAILABLE 0
+#endif
+
+#if defined(__clang__)
+ // NB: !__is_identifier() is correct: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66970#c11
+ #if !__is_identifier(__is_aggregate)
+ #define EASTL_IS_AGGREGATE_AVAILABLE 1
+ #else
+ #define EASTL_IS_AGGREGATE_AVAILABLE 0
+ #endif
+#elif defined(_MSC_VER) && (_MSC_VER >= 1915) // VS2017 15.8+
+ #define EASTL_IS_AGGREGATE_AVAILABLE 1
+#elif defined(EA_COMPILER_GNUC)
+ #define EASTL_IS_AGGREGATE_AVAILABLE 1
+#else
+ #define EASTL_IS_AGGREGATE_AVAILABLE 0
+#endif
+
/// EASTL_ENABLE_PAIR_FIRST_ELEMENT_CONSTRUCTOR
/// This feature define allows users to toggle the problematic eastl::pair implicit
diff --git a/EASTL/include/EASTL/internal/copy_help.h b/EASTL/include/EASTL/internal/copy_help.h
index 67b5d87..0b2c1b8 100644
--- a/EASTL/include/EASTL/internal/copy_help.h
+++ b/EASTL/include/EASTL/internal/copy_help.h
@@ -121,19 +121,40 @@ namespace eastl
};
+ namespace internal {
+ // This exists to handle the case when EASTL_ITC_NS is `std`
+ // and the C++ version is older than C++20, in this case
+ // std::contiguous_iterator_tag does not exist so we can't use
+ // is_same<> directly.
+ #if !EASTL_STD_ITERATOR_CATEGORY_ENABLED || defined(EA_COMPILER_CPP20_ENABLED)
+ template <typename IC>
+ using is_contiguous_iterator_helper = eastl::is_same<IC, EASTL_ITC_NS::contiguous_iterator_tag>;
+ #else
+ template <typename IC>
+ using is_contiguous_iterator_helper = eastl::false_type;
+ #endif
+
+ template <typename InputIterator, typename OutputIterator>
+ struct can_be_memmoved_helper {
+ using IIC = typename eastl::iterator_traits<InputIterator>::iterator_category;
+ using OIC = typename eastl::iterator_traits<OutputIterator>::iterator_category;
+ using value_type_input = typename eastl::iterator_traits<InputIterator>::value_type;
+ using value_type_output = typename eastl::iterator_traits<OutputIterator>::value_type;
+
+ static constexpr bool value = eastl::is_trivially_copyable<value_type_output>::value &&
+ eastl::is_same<value_type_input, value_type_output>::value &&
+ (eastl::is_pointer<InputIterator>::value || is_contiguous_iterator_helper<IIC>::value) &&
+ (eastl::is_pointer<OutputIterator>::value || is_contiguous_iterator_helper<OIC>::value);
+
+ };
+ }
template <bool isMove, typename InputIterator, typename OutputIterator>
inline OutputIterator move_and_copy_chooser(InputIterator first, InputIterator last, OutputIterator result)
{
typedef typename eastl::iterator_traits<InputIterator>::iterator_category IIC;
- typedef typename eastl::iterator_traits<OutputIterator>::iterator_category OIC;
- typedef typename eastl::iterator_traits<InputIterator>::value_type value_type_input;
- typedef typename eastl::iterator_traits<OutputIterator>::value_type value_type_output;
- const bool canBeMemmoved = eastl::is_trivially_copyable<value_type_output>::value &&
- eastl::is_same<value_type_input, value_type_output>::value &&
- (eastl::is_pointer<InputIterator>::value || eastl::is_same<IIC, eastl::contiguous_iterator_tag>::value) &&
- (eastl::is_pointer<OutputIterator>::value || eastl::is_same<OIC, eastl::contiguous_iterator_tag>::value);
+ const bool canBeMemmoved = internal::can_be_memmoved_helper<InputIterator, OutputIterator>::value;
return eastl::move_and_copy_helper<IIC, isMove, canBeMemmoved>::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.
}
@@ -143,7 +164,7 @@ namespace eastl
template <bool isMove, typename InputIterator, typename OutputIterator>
inline OutputIterator move_and_copy_unwrapper(InputIterator first, InputIterator last, OutputIterator result)
{
- return OutputIterator(eastl::move_and_copy_chooser<isMove>(eastl::unwrap_iterator(first), eastl::unwrap_iterator(last), eastl::unwrap_iterator(result))); // Have to convert to OutputIterator because result.base() could be a T*
+ return OutputIterator(eastl::move_and_copy_chooser<isMove>(eastl::unwrap_iterator(first), eastl::unwrap_iterator(last), eastl::unwrap_iterator(result))); // Have to convert to OutputIterator because unwrap_iterator(result) could be a T*
}
diff --git a/EASTL/include/EASTL/internal/fixed_pool.h b/EASTL/include/EASTL/internal/fixed_pool.h
index 4d71035..61c0557 100644
--- a/EASTL/include/EASTL/internal/fixed_pool.h
+++ b/EASTL/include/EASTL/internal/fixed_pool.h
@@ -1363,9 +1363,8 @@ namespace eastl
}
fixed_vector_allocator(const fixed_vector_allocator& x)
+ : mOverflowAllocator(x.mOverflowAllocator), mpPoolBegin(x.mpPoolBegin)
{
- mpPoolBegin = x.mpPoolBegin;
- mOverflowAllocator = x.mOverflowAllocator;
}
fixed_vector_allocator& operator=(const fixed_vector_allocator& x)
@@ -1480,12 +1479,14 @@ namespace eastl
void* allocate(size_t /*n*/, int /*flags*/ = 0)
{
EASTL_ASSERT(false); // A fixed_vector should not reallocate, else the user has exhausted its space.
+ EASTL_CRASH(); // We choose to crash here since the owning vector can't handle an allocator returning null. Better to crash earlier.
return NULL;
}
void* allocate(size_t /*n*/, size_t /*alignment*/, size_t /*offset*/, int /*flags*/ = 0)
{
- EASTL_ASSERT(false);
+ EASTL_ASSERT(false); // A fixed_vector should not reallocate, else the user has exhausted its space.
+ EASTL_CRASH(); // We choose to crash here since the owning vector can't handle an allocator returning null. Better to crash earlier.
return NULL;
}
diff --git a/EASTL/include/EASTL/internal/function.h b/EASTL/include/EASTL/internal/function.h
index 785969d..ace71d8 100644
--- a/EASTL/include/EASTL/internal/function.h
+++ b/EASTL/include/EASTL/internal/function.h
@@ -133,7 +133,7 @@ namespace eastl
{
return !f;
}
-
+#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <typename R, typename... Args>
bool operator==(std::nullptr_t, const function<R(Args...)>& f) EA_NOEXCEPT
{
@@ -151,7 +151,7 @@ namespace eastl
{
return !!f;
}
-
+#endif
template <typename R, typename... Args>
void swap(function<R(Args...)>& lhs, function<R(Args...)>& rhs)
{
diff --git a/EASTL/include/EASTL/internal/functional_base.h b/EASTL/include/EASTL/internal/functional_base.h
index ef27800..de446db 100644
--- a/EASTL/include/EASTL/internal/functional_base.h
+++ b/EASTL/include/EASTL/internal/functional_base.h
@@ -118,7 +118,8 @@ namespace eastl
template <typename R, typename F, typename... Args>
struct is_invocable_r_impl<R, F, void_t<typename invoke_result<F, Args...>::type>, Args...>
- : public is_convertible<typename invoke_result<F, Args...>::type, R> {};
+ : public disjunction<is_convertible<typename invoke_result<F, Args...>::type, R>,
+ is_same<typename remove_cv<R>::type, void>> {};
template <typename R, typename F, typename... Args>
struct is_invocable_r : public is_invocable_r_impl<R, F, void, Args...> {};
@@ -232,7 +233,7 @@ namespace eastl
T& get() const EA_NOEXCEPT;
template <typename... ArgTypes>
- typename eastl::result_of<T&(ArgTypes&&...)>::type operator() (ArgTypes&&...) const;
+ typename eastl::invoke_result<T&, ArgTypes...>::type operator() (ArgTypes&&...) const;
private:
T* val;
@@ -269,7 +270,7 @@ namespace eastl
template <typename T>
template <typename... ArgTypes>
- typename eastl::result_of<T&(ArgTypes&&...)>::type reference_wrapper<T>::operator() (ArgTypes&&... args) const
+ typename eastl::invoke_result<T&, ArgTypes...>::type reference_wrapper<T>::operator() (ArgTypes&&... args) const
{
return eastl::invoke(*val, eastl::forward<ArgTypes>(args)...);
}
diff --git a/EASTL/include/EASTL/internal/generic_iterator.h b/EASTL/include/EASTL/internal/generic_iterator.h
index b32998a..0f1e28b 100644
--- a/EASTL/include/EASTL/internal/generic_iterator.h
+++ b/EASTL/include/EASTL/internal/generic_iterator.h
@@ -56,7 +56,6 @@ namespace eastl
typedef typename eastl::iterator_traits<Iterator>::reference reference;
typedef typename eastl::iterator_traits<Iterator>::pointer pointer;
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.
typedef Container container_type;
typedef generic_iterator<Iterator, Container> this_type;
@@ -109,6 +108,15 @@ namespace eastl
const iterator_type& base() const
{ return mIterator; }
+ private:
+ // Unwrapping interface, not part of the public API.
+ const iterator_type& unwrap() const
+ { return mIterator; }
+
+ // The unwrapper helpers need access to unwrap().
+ friend is_iterator_wrapper_helper<this_type, true>;
+ friend is_iterator_wrapper<this_type>;
+
}; // class generic_iterator
@@ -187,7 +195,7 @@ namespace eastl
/// unwrap_generic_iterator
///
- /// Returns Iterator::get_base() if it's a generic_iterator, else returns Iterator as-is.
+ /// Returns `it.base()` if it's a generic_iterator, else returns `it` as-is.
///
/// Example usage:
/// vector<int> intVector;
@@ -196,7 +204,10 @@ namespace eastl
///
template <typename Iterator>
inline typename eastl::is_iterator_wrapper_helper<Iterator, eastl::is_generic_iterator<Iterator>::value>::iterator_type unwrap_generic_iterator(Iterator it)
- { return eastl::is_iterator_wrapper_helper<Iterator, eastl::is_generic_iterator<Iterator>::value>::get_base(it); }
+ {
+ // get_unwrapped(it) -> it.unwrap() which is equivalent to `it.base()` for generic_iterator and to `it` otherwise.
+ return eastl::is_iterator_wrapper_helper<Iterator, eastl::is_generic_iterator<Iterator>::value>::get_unwrapped(it);
+ }
} // namespace eastl
diff --git a/EASTL/include/EASTL/internal/hashtable.h b/EASTL/include/EASTL/internal/hashtable.h
index a9347b1..077f5b4 100644
--- a/EASTL/include/EASTL/internal/hashtable.h
+++ b/EASTL/include/EASTL/internal/hashtable.h
@@ -879,6 +879,12 @@ namespace eastl
RehashPolicy mRehashPolicy; // To do: Use base class optimization to make this go away.
allocator_type mAllocator; // To do: Use base class optimization to make this go away.
+ struct NodeFindKeyData {
+ node_type* node;
+ hash_code_t code;
+ size_type bucket_index;
+ };
+
public:
hashtable(size_type nBucketCount, const H1&, const H2&, const H&, const Equal&, const ExtractKey&,
const allocator_type& allocator = EASTL_HASHTABLE_DEFAULT_ALLOCATOR);
@@ -1003,11 +1009,6 @@ namespace eastl
template <class... Args>
iterator emplace_hint(const_iterator position, Args&&... args);
- template <class... Args> insert_return_type try_emplace(const key_type& k, Args&&... args);
- template <class... Args> insert_return_type try_emplace(key_type&& k, Args&&... args);
- template <class... Args> iterator try_emplace(const_iterator position, const key_type& k, Args&&... args);
- template <class... Args> iterator try_emplace(const_iterator position, key_type&& k, Args&&... args);
-
insert_return_type insert(const value_type& value);
insert_return_type insert(value_type&& otherValue);
iterator insert(const_iterator hint, const value_type& value);
@@ -1200,6 +1201,9 @@ namespace eastl
node_type** DoAllocateBuckets(size_type n);
void DoFreeBuckets(node_type** pBucketArray, size_type n);
+ template <bool bDeleteOnException, typename Enabled = bool_constant<bUniqueKeys>, ENABLE_IF_TRUETYPE(Enabled) = nullptr> // only enabled when keys are unique
+ eastl::pair<iterator, bool> DoInsertUniqueNode(const key_type& k, hash_code_t c, size_type n, node_type* pNodeNew);
+
template <typename BoolConstantT, class... Args, ENABLE_IF_TRUETYPE(BoolConstantT) = nullptr>
eastl::pair<iterator, bool> DoInsertValue(BoolConstantT, Args&&... args);
@@ -1278,6 +1282,7 @@ namespace eastl
void DoRehash(size_type nBucketCount);
node_type* DoFindNode(node_type* pNode, const key_type& k, hash_code_t c) const;
+ NodeFindKeyData DoFindKeyData(const key_type& k) const;
template <typename T>
ENABLE_IF_HAS_HASHCODE(T, node_type) DoFindNode(T* pNode, hash_code_t c) const
@@ -1293,6 +1298,14 @@ namespace eastl
template <typename U, typename BinaryPredicate>
node_type* DoFindNodeT(node_type* pNode, const U& u, BinaryPredicate predicate) const;
+ private:
+ template <typename V, typename Enabled = bool_constant<bUniqueKeys>, ENABLE_IF_TRUETYPE(Enabled) = nullptr>
+ eastl::pair<iterator, bool> DoInsertValueExtraForwarding(const key_type& k,
+ hash_code_t c,
+ node_type* pNodeNew,
+ V&& value);
+
+
}; // class hashtable
@@ -1953,6 +1966,16 @@ namespace eastl
}
+ template <typename K, typename V, typename A, typename EK, typename Eq,
+ typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
+ inline typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::NodeFindKeyData
+ hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoFindKeyData(const key_type& k) const {
+ NodeFindKeyData d;
+ d.code = get_hash_code(k);
+ d.bucket_index = (size_type)bucket_index(k, d.code, (uint32_t)mnBucketCount);
+ d.node = DoFindNode(mpBucketArray[d.bucket_index], k, d.code);
+ return d;
+ }
template <typename K, typename V, typename A, typename EK, typename Eq,
typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
@@ -1984,6 +2007,41 @@ namespace eastl
}
+ template <typename K, typename V, typename A, typename EK, typename Eq,
+ typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
+ template <bool bDeleteOnException, typename Enabled, ENABLE_IF_TRUETYPE(Enabled)> // only enabled when keys are unique
+ eastl::pair<typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::iterator, bool>
+ hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoInsertUniqueNode(const key_type& k, hash_code_t c, size_type n, node_type* pNodeNew)
+ {
+ const eastl::pair<bool, uint32_t> bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1);
+
+ set_code(pNodeNew, c); // This is a no-op for most hashtables.
+
+ #if EASTL_EXCEPTIONS_ENABLED
+ try
+ {
+ #endif
+ if(bRehash.first)
+ {
+ n = (size_type)bucket_index(k, c, (uint32_t)bRehash.second);
+ DoRehash(bRehash.second);
+ }
+
+ EASTL_ASSERT((uintptr_t)mpBucketArray != (uintptr_t)&gpEmptyBucketArray[0]);
+ pNodeNew->mpNext = mpBucketArray[n];
+ mpBucketArray[n] = pNodeNew;
+ ++mnElementCount;
+
+ return eastl::pair<iterator, bool>(iterator(pNodeNew, mpBucketArray + n), true);
+ #if EASTL_EXCEPTIONS_ENABLED
+ }
+ catch(...)
+ {
+ EA_CONSTEXPR_IF(bDeleteOnException) { DoFreeNode(pNodeNew); }
+ throw;
+ }
+ #endif
+ }
template <typename K, typename V, typename A, typename EK, typename Eq,
typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
@@ -2010,34 +2068,7 @@ namespace eastl
if(pNode == NULL) // If value is not present... add it.
{
- const eastl::pair<bool, uint32_t> bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1);
-
- set_code(pNodeNew, c); // This is a no-op for most hashtables.
-
- #if EASTL_EXCEPTIONS_ENABLED
- try
- {
- #endif
- if(bRehash.first)
- {
- n = (size_type)bucket_index(k, c, (uint32_t)bRehash.second);
- DoRehash(bRehash.second);
- }
-
- EASTL_ASSERT((uintptr_t)mpBucketArray != (uintptr_t)&gpEmptyBucketArray[0]);
- pNodeNew->mpNext = mpBucketArray[n];
- mpBucketArray[n] = pNodeNew;
- ++mnElementCount;
-
- return eastl::pair<iterator, bool>(iterator(pNodeNew, mpBucketArray + n), true);
- #if EASTL_EXCEPTIONS_ENABLED
- }
- catch(...)
- {
- DoFreeNode(pNodeNew);
- throw;
- }
- #endif
+ return DoInsertUniqueNode<true>(k, c, n, pNodeNew);
}
else
{
@@ -2133,14 +2164,33 @@ namespace eastl
// The reason is because the specializations below are slightly more efficient because they can delay
// the creation of a node until it's known that it will be needed.
////////////////////////////////////////////////////////////////////////////////////////////////////
-
template <typename K, typename V, typename A, typename EK, typename Eq,
typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
template <typename BoolConstantT>
- eastl::pair<typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::iterator, bool>
+ inline eastl::pair<typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::iterator, bool>
hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoInsertValueExtra(BoolConstantT, const key_type& k,
hash_code_t c, node_type* pNodeNew, value_type&& value, ENABLE_IF_TRUETYPE(BoolConstantT)) // true_type means bUniqueKeys is true.
{
+ return DoInsertValueExtraForwarding(k, c, pNodeNew, eastl::move(value));
+ }
+
+ template <typename K, typename V, typename A, typename EK, typename Eq,
+ typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
+ template <typename BoolConstantT>
+ inline eastl::pair<typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::iterator, bool>
+ hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoInsertValueExtra(BoolConstantT, const key_type& k,
+ hash_code_t c, node_type* pNodeNew, const value_type& value, ENABLE_IF_TRUETYPE(BoolConstantT)) // true_type means bUniqueKeys is true.
+ {
+ return DoInsertValueExtraForwarding(k, c, pNodeNew, value);
+ }
+
+ template <typename K, typename V, typename A, typename EK, typename Eq,
+ typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
+ template <typename VFwd, typename Enabled, ENABLE_IF_TRUETYPE(Enabled)> // true_type means bUniqueKeys is true.
+ eastl::pair<typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::iterator, bool>
+ hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoInsertValueExtraForwarding(const key_type& k,
+ hash_code_t c, node_type* pNodeNew, VFwd&& value)
+ {
// Adds the value to the hash table if not already present.
// If already present then the existing value is returned via an iterator/bool pair.
size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount);
@@ -2148,56 +2198,18 @@ namespace eastl
if(pNode == NULL) // If value is not present... add it.
{
- const eastl::pair<bool, uint32_t> bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1);
-
- // Allocate the new node before doing the rehash so that we don't
+ // Allocate the new node before doing the rehash so that we don't
// do a rehash if the allocation throws.
- #if EASTL_EXCEPTIONS_ENABLED
- bool nodeAllocated; // If exceptions are enabled then we we need to track if we allocated the node so we can free it in the catch block.
- #endif
-
if(pNodeNew)
{
- ::new(eastl::addressof(pNodeNew->mValue)) value_type(eastl::move(value)); // It's expected that pNodeNew was allocated with allocate_uninitialized_node.
- #if EASTL_EXCEPTIONS_ENABLED
- nodeAllocated = false;
- #endif
+ ::new(eastl::addressof(pNodeNew->mValue)) value_type(eastl::forward<VFwd>(value)); // It's expected that pNodeNew was allocated with allocate_uninitialized_node.
+ return DoInsertUniqueNode<false>(k, c, n, pNodeNew);
}
else
{
pNodeNew = DoAllocateNode(eastl::move(value));
- #if EASTL_EXCEPTIONS_ENABLED
- nodeAllocated = true;
- #endif
+ return DoInsertUniqueNode<true>(k, c, n, pNodeNew);
}
-
- set_code(pNodeNew, c); // This is a no-op for most hashtables.
-
- #if EASTL_EXCEPTIONS_ENABLED
- try
- {
- #endif
- if(bRehash.first)
- {
- n = (size_type)bucket_index(k, c, (uint32_t)bRehash.second);
- DoRehash(bRehash.second);
- }
-
- EASTL_ASSERT((uintptr_t)mpBucketArray != (uintptr_t)&gpEmptyBucketArray[0]);
- pNodeNew->mpNext = mpBucketArray[n];
- mpBucketArray[n] = pNodeNew;
- ++mnElementCount;
-
- return eastl::pair<iterator, bool>(iterator(pNodeNew, mpBucketArray + n), true);
- #if EASTL_EXCEPTIONS_ENABLED
- }
- catch(...)
- {
- if(nodeAllocated) // If we allocated the node within this function, free it. Else let the caller retain ownership of it.
- DoFreeNode(pNodeNew);
- throw;
- }
- #endif
}
// Else the value is already present, so don't add a new node. And don't free pNodeNew.
@@ -2303,78 +2315,6 @@ namespace eastl
#endif
}
-
- template <typename K, typename V, typename A, typename EK, typename Eq,
- typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
- template<typename BoolConstantT>
- eastl::pair<typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::iterator, bool>
- hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoInsertValueExtra(BoolConstantT, const key_type& k, hash_code_t c, node_type* pNodeNew, const value_type& value,
- ENABLE_IF_TRUETYPE(BoolConstantT)) // true_type means bUniqueKeys is true.
- {
- // Adds the value to the hash table if not already present.
- // If already present then the existing value is returned via an iterator/bool pair.
- size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount);
- node_type* const pNode = DoFindNode(mpBucketArray[n], k, c);
-
- if(pNode == NULL) // If value is not present... add it.
- {
- const eastl::pair<bool, uint32_t> bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1);
-
- // Allocate the new node before doing the rehash so that we don't
- // do a rehash if the allocation throws.
- #if EASTL_EXCEPTIONS_ENABLED
- bool nodeAllocated; // If exceptions are enabled then we we need to track if we allocated the node so we can free it in the catch block.
- #endif
-
- if(pNodeNew)
- {
- ::new(eastl::addressof(pNodeNew->mValue)) value_type(value); // It's expected that pNodeNew was allocated with allocate_uninitialized_node.
- #if EASTL_EXCEPTIONS_ENABLED
- nodeAllocated = false;
- #endif
- }
- else
- {
- pNodeNew = DoAllocateNode(value);
- #if EASTL_EXCEPTIONS_ENABLED
- nodeAllocated = true;
- #endif
- }
-
- set_code(pNodeNew, c); // This is a no-op for most hashtables.
-
- #if EASTL_EXCEPTIONS_ENABLED
- try
- {
- #endif
- if(bRehash.first)
- {
- n = (size_type)bucket_index(k, c, (uint32_t)bRehash.second);
- DoRehash(bRehash.second);
- }
-
- EASTL_ASSERT((uintptr_t)mpBucketArray != (uintptr_t)&gpEmptyBucketArray[0]);
- pNodeNew->mpNext = mpBucketArray[n];
- mpBucketArray[n] = pNodeNew;
- ++mnElementCount;
-
- return eastl::pair<iterator, bool>(iterator(pNodeNew, mpBucketArray + n), true);
- #if EASTL_EXCEPTIONS_ENABLED
- }
- catch(...)
- {
- if(nodeAllocated) // If we allocated the node within this function, free it. Else let the caller retain ownership of it.
- DoFreeNode(pNodeNew);
- throw;
- }
- #endif
- }
- // Else the value is already present, so don't add a new node. And don't free pNodeNew.
-
- return eastl::pair<iterator, bool>(iterator(pNode, mpBucketArray + n), false);
- }
-
-
template <typename K, typename V, typename A, typename EK, typename Eq,
typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
template<typename BoolConstantT>
@@ -2695,54 +2635,6 @@ namespace eastl
}
template <typename K, typename V, typename A, typename EK, typename Eq,
- typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
- template <class... Args>
- // inline eastl::pair<typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::iterator, bool>
- inline typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::insert_return_type
- hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::try_emplace(const key_type& key, Args&&... args)
- {
- return DoInsertValue(has_unique_keys_type(), piecewise_construct, eastl::forward_as_tuple(key),
- eastl::forward_as_tuple(eastl::forward<Args>(args)...));
- }
-
- template <typename K, typename V, typename A, typename EK, typename Eq,
- typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
- template <class... Args>
- // inline eastl::pair<typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::iterator, bool>
- inline typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::insert_return_type
- hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::try_emplace(key_type&& key, Args&&... args)
- {
- return DoInsertValue(has_unique_keys_type(), piecewise_construct, eastl::forward_as_tuple(eastl::move(key)),
- eastl::forward_as_tuple(eastl::forward<Args>(args)...));
- }
-
- template <typename K, typename V, typename A, typename EK, typename Eq,
- typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
- template <class... Args>
- inline typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::iterator
- hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::try_emplace(const_iterator, const key_type& key, Args&&... args)
- {
- insert_return_type result = DoInsertValue(
- has_unique_keys_type(),
- value_type(piecewise_construct, eastl::forward_as_tuple(key), eastl::forward_as_tuple(eastl::forward<Args>(args)...)));
-
- return DoGetResultIterator(has_unique_keys_type(), result);
- }
-
- template <typename K, typename V, typename A, typename EK, typename Eq,
- typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
- template <class... Args>
- inline typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::iterator
- hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::try_emplace(const_iterator, key_type&& key, Args&&... args)
- {
- insert_return_type result =
- DoInsertValue(has_unique_keys_type(), value_type(piecewise_construct, eastl::forward_as_tuple(eastl::move(key)),
- eastl::forward_as_tuple(eastl::forward<Args>(args)...)));
-
- return DoGetResultIterator(has_unique_keys_type(), result);
- }
-
- template <typename K, typename V, typename A, typename EK, typename Eq,
typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::insert_return_type
hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::insert(value_type&& otherValue)
@@ -2962,14 +2854,25 @@ namespace eastl
while(*pBucketArray && !compare(k, c, *pBucketArray))
pBucketArray = &(*pBucketArray)->mpNext;
+ node_type* pDeleteList = nullptr;
while(*pBucketArray && compare(k, c, *pBucketArray))
{
node_type* const pNode = *pBucketArray;
*pBucketArray = pNode->mpNext;
- DoFreeNode(pNode);
+ // Don't free the node here, k might be a reference to the key inside this node,
+ // and we're re-using it when we compare to the following nodes.
+ // Instead, add it to the list of things to be deleted.
+ pNode->mpNext = pDeleteList;
+ pDeleteList = pNode;
--mnElementCount;
}
+ while (pDeleteList) {
+ node_type* const pToDelete = pDeleteList;
+ pDeleteList = pDeleteList->mpNext;
+ DoFreeNode(pToDelete);
+ }
+
return nElementCountSaved - mnElementCount;
}
diff --git a/EASTL/include/EASTL/internal/integer_sequence.h b/EASTL/include/EASTL/internal/integer_sequence.h
index 2a5539d..ba5dd4e 100644
--- a/EASTL/include/EASTL/internal/integer_sequence.h
+++ b/EASTL/include/EASTL/internal/integer_sequence.h
@@ -24,6 +24,21 @@ public:
static EA_CONSTEXPR size_t size() EA_NOEXCEPT { return sizeof...(Ints); }
};
+template <size_t... Is>
+using index_sequence = integer_sequence<size_t, Is...>;
+
+#if (defined(EA_COMPILER_GNUC) && EA_COMPILER_VERSION >= 8001)
+
+template <typename T, T N>
+using make_integer_sequence = integer_sequence<T, __integer_pack(N)...>;
+
+#elif (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_BUILTIN(__make_integer_seq)) || (defined(EA_COMPILER_MSVC) && (EA_COMPILER_VERSION >= 1910))
+
+template <class T, T N>
+using make_integer_sequence = __make_integer_seq<integer_sequence, T, N>;
+
+#else
+
template <size_t N, typename IndexSeq>
struct make_index_sequence_impl;
@@ -39,12 +54,6 @@ struct make_index_sequence_impl<0, integer_sequence<size_t, Is...>>
typedef integer_sequence<size_t, Is...> type;
};
-template <size_t... Is>
-using index_sequence = integer_sequence<size_t, Is...>;
-
-template <size_t N>
-using make_index_sequence = typename make_index_sequence_impl<N, integer_sequence<size_t>>::type;
-
template <typename Target, typename Seq>
struct integer_sequence_convert_impl;
@@ -54,15 +63,20 @@ struct integer_sequence_convert_impl<Target, integer_sequence<size_t, Is...>>
typedef integer_sequence<Target, Is...> type;
};
-template <typename T, size_t N>
+template <typename T, T N>
struct make_integer_sequence_impl
{
- typedef typename integer_sequence_convert_impl<T, make_index_sequence<N>>::type type;
+ typedef typename integer_sequence_convert_impl<T, typename make_index_sequence_impl<N, integer_sequence<size_t>>::type>::type type;
};
-template <typename T, size_t N>
+template <typename T, T N>
using make_integer_sequence = typename make_integer_sequence_impl<T, N>::type;
+#endif
+
+template <size_t N>
+using make_index_sequence = make_integer_sequence<size_t, N>;
+
// Helper alias template that converts any type parameter pack into an index sequence of the same length
template<typename... T>
using index_sequence_for = make_index_sequence<sizeof...(T)>;
diff --git a/EASTL/include/EASTL/internal/red_black_tree.h b/EASTL/include/EASTL/internal/red_black_tree.h
index 111fbb4..5b29b7c 100644
--- a/EASTL/include/EASTL/internal/red_black_tree.h
+++ b/EASTL/include/EASTL/internal/red_black_tree.h
@@ -478,11 +478,6 @@ namespace eastl
template <class... Args>
iterator emplace_hint(const_iterator position, Args&&... args);
- template <class... Args> eastl::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
- template <class... Args> eastl::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);
- template <class... Args> iterator try_emplace(const_iterator position, const key_type& k, Args&&... args);
- template <class... Args> iterator try_emplace(const_iterator position, key_type&& k, Args&&... args);
-
// Standard conversion overload to avoid the overhead of mismatched 'pair<const Key, Value>' types.
template <class P, class = typename eastl::enable_if<eastl::is_constructible<value_type, P&&>::value>::type>
insert_return_type insert(P&& otherValue);
@@ -1109,43 +1104,6 @@ namespace eastl
}
template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <class... Args>
- inline eastl::pair<typename rbtree<K, V, C, A, E, bM, bU>::iterator, bool>
- rbtree<K, V, C, A, E, bM, bU>::try_emplace(const key_type& key, Args&&... args)
- {
- return DoInsertValue(has_unique_keys_type(), piecewise_construct, eastl::forward_as_tuple(key), eastl::forward_as_tuple(eastl::forward<Args>(args)...));
- }
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <class... Args>
- inline eastl::pair<typename rbtree<K, V, C, A, E, bM, bU>::iterator, bool>
- rbtree<K, V, C, A, E, bM, bU>::try_emplace(key_type&& key, Args&&... args)
- {
- return DoInsertValue(has_unique_keys_type(), piecewise_construct, eastl::forward_as_tuple(eastl::move(key)), eastl::forward_as_tuple(eastl::forward<Args>(args)...));
- }
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <class... Args>
- inline typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::try_emplace(const_iterator position, const key_type& key, Args&&... args)
- {
- return DoInsertValueHint(
- has_unique_keys_type(), position,
- piecewise_construct, eastl::forward_as_tuple(key), eastl::forward_as_tuple(eastl::forward<Args>(args)...));
- }
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <class... Args>
- inline typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::try_emplace(const_iterator position, key_type&& key, Args&&... args)
- {
- return DoInsertValueHint(
- has_unique_keys_type(), position,
- piecewise_construct, eastl::forward_as_tuple(eastl::move(key)), eastl::forward_as_tuple(eastl::forward<Args>(args)...));
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
template <class P, class>
inline typename rbtree<K, V, C, A, E, bM, bU>::insert_return_type // map/set::insert return a pair, multimap/multiset::iterator return an iterator.
rbtree<K, V, C, A, E, bM, bU>::insert(P&& otherValue)
diff --git a/EASTL/include/EASTL/internal/thread_support.h b/EASTL/include/EASTL/internal/thread_support.h
index 60272a9..49856c0 100644
--- a/EASTL/include/EASTL/internal/thread_support.h
+++ b/EASTL/include/EASTL/internal/thread_support.h
@@ -93,92 +93,6 @@ namespace eastl
{
namespace Internal
{
- /// atomic_increment
- /// Returns the new value.
- inline int32_t atomic_increment(int32_t* p32) EA_NOEXCEPT
- {
- #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");
- return _InterlockedIncrement((volatile long*)p32);
- #elif defined(EA_COMPILER_GNUC)
- int32_t result;
- __asm__ __volatile__ ("lock; xaddl %0, %1"
- : "=r" (result), "=m" (*p32)
- : "0" (1), "m" (*p32)
- : "memory"
- );
- return result + 1;
- #else
- EASTL_FAIL_MSG("EASTL thread safety is not implemented yet. See EAThread for how to do this for the given platform.");
- return ++*p32;
- #endif
- }
-
- /// atomic_decrement
- /// Returns the new value.
- inline int32_t atomic_decrement(int32_t* p32) EA_NOEXCEPT
- {
- #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.
- #elif defined(EA_COMPILER_GNUC)
- int32_t result;
- __asm__ __volatile__ ("lock; xaddl %0, %1"
- : "=r" (result), "=m" (*p32)
- : "0" (-1), "m" (*p32)
- : "memory"
- );
- return result - 1;
- #else
- EASTL_FAIL_MSG("EASTL thread safety is not implemented yet. See EAThread for how to do this for the given platform.");
- return --*p32;
- #endif
- }
-
-
- /// atomic_compare_and_swap
- /// Safely sets the value to a new value if the original value is equal to
- /// a condition value. Returns true if the condition was met and the
- /// assignment occurred. The comparison and value setting are done as
- /// an atomic operation and thus another thread cannot intervene between
- /// 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(__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);
- #elif defined(EA_COMPILER_GNUC)
- // GCC Inline ASM Constraints
- // r <--> Any general purpose register
- // a <--> The a register.
- // 1 <--> The constraint '1' for operand 2 says that it must occupy the same location as operand 1.
- // =a <--> output registers
- // =r <--> output registers
-
- int32_t result;
- __asm__ __volatile__(
- "lock; cmpxchgl %3, (%1) \n" // Test *p32 against EAX, if same, then *p32 = newValue
- : "=a" (result), "=r" (p32) // outputs
- : "a" (condition), "r" (newValue), "1" (p32) // inputs
- : "memory" // clobbered
- );
- return result == condition;
- #else
- EASTL_FAIL_MSG("EASTL thread safety is not implemented yet. See EAThread for how to do this for the given platform.");
- if(*p32 == condition)
- {
- *p32 = newValue;
- return true;
- }
- return false;
- #endif
- }
-
-
// mutex
#if EASTL_CPP11_MUTEX_ENABLED
using std::mutex;
diff --git a/EASTL/include/EASTL/internal/type_compound.h b/EASTL/include/EASTL/internal/type_compound.h
index 1f85250..339dc8e 100644
--- a/EASTL/include/EASTL/internal/type_compound.h
+++ b/EASTL/include/EASTL/internal/type_compound.h
@@ -128,58 +128,18 @@ namespace eastl
#define EASTL_TYPE_TRAIT_is_member_function_pointer_CONFORMANCE 1 // is_member_function_pointer is conforming; doesn't make mistakes.
- // To do: Revise this to support C++11 variadic templates when possible.
- // To do: We can probably also use remove_cv to simply the multitude of types below.
-
- template <typename T> struct is_mem_fun_pointer_value : public false_type{};
-
- template <typename R, typename T> struct is_mem_fun_pointer_value<R (T::*)()> : public true_type{};
- template <typename R, typename T> struct is_mem_fun_pointer_value<R (T::*)() const> : public true_type{};
- template <typename R, typename T> struct is_mem_fun_pointer_value<R (T::*)() volatile> : public true_type{};
- template <typename R, typename T> struct is_mem_fun_pointer_value<R (T::*)() const volatile> : public true_type{};
-
- template <typename R, typename T, typename Arg0> struct is_mem_fun_pointer_value<R (T::*)(Arg0)> : public true_type{};
- template <typename R, typename T, typename Arg0> struct is_mem_fun_pointer_value<R (T::*)(Arg0) const> : public true_type{};
- template <typename R, typename T, typename Arg0> struct is_mem_fun_pointer_value<R (T::*)(Arg0) volatile> : public true_type{};
- template <typename R, typename T, typename Arg0> struct is_mem_fun_pointer_value<R (T::*)(Arg0) const volatile> : public true_type{};
-
- template <typename R, typename T, typename Arg0, typename Arg1> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1)> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1) const> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1) volatile> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1) const volatile> : public true_type{};
-
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2)> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2) const> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2) volatile> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2) const volatile> : public true_type{};
-
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3)> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3) const> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3) volatile> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3) const volatile> : public true_type{};
-
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4)> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4) const> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4) volatile> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4) const volatile> : public true_type{};
-
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5)> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5) const> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5) volatile> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5) const volatile> : public true_type{};
-
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6)> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) const> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) volatile> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) const volatile> : public true_type{};
-
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6, typename Arg7> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7)> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6, typename Arg7> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7) const> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6, typename Arg7> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7) volatile> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6, typename Arg7> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7) const volatile> : public true_type{};
+ namespace internal
+ {
+ template<typename T>
+ struct is_member_function_pointer_helper : false_type {};
- template <typename T>
- struct is_member_function_pointer : public integral_constant<bool, is_mem_fun_pointer_value<T>::value>{};
+ template<typename T, typename U>
+ struct is_member_function_pointer_helper<T U::*> : is_function<T> {};
+ }
+
+ template<typename T>
+ struct is_member_function_pointer
+ : internal::is_member_function_pointer_helper<typename remove_cv<T>::type> {};
#if EASTL_VARIABLE_TEMPLATES_ENABLED
template<typename T>
@@ -198,13 +158,19 @@ namespace eastl
#define EASTL_TYPE_TRAIT_is_member_pointer_CONFORMANCE 1 // is_member_pointer is conforming; doesn't make mistakes.
- template <typename T>
- struct is_member_pointer
- : public eastl::integral_constant<bool, eastl::is_member_function_pointer<T>::value>{};
+ namespace internal {
+ template <typename T>
+ struct is_member_pointer_helper
+ : public eastl::false_type {};
- template <typename T, typename U>
- struct is_member_pointer<U T::*>
- : public eastl::true_type{};
+ template <typename T, typename U>
+ struct is_member_pointer_helper<U T::*>
+ : public eastl::true_type {};
+ }
+
+ template<typename T>
+ struct is_member_pointer
+ : public internal::is_member_pointer_helper<typename remove_cv<T>::type>::type {};
#if EASTL_VARIABLE_TEMPLATES_ENABLED
template<typename T>
@@ -690,7 +656,7 @@ namespace eastl
///////////////////////////////////////////////////////////////////////
// is_final
///////////////////////////////////////////////////////////////////////
- #if EA_COMPILER_HAS_FEATURE(is_final)
+ #if EASTL_IS_FINAL_AVAILABLE == 1
template <typename T>
struct is_final : public integral_constant<bool, __is_final(T)> {};
#else
@@ -722,7 +688,7 @@ namespace eastl
// * no default member initializers
//
///////////////////////////////////////////////////////////////////////
- #if EA_COMPILER_HAS_FEATURE(is_aggregate) || defined(_MSC_VER) && (_MSC_VER >= 1916) // VS2017 15.9+
+ #if EASTL_IS_AGGREGATE_AVAILABLE == 1
#define EASTL_TYPE_TRAIT_is_aggregate_CONFORMANCE 1
template <typename T>
diff --git a/EASTL/include/EASTL/internal/type_detected.h b/EASTL/include/EASTL/internal/type_detected.h
new file mode 100644
index 0000000..e368a6f
--- /dev/null
+++ b/EASTL/include/EASTL/internal/type_detected.h
@@ -0,0 +1,180 @@
+/////////////////////////////////////////////////////////////////////////////
+// Copyright (c) Electronic Arts Inc. All rights reserved.
+/////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef EASTL_INTERNAL_TYPE_DETECTED_H
+#define EASTL_INTERNAL_TYPE_DETECTED_H
+
+
+#include <EABase/eabase.h>
+#if defined(EA_PRAGMA_ONCE_SUPPORTED)
+#pragma once
+#endif
+
+#include <EASTL/type_traits.h>
+
+namespace eastl
+{
+ ///////////////////////////////////////////////////////////////////////
+ // nonesuch
+ //
+ // Type given as a result from detected_t if the supplied arguments does not respect the constraint.
+ //
+ // https://en.cppreference.com/w/cpp/experimental/nonesuch
+ //
+ ///////////////////////////////////////////////////////////////////////
+ struct nonesuch
+ {
+ ~nonesuch() = delete;
+ nonesuch(nonesuch const&) = delete;
+ void operator=(nonesuch const&) = delete;
+ };
+
+ namespace internal
+ {
+ template <class Default, class AlwaysVoid, template <class...> class Op, class... Args>
+ struct detector
+ {
+ using type = Default;
+ using value_t = false_type;
+ };
+
+ template <class Default, template <class...> class Op, class... Args>
+ struct detector<Default, void_t<Op<Args...>>, Op, Args...>
+ {
+ using type = Op<Args...>;
+ using value_t = true_type;
+ };
+ } // namespace internal
+
+ ///////////////////////////////////////////////////////////////////////
+ // is_detected
+ //
+ // Checks if some supplied arguments (Args) respect a constraint (Op).
+ // is_detected expands to true_type if the arguments respect the constraint, false_type otherwise.
+ // This helper is convenient to use for compile time introspection.
+ //
+ // https://en.cppreference.com/w/cpp/experimental/is_detected
+ //
+ // Example:
+ // template <class T, class U>
+ // using detect_can_use_addition_operator = decltype(declval<T>() + declval<U>());
+ //
+ // template <class T, class U>
+ // void sum(const T& t, const U& u)
+ // {
+ // static_assert(is_detected<detect_can_use_addition_operator, T, U>::value, "Supplied types cannot be summedtogether.");
+ // // or...
+ // static_assert(is_detected_v<detect_can_use_addition_operator, T, U>, "Supplied types cannot be summedtogether.");
+ // return t + u;
+ // }
+ //
+ ///////////////////////////////////////////////////////////////////////
+ template <template <class...> class Op, class... Args>
+ using is_detected = typename internal::detector<nonesuch, void, Op, Args...>::value_t;
+
+#if EASTL_VARIABLE_TEMPLATES_ENABLED
+ template <template <class...> class Op, class... Args>
+ EA_CONSTEXPR bool is_detected_v = is_detected<Op, Args...>::value;
+#endif
+
+ ///////////////////////////////////////////////////////////////////////
+ // detected_t
+ //
+ // Check which type we obtain after expanding some arguments (Args) over a constraint (Op).
+ // If the constraint cannot be applied, the result type will be nonesuch.
+ //
+ // https://en.cppreference.com/w/cpp/experimental/is_detected
+ //
+ // Example:
+ // template <class T, class U>
+ // using detect_can_use_addition_operator = decltype(declval<T>() + declval<U>());
+ //
+ // using result_type = detected_t<detect_can_use_addition_operator, int, int>;
+ // // result_type == int
+ // using failed_result_type = detected_t<detect_can_use_addition_operator, int, string>;
+ // // failed_result_type == nonesuch
+ //
+ ///////////////////////////////////////////////////////////////////////
+ template <template <class...> class Op, class... Args>
+ using detected_t = typename internal::detector<nonesuch, void, Op, Args...>::type;
+
+ ///////////////////////////////////////////////////////////////////////
+ // detected_or
+ //
+ // Checks if some supplied arguments (Args) respect a constraint (Op).
+ // Expand to a struct that contains two type aliases:
+ // - type: the type we obtain after expanding some arguments (Args) over a constraint (Op).
+ // If the constraint cannot be applied, the result type will be the suplied Default type.
+ // - value_t: true_type if the arguments respect the constraint, false_type otherwise.
+ //
+ // https://en.cppreference.com/w/cpp/experimental/is_detected
+ //
+ // Example:
+ // template <class T, class U>
+ // using detected_calling_foo = decltype(declval<T>().foo());
+ //
+ // using result = detected_or<bool, detected_calling_foo, std::string>; // std::string doesn't have foo member.
+ // function.
+ // // result::type == bool
+ // // result::value_t == false_type
+ //
+ ///////////////////////////////////////////////////////////////////////
+ template <class Default, template <class...> class Op, class... Args>
+ using detected_or = internal::detector<Default, void, Op, Args...>;
+
+ ///////////////////////////////////////////////////////////////////////
+ // detected_or_t
+ //
+ // Equivalent to detected_or<Default, Op, Args...>::type.
+ //
+ ///////////////////////////////////////////////////////////////////////
+ template <class Default, template <class...> class Op, class... Args>
+ using detected_or_t = typename detected_or<Default, Op, Args...>::type;
+
+ ///////////////////////////////////////////////////////////////////////
+ // is_detected_exact
+ //
+ // Check that the type we obtain after expanding some arguments (Args) over a constraint (Op) is equivalent to
+ // Expected.
+ //
+ // template <class T, class U>
+ // using detected_calling_size = decltype(declval<T>().size());
+ //
+ // using result = is_detected_exact<int, detected_calling_size, std::string>;
+ // result == false_type // std::string::size returns eastl_size_t which is not the same as int.
+ //
+ ///////////////////////////////////////////////////////////////////////
+ template <class Expected, template <class...> class Op, class... Args>
+ using is_detected_exact = is_same<Expected, detected_t<Op, Args...>>;
+
+#if EASTL_VARIABLE_TEMPLATES_ENABLED
+ template <class Expected, template <class...> class Op, class... Args>
+ EA_CONSTEXPR bool is_detected_exact_v = is_detected_exact<Expected, Op, Args...>::value;
+#endif
+
+ ///////////////////////////////////////////////////////////////////////
+ // is_detected_convertible
+ //
+ // Check that the type we obtain after expanding some arguments (Args) over a constraint (Op) is convertible to
+ // Expected.
+ //
+ // template <class T, class U>
+ // using detected_calling_size = decltype(declval<T>().size());
+ //
+ // using result = is_detected_convertible<int, detected_calling_size, std::string>;
+ // result == true_type // std::string::size returns eastl_size_t which is convertible to int.
+ //
+ ///////////////////////////////////////////////////////////////////////
+ template <class To, template <class...> class Op, class... Args>
+ using is_detected_convertible = is_convertible<detected_t<Op, Args...>, To>;
+
+#if EASTL_VARIABLE_TEMPLATES_ENABLED
+ template <class To, template <class...> class Op, class... Args>
+ EA_CONSTEXPR bool is_detected_convertible_v = is_detected_convertible<To, Op, Args...>::value;
+#endif
+
+} // namespace eastl
+
+#endif // EASTL_INTERNAL_TYPE_DETECTED_H \ No newline at end of file
diff --git a/EASTL/include/EASTL/internal/type_fundamental.h b/EASTL/include/EASTL/internal/type_fundamental.h
index 5ff9259..c99b70c 100644
--- a/EASTL/include/EASTL/internal/type_fundamental.h
+++ b/EASTL/include/EASTL/internal/type_fundamental.h
@@ -130,6 +130,10 @@ namespace eastl
template <> struct is_integral_helper<bool> : public true_type{};
template <> struct is_integral_helper<char> : public true_type{};
+
+ #if defined(EA_CHAR8_UNIQUE) && EA_CHAR8_UNIQUE
+ template <> struct is_integral_helper<char8_t> : public true_type{};
+ #endif
#if defined(EA_CHAR16_NATIVE) && EA_CHAR16_NATIVE
template <> struct is_integral_helper<char16_t> : public true_type{};
#endif
@@ -139,7 +143,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<wchar_t> : public true_type{};
#endif
- #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(__clang__))
+ #if EASTL_GCC_STYLE_INT128_SUPPORTED
template <> struct is_integral_helper<__int128_t> : public true_type{};
template <> struct is_integral_helper<__uint128_t> : public true_type{};
#endif
diff --git a/EASTL/include/EASTL/internal/type_pod.h b/EASTL/include/EASTL/internal/type_pod.h
index 998e957..fef5511 100644
--- a/EASTL/include/EASTL/internal/type_pod.h
+++ b/EASTL/include/EASTL/internal/type_pod.h
@@ -693,7 +693,7 @@ namespace eastl
//
template <typename T>
- struct is_trivially_copyable { static const bool value = __is_trivially_copyable(T); };
+ struct is_trivially_copyable : public bool_constant<__is_trivially_copyable(T)> {};
#elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_MSVC) || defined(EA_COMPILER_GNUC))
#define EASTL_TYPE_TRAIT_is_trivially_copyable_CONFORMANCE 1
@@ -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(__clang__) && EA_COMPILER_HAS_FEATURE(is_trivially_constructible))
+ #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_trivially_constructible)) || defined(EA_COMPILER_MSVC))
template <typename T, typename Arg0 = eastl::unused>
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(__clang__) && EA_COMPILER_HAS_FEATURE(is_trivially_constructible))
+ #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_trivially_constructible)) || defined(EA_COMPILER_MSVC))
#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.
@@ -1691,7 +1691,7 @@ namespace eastl
//
///////////////////////////////////////////////////////////////////////
- #if 0 // defined(_MSC_VER) && (_MSC_VER >= 1800) // VS2013+ -- Disabled due to __is_destructible being broken in VC++ versions up to at least VS2013. A ticket will be submitted for this
+ #if defined(_MSC_VER) && (_MSC_VER >= 1920)
#define EASTL_TYPE_TRAIT_is_destructible_CONFORMANCE 1
template <typename T>
@@ -1710,24 +1710,19 @@ namespace eastl
struct is_destructible
: public eastl::integral_constant<bool, !eastl::is_array_of_unknown_bounds<T>::value &&
!eastl::is_void<T>::value &&
- !eastl::is_function<T>::value &&
- !eastl::is_abstract<T>::value> {};
+ !eastl::is_function<T>::value> {};
#else
#define EASTL_TYPE_TRAIT_is_destructible_CONFORMANCE 1
- template <typename U>
- struct destructible_test_helper{ U u; };
-
template <typename>
eastl::false_type destructible_test_function(...);
- template <typename T, typename U = decltype(eastl::declval<eastl::destructible_test_helper<T> >().~destructible_test_helper<T>())>
+ template <typename T, typename U = typename eastl::remove_all_extents<T>::type, typename V = decltype(eastl::declval<U&>().~U())>
eastl::true_type destructible_test_function(int);
template <typename T, bool = eastl::is_array_of_unknown_bounds<T>::value || // Exclude these types from being considered destructible.
eastl::is_void<T>::value ||
- eastl::is_function<T>::value ||
- eastl::is_abstract<T>::value>
+ eastl::is_function<T>::value>
struct is_destructible_helper
: public eastl::identity<decltype(eastl::destructible_test_function<T>(0))>::type {}; // Need to wrap decltype with identity because some compilers otherwise don't like the bare decltype usage.
@@ -1735,6 +1730,14 @@ namespace eastl
struct is_destructible_helper<T, true>
: public eastl::false_type {};
+ template <typename T, bool Whatever>
+ struct is_destructible_helper<T&, Whatever> // Reference are trivially destructible.
+ : public eastl::true_type {};
+
+ template <typename T, bool Whatever>
+ struct is_destructible_helper<T&&, Whatever> // Reference are trivially destructible.
+ : public eastl::true_type {};
+
template <typename T>
struct is_destructible
: public is_destructible_helper<T> {};
@@ -1771,7 +1774,7 @@ namespace eastl
//
///////////////////////////////////////////////////////////////////////
- #if 0 // defined(_MSC_VER) && (_MSC_VER >= 1800) // VS2013+ -- Disabled due to __is_trivially_destructible being broken in VC++ versions up to at least VS2013. A ticket will be submitted for this
+ #if defined(_MSC_VER) && (_MSC_VER >= 1920)
#define EASTL_TYPE_TRAIT_is_trivially_destructible_CONFORMANCE 1
template <typename T>
@@ -1822,7 +1825,7 @@ namespace eastl
//
///////////////////////////////////////////////////////////////////////
- #if 0 // defined(_MSC_VER) && (_MSC_VER >= 1800) // VS2013+ -- Disabled due to __is_nothrow_destructible being broken in VC++ versions up to at least VS2013. A ticket will be submitted for this
+ #if defined(_MSC_VER) && (_MSC_VER >= 1920)
#define EASTL_TYPE_TRAIT_is_nothrow_destructible_CONFORMANCE ((_MSC_VER >= 1900) ? 1 : 0) // VS2013 (1800) doesn't support noexcept and so can't support all usage of this properly (in particular default exception specifications defined in [C++11 Standard, 15.4 paragraph 14].
template <typename T>
diff --git a/EASTL/include/EASTL/internal/type_properties.h b/EASTL/include/EASTL/internal/type_properties.h
index df90fcb..78bdfca 100644
--- a/EASTL/include/EASTL/internal/type_properties.h
+++ b/EASTL/include/EASTL/internal/type_properties.h
@@ -104,47 +104,31 @@ namespace eastl
///////////////////////////////////////////////////////////////////////
// is_signed
//
- // is_signed<T>::value == true if and only if T is one of the following types:
- // [const] [volatile] char (maybe)
- // [const] [volatile] signed char
- // [const] [volatile] short
- // [const] [volatile] int
- // [const] [volatile] long
- // [const] [volatile] long long
- // [const] [volatile] float
- // [const] [volatile] double
- // [const] [volatile] long double
+ // is_signed<T>::value == true if T is a (possibly cv-qualified) floating-point or signed integer type.
//
- // Used to determine if a integral type is signed or unsigned.
+ // Used to determine if a type is signed.
// Given that there are some user-made classes which emulate integral
// types, we provide the EASTL_DECLARE_SIGNED macro to allow you to
// set a given class to be identified as a signed type.
///////////////////////////////////////////////////////////////////////
#define EASTL_TYPE_TRAIT_is_signed_CONFORMANCE 1 // is_signed is conforming.
+
+#ifdef _MSC_VER
+ #pragma warning(push)
+ #pragma warning(disable: 4296) // '<': expression is always false
+#endif
+ template<typename T, bool = is_arithmetic<T>::value>
+ struct is_signed_helper : bool_constant<T(-1) < T(0)> {};
+#ifdef _MSC_VER
+ #pragma warning(pop)
+#endif
- template <typename T> struct is_signed_helper : public false_type{};
-
- template <> struct is_signed_helper<signed char> : public true_type{};
- template <> struct is_signed_helper<signed short> : public true_type{};
- template <> struct is_signed_helper<signed int> : public true_type{};
- template <> struct is_signed_helper<signed long> : public true_type{};
- template <> struct is_signed_helper<signed long long> : public true_type{};
- template <> struct is_signed_helper<float> : public true_type{};
- template <> struct is_signed_helper<double> : public true_type{};
- template <> struct is_signed_helper<long double> : public true_type{};
-
- #if (CHAR_MAX == SCHAR_MAX)
- template <> struct is_signed_helper<char> : public true_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__ == 2147483647) || (__WCHAR_MAX__ == 32767)) // GCC defines __WCHAR_MAX__ for most platforms.
- template <> struct is_signed_helper<wchar_t> : public true_type{};
- #endif
- #endif
+ template<typename T>
+ struct is_signed_helper<T, false> : false_type {};
template <typename T>
- struct is_signed : public eastl::is_signed_helper<typename eastl::remove_cv<T>::type>{};
+ struct is_signed : public eastl::is_signed_helper<T>::type {};
#if EASTL_VARIABLE_TEMPLATES_ENABLED
template <class T>
@@ -164,41 +148,31 @@ namespace eastl
///////////////////////////////////////////////////////////////////////
// is_unsigned
//
- // is_unsigned<T>::value == true if and only if T is one of the following types:
- // [const] [volatile] char (maybe)
- // [const] [volatile] unsigned char
- // [const] [volatile] unsigned short
- // [const] [volatile] unsigned int
- // [const] [volatile] unsigned long
- // [const] [volatile] unsigned long long
+ // is_unsigned<T>::value == true if T is a (possibly cv-qualified) bool or unsigned integer type.
//
- // Used to determine if a integral type is signed or unsigned.
+ // Used to determine if a type is unsigned.
// Given that there are some user-made classes which emulate integral
// types, we provide the EASTL_DECLARE_UNSIGNED macro to allow you to
// set a given class to be identified as an unsigned type.
///////////////////////////////////////////////////////////////////////
#define EASTL_TYPE_TRAIT_is_unsigned_CONFORMANCE 1 // is_unsigned is conforming.
+
+#ifdef _MSC_VER
+ #pragma warning(push)
+ #pragma warning(disable: 4296) // '<': expression is always false
+#endif
+ template<typename T, bool = is_arithmetic<T>::value>
+ struct is_unsigned_helper : integral_constant<bool, T(0) < T(-1)> {};
+#ifdef _MSC_VER
+ #pragma warning(pop)
+#endif
- template <typename T> struct is_unsigned_helper : public false_type{};
-
- template <> struct is_unsigned_helper<unsigned char> : public true_type{};
- template <> struct is_unsigned_helper<unsigned short> : public true_type{};
- template <> struct is_unsigned_helper<unsigned int> : public true_type{};
- template <> struct is_unsigned_helper<unsigned long> : public true_type{};
- template <> struct is_unsigned_helper<unsigned long long> : public true_type{};
-
- #if (CHAR_MAX == UCHAR_MAX)
- template <> struct is_unsigned_helper<char> : public true_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(_MSC_VER) || (defined(__WCHAR_MAX__) && ((__WCHAR_MAX__ == 4294967295U) || (__WCHAR_MAX__ == 65535))) // GCC defines __WCHAR_MAX__ for most platforms.
- template <> struct is_unsigned_helper<wchar_t> : public true_type{};
- #endif
- #endif
+ template<typename T>
+ struct is_unsigned_helper<T, false> : false_type {};
template <typename T>
- struct is_unsigned : public eastl::is_unsigned_helper<typename eastl::remove_cv<T>::type>{};
+ struct is_unsigned : public eastl::is_unsigned_helper<T>::type {};
#if EASTL_VARIABLE_TEMPLATES_ENABLED
template <class T>
@@ -213,7 +187,53 @@ namespace eastl
template <> struct is_unsigned<const volatile T> : public true_type{}; \
}
+ ///////////////////////////////////////////////////////////////////////
+ // is_bounded_array
+ //
+ // is_bounded_array<T>::value == true if T is an array type of known bound.
+ //
+ // is_bounded_array<int>::value is false.
+ // is_bounded_array<int[5]>::value is true.
+ // is_bounded_array<int[]>::value is false.
+ //
+ ///////////////////////////////////////////////////////////////////////
+
+ #define EASTL_TYPE_TRAIT_is_bounded_array_CONFORMANCE 1 // is_bounded_array is conforming.
+
+ template<class T>
+ struct is_bounded_array: eastl::false_type {};
+
+ template<class T, size_t N>
+ struct is_bounded_array<T[N]> : eastl::true_type {};
+ #if EASTL_VARIABLE_TEMPLATES_ENABLED
+ template <class T>
+ EA_CONSTEXPR bool is_bounded_array_v = is_bounded_array<T>::value;
+ #endif
+
+ ///////////////////////////////////////////////////////////////////////
+ // is_unbounded_array
+ //
+ // is_unbounded_array<T>::value == true if T is an array type of known bound.
+ //
+ // is_unbounded_array<int>::value is false.
+ // is_unbounded_array<int[5]>::value is false.
+ // is_unbounded_array<int[]>::value is true.
+ //
+ ///////////////////////////////////////////////////////////////////////
+
+ #define EASTL_TYPE_TRAIT_is_unbounded_array_CONFORMANCE 1 // is_unbounded_array is conforming.
+
+ template<class T>
+ struct is_unbounded_array: eastl::false_type {};
+
+ template<class T>
+ struct is_unbounded_array<T[]> : eastl::true_type {};
+
+ #if EASTL_VARIABLE_TEMPLATES_ENABLED
+ template <class T>
+ EA_CONSTEXPR bool is_unbounded_array_v = is_unbounded_array<T>::value;
+ #endif
///////////////////////////////////////////////////////////////////////
// alignment_of
@@ -241,7 +261,7 @@ namespace eastl
///////////////////////////////////////////////////////////////////////
// is_aligned
- //
+ //
// Defined as true if the type has alignment requirements greater
// than default alignment, which is taken to be 8. This allows for
// doing specialized object allocation and placement for such types.
diff --git a/EASTL/include/EASTL/internal/type_transformations.h b/EASTL/include/EASTL/internal/type_transformations.h
index 2d77a55..5454cfa 100644
--- a/EASTL/include/EASTL/internal/type_transformations.h
+++ b/EASTL/include/EASTL/internal/type_transformations.h
@@ -153,7 +153,7 @@ namespace eastl
struct int128_helper
{
- #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(__clang__))
+ #if EASTL_GCC_STYLE_INT128_SUPPORTED
typedef __int128_t type;
#endif
};
@@ -168,7 +168,7 @@ namespace eastl
eastl::conditional_t<sizeof(T) <= sizeof(signed int), int_helper,
eastl::conditional_t<sizeof(T) <= sizeof(signed long), long_helper,
eastl::conditional_t<sizeof(T) <= sizeof(signed long long), longlong_helper,
- #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) && defined(__clang__))
+ #if EASTL_GCC_STYLE_INT128_SUPPORTED
eastl::conditional_t<sizeof(T) <= sizeof(__int128_t), int128_helper,
no_type_helper
>
@@ -223,7 +223,7 @@ namespace eastl
template <> struct make_signed<unsigned long> { typedef signed long type; };
template <> struct make_signed<signed long long> { typedef signed long long type; };
template <> struct make_signed<unsigned long long> { typedef signed long long type; };
- #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(__clang__))
+ #if EASTL_GCC_STYLE_INT128_SUPPORTED
template <> struct make_signed<__int128_t> { typedef __int128_t type; };
template <> struct make_signed<__uint128_t> { typedef __int128_t type; };
#endif
@@ -318,7 +318,7 @@ namespace eastl
struct int128_helper
{
- #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(__clang__))
+ #if EASTL_GCC_STYLE_INT128_SUPPORTED
typedef __uint128_t type;
#endif
};
@@ -334,7 +334,7 @@ namespace eastl
eastl::conditional_t<sizeof(T) <= sizeof(unsigned int), int_helper,
eastl::conditional_t<sizeof(T) <= sizeof(unsigned long), long_helper,
eastl::conditional_t<sizeof(T) <= sizeof(unsigned long long), longlong_helper,
- #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) && defined(__clang__))
+ #if EASTL_GCC_STYLE_INT128_SUPPORTED
eastl::conditional_t<sizeof(T) <= sizeof(__uint128_t), int128_helper,
no_type_helper
>
@@ -390,7 +390,7 @@ namespace eastl
template <> struct make_unsigned<unsigned long> { typedef unsigned long type; };
template <> struct make_unsigned<signed long long> { typedef unsigned long long type; };
template <> struct make_unsigned<unsigned long long> { typedef unsigned long long type; };
- #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(__clang__))
+ #if EASTL_GCC_STYLE_INT128_SUPPORTED
template <> struct make_unsigned<__int128_t> { typedef __uint128_t type; };
template <> struct make_unsigned<__uint128_t> { typedef __uint128_t type; };
#endif
@@ -477,15 +477,33 @@ namespace eastl
// add_pointer
//
// Add pointer to a type.
- // Provides the member typedef type which is the type T*. If T is a
- // reference type, then type is a pointer to the referred type.
- //
+ // Provides the member typedef type which is the type T*.
+ //
+ // If T is a reference type,
+ // type member is a pointer to the referred type.
+ // If T is an object type, a function type that is not cv- or ref-qualified,
+ // or a (possibly cv-qualified) void type,
+ // type member is T*.
+ // Otherwise (T is a cv- or ref-qualified function type),
+ // type member is T (ie. not a pointer).
+ //
+ // cv- and ref-qualified function types are invalid, which is why there is a specific clause for it.
+ // See https://cplusplus.github.io/LWG/issue2101 for more.
+ //
///////////////////////////////////////////////////////////////////////
#define EASTL_TYPE_TRAIT_add_pointer_CONFORMANCE 1
- template<class T>
- struct add_pointer { typedef typename eastl::remove_reference<T>::type* type; };
+ namespace internal
+ {
+ template <typename T>
+ auto try_add_pointer(int) -> type_identity<typename std::remove_reference<T>::type*>;
+ template <typename T>
+ auto try_add_pointer(...) -> type_identity<T>;
+ }
+
+ template <typename T>
+ struct add_pointer : decltype(internal::try_add_pointer<T>(0)) {};
#if EASTL_VARIABLE_TEMPLATES_ENABLED
template <class T>
@@ -747,32 +765,6 @@ namespace eastl
return u.destValue;
}
-
-
- ///////////////////////////////////////////////////////////////////////
- // void_t
- //
- // Maps a sequence of any types to void. This utility class is used in
- // template meta programming to simplify compile time reflection mechanisms
- // required by the standard library.
- //
- // http://en.cppreference.com/w/cpp/types/void_t
- //
- // Example:
- // template <typename T, typename = void>
- // struct is_iterable : false_type {};
- //
- // template <typename T>
- // struct is_iterable<T, void_t<decltype(declval<T>().begin()),
- // decltype(declval<T>().end())>> : true_type {};
- //
- ///////////////////////////////////////////////////////////////////////
- #if EASTL_VARIABLE_TEMPLATES_ENABLED
- template <class...>
- using void_t = void;
- #endif
-
-
} // namespace eastl
diff --git a/EASTL/include/EASTL/internal/type_void_t.h b/EASTL/include/EASTL/internal/type_void_t.h
new file mode 100644
index 0000000..40c6818
--- /dev/null
+++ b/EASTL/include/EASTL/internal/type_void_t.h
@@ -0,0 +1,43 @@
+/////////////////////////////////////////////////////////////////////////////
+// Copyright (c) Electronic Arts Inc. All rights reserved.
+/////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef EASTL_INTERNAL_TYPE_VOID_T_H
+#define EASTL_INTERNAL_TYPE_VOID_T_H
+
+
+#include <EABase/eabase.h>
+#if defined(EA_PRAGMA_ONCE_SUPPORTED)
+ #pragma once
+#endif
+
+namespace eastl
+{
+
+ ///////////////////////////////////////////////////////////////////////
+ // void_t
+ //
+ // Maps a sequence of any types to void. This utility class is used in
+ // template meta programming to simplify compile time reflection mechanisms
+ // required by the standard library.
+ //
+ // http://en.cppreference.com/w/cpp/types/void_t
+ //
+ // Example:
+ // template <typename T, typename = void>
+ // struct is_iterable : false_type {};
+ //
+ // template <typename T>
+ // struct is_iterable<T, void_t<decltype(declval<T>().begin()),
+ // decltype(declval<T>().end())>> : true_type {};
+ //
+ ///////////////////////////////////////////////////////////////////////
+ template <class...>
+ using void_t = void;
+
+
+} // namespace eastl
+
+
+#endif // Header include guard
diff --git a/EASTL/include/EASTL/iterator.h b/EASTL/include/EASTL/iterator.h
index 6760348..6c268aa 100644
--- a/EASTL/include/EASTL/iterator.h
+++ b/EASTL/include/EASTL/iterator.h
@@ -9,6 +9,8 @@
#include <EASTL/internal/config.h>
#include <EASTL/internal/move_help.h>
+#include <EASTL/internal/type_detected.h>
+#include <EASTL/internal/type_void_t.h>
#include <EASTL/initializer_list.h>
EA_DISABLE_ALL_VC_WARNINGS();
@@ -93,16 +95,35 @@ namespace eastl
// struct iterator_traits
- template <typename Iterator>
- struct iterator_traits
+ namespace internal
{
- typedef typename Iterator::iterator_category iterator_category;
- typedef typename Iterator::value_type value_type;
- typedef typename Iterator::difference_type difference_type;
- typedef typename Iterator::pointer pointer;
- typedef typename Iterator::reference reference;
- };
+ // Helper to make iterator_traits SFINAE friendly as N3844 requires.
+ template <typename Iterator, class = void>
+ struct default_iterator_traits {};
+ template <typename Iterator>
+ struct default_iterator_traits<
+ Iterator,
+ void_t<
+ typename Iterator::iterator_category,
+ typename Iterator::value_type,
+ typename Iterator::difference_type,
+ typename Iterator::pointer,
+ typename Iterator::reference
+ >
+ >
+ {
+ typedef typename Iterator::iterator_category iterator_category;
+ typedef typename Iterator::value_type value_type;
+ typedef typename Iterator::difference_type difference_type;
+ typedef typename Iterator::pointer pointer;
+ typedef typename Iterator::reference reference;
+ };
+ }
+
+ template <typename Iterator>
+ struct iterator_traits : internal::default_iterator_traits<Iterator> {};
+
template <typename T>
struct iterator_traits<T*>
{
@@ -129,37 +150,46 @@ namespace eastl
/// is_iterator_wrapper
///
/// Tells if an Iterator type is a wrapper type as opposed to a regular type.
- /// Relies on the class declaring a typedef called wrapped_iterator_type.
+ /// Relies on the class declaring a member function called unwrap.
///
/// Examples of wrapping iterators:
- /// reverse_iterator
/// generic_iterator
/// move_iterator
+ /// reverse_iterator<T> (if T is a wrapped iterator)
/// Examples of non-wrapping iterators:
/// iterator
/// list::iterator
/// char*
///
/// Example behavior:
- /// is_iterator_wrapper(int*)::value => false
- /// is_iterator_wrapper(eastl::array<char>*)::value => false
- /// is_iterator_wrapper(eastl::vector<int>::iterator)::value => false
- /// is_iterator_wrapper(eastl::generic_iterator<int*>)::value => true
- /// is_iterator_wrapper(eastl::move_iterator<eastl::array<int>::iterator>)::value => true
+ /// is_iterator_wrapper(int*)::value => false
+ /// is_iterator_wrapper(eastl::array<char>*)::value => false
+ /// is_iterator_wrapper(eastl::vector<int>::iterator)::value => false
+ /// is_iterator_wrapper(eastl::generic_iterator<int*>)::value => true
+ /// is_iterator_wrapper(eastl::move_iterator<eastl::array<int>::iterator>)::value => true
+ /// is_iterator_wrapper(eastl::reverse_iterator<int*>)::value => false
+ /// is_iterator_wrapper(eastl::reverse_iterator<eastl::move_iterator<int*>>)::value => true
///
template<typename Iterator>
class is_iterator_wrapper
{
- template<typename>
- static eastl::no_type test(...);
-
- template<typename U>
- static eastl::yes_type test(typename U::wrapped_iterator_type*, typename eastl::enable_if<eastl::is_class<U>::value>::type* = 0);
-
+#if defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_CLANG_CL)
+ // Using a default template type parameter trick here because
+ // of a bug in clang that makes the other implementation not
+ // work when unwrap() is private and this is class is a
+ // friend.
+ // See: https://bugs.llvm.org/show_bug.cgi?id=25334
+ template<typename T, typename U = decltype(eastl::declval<T>().unwrap())>
+ using detect_has_unwrap = U;
+#else
+ // Note: the above implementation does not work on GCC when
+ // unwrap() is private and this class is a friend. So we're
+ // forced to diverge here to support both GCC and clang.
+ template<typename T>
+ using detect_has_unwrap = decltype(eastl::declval<T>().unwrap());
+#endif
public:
- EA_DISABLE_VC_WARNING(6334)
- static const bool value = (sizeof(test<Iterator>(NULL)) == sizeof(eastl::yes_type));
- EA_RESTORE_VC_WARNING()
+ static const bool value = eastl::is_detected<detect_has_unwrap, Iterator>::value;
};
@@ -180,25 +210,28 @@ namespace eastl
template <typename Iterator, bool isWrapper>
struct is_iterator_wrapper_helper
{
- typedef Iterator iterator_type;
+ using iterator_type = Iterator;
- static iterator_type get_base(Iterator it)
- { return it; }
+ static iterator_type get_unwrapped(Iterator it) { return it; }
};
template <typename Iterator>
struct is_iterator_wrapper_helper<Iterator, true>
{
- typedef typename Iterator::iterator_type iterator_type;
+ // get_unwrapped must return by value since we're returning
+ // it.unwrap(), and `it` will be out of scope as soon as
+ // get_unwrapped returns.
+ using iterator_type =
+ typename eastl::remove_cvref<decltype(eastl::declval<Iterator>().unwrap())>::type;
- static iterator_type get_base(Iterator it)
- { return it.base(); }
+ static iterator_type get_unwrapped(Iterator it) { return it.unwrap(); }
};
+
template <typename Iterator>
inline typename is_iterator_wrapper_helper<Iterator, eastl::is_iterator_wrapper<Iterator>::value>::iterator_type unwrap_iterator(Iterator it)
- { return eastl::is_iterator_wrapper_helper<Iterator, eastl::is_iterator_wrapper<Iterator>::value>::get_base(it); }
+ { return eastl::is_iterator_wrapper_helper<Iterator, eastl::is_iterator_wrapper<Iterator>::value>::get_unwrapped(it); }
@@ -222,9 +255,13 @@ namespace eastl
typename eastl::iterator_traits<Iterator>::pointer,
typename eastl::iterator_traits<Iterator>::reference>
{
+ private:
+ using base_wrapped_iterator_type =
+ typename eastl::is_iterator_wrapper_helper<Iterator,
+ eastl::is_iterator_wrapper<Iterator>::value>::iterator_type;
+
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.
typedef typename eastl::iterator_traits<Iterator>::pointer pointer;
typedef typename eastl::iterator_traits<Iterator>::reference reference;
typedef typename eastl::iterator_traits<Iterator>::difference_type difference_type;
@@ -304,6 +341,18 @@ namespace eastl
// operator[] may return something other than reference.
EA_CPP14_CONSTEXPR reference operator[](difference_type n) const
{ return mIterator[-n - 1]; }
+
+
+ private:
+ // Unwrapping interface, not part of the public API.
+ template <typename U = iterator_type>
+ EA_CPP14_CONSTEXPR typename eastl::enable_if<eastl::is_iterator_wrapper<U>::value, reverse_iterator<base_wrapped_iterator_type>>::type unwrap() const
+ { return reverse_iterator<base_wrapped_iterator_type>(unwrap_iterator(mIterator)); }
+
+ // The unwrapper helpers need access to unwrap() (when it exists).
+ using this_type = reverse_iterator<Iterator>;
+ friend is_iterator_wrapper_helper<this_type, is_iterator_wrapper<iterator_type>::value>;
+ friend is_iterator_wrapper<this_type>;
};
@@ -380,21 +429,15 @@ namespace eastl
struct is_reverse_iterator< eastl::reverse_iterator<Iterator> >
: public eastl::true_type {};
-
-
- /// unwrap_reverse_iterator
- ///
- /// Returns Iterator::get_base() if it's a reverse_iterator, else returns Iterator as-is.
- ///
- /// Example usage:
- /// vector<int> intVector;
- /// eastl::reverse_iterator<vector<int>::iterator> reverseIterator(intVector.begin());
- /// vector<int>::iterator it = unwrap_reverse_iterator(reverseIterator);
- ///
- /// Disabled until there is considered a good use for it.
- /// template <typename Iterator>
- /// inline typename eastl::is_iterator_wrapper_helper<Iterator, eastl::is_reverse_iterator<Iterator>::value>::iterator_type unwrap_reverse_iterator(Iterator it)
- /// { return eastl::is_iterator_wrapper_helper<Iterator, eastl::is_reverse_iterator<Iterator>::value>::get_base(it); }
+ /// unwrap_reverse_iterator is not implemented since there's no
+ /// good use case and there's some abiguitiy. Note that
+ /// unwrap_iterator(reverse_iterator<T>) returns
+ /// reverse_iterator<unwrap(T)>. However, given what
+ /// unwrap_generic_iterator and unwrap_move_iterator do, one might
+ /// expect unwrap_reverse_iterator(reverse_iterator<T>) to return
+ /// T, which is not the same. To avoid that confusion, and because
+ /// there's no current use case for this, we don't provide
+ /// unwrap_reverse_iterator.
@@ -414,7 +457,6 @@ namespace eastl
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.
typedef iterator_traits<Iterator> traits_type;
typedef typename traits_type::iterator_category iterator_category;
typedef typename traits_type::value_type value_type;
@@ -496,6 +538,16 @@ namespace eastl
reference operator[](difference_type n) const
{ return eastl::move(mIterator[n]); }
+
+ private:
+ // Unwrapping interface, not part of the public API.
+ iterator_type unwrap() const
+ { return mIterator; }
+
+ // The unwrapper helpers need access to unwrap().
+ using this_type = move_iterator<Iterator>;
+ friend is_iterator_wrapper_helper<this_type, true>;
+ friend is_iterator_wrapper<this_type>;
};
template<typename Iterator1, typename Iterator2>
@@ -589,7 +641,7 @@ namespace eastl
/// unwrap_move_iterator
///
- /// Returns Iterator::get_base() if it's a move_iterator, else returns Iterator as-is.
+ /// Returns `it.base()` if it's a move_iterator, else returns `it` as-is.
///
/// Example usage:
/// vector<int> intVector;
@@ -598,9 +650,10 @@ namespace eastl
///
template <typename Iterator>
inline typename eastl::is_iterator_wrapper_helper<Iterator, eastl::is_move_iterator<Iterator>::value>::iterator_type unwrap_move_iterator(Iterator it)
- { return eastl::is_iterator_wrapper_helper<Iterator, eastl::is_move_iterator<Iterator>::value>::get_base(it); }
-
-
+ {
+ // get_unwrapped(it) -> it.unwrap() which is equivalent to `it.base()` for move_iterator and to `it` otherwise.
+ return eastl::is_iterator_wrapper_helper<Iterator, eastl::is_move_iterator<Iterator>::value>::get_unwrapped(it);
+ }
/// back_insert_iterator
diff --git a/EASTL/include/EASTL/list.h b/EASTL/include/EASTL/list.h
index 5e79437..be99c01 100644
--- a/EASTL/include/EASTL/list.h
+++ b/EASTL/include/EASTL/list.h
@@ -403,10 +403,10 @@ namespace eastl
void clear() EA_NOEXCEPT;
void reset_lose_memory() EA_NOEXCEPT; // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
- void remove(const T& x);
+ size_type remove(const T& x);
template <typename Predicate>
- void remove_if(Predicate);
+ size_type remove_if(Predicate);
void reverse() EA_NOEXCEPT;
@@ -1457,9 +1457,10 @@ namespace eastl
template <typename T, typename Allocator>
- void list<T, Allocator>::remove(const value_type& value)
+ typename list<T, Allocator>::size_type list<T, Allocator>::remove(const value_type& value)
{
iterator current((ListNodeBase*)internalNode().mpNext);
+ size_type numRemoved = 0;
while(current.mpNode != &internalNode())
{
@@ -1469,23 +1470,30 @@ namespace eastl
{
++current;
DoErase((ListNodeBase*)current.mpNode->mpPrev);
+ ++numRemoved;
}
}
+ return numRemoved;
}
template <typename T, typename Allocator>
template <typename Predicate>
- inline void list<T, Allocator>::remove_if(Predicate predicate)
+ inline typename list<T, Allocator>::size_type list<T, Allocator>::remove_if(Predicate predicate)
{
+ size_type numRemoved = 0;
for(iterator first((ListNodeBase*)internalNode().mpNext), last((ListNodeBase*)&internalNode()); first != last; )
{
iterator temp(first);
++temp;
if(predicate(first.mpNode->mValue))
+ {
DoErase((ListNodeBase*)first.mpNode);
+ ++numRemoved;
+ }
first = temp;
}
+ return numRemoved;
}
@@ -2100,6 +2108,13 @@ namespace eastl
#endif
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T, typename Allocator>
+ inline synth_three_way_result<T> operator<=>(const list<T, Allocator>& a, const list<T, Allocator>& b)
+ {
+ return eastl::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end(), synth_three_way{});
+ }
+#else
template <typename T, typename Allocator>
bool operator<(const list<T, Allocator>& a, const list<T, Allocator>& b)
{
@@ -2129,7 +2144,7 @@ namespace eastl
{
return !(a < b);
}
-
+#endif
template <typename T, typename Allocator>
void swap(list<T, Allocator>& a, list<T, Allocator>& b)
{
@@ -2143,17 +2158,17 @@ namespace eastl
// https://en.cppreference.com/w/cpp/container/list/erase2
///////////////////////////////////////////////////////////////////////
template <class T, class Allocator, class U>
- void erase(list<T, Allocator>& c, const U& value)
+ typename list<T, Allocator>::size_type erase(list<T, Allocator>& c, const U& value)
{
// Erases all elements that compare equal to value from the container.
- c.remove_if([&](auto& elem) { return elem == value; });
+ return c.remove(value);
}
template <class T, class Allocator, class Predicate>
- void erase_if(list<T, Allocator>& c, Predicate predicate)
+ typename list<T, Allocator>::size_type erase_if(list<T, Allocator>& c, Predicate predicate)
{
// Erases all elements that satisfy the predicate pred from the container.
- c.remove_if(predicate);
+ return c.remove_if(predicate);
}
diff --git a/EASTL/include/EASTL/map.h b/EASTL/include/EASTL/map.h
index 0e6c1d0..7824250 100644
--- a/EASTL/include/EASTL/map.h
+++ b/EASTL/include/EASTL/map.h
@@ -156,6 +156,17 @@ namespace eastl
T& at(const Key& key);
const T& at(const Key& key) const;
+ template <class... Args> eastl::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
+ template <class... Args> eastl::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);
+ template <class... Args> iterator try_emplace(const_iterator position, const key_type& k, Args&&... args);
+ template <class... Args> iterator try_emplace(const_iterator position, key_type&& k, Args&&... args);
+
+ private:
+ template <class KFwd, class... Args>
+ eastl::pair<iterator, bool> try_emplace_forward(KFwd&& k, Args&&... args);
+
+ template <class KFwd, class... Args>
+ iterator try_emplace_forward(const_iterator hint, KFwd&& key, Args&&... args);
}; // map
@@ -268,7 +279,6 @@ namespace eastl
private:
// these base member functions are not included in multimaps
- using base_type::try_emplace;
using base_type::insert_or_assign;
}; // multimap
@@ -439,31 +449,28 @@ namespace eastl
//return it->second;
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename Key, typename T, typename Compare, typename Allocator>
+ inline synth_three_way_result<eastl::pair<const Key, T>> operator<=>(const map<Key, T, Compare, Allocator>& a,
+ const map<Key, T, Compare, Allocator>& b)
+ {
+ return eastl::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end(), synth_three_way{});
+ }
+#endif
template <typename Key, typename T, typename Compare, typename Allocator>
inline T& map<Key, T, Compare, Allocator>::at(const Key& key)
{
- iterator itLower(lower_bound(key)); // itLower->first is >= key.
-
- if(itLower == end())
- {
- #if EASTL_EXCEPTIONS_ENABLED
- throw std::out_of_range("map::at key does not exist");
- #else
- EASTL_FAIL_MSG("map::at key does not exist");
- #endif
- }
-
- return (*itLower).second;
+ // use the use const version of ::at to remove duplication
+ return const_cast<T&>(const_cast<map<Key, T, Compare, Allocator> const*>(this)->at(key));
}
-
template <typename Key, typename T, typename Compare, typename Allocator>
inline const T& map<Key, T, Compare, Allocator>::at(const Key& key) const
{
- const_iterator itLower(lower_bound(key)); // itLower->first is >= key.
+ const_iterator candidate = this->find(key);
- if(itLower == end())
+ if (candidate == end())
{
#if EASTL_EXCEPTIONS_ENABLED
throw std::out_of_range("map::at key does not exist");
@@ -472,7 +479,7 @@ namespace eastl
#endif
}
- return (*itLower).second;
+ return candidate->second;
}
@@ -482,8 +489,9 @@ namespace eastl
// https://en.cppreference.com/w/cpp/container/map/erase_if
///////////////////////////////////////////////////////////////////////
template <class Key, class T, class Compare, class Allocator, class Predicate>
- void erase_if(map<Key, T, Compare, Allocator>& c, Predicate predicate)
+ typename map<Key, T, Compare, Allocator>::size_type erase_if(map<Key, T, Compare, Allocator>& c, Predicate predicate)
{
+ auto oldSize = c.size();
for (auto i = c.begin(), last = c.end(); i != last;)
{
if (predicate(*i))
@@ -495,8 +503,84 @@ namespace eastl
++i;
}
}
+ return oldSize - c.size();
+ }
+
+
+ template <class Key, class T, class Compare, class Allocator>
+ template <class... Args>
+ inline eastl::pair<typename map<Key, T, Compare, Allocator>::iterator, bool>
+ map<Key, T, Compare, Allocator>::try_emplace(const key_type& key, Args&&... args)
+ {
+ return try_emplace_forward(key, eastl::forward<Args>(args)...);
+ }
+
+ template <class Key, class T, class Compare, class Allocator>
+ template <class... Args>
+ inline eastl::pair<typename map<Key, T, Compare, Allocator>::iterator, bool>
+ map<Key, T, Compare, Allocator>::try_emplace(key_type&& key, Args&&... args)
+ {
+ return try_emplace_forward(eastl::move(key), eastl::forward<Args>(args)...);
+ }
+
+ template <class Key, class T, class Compare, class Allocator>
+ template <class KFwd, class... Args>
+ inline eastl::pair<typename map<Key, T, Compare, Allocator>::iterator, bool>
+ map<Key, T, Compare, Allocator>::try_emplace_forward(KFwd&& key, Args&&... args)
+ {
+ bool canInsert;
+ node_type* const pPosition = base_type::DoGetKeyInsertionPositionUniqueKeys(canInsert, key);
+ if (!canInsert)
+ {
+ return pair<iterator, bool>(iterator(pPosition), false);
+ }
+ node_type* const pNodeNew =
+ base_type::DoCreateNode(piecewise_construct, eastl::forward_as_tuple(eastl::forward<KFwd>(key)),
+ eastl::forward_as_tuple(eastl::forward<Args>(args)...));
+ // the key might be moved above, so we can't re-use it,
+ // we need to get it back from the node's value.
+ const auto& k = extract_key{}(pNodeNew->mValue);
+ const iterator itResult(base_type::DoInsertValueImpl(pPosition, false, k, pNodeNew));
+ return pair<iterator, bool>(itResult, true);
+ }
+
+ template <class Key, class T, class Compare, class Allocator>
+ template <class... Args>
+ inline typename map<Key, T, Compare, Allocator>::iterator
+ map<Key, T, Compare, Allocator>::try_emplace(const_iterator hint, const key_type& key, Args&&... args)
+ {
+ return try_emplace_forward(hint, key, eastl::forward<Args>(args)...);
}
+ template <class Key, class T, class Compare, class Allocator>
+ template <class... Args>
+ inline typename map<Key, T, Compare, Allocator>::iterator
+ map<Key, T, Compare, Allocator>::try_emplace(const_iterator hint, key_type&& key, Args&&... args)
+ {
+ return try_emplace_forward(hint, eastl::move(key), eastl::forward<Args>(args)...);
+ }
+
+ template <class Key, class T, class Compare, class Allocator>
+ template <class KFwd, class... Args>
+ inline typename map<Key, T, Compare, Allocator>::iterator
+ map<Key, T, Compare, Allocator>::try_emplace_forward(const_iterator hint, KFwd&& key, Args&&... args)
+ {
+ bool bForceToLeft;
+ node_type* const pPosition = base_type::DoGetKeyInsertionPositionUniqueKeysHint(hint, bForceToLeft, key);
+
+ if (!pPosition)
+ {
+ // the hint didn't help, we need to do a normal insert.
+ return try_emplace_forward(eastl::forward<KFwd>(key), eastl::forward<Args>(args)...).first;
+ }
+
+ node_type* const pNodeNew =
+ base_type::DoCreateNode(piecewise_construct, eastl::forward_as_tuple(eastl::forward<KFwd>(key)),
+ eastl::forward_as_tuple(eastl::forward<Args>(args)...));
+ // the key might be moved above, so we can't re-use it,
+ // we need to get it back from the node's value.
+ return base_type::DoInsertValueImpl(pPosition, bForceToLeft, extract_key{}(pNodeNew->mValue), pNodeNew);
+ }
///////////////////////////////////////////////////////////////////////
// multimap
@@ -658,8 +742,9 @@ namespace eastl
// https://en.cppreference.com/w/cpp/container/multimap/erase_if
///////////////////////////////////////////////////////////////////////
template <class Key, class T, class Compare, class Allocator, class Predicate>
- void erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate predicate)
+ typename multimap<Key, T, Compare, Allocator>::size_type erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate predicate)
{
+ auto oldSize = c.size();
// Erases all elements that satisfy the predicate pred from the container.
for (auto i = c.begin(), last = c.end(); i != last;)
{
@@ -672,7 +757,26 @@ namespace eastl
++i;
}
}
+ return oldSize - c.size();
+ }
+
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename Key, typename T, typename Compare, typename Allocator>
+ inline synth_three_way_result<eastl::pair<const Key, T>> operator<=>(const multimap<Key, T, Compare, Allocator>& a,
+ const multimap<Key, T, Compare, Allocator>& b)
+ {
+ return eastl::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end(), synth_three_way{});
}
+#endif
+
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename Key, typename T, typename Compare, typename Allocator>
+ inline synth_three_way_result<eastl::pair<const Key, T>> operator<=>(const multimap<Key, T, Compare, Allocator>& a,
+ const multimap<Key, T, Compare, Allocator>& b)
+ {
+ return eastl::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end(), synth_three_way{});
+ }
+#endif
} // namespace eastl
diff --git a/EASTL/include/EASTL/memory.h b/EASTL/include/EASTL/memory.h
index 1993b8e..ab2798f 100644
--- a/EASTL/include/EASTL/memory.h
+++ b/EASTL/include/EASTL/memory.h
@@ -1682,6 +1682,41 @@ namespace eastl
{ return eastl::addressof(r); } // 20.6.3.2: if element_type is (possibly cv-qualified) void, the type of r is unspecified; otherwise, it is T&.
};
+ ///////////////////////////////////////////////////////////////////////
+ // to_address
+ //
+ // Helper that call the customization point in pointer_traits<T>::to_address for retrieving the address of a pointer.
+ // This is useful if you are using fancy-pointers.
+ ///////////////////////////////////////////////////////////////////////
+
+ namespace Internal
+ {
+ template <class T>
+ using detect_pointer_traits_to_address = decltype(eastl::pointer_traits<T>::to_address(eastl::declval<const T&>()));
+
+ template <class T>
+ using result_detect_pointer_traits_to_address = eastl::is_detected<detect_pointer_traits_to_address, T>;
+ }
+
+ template<class T>
+ EA_CPP14_CONSTEXPR T* to_address(T* p) noexcept
+ {
+ static_assert(!eastl::is_function<T>::value, "Cannot call to_address with a function pointer. C++20 20.2.4.1 - Pointer conversion.");
+ return p;
+ }
+
+ template <class Ptr, typename eastl::enable_if<Internal::result_detect_pointer_traits_to_address<Ptr>::value, int>::type = 0>
+ EA_CPP14_CONSTEXPR auto to_address(const Ptr& ptr) noexcept -> decltype(eastl::pointer_traits<Ptr>::to_address(ptr))
+ {
+ return eastl::pointer_traits<Ptr>::to_address(ptr);
+ }
+
+ template <class Ptr, typename eastl::enable_if<!Internal::result_detect_pointer_traits_to_address<Ptr>::value, int>::type = 0>
+ EA_CPP14_CONSTEXPR auto to_address(const Ptr& ptr) noexcept -> decltype(to_address(ptr.operator->()))
+ {
+ return to_address(ptr.operator->());
+ }
+
} // namespace eastl
diff --git a/EASTL/include/EASTL/numeric.h b/EASTL/include/EASTL/numeric.h
index 4b83c94..200be6c 100644
--- a/EASTL/include/EASTL/numeric.h
+++ b/EASTL/include/EASTL/numeric.h
@@ -233,6 +233,103 @@ namespace eastl
}
+ #if defined(EA_COMPILER_CPP20_ENABLED)
+ /// midpoint
+ ///
+ /// Computes the midpoint between the LHS and RHS by adding them together, then dividing the sum by 2.
+ /// If the operands are of integer type and the sum is odd, the result will be rounded closer to the LHS.
+ /// If the operands are floating points, then at most one inexact operation occurs.
+ ///
+ template <typename T>
+ constexpr eastl::enable_if_t<eastl::is_arithmetic_v<T> && !eastl::is_same_v<eastl::remove_cv_t<T>, bool>, T> midpoint(const T lhs, const T rhs) EA_NOEXCEPT
+ {
+ // If T is an integral type...
+ if constexpr(eastl::is_integral_v<T>)
+ {
+ using U = eastl::make_unsigned_t<T>;
+
+ int sign = 1;
+ U m = lhs;
+ U M = rhs;
+
+ if (lhs > rhs)
+ {
+ sign = -1;
+ m = rhs;
+ M = lhs;
+ }
+
+ return lhs + static_cast<T>(sign * static_cast<T>((U(M - m)) / 2 ));
+ }
+
+ // otherwise if T is a floating point
+ else
+ {
+ const T LO = eastl::numeric_limits<T>::min() * 2;
+ const T HI = eastl::numeric_limits<T>::max() / 2;
+
+ const T lhs_abs = (lhs < 0) ? -lhs : lhs;
+ const T rhs_abs = (rhs < 0) ? -rhs : rhs;
+
+ if (lhs_abs <= HI && rhs_abs <= HI)
+ return (lhs + rhs) / 2;
+ if (lhs_abs < LO)
+ return lhs + (rhs / 2);
+ if (rhs_abs < LO)
+ return (lhs / 2) + rhs;
+ return (lhs / 2) + (rhs / 2);
+ }
+ }
+
+
+ /// midpoint
+ ///
+ /// Computes the midpoint address between pointers LHS and RHS.
+ /// The midpoint address closer to the LHS is chosen.
+ ///
+ template <typename T>
+ constexpr eastl::enable_if_t<eastl::is_object_v<T>, T*> midpoint(T* lhs, T* rhs)
+ {
+ return lhs + ((rhs - lhs) / 2);
+ }
+
+
+ template <class T>
+ constexpr T shared_lerp(const T a, const T b, const T t) EA_NOEXCEPT
+ {
+ if ((a <= 0 && b >= 0) || (a >= 0 && b <= 0))
+ {
+ return t * b + (1 - t) * a;
+ }
+
+ if (t == 1)
+ {
+ return b;
+ }
+
+ const T X = a + t * (b - a);
+
+ if ((t > 1) == (b > a))
+ {
+ return (b > X) ? b : X;
+ }
+ return (b < X) ? b : X;
+ }
+
+ /// lerp
+ ///
+ /// Calculates the linear interpolation of two points A and B expressed A + T * (B - A)
+ /// where T is some value in range [0, 1]. If T is outside this range, the linear extrapolation will be computed.
+ ///
+ /// https://en.cppreference.com/w/cpp/numeric/lerp
+ ///
+ /// C++ proposal paper:
+ /// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0811r3.html
+ ///
+ constexpr float lerp(float a, float b, float t) EA_NOEXCEPT { return shared_lerp(a, b, t); }
+ constexpr double lerp(double a, double b, double t) EA_NOEXCEPT { return shared_lerp(a, b, t); }
+ constexpr long double lerp(long double a, long double b, long double t) EA_NOEXCEPT { return shared_lerp(a, b, t); }
+ #endif
} // namespace eastl
diff --git a/EASTL/include/EASTL/numeric_limits.h b/EASTL/include/EASTL/numeric_limits.h
index e991e7e..0d7dc97 100644
--- a/EASTL/include/EASTL/numeric_limits.h
+++ b/EASTL/include/EASTL/numeric_limits.h
@@ -614,6 +614,65 @@ namespace eastl
};
+ #if defined(EA_CHAR8_UNIQUE) && EA_CHAR8_UNIQUE
+ template<>
+ struct numeric_limits<char8_t>
+ {
+ typedef char8_t value_type;
+
+ static EA_CONSTEXPR_OR_CONST bool is_specialized = true;
+ static EA_CONSTEXPR_OR_CONST int digits = EASTL_LIMITS_DIGITS(value_type);
+ static EA_CONSTEXPR_OR_CONST int digits10 = EASTL_LIMITS_DIGITS10(value_type);
+ static EA_CONSTEXPR_OR_CONST int max_digits10 = 0;
+ static EA_CONSTEXPR_OR_CONST bool is_signed = EASTL_LIMITS_IS_SIGNED(value_type);
+ static EA_CONSTEXPR_OR_CONST bool is_integer = true;
+ static EA_CONSTEXPR_OR_CONST bool is_exact = true;
+ static EA_CONSTEXPR_OR_CONST int radix = 2;
+ static EA_CONSTEXPR_OR_CONST int min_exponent = 0;
+ static EA_CONSTEXPR_OR_CONST int min_exponent10 = 0;
+ static EA_CONSTEXPR_OR_CONST int max_exponent = 0;
+ static EA_CONSTEXPR_OR_CONST int max_exponent10 = 0;
+ static EA_CONSTEXPR_OR_CONST bool is_bounded = true;
+ static EA_CONSTEXPR_OR_CONST bool is_modulo = true;
+ static EA_CONSTEXPR_OR_CONST bool traps = true;
+ static EA_CONSTEXPR_OR_CONST bool tinyness_before = false;
+ static EA_CONSTEXPR_OR_CONST float_round_style round_style = round_toward_zero;
+ static EA_CONSTEXPR_OR_CONST bool has_infinity = false;
+ static EA_CONSTEXPR_OR_CONST bool has_quiet_NaN = false;
+ static EA_CONSTEXPR_OR_CONST bool has_signaling_NaN = false;
+ static EA_CONSTEXPR_OR_CONST float_denorm_style has_denorm = denorm_absent;
+ static EA_CONSTEXPR_OR_CONST bool has_denorm_loss = false;
+ static EA_CONSTEXPR_OR_CONST bool is_iec559 = false;
+
+ static EA_CONSTEXPR value_type min()
+ { return EASTL_LIMITS_MIN(value_type); }
+
+ static EA_CONSTEXPR value_type max()
+ { return EASTL_LIMITS_MAX(value_type); }
+
+ static EA_CONSTEXPR value_type lowest()
+ { return EASTL_LIMITS_MIN(value_type); }
+
+ static EA_CONSTEXPR value_type epsilon()
+ { return 0; }
+
+ static EA_CONSTEXPR value_type round_error()
+ { return 0; }
+
+ static EA_CONSTEXPR value_type infinity()
+ { return 0; }
+
+ static EA_CONSTEXPR value_type quiet_NaN()
+ { return 0; }
+
+ static EA_CONSTEXPR value_type signaling_NaN()
+ { return 0; }
+
+ static EA_CONSTEXPR value_type denorm_min()
+ { return (value_type)0; }
+ };
+ #endif
+
#if EA_CHAR16_NATIVE // If char16_t is a true unique type (as called for by the C++11 Standard)...
// numeric_limits<char16_t>
@@ -1435,6 +1494,19 @@ namespace eastl
static value_type round_error()
{ return 0.5f; }
+ #if defined(_MSVC_STL_UPDATE) && _MSVC_STL_UPDATE >= 202206L // If using a recent version of MSVC's STL...
+ static value_type infinity()
+ { return __builtin_huge_valf(); }
+
+ static value_type quiet_NaN()
+ { return __builtin_nanf("0"); }
+
+ static value_type signaling_NaN()
+ { return __builtin_nansf("1"); }
+
+ static value_type denorm_min()
+ { return FLT_TRUE_MIN; }
+ #else
static value_type infinity()
{ return _CSTD _FInf._Float; }
@@ -1446,6 +1518,7 @@ namespace eastl
static value_type denorm_min()
{ return _CSTD _FDenorm._Float; }
+ #endif
#endif
};
@@ -1553,6 +1626,19 @@ namespace eastl
static value_type round_error()
{ return 0.5f; }
+ #if defined(_MSVC_STL_UPDATE) && _MSVC_STL_UPDATE >= 202206L // If using a recent version of MSVC's STL...
+ static value_type infinity()
+ { return __builtin_huge_val(); }
+
+ static value_type quiet_NaN()
+ { return __builtin_nan("0"); }
+
+ static value_type signaling_NaN()
+ { return __builtin_nans("1"); }
+
+ static value_type denorm_min()
+ { return DBL_TRUE_MIN; }
+ #else
static value_type infinity()
{ return _CSTD _Inf._Double; }
@@ -1564,6 +1650,7 @@ namespace eastl
static value_type denorm_min()
{ return _CSTD _Denorm._Double; }
+ #endif
#endif
};
@@ -1671,6 +1758,19 @@ namespace eastl
static value_type round_error()
{ return 0.5f; }
+ #if defined(_MSVC_STL_UPDATE) && _MSVC_STL_UPDATE >= 202206L // If using a recent version of MSVC's STL...
+ static value_type infinity()
+ { return __builtin_huge_val(); }
+
+ static value_type quiet_NaN()
+ { return __builtin_nan("0"); }
+
+ static value_type signaling_NaN()
+ { return __builtin_nans("1"); }
+
+ static value_type denorm_min()
+ { return LDBL_TRUE_MIN; }
+ #else
static value_type infinity()
{ return _CSTD _LInf._Long_double; }
@@ -1682,6 +1782,7 @@ namespace eastl
static value_type denorm_min()
{ return _CSTD _LDenorm._Long_double; }
+ #endif
#endif
};
diff --git a/EASTL/include/EASTL/optional.h b/EASTL/include/EASTL/optional.h
index 763bfd8..15cacd0 100644
--- a/EASTL/include/EASTL/optional.h
+++ b/EASTL/include/EASTL/optional.h
@@ -552,6 +552,17 @@ namespace eastl
inline EA_CONSTEXPR bool operator>=(const optional<T>& lhs, const optional<T>& rhs)
{ return !(lhs < rhs); }
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <class T, class U=T> requires std::three_way_comparable_with<T, U>
+ inline EA_CONSTEXPR std::compare_three_way_result_t<T, U> operator<=>(const optional<T>& lhs, const optional<U>& rhs)
+ {
+ if (lhs && rhs)
+ {
+ return *lhs <=> *rhs;
+ }
+ return lhs.has_value() <=> rhs.has_value();
+ }
+#endif
///////////////////////////////////////////////////////////////////////////////
// Compare an optional object with a nullopt
@@ -559,7 +570,11 @@ namespace eastl
template <class T>
inline EA_CONSTEXPR bool operator==(const optional<T>& opt, eastl::nullopt_t) EA_NOEXCEPT
{ return !opt; }
-
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <class T>
+ inline EA_CONSTEXPR std::strong_ordering operator<=>(const optional<T>& opt, eastl::nullopt_t) EA_NOEXCEPT
+ { return opt.has_value() <=> false; }
+#else
template <class T>
inline EA_CONSTEXPR bool operator==(eastl::nullopt_t, const optional<T>& opt) EA_NOEXCEPT
{ return !opt; }
@@ -603,7 +618,7 @@ namespace eastl
template <class T>
inline EA_CONSTEXPR bool operator>=(eastl::nullopt_t, const optional<T>& opt) EA_NOEXCEPT
{ return !opt; }
-
+#endif
///////////////////////////////////////////////////////////////////////////////
// Compare an optional object with a T
@@ -656,6 +671,11 @@ namespace eastl
inline EA_CONSTEXPR bool operator>=(const T& value, const optional<T>& opt)
{ return !(value < opt); }
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <class T, class U=T> requires std::three_way_comparable_with<T, U>
+ inline EA_CONSTEXPR std::compare_three_way_result_t<T, U> operator<=>(const optional<T>& opt, const U& value)
+ { return (opt.has_value()) ? *opt <=> value : std::strong_ordering::less; }
+#endif
///////////////////////////////////////////////////////////////////////////////
/// hash
diff --git a/EASTL/include/EASTL/queue.h b/EASTL/include/EASTL/queue.h
index 9e06e20..8b29555 100644
--- a/EASTL/include/EASTL/queue.h
+++ b/EASTL/include/EASTL/queue.h
@@ -308,6 +308,14 @@ namespace eastl
{
return (a.c == b.c);
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T, typename Container> requires std::three_way_comparable<Container>
+
+ inline synth_three_way_result<T> operator<=>(const queue<T, Container>& a, const queue<T, Container>& b)
+ {
+ return a.c <=> b.c;
+ }
+#endif
template <typename T, typename Container>
inline bool operator!=(const queue<T, Container>& a, const queue<T, Container>& b)
@@ -339,7 +347,6 @@ namespace eastl
return !(a.c < b.c);
}
-
template <typename T, typename Container>
inline void swap(queue<T, Container>& a, queue<T, Container>& b) EA_NOEXCEPT_IF((eastl::is_nothrow_swappable<typename queue<T, Container>::container_type>::value)) // EDG has a bug and won't let us use Container in this noexcept statement
{
diff --git a/EASTL/include/EASTL/set.h b/EASTL/include/EASTL/set.h
index a66a885..8256162 100644
--- a/EASTL/include/EASTL/set.h
+++ b/EASTL/include/EASTL/set.h
@@ -401,8 +401,9 @@ namespace eastl
// https://en.cppreference.com/w/cpp/container/set/erase_if
///////////////////////////////////////////////////////////////////////
template <class Key, class Compare, class Allocator, class Predicate>
- void erase_if(set<Key, Compare, Allocator>& c, Predicate predicate)
+ typename set<Key, Compare, Allocator>::size_type erase_if(set<Key, Compare, Allocator>& c, Predicate predicate)
{
+ auto oldSize = c.size();
for (auto i = c.begin(), last = c.end(); i != last;)
{
if (predicate(*i))
@@ -414,8 +415,17 @@ namespace eastl
++i;
}
}
+ return oldSize - c.size();
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <class Key, class Compare, class Allocator>
+ synth_three_way_result<Key> operator<=>(const set<Key, Compare, Allocator>& a, const set<Key, Compare, Allocator>& b)
+ {
+ return eastl::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end(), synth_three_way{});
+ }
+#endif
+
///////////////////////////////////////////////////////////////////////
// multiset
@@ -611,8 +621,9 @@ namespace eastl
// https://en.cppreference.com/w/cpp/container/multiset/erase_if
///////////////////////////////////////////////////////////////////////
template <class Key, class Compare, class Allocator, class Predicate>
- void erase_if(multiset<Key, Compare, Allocator>& c, Predicate predicate)
+ typename multiset<Key, Compare, Allocator>::size_type erase_if(multiset<Key, Compare, Allocator>& c, Predicate predicate)
{
+ auto oldSize = c.size();
// Erases all elements that satisfy the predicate pred from the container.
for (auto i = c.begin(), last = c.end(); i != last;)
{
@@ -625,8 +636,17 @@ namespace eastl
++i;
}
}
+ return oldSize - c.size();
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <class Key, class Compare, class Allocator>
+ synth_three_way_result<Key> operator<=>(const multiset<Key, Compare, Allocator>& a, const multiset<Key, Compare, Allocator>& b)
+ {
+ return eastl::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end(), synth_three_way{});
+ }
+#endif
+
} // namespace eastl
diff --git a/EASTL/include/EASTL/shared_ptr.h b/EASTL/include/EASTL/shared_ptr.h
index 5535adf..e7eb778 100644
--- a/EASTL/include/EASTL/shared_ptr.h
+++ b/EASTL/include/EASTL/shared_ptr.h
@@ -48,6 +48,7 @@
#include <EASTL/unique_ptr.h>
#include <EASTL/functional.h>
#include <EASTL/allocator.h>
+#include <EASTL/atomic.h>
#if EASTL_RTTI_ENABLED
#include <typeinfo>
#endif
@@ -117,8 +118,8 @@ namespace eastl
/// This is a small utility class used by shared_ptr and weak_ptr.
struct ref_count_sp
{
- int32_t mRefCount; /// Reference count on the contained pointer. Starts as 1 by default.
- int32_t mWeakRefCount; /// Reference count on contained pointer plus this ref_count_sp object itself. Starts as 1 by default.
+ atomic<int32_t> mRefCount; /// Reference count on the contained pointer. Starts as 1 by default.
+ atomic<int32_t> mWeakRefCount; /// Reference count on contained pointer plus this ref_count_sp object itself. Starts as 1 by default.
public:
ref_count_sp(int32_t refCount = 1, int32_t weakRefCount = 1) EA_NOEXCEPT;
@@ -147,44 +148,49 @@ namespace eastl
inline int32_t ref_count_sp::use_count() const EA_NOEXCEPT
{
- return mRefCount; // To figure out: is this right?
+ return mRefCount.load(memory_order_relaxed); // To figure out: is this right?
}
inline void ref_count_sp::addref() EA_NOEXCEPT
{
- Internal::atomic_increment(&mRefCount);
- Internal::atomic_increment(&mWeakRefCount);
+ mRefCount.fetch_add(1, memory_order_relaxed);
+ mWeakRefCount.fetch_add(1, memory_order_relaxed);
}
inline void ref_count_sp::release()
{
- EASTL_ASSERT((mRefCount > 0) && (mWeakRefCount > 0));
- if(Internal::atomic_decrement(&mRefCount) == 0)
+ EASTL_ASSERT((mRefCount.load(memory_order_relaxed) > 0));
+ if(mRefCount.fetch_sub(1, memory_order_release) == 1)
+ {
+ atomic_thread_fence(memory_order_acquire);
free_value();
+ }
- if(Internal::atomic_decrement(&mWeakRefCount) == 0)
- free_ref_count_sp();
+ weak_release();
}
inline void ref_count_sp::weak_addref() EA_NOEXCEPT
{
- Internal::atomic_increment(&mWeakRefCount);
+ mWeakRefCount.fetch_add(1, memory_order_relaxed);
}
inline void ref_count_sp::weak_release()
{
- EASTL_ASSERT(mWeakRefCount > 0);
- if(Internal::atomic_decrement(&mWeakRefCount) == 0)
+ EASTL_ASSERT(mWeakRefCount.load(memory_order_relaxed) > 0);
+ if(mWeakRefCount.fetch_sub(1, memory_order_release) == 1)
+ {
+ atomic_thread_fence(memory_order_acquire);
free_ref_count_sp();
+ }
}
inline ref_count_sp* ref_count_sp::lock() EA_NOEXCEPT
{
- for(int32_t refCountTemp = mRefCount; refCountTemp != 0; refCountTemp = mRefCount)
+ for(int32_t refCountTemp = mRefCount.load(memory_order_relaxed); refCountTemp != 0; )
{
- if(Internal::atomic_compare_and_swap(&mRefCount, refCountTemp + 1, refCountTemp))
+ if(mRefCount.compare_exchange_weak(refCountTemp, refCountTemp + 1, memory_order_relaxed))
{
- Internal::atomic_increment(&mWeakRefCount);
+ mWeakRefCount.fetch_add(1, memory_order_relaxed);
return this;
}
}
@@ -810,14 +816,14 @@ namespace eastl
/// Returns: the number of shared_ptr objects, *this included, that share ownership with *this, or 0 when *this is empty.
int use_count() const EA_NOEXCEPT
{
- return mpRefCount ? mpRefCount->mRefCount : 0;
+ return mpRefCount ? mpRefCount->use_count() : 0;
}
/// unique
/// Returns: use_count() == 1.
bool unique() const EA_NOEXCEPT
{
- return (mpRefCount && (mpRefCount->mRefCount == 1));
+ return (mpRefCount && (mpRefCount->use_count() == 1));
}
@@ -970,6 +976,13 @@ namespace eastl
return (a.get() == b.get());
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T, typename U>
+ std::strong_ordering operator<=>(const shared_ptr<T>& a, const shared_ptr<U>& b) EA_NOEXCEPT
+ {
+ return a.get() <=> b.get();
+ }
+#else
template <typename T, typename U>
inline bool operator!=(const shared_ptr<T>& a, const shared_ptr<U>& b) EA_NOEXCEPT
{
@@ -1006,6 +1019,7 @@ namespace eastl
{
return !(a < b);
}
+#endif
template <typename T>
inline bool operator==(const shared_ptr<T>& a, std::nullptr_t) EA_NOEXCEPT
@@ -1013,6 +1027,13 @@ namespace eastl
return !a;
}
+ #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T>
+ inline std::strong_ordering operator<=>(const shared_ptr<T>& a, std::nullptr_t) EA_NOEXCEPT
+ {
+ return a.get() <=> nullptr;
+ }
+ #else
template <typename T>
inline bool operator==(std::nullptr_t, const shared_ptr<T>& b) EA_NOEXCEPT
{
@@ -1078,7 +1099,7 @@ namespace eastl
{
return !(nullptr < b);
}
-
+#endif
@@ -1508,13 +1529,13 @@ namespace eastl
// Returns: 0 if *this is empty ; otherwise, the number of shared_ptr instances that share ownership with *this.
int use_count() const EA_NOEXCEPT
{
- return mpRefCount ? mpRefCount->mRefCount : 0;
+ return mpRefCount ? mpRefCount->use_count() : 0;
}
// Returns: use_count() == 0
bool expired() const EA_NOEXCEPT
{
- return (!mpRefCount || (mpRefCount->mRefCount == 0));
+ return (!mpRefCount || (mpRefCount->use_count() == 0));
}
void reset()
diff --git a/EASTL/include/EASTL/slist.h b/EASTL/include/EASTL/slist.h
index 1dbb44f..dc3c447 100644
--- a/EASTL/include/EASTL/slist.h
+++ b/EASTL/include/EASTL/slist.h
@@ -353,10 +353,10 @@ namespace eastl
void clear() EA_NOEXCEPT;
void reset_lose_memory() EA_NOEXCEPT; // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
- void remove(const value_type& value);
+ size_type remove(const value_type& value);
template <typename Predicate>
- void remove_if(Predicate predicate);
+ size_type remove_if(Predicate predicate);
void reverse() EA_NOEXCEPT;
@@ -1249,32 +1249,42 @@ namespace eastl
template <typename T, typename Allocator>
- void slist<T, Allocator>::remove(const value_type& value)
+ typename slist<T, Allocator>::size_type slist<T, Allocator>::remove(const value_type& value)
{
base_node_type* pNode = &internalNode();
+ size_type numErased = 0;
while(pNode && pNode->mpNext)
{
- if(static_cast<node_type*>(pNode->mpNext)->mValue == value)
+ if (static_cast<node_type*>(pNode->mpNext)->mValue == value)
+ {
DoEraseAfter((SListNodeBase*)pNode); // This will take care of modifying pNode->mpNext.
+ ++numErased;
+ }
else
pNode = pNode->mpNext;
}
+ return numErased;
}
template <typename T, typename Allocator>
template <typename Predicate>
- void slist<T, Allocator>::remove_if(Predicate predicate)
+ inline typename slist<T, Allocator>::size_type slist<T, Allocator>::remove_if(Predicate predicate)
{
base_node_type* pNode = &internalNode();
+ size_type numErased = 0;
while(pNode && pNode->mpNext)
{
- if(predicate(static_cast<node_type*>(pNode->mpNext)->mValue))
+ if (predicate(static_cast<node_type*>(pNode->mpNext)->mValue))
+ {
DoEraseAfter((SListNodeBase*)pNode); // This will take care of modifying pNode->mpNext.
+ ++numErased;
+ }
else
pNode = pNode->mpNext;
}
+ return numErased;
}
@@ -1811,7 +1821,13 @@ namespace eastl
#endif
}
-
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T, typename Allocator>
+ inline synth_three_way_result<T> operator<=>(const slist<T, Allocator>& a, const slist<T, Allocator>& b)
+ {
+ return eastl::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end(), synth_three_way{});
+ }
+#else
template <typename T, typename Allocator>
inline bool operator<(const slist<T, Allocator>& a, const slist<T, Allocator>& b)
{
@@ -1845,7 +1861,7 @@ namespace eastl
{
return !(a < b);
}
-
+#endif
template <typename T, typename Allocator>
inline void swap(slist<T, Allocator>& a, slist<T, Allocator>& b)
@@ -1858,17 +1874,17 @@ namespace eastl
///
/// https://en.cppreference.com/w/cpp/container/forward_list/erase2
template <class T, class Allocator, class U>
- void erase(slist<T, Allocator>& c, const U& value)
+ typename slist<T, Allocator>::size_type erase(slist<T, Allocator>& c, const U& value)
{
// Erases all elements that compare equal to value from the container.
- c.remove_if([&](auto& elem) { return elem == value; });
+ return c.remove(value);
}
template <class T, class Allocator, class Predicate>
- void erase_if(slist<T, Allocator>& c, Predicate predicate)
+ typename slist<T, Allocator>::size_type erase_if(slist<T, Allocator>& c, Predicate predicate)
{
// Erases all elements that satisfy the predicate pred from the container.
- c.remove_if(predicate);
+ return c.remove_if(predicate);
}
diff --git a/EASTL/include/EASTL/sort.h b/EASTL/include/EASTL/sort.h
index 60cfcd8..fb1c6e5 100644
--- a/EASTL/include/EASTL/sort.h
+++ b/EASTL/include/EASTL/sort.h
@@ -715,18 +715,20 @@ namespace eastl
template <typename RandomAccessIterator, typename T>
inline RandomAccessIterator get_partition_impl(RandomAccessIterator first, RandomAccessIterator last, T&& pivotValue)
{
+ using PureT = decay_t<T>;
+
for(; ; ++first)
{
- while(*first < pivotValue)
+ while(eastl::less<PureT>()(*first, pivotValue))
{
- EASTL_VALIDATE_COMPARE(!(pivotValue < *first)); // Validate that the compare function is sane.
+ EASTL_VALIDATE_COMPARE(!eastl::less<PureT>()(pivotValue, *first)); // Validate that the compare function is sane.
++first;
}
--last;
- while(pivotValue < *last)
+ while(eastl::less<PureT>()(pivotValue, *last))
{
- EASTL_VALIDATE_COMPARE(!(*last < pivotValue)); // Validate that the compare function is sane.
+ EASTL_VALIDATE_COMPARE(!eastl::less<PureT>()(*last, pivotValue)); // Validate that the compare function is sane.
--last;
}
@@ -813,9 +815,9 @@ namespace eastl
RandomAccessIterator end(current), prev(current);
value_type value(eastl::forward<value_type>(*current));
- for(--prev; value < *prev; --end, --prev) // We skip checking for (prev >= first) because quick_sort (our caller) makes this unnecessary.
+ for(--prev; eastl::less<value_type>()(value, *prev); --end, --prev) // We skip checking for (prev >= first) because quick_sort (our caller) makes this unnecessary.
{
- EASTL_VALIDATE_COMPARE(!(*prev < value)); // Validate that the compare function is sane.
+ EASTL_VALIDATE_COMPARE(!eastl::less<value_type>()(*prev, value)); // Validate that the compare function is sane.
*end = eastl::forward<value_type>(*prev);
}
@@ -860,9 +862,9 @@ namespace eastl
for(RandomAccessIterator i = middle; i < last; ++i)
{
- if(*i < *first)
+ if(eastl::less<value_type>()(*i, *first))
{
- EASTL_VALIDATE_COMPARE(!(*first < *i)); // Validate that the compare function is sane.
+ EASTL_VALIDATE_COMPARE(!eastl::less<value_type>()(*first, *i)); // Validate that the compare function is sane.
value_type temp(eastl::forward<value_type>(*i));
*i = eastl::forward<value_type>(*first);
eastl::adjust_heap<RandomAccessIterator, difference_type, value_type>
@@ -1712,6 +1714,7 @@ namespace eastl
bucketPosition[i + 1] = bucketPosition[i] + bucketSize[i];
bucketSize[i] = 0; // Clear the bucket for the next pass
}
+ bucketSize[numBuckets - 1] = 0;
uint32_t jNext = j + DigitBits;
for (temp = srcFirst; temp != last; ++temp)
diff --git a/EASTL/include/EASTL/stack.h b/EASTL/include/EASTL/stack.h
index 3edd5f5..f060b60 100644
--- a/EASTL/include/EASTL/stack.h
+++ b/EASTL/include/EASTL/stack.h
@@ -284,6 +284,13 @@ namespace eastl
return (a.c == b.c);
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T, typename Container> requires std::three_way_comparable<Container>
+ inline synth_three_way_result<T> operator<=>(const stack<T, Container>& a, const stack<T, Container>& b)
+ {
+ return a.c <=> b.c;
+ }
+#endif
template <typename T, typename Container>
inline bool operator!=(const stack<T, Container>& a, const stack<T, Container>& b)
@@ -319,7 +326,6 @@ namespace eastl
return !(a.c < b.c);
}
-
template <typename T, typename Container>
inline void swap(stack<T, Container>& a, stack<T, Container>& b) EA_NOEXCEPT_IF((eastl::is_nothrow_swappable<typename stack<T, Container>::container_type>::value))
{
diff --git a/EASTL/include/EASTL/string.h b/EASTL/include/EASTL/string.h
index 2352a61..3a70b79 100644
--- a/EASTL/include/EASTL/string.h
+++ b/EASTL/include/EASTL/string.h
@@ -294,7 +294,7 @@ namespace eastl
typedef ptrdiff_t difference_type;
typedef Allocator allocator_type;
- static const size_type npos = (size_type)-1; /// 'npos' means non-valid position or simply non-position.
+ static const EA_CONSTEXPR size_type npos = (size_type)-1; /// 'npos' means non-valid position or simply non-position.
public:
// CtorDoNotInitialize exists so that we can create a constructor that allocates but doesn't
@@ -1798,7 +1798,9 @@ namespace eastl
}
if (nReturnValue >= 0)
+ {
internalLayout().SetSize(nInitialSize + nReturnValue);
+ }
#if EASTL_VA_COPY_ENABLED
// va_end for arguments will be called by the caller.
@@ -1854,7 +1856,9 @@ namespace eastl
}
if(nReturnValue >= 0)
+ {
internalLayout().SetSize(nInitialSize + nReturnValue);
+ }
#if EASTL_VA_COPY_ENABLED
// va_end for arguments will be called by the caller.
@@ -3764,7 +3768,7 @@ namespace eastl
return ((a.size() == b.size()) && (memcmp(a.data(), b.data(), (size_t)a.size() * sizeof(typename basic_string<T, Allocator>::value_type)) == 0));
}
-
+#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <typename T, typename Allocator>
inline bool operator==(const typename basic_string<T, Allocator>::value_type* p, const basic_string<T, Allocator>& b)
{
@@ -3772,7 +3776,7 @@ namespace eastl
const size_type n = (size_type)CharStrlen(p);
return ((n == b.size()) && (memcmp(p, b.data(), (size_t)n * sizeof(*p)) == 0));
}
-
+#endif
template <typename T, typename Allocator>
inline bool operator==(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::value_type* p)
@@ -3781,6 +3785,52 @@ namespace eastl
const size_type n = (size_type)CharStrlen(p);
return ((a.size() == n) && (memcmp(a.data(), p, (size_t)n * sizeof(*p)) == 0));
}
+
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T, typename Allocator>
+ inline auto operator<=>(const basic_string<T, Allocator>& a, const basic_string<T, Allocator>& b)
+ {
+ return basic_string<T, Allocator>::compare(a.begin(), a.end(), b.begin(), b.end()) <=> 0;
+ }
+
+ template <typename T, typename Allocator>
+ inline auto operator<=>(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::value_type* p)
+ {
+ typedef typename basic_string<T, Allocator>::size_type size_type;
+ const size_type n = (size_type)CharStrlen(p);
+ return basic_string<T, Allocator>::compare(a.begin(), a.end(), p, p + n) <=> 0;
+ }
+
+ template <typename T, typename Allocator>
+ inline auto operator<=>(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::view_type v)
+ {
+ typedef typename basic_string<T, Allocator>::view_type view_type;
+ return static_cast<view_type>(a) <=> v;
+ }
+
+#else
+
+ template <typename T, typename Allocator>
+ inline bool operator==(const typename basic_string<T, Allocator>::view_type v, const basic_string<T, Allocator>& b)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ typedef typename basic_string<T, Allocator>::view_type view_type;
+ return v == static_cast<view_type>(b);
+ }
+
+ template <typename T, typename Allocator>
+ inline bool operator==(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::view_type v)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ typedef typename basic_string<T, Allocator>::view_type view_type;
+ return static_cast<view_type>(a) == v;
+ }
template <typename T, typename Allocator>
@@ -3789,7 +3839,6 @@ namespace eastl
return !(a == b);
}
-
template <typename T, typename Allocator>
inline bool operator!=(const typename basic_string<T, Allocator>::value_type* p, const basic_string<T, Allocator>& b)
{
@@ -3802,6 +3851,28 @@ namespace eastl
{
return !(a == p);
}
+
+
+ template <typename T, typename Allocator>
+ inline bool operator!=(const typename basic_string<T, Allocator>::view_type v, const basic_string<T, Allocator>& b)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ return !(v == b);
+ }
+
+
+ template <typename T, typename Allocator>
+ inline bool operator!=(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::view_type v)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ return !(a == v);
+ }
// Operator< (and also >, <=, and >=).
@@ -3827,6 +3898,30 @@ namespace eastl
const size_type n = (size_type)CharStrlen(p);
return basic_string<T, Allocator>::compare(a.begin(), a.end(), p, p + n) < 0;
}
+
+
+ template <typename T, typename Allocator>
+ inline bool operator<(const typename basic_string<T, Allocator>::view_type v, const basic_string<T, Allocator>& b)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ typedef typename basic_string<T, Allocator>::view_type view_type;
+ return v < static_cast<view_type>(b);
+ }
+
+
+ template <typename T, typename Allocator>
+ inline bool operator<(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::view_type v)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ typedef typename basic_string<T, Allocator>::view_type view_type;
+ return static_cast<view_type>(a) < v;
+ }
template <typename T, typename Allocator>
@@ -3848,6 +3943,28 @@ namespace eastl
{
return p < a;
}
+
+
+ template <typename T, typename Allocator>
+ inline bool operator>(const typename basic_string<T, Allocator>::view_type v, const basic_string<T, Allocator>& b)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ return b < v;
+ }
+
+
+ template <typename T, typename Allocator>
+ inline bool operator>(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::view_type v)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ return v < a;
+ }
template <typename T, typename Allocator>
@@ -3869,6 +3986,28 @@ namespace eastl
{
return !(p < a);
}
+
+
+ template <typename T, typename Allocator>
+ inline bool operator<=(const typename basic_string<T, Allocator>::view_type v, const basic_string<T, Allocator>& b)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ return !(b < v);
+ }
+
+
+ template <typename T, typename Allocator>
+ inline bool operator<=(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::view_type v)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ return !(v < a);
+ }
template <typename T, typename Allocator>
@@ -3890,7 +4029,29 @@ namespace eastl
{
return !(a < p);
}
+
+
+ template <typename T, typename Allocator>
+ inline bool operator>=(const typename basic_string<T, Allocator>::view_type v, const basic_string<T, Allocator>& b)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ return !(v < b);
+ }
+
+
+ template <typename T, typename Allocator>
+ inline bool operator>=(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::view_type v)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+ return !(a < v);
+ }
+#endif
template <typename T, typename Allocator>
inline void swap(basic_string<T, Allocator>& a, basic_string<T, Allocator>& b)
@@ -4060,7 +4221,12 @@ namespace eastl
/// http://en.cppreference.com/w/cpp/string/basic_string/operator%22%22s
///
#if EASTL_USER_LITERALS_ENABLED && EASTL_INLINE_NAMESPACES_ENABLED
- EA_DISABLE_VC_WARNING(4455) // disable warning C4455: literal suffix identifiers that do not start with an underscore are reserved
+ // Disabling the Clang/GCC/MSVC warning about using user
+ // defined literals without a leading '_' as they are reserved
+ // for standard libary usage.
+ EA_DISABLE_VC_WARNING(4455)
+ EA_DISABLE_CLANG_WARNING(-Wuser-defined-literals)
+ EA_DISABLE_GCC_WARNING(-Wliteral-suffix)
inline namespace literals
{
inline namespace string_literals
@@ -4076,7 +4242,9 @@ namespace eastl
#endif
}
}
- EA_RESTORE_VC_WARNING() // warning: 4455
+ EA_RESTORE_GCC_WARNING() // -Wliteral-suffix
+ EA_RESTORE_CLANG_WARNING() // -Wuser-defined-literals
+ EA_RESTORE_VC_WARNING() // warning: 4455
#endif
@@ -4084,17 +4252,40 @@ namespace eastl
///
/// https://en.cppreference.com/w/cpp/string/basic_string/erase2
template <class CharT, class Allocator, class U>
- void erase(basic_string<CharT, Allocator>& c, const U& value)
+ typename basic_string<CharT, Allocator>::size_type erase(basic_string<CharT, Allocator>& c, const U& value)
{
// Erases all elements that compare equal to value from the container.
- c.erase(eastl::remove(c.begin(), c.end(), value), c.end());
+ auto origEnd = c.end();
+ auto newEnd = eastl::remove(c.begin(), origEnd, value);
+ auto numRemoved = eastl::distance(newEnd, origEnd);
+ c.erase(newEnd, origEnd);
+
+ // Note: This is technically a lossy conversion when size_type
+ // is 32bits and ptrdiff_t is 64bits (could happen on 64bit
+ // systems when EASTL_SIZE_T_32BIT is set). In practice this
+ // is fine because if EASTL_SIZE_T_32BIT is set then the
+ // string should not have more characters than fit in a
+ // uint32_t and so the distance here should fit in a
+ // size_type.
+ return static_cast<typename basic_string<CharT, Allocator>::size_type>(numRemoved);
}
template <class CharT, class Allocator, class Predicate>
- void erase_if(basic_string<CharT, Allocator>& c, Predicate predicate)
+ typename basic_string<CharT, Allocator>::size_type erase_if(basic_string<CharT, Allocator>& c, Predicate predicate)
{
// Erases all elements that satisfy the predicate pred from the container.
- c.erase(eastl::remove_if(c.begin(), c.end(), predicate), c.end());
+ auto origEnd = c.end();
+ auto newEnd = eastl::remove_if(c.begin(), origEnd, predicate);
+ auto numRemoved = eastl::distance(newEnd, origEnd);
+ c.erase(newEnd, origEnd);
+ // Note: This is technically a lossy conversion when size_type
+ // is 32bits and ptrdiff_t is 64bits (could happen on 64bit
+ // systems when EASTL_SIZE_T_32BIT is set). In practice this
+ // is fine because if EASTL_SIZE_T_32BIT is set then the
+ // string should not have more characters than fit in a
+ // uint32_t and so the distance here should fit in a
+ // size_type.
+ return static_cast<typename basic_string<CharT, Allocator>::size_type>(numRemoved);
}
} // namespace eastl
diff --git a/EASTL/include/EASTL/string_view.h b/EASTL/include/EASTL/string_view.h
index 54452a3..f600e50 100644
--- a/EASTL/include/EASTL/string_view.h
+++ b/EASTL/include/EASTL/string_view.h
@@ -451,64 +451,268 @@ namespace eastl
// global operators
+ // Disabling symmetric comparisons that require conversions, since they are causing an internal compiler error
+ // when compiled using MSVC when certain flags are enabled (/Zi /O2 /Zc:inline)
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator==(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return (lhs.size() == rhs.size()) && (lhs.compare(rhs) == 0);
+ // }
+ //
+ // // type_identity_t is used in this context to forcefully trigger conversion operators towards basic_string_view.
+ // // Mostly we want basic_string::operator basic_string_view() to kick-in to be able to compare strings and string_views.
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator==(type_identity_t<basic_string_view<CharT>> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return (lhs.size() == rhs.size()) && (lhs.compare(rhs) == 0);
+ // }
+
template <class CharT>
- inline EA_CONSTEXPR bool operator==(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ inline EA_CONSTEXPR bool operator==(basic_string_view<CharT> lhs, type_identity_t<basic_string_view<CharT>> rhs) EA_NOEXCEPT
{
return (lhs.size() == rhs.size()) && (lhs.compare(rhs) == 0);
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <class CharT>
- inline EA_CONSTEXPR bool operator==(decay_t<basic_string_view<CharT>> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ inline EA_CONSTEXPR auto operator<=>(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
{
- return (lhs.size() == rhs.size()) && (lhs.compare(rhs) == 0);
+ return static_cast<std::weak_ordering>(lhs.compare(rhs) <=> 0);
}
template <class CharT>
- inline EA_CONSTEXPR bool operator==(basic_string_view<CharT> lhs, decay_t<basic_string_view<CharT>> rhs) EA_NOEXCEPT
+ inline EA_CONSTEXPR auto operator<=>(basic_string_view<CharT> lhs, typename basic_string_view<CharT>::const_pointer rhs) EA_NOEXCEPT
{
- return (lhs.size() == rhs.size()) && (lhs.compare(rhs) == 0);
+ typedef basic_string_view<CharT> view_type;
+ return static_cast<std::weak_ordering>(lhs <=> static_cast<view_type>(rhs));
}
+#else
template <class CharT>
- inline EA_CONSTEXPR bool operator==(decay_t<basic_string_view<CharT>> lhs, decay_t<basic_string_view<CharT>> rhs) EA_NOEXCEPT
+ inline EA_CONSTEXPR bool operator==(typename basic_string_view<CharT>::const_pointer lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
{
- return (lhs.size() == rhs.size()) && (lhs.compare(rhs) == 0);
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ typedef basic_string_view<CharT> view_type;
+ return static_cast<view_type>(lhs) == rhs;
+ }
+
+ template <class CharT>
+ inline EA_CONSTEXPR bool operator==(basic_string_view<CharT> lhs, typename basic_string_view<CharT>::const_pointer rhs) EA_NOEXCEPT
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ typedef basic_string_view<CharT> view_type;
+ return lhs == static_cast<view_type>(rhs);
}
+ // Disabling symmetric comparisons that require conversions, since they are causing an internal compiler error
+ // when compiled using MSVC when certain flags are enabled (/Zi /O2 /Zc:inline)
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator!=(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return !(lhs == rhs);
+ // }
+ //
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator!=(type_identity_t<basic_string_view<CharT>> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return !(lhs == rhs);
+ // }
+ template <class CharT>
+ inline EA_CONSTEXPR bool operator!=(basic_string_view<CharT> lhs, type_identity_t<basic_string_view<CharT>> rhs) EA_NOEXCEPT
+ {
+ return !(lhs == rhs);
+ }
+ template <class CharT>
+ inline EA_CONSTEXPR bool operator!=(typename basic_string_view<CharT>::const_pointer lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ return !(lhs == rhs);
+ }
template <class CharT>
- inline EA_CONSTEXPR bool operator!=(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ inline EA_CONSTEXPR bool operator!=(basic_string_view<CharT> lhs, typename basic_string_view<CharT>::const_pointer rhs) EA_NOEXCEPT
{
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
return !(lhs == rhs);
}
+ // Disabling symmetric comparisons that require conversions, since they are causing an internal compiler error
+ // when compiled using MSVC when certain flags are enabled (/Zi /O2 /Zc:inline)
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator<(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return lhs.compare(rhs) < 0;
+ // }
+ //
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator<(type_identity_t<basic_string_view<CharT>> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return lhs.compare(rhs) < 0;
+ // }
+
template <class CharT>
- inline EA_CONSTEXPR bool operator<(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ inline EA_CONSTEXPR bool operator<(basic_string_view<CharT> lhs, type_identity_t<basic_string_view<CharT>> rhs) EA_NOEXCEPT
{
return lhs.compare(rhs) < 0;
}
template <class CharT>
- inline EA_CONSTEXPR bool operator<=(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ inline EA_CONSTEXPR bool operator<(typename basic_string_view<CharT>::const_pointer lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ typedef basic_string_view<CharT> view_type;
+ return static_cast<view_type>(lhs) < rhs;
+ }
+
+ template <class CharT>
+ inline EA_CONSTEXPR bool operator<(basic_string_view<CharT> lhs, typename basic_string_view<CharT>::const_pointer rhs) EA_NOEXCEPT
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ typedef basic_string_view<CharT> view_type;
+ return lhs < static_cast<view_type>(rhs);
+ }
+
+ // Disabling symmetric comparisons that require conversions, since they are causing an internal compiler error
+ // when compiled using MSVC when certain flags are enabled (/Zi /O2 /Zc:inline)
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator<=(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return !(rhs < lhs);
+ // }
+ //
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator<=(type_identity_t<basic_string_view<CharT>> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return !(rhs < lhs);
+ // }
+
+ template <class CharT>
+ inline EA_CONSTEXPR bool operator<=(basic_string_view<CharT> lhs, type_identity_t<basic_string_view<CharT>> rhs) EA_NOEXCEPT
+ {
+ return !(rhs < lhs);
+ }
+
+ template <class CharT>
+ inline EA_CONSTEXPR bool operator<=(typename basic_string_view<CharT>::const_pointer lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
{
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
return !(rhs < lhs);
}
template <class CharT>
- inline EA_CONSTEXPR bool operator>(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ inline EA_CONSTEXPR bool operator<=(basic_string_view<CharT> lhs, typename basic_string_view<CharT>::const_pointer rhs) EA_NOEXCEPT
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ return !(rhs < lhs);
+ }
+
+ // Disabling symmetric comparisons that require conversions, since they are causing an internal compiler error
+ // when compiled using MSVC when certain flags are enabled (/Zi /O2 /Zc:inline)
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator>(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return rhs < lhs;
+ // }
+ //
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator>(type_identity_t<basic_string_view<CharT>> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return rhs < lhs;
+ // }
+
+ template <class CharT>
+ inline EA_CONSTEXPR bool operator>(basic_string_view<CharT> lhs, type_identity_t<basic_string_view<CharT>> rhs) EA_NOEXCEPT
+ {
+ return rhs < lhs;
+ }
+
+ template <class CharT>
+ inline EA_CONSTEXPR bool operator>(typename basic_string_view<CharT>::const_pointer lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ return rhs < lhs;
+ }
+
+ template <class CharT>
+ inline EA_CONSTEXPR bool operator>(basic_string_view<CharT> lhs, typename basic_string_view<CharT>::const_pointer rhs) EA_NOEXCEPT
{
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
return rhs < lhs;
}
+ // Disabling symmetric comparisons that require conversions, since they are causing an internal compiler error
+ // when compiled using MSVC when certain flags are enabled (/Zi /O2 /Zc:inline)
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator>=(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return !(lhs < rhs);
+ // }
+ //
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator>=(type_identity_t<basic_string_view<CharT>> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return !(lhs < rhs);
+ // }
+
+ template <class CharT>
+ inline EA_CONSTEXPR bool operator>=(basic_string_view<CharT> lhs, type_identity_t<basic_string_view<CharT>> rhs) EA_NOEXCEPT
+ {
+ return !(lhs < rhs);
+ }
+
template <class CharT>
- inline EA_CONSTEXPR bool operator>=(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ inline EA_CONSTEXPR bool operator>=(typename basic_string_view<CharT>::const_pointer lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
{
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
return !(lhs < rhs);
}
- // string_view / wstring_view
+ template <class CharT>
+ inline EA_CONSTEXPR bool operator>=(basic_string_view<CharT> lhs, typename basic_string_view<CharT>::const_pointer rhs) EA_NOEXCEPT
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ return !(lhs < rhs);
+ }
+#endif
+ // string_view / wstring_view
typedef basic_string_view<char> string_view;
typedef basic_string_view<wchar_t> wstring_view;
@@ -599,7 +803,13 @@ namespace eastl
#if EASTL_USER_LITERALS_ENABLED && EASTL_INLINE_NAMESPACES_ENABLED
- EA_DISABLE_VC_WARNING(4455) // disable warning C4455: literal suffix identifiers that do not start with an underscore are reserved
+ // Disabling the Clang/GCC/MSVC warning about using user
+ // defined literals without a leading '_' as they are reserved
+ // for standard libary usage.
+ EA_DISABLE_VC_WARNING(4455)
+ EA_DISABLE_CLANG_WARNING(-Wuser-defined-literals)
+ EA_DISABLE_GCC_WARNING(-Wliteral-suffix)
+
inline namespace literals
{
inline namespace string_view_literals
@@ -609,11 +819,16 @@ namespace eastl
EA_CONSTEXPR inline u32string_view operator "" sv(const char32_t* str, size_t len) EA_NOEXCEPT { return {str, len}; }
EA_CONSTEXPR inline wstring_view operator "" sv(const wchar_t* str, size_t len) EA_NOEXCEPT { return {str, len}; }
+ // We've seen _sv trigger the following warning on clang:
+ // identifier '_sv' is reserved because it starts with '_' at global scope [-Wreserved-identifier]
+ // Temporarily disable the warning until we figure out why it thinks _sv is "at global scope".
+ EA_DISABLE_CLANG_WARNING(-Wreserved-identifier)
// Backwards compatibility.
EA_CONSTEXPR inline string_view operator "" _sv(const char* str, size_t len) EA_NOEXCEPT { return {str, len}; }
EA_CONSTEXPR inline u16string_view operator "" _sv(const char16_t* str, size_t len) EA_NOEXCEPT { return {str, len}; }
EA_CONSTEXPR inline u32string_view operator "" _sv(const char32_t* str, size_t len) EA_NOEXCEPT { return {str, len}; }
EA_CONSTEXPR inline wstring_view operator "" _sv(const wchar_t* str, size_t len) EA_NOEXCEPT { return {str, len}; }
+ EA_RESTORE_CLANG_WARNING() // -Wreserved-identifier
// C++20 char8_t support.
#if EA_CHAR8_UNIQUE
@@ -622,7 +837,10 @@ namespace eastl
#endif
}
}
- EA_RESTORE_VC_WARNING() // warning: 4455
+
+ EA_RESTORE_GCC_WARNING() // -Wliteral-suffix
+ EA_RESTORE_CLANG_WARNING() // -Wuser-defined-literals
+ EA_RESTORE_VC_WARNING() // warning: 4455
#endif
} // namespace eastl
diff --git a/EASTL/include/EASTL/tuple.h b/EASTL/include/EASTL/tuple.h
index cec5115..12460c6 100644
--- a/EASTL/include/EASTL/tuple.h
+++ b/EASTL/include/EASTL/tuple.h
@@ -6,6 +6,7 @@
#define EASTL_TUPLE_H
#include <EASTL/internal/config.h>
+#include <EASTL/compare.h>
#include <EASTL/functional.h>
#include <EASTL/type_traits.h>
#include <EASTL/utility.h>
@@ -199,7 +200,7 @@ namespace Internal
// We shouldn't need this explicit constructor as it should be handled by the template below but OSX clang
// is_constructible type trait incorrectly gives false for is_constructible<T&&, T&&>::value
- explicit TupleLeaf(ValueType&& v) : mValue(eastl::move(v)) {}
+ explicit TupleLeaf(ValueType&& v) : mValue(eastl::forward<ValueType>(v)) {}
template <typename T, typename = typename enable_if<is_constructible<ValueType, T&&>::value>::type>
explicit TupleLeaf(T&& t)
@@ -233,50 +234,6 @@ namespace Internal
ValueType mValue;
};
- // TupleLeaf: Specialize for when ValueType is a reference
- template <size_t I, typename ValueType, bool IsEmpty>
- class TupleLeaf<I, ValueType&, IsEmpty>
- {
- public:
- TupleLeaf(const TupleLeaf&) = default;
- TupleLeaf& operator=(const TupleLeaf&) = delete;
-
- template <typename T, typename = typename enable_if<is_constructible<ValueType, T&&>::value>::type>
- explicit TupleLeaf(T&& t)
- : mValue(eastl::forward<T>(t))
- {
- }
-
- explicit TupleLeaf(ValueType& t) : mValue(t)
- {
- }
-
- template <typename T>
- explicit TupleLeaf(const TupleLeaf<I, T>& t)
- : mValue(t.getInternal())
- {
- }
-
- template <typename T>
- TupleLeaf& operator=(T&& t)
- {
- mValue = eastl::forward<T>(t);
- return *this;
- }
-
- int swap(TupleLeaf& t)
- {
- eastl::Internal::swap(*this, t);
- return 0;
- }
-
- ValueType& getInternal() { return mValue; }
- const ValueType& getInternal() const { return mValue; }
-
- private:
- ValueType& mValue;
- };
-
// TupleLeaf: partial specialization for when we can use the Empty Base Class Optimization
template <size_t I, typename ValueType>
class TupleLeaf<I, ValueType, true> : private ValueType
@@ -609,7 +566,6 @@ namespace Internal
}
};
-
// TupleLess
//
//
@@ -718,6 +674,16 @@ namespace Internal
return TC2::DoCat2(eastl::forward<TupleArg1>(t1), eastl::forward<TupleArg2>(t2));
}
};
+
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename... T1s, typename... T2s, size_t... Is>
+ constexpr auto TupleThreeWay(const tuple<T1s...>& t1, const tuple<T2s...>& t2, index_sequence<Is...> is)
+ {
+ std::common_comparison_category_t<synth_three_way_result<T1s, T2s>...> result = std::strong_ordering::equal;
+ ((result = synth_three_way{}(get<Is>(t1), get<Is>(t2)), result != 0) || ...);
+ return result;
+ }
+#endif
} // namespace Internal
@@ -868,6 +834,13 @@ inline bool operator==(const tuple<T1s...>& t1, const tuple<T2s...>& t2)
return Internal::TupleEqual<sizeof...(T1s)>()(t1, t2);
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+template <typename... T1s, typename... T2s>
+inline constexpr std::common_comparison_category_t<synth_three_way_result<T1s, T2s>...> operator<=>(const tuple<T1s...>& t1, const tuple<T2s...>& t2)
+{
+ return Internal::TupleThreeWay(t1, t2, make_index_sequence<sizeof...(T1s)>{});
+}
+#else
template <typename... T1s, typename... T2s>
inline bool operator<(const tuple<T1s...>& t1, const tuple<T2s...>& t2)
{
@@ -878,7 +851,7 @@ template <typename... T1s, typename... T2s> inline bool operator!=(const tuple<T
template <typename... T1s, typename... T2s> inline bool operator> (const tuple<T1s...>& t1, const tuple<T2s...>& t2) { return t2 < t1; }
template <typename... T1s, typename... T2s> inline bool operator<=(const tuple<T1s...>& t1, const tuple<T2s...>& t2) { return !(t2 < t1); }
template <typename... T1s, typename... T2s> inline bool operator>=(const tuple<T1s...>& t1, const tuple<T2s...>& t2) { return !(t1 < t2); }
-
+#endif
// tuple_cat
//
diff --git a/EASTL/include/EASTL/type_traits.h b/EASTL/include/EASTL/type_traits.h
index 2cf5d7a..73d2216 100644
--- a/EASTL/include/EASTL/type_traits.h
+++ b/EASTL/include/EASTL/type_traits.h
@@ -93,6 +93,8 @@
// is_abstract T is an abstract class.
// is_signed T is a signed integral type.
// is_unsigned T is an unsigned integral type.
+// is_bounded_array T is a type is an array type of known bound
+// is_unbounded_array T is a type is an array type of unknown bound
//
// is_constructible
// is_trivially_constructible
@@ -131,6 +133,7 @@
// remove_cv
// remove_const The member typedef type shall be the same as T except that any top level const-qualifier has been removed. remove_const<const volatile int>::type evaluates to volatile int, whereas remove_const<const int*> is const int*.
// remove_volatile
+// remove_cvref
// add_cv
// add_const
// add_volatile
@@ -177,6 +180,12 @@
// is_nothrow_swappable "
// is_reference_wrapper Found in <EASTL/functional.h>
// remove_reference_wrapper "
+// is_detected Checks if some supplied arguments (Args) respect a constraint (Op).
+// detected_t Check which type we obtain after expanding some arguments (Args) over a constraint (Op).
+// detected_or Checks if some supplied arguments (Args) respect a constraint (Op) and allow to overwrite return type.
+// detected_or_t Equivalent to detected_or<Default, Op, Args...>::type.
+// is_detected_exact Check that the type we obtain after expanding some arguments (Args) over a constraint (Op) is equivalent to Expected.
+// is_detected_convertible Check that the type we obtain after expanding some arguments (Args) over a constraint (Op) is convertible to Expected.
//
// Deprecated pre-C++11 type traits
// has_trivial_constructor The default constructor for T is trivial.
@@ -621,12 +630,8 @@ namespace eastl
#define EASTL_TYPE_TRAIT_is_const_CONFORMANCE 1 // is_const is conforming.
- template <typename T> struct is_const_value : public eastl::false_type{};
- template <typename T> struct is_const_value<const T*> : public eastl::true_type{};
- template <typename T> struct is_const_value<const volatile T*> : public eastl::true_type{};
-
- template <typename T> struct is_const : public eastl::is_const_value<T*>{};
- template <typename T> struct is_const<T&> : public eastl::false_type{}; // Note here that T is const, not the reference to T. So is_const is false. See section 8.3.2p1 of the C++ standard.
+ template <typename T> struct is_const : public eastl::false_type {};
+ template <typename T> struct is_const<const T> : public eastl::true_type {};
#if EASTL_VARIABLE_TEMPLATES_ENABLED
template <class T>
@@ -643,12 +648,8 @@ namespace eastl
#define EASTL_TYPE_TRAIT_is_volatile_CONFORMANCE 1 // is_volatile is conforming.
- template <typename T> struct is_volatile_value : public eastl::false_type{};
- template <typename T> struct is_volatile_value<volatile T*> : public eastl::true_type{};
- template <typename T> struct is_volatile_value<const volatile T*> : public eastl::true_type{};
-
- template <typename T> struct is_volatile : public eastl::is_volatile_value<T*>{};
- template <typename T> struct is_volatile<T&> : public eastl::false_type{}; // Note here that T is volatile, not the reference to T. So is_const is false. See section 8.3.2p1 of the C++ standard.
+ template <typename T> struct is_volatile : public eastl::false_type {};
+ template <typename T> struct is_volatile<volatile T> : public eastl::true_type {};
#if EASTL_VARIABLE_TEMPLATES_ENABLED
template <class T>
@@ -686,39 +687,21 @@ namespace eastl
#define EASTL_TYPE_TRAIT_is_function_CONFORMANCE 1 // is_function is conforming.
- template <typename>
+ // afaik, original credit is to Walter Brown who described this implementation at CppCon 2019.
+ // libc++, libstdc++ and MS STL all use similar implementations.
+ // This relies on the fact that only function and reference types can't be const qualified.
+ // Rather than listing an obscene number of specializations for const, volatile, l- and r-value reference,
+ // noexcept and all relevant combinations we take advantage of this fact.
+#ifdef _MSC_VER
+ #pragma warning(push)
+ #pragma warning(disable: 4180) // qualifier applied to function type has no meaning; ignored
+#endif
+ template <typename T>
struct is_function
- : public eastl::false_type {};
-
- #if EA_PLATFORM_PTR_SIZE == 4 && defined(EA_PLATFORM_MICROSOFT) && defined(_MSC_EXTENSIONS)
- // __cdecl specialization
- template <typename ReturnValue, typename... ArgPack>
- struct is_function<ReturnValue __cdecl (ArgPack...)>
- : public eastl::true_type {};
-
- template <typename ReturnValue, typename... ArgPack>
- struct is_function<ReturnValue __cdecl (ArgPack..., ...)> // The second ellipsis handles the case of a function that takes ellipsis, like printf.
- : public eastl::true_type {};
-
- // __stdcall specialization
- template <typename ReturnValue, typename... ArgPack>
- struct is_function<ReturnValue __stdcall (ArgPack...)>
- : public eastl::true_type {};
-
- // When functions use a variable number of arguments, it is the caller that cleans the stack (cf. cdecl).
- //
- // template <typename ReturnValue, typename... ArgPack>
- // struct is_function<ReturnValue __stdcall (ArgPack..., ...)> // The second ellipsis handles the case of a function that takes ellipsis, like printf.
- // : public eastl::true_type {};
- #else
- template <typename ReturnValue, typename... ArgPack>
- struct is_function<ReturnValue (ArgPack...)>
- : public eastl::true_type {};
-
- template <typename ReturnValue, typename... ArgPack>
- struct is_function<ReturnValue (ArgPack..., ...)> // The second ellipsis handles the case of a function that takes ellipsis, like printf.
- : public eastl::true_type {};
- #endif
+ : public eastl::bool_constant<!eastl::is_reference<T>::value && !eastl::is_const<const T>::value>::type {};
+#ifdef _MSC_VER
+ #pragma warning(pop)
+#endif
#if EASTL_VARIABLE_TEMPLATES_ENABLED
template<typename T>
@@ -900,12 +883,16 @@ namespace eastl
#define EASTL_TYPE_TRAIT_add_lvalue_reference_CONFORMANCE 1 // add_lvalue_reference is conforming.
- template <typename T> struct add_lvalue_reference { typedef T& type; }; // If T is an && type then T&& & will be equivalent to T&.
- template <typename T> struct add_lvalue_reference<T&> { typedef T& type; }; // This shouldn't be required for modern compilers, as they recognize that a reference to a reference is still a reference.
- template <> struct add_lvalue_reference<void> { typedef void type; };
- template <> struct add_lvalue_reference<const void> { typedef const void type; };
- template <> struct add_lvalue_reference<volatile void> { typedef volatile void type; };
- template <> struct add_lvalue_reference<const volatile void> { typedef const volatile void type; };
+ namespace internal
+ {
+ template <typename T>
+ auto try_add_lvalue_reference(int)->type_identity<T&>;
+
+ template <typename T>
+ auto try_add_lvalue_reference(...)->type_identity<T>;
+ }
+
+ template <typename T> struct add_lvalue_reference : decltype(internal::try_add_lvalue_reference<T>(0)) {};
#if defined(EA_COMPILER_NO_TEMPLATE_ALIASES)
// To do: define macro.
@@ -935,12 +922,16 @@ namespace eastl
#define EASTL_TYPE_TRAIT_add_rvalue_reference_CONFORMANCE 1
- template <typename T> struct add_rvalue_reference { typedef T&& type; }; // Dinkumware has this as { typedef typename eastl::remove_reference<T>::type&& type; }, but that doesn't seem right to me.
- template <typename T> struct add_rvalue_reference<T&> { typedef T& type; }; // The Standard section 20.7.9.2 specifies that we do this, though it seems like the compiler ought to not require this, as C++11 stipulates that & + && -> &.
- template <> struct add_rvalue_reference<void> { typedef void type; };
- template <> struct add_rvalue_reference<const void> { typedef const void type; };
- template <> struct add_rvalue_reference<volatile void> { typedef volatile void type; };
- template <> struct add_rvalue_reference<const volatile void> { typedef const volatile void type; };
+ namespace internal
+ {
+ template <typename T>
+ auto try_add_rvalue_reference(int)->type_identity<T&&>;
+
+ template <typename T>
+ auto try_add_rvalue_reference(...)->type_identity<T>;
+ }
+
+ template <typename T> struct add_rvalue_reference : decltype(internal::try_add_rvalue_reference<T>(0)) {};
#if defined(EA_COMPILER_NO_TEMPLATE_ALIASES)
// To do: define macro.
@@ -1040,9 +1031,11 @@ namespace eastl
// The following files implement the type traits themselves.
#include <EASTL/internal/type_fundamental.h>
#include <EASTL/internal/type_transformations.h>
+#include <EASTL/internal/type_void_t.h>
#include <EASTL/internal/type_properties.h>
#include <EASTL/internal/type_compound.h>
#include <EASTL/internal/type_pod.h>
+#include <EASTL/internal/type_detected.h>
#endif // Header include guard
diff --git a/EASTL/include/EASTL/unique_ptr.h b/EASTL/include/EASTL/unique_ptr.h
index c5d2480..195cc42 100644
--- a/EASTL/include/EASTL/unique_ptr.h
+++ b/EASTL/include/EASTL/unique_ptr.h
@@ -536,27 +536,12 @@ namespace eastl
///
/// auto pArray = make_unique<Test[]>(4);
///
- namespace Internal
- {
- template <typename T>
- struct unique_type
- { typedef unique_ptr<T> unique_type_single; };
-
- template <typename T>
- struct unique_type<T[]>
- { typedef unique_ptr<T[]> unique_type_unbounded_array; };
-
- template <typename T, size_t N>
- struct unique_type<T[N]>
- { typedef void unique_type_bounded_array; };
- }
-
template <typename T, typename... Args>
- inline typename Internal::unique_type<T>::unique_type_single make_unique(Args&&... args)
+ inline typename eastl::enable_if<!eastl::is_array<T>::value, eastl::unique_ptr<T>>::type make_unique(Args&&... args)
{ return unique_ptr<T>(new T(eastl::forward<Args>(args)...)); }
template <typename T>
- inline typename Internal::unique_type<T>::unique_type_unbounded_array make_unique(size_t n)
+ inline typename eastl::enable_if<eastl::is_unbounded_array<T>::value, eastl::unique_ptr<T>>::type make_unique(size_t n)
{
typedef typename eastl::remove_extent<T>::type TBase;
return unique_ptr<T>(new TBase[n]);
@@ -564,7 +549,7 @@ namespace eastl
// It's not possible to create a unique_ptr for arrays of a known bound (e.g. int[4] as opposed to int[]).
template <typename T, typename... Args>
- typename Internal::unique_type<T>::unique_type_bounded_array
+ typename eastl::enable_if<eastl::is_bounded_array<T>::value>::type
make_unique(Args&&...) = delete;
@@ -596,12 +581,20 @@ namespace eastl
{
return (a.get() == b.get());
}
-
+ #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T1, typename D1, typename T2, typename D2>
+ requires std::three_way_comparable_with<typename unique_ptr<T1, D1>::pointer, typename unique_ptr<T2, D2>::pointer>
+ inline std::compare_three_way_result_t<typename unique_ptr<T1, D1>::pointer, typename unique_ptr<T2, D2>::pointer> operator<=>(const unique_ptr<T1, D1>& a, const unique_ptr<T2, D2>& b)
+ {
+ return a.get() <=> b.get();
+ }
+ #else
template <typename T1, typename D1, typename T2, typename D2>
inline bool operator!=(const unique_ptr<T1, D1>& a, const unique_ptr<T2, D2>& b)
{
return !(a.get() == b.get());
}
+ #endif
/// Returns which unique_ptr is 'less' than the other. Useful when storing
/// sorted containers of unique_ptr objects.
@@ -646,6 +639,14 @@ namespace eastl
return !a;
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T, typename D>
+ requires std::three_way_comparable_with<typename unique_ptr<T, D>::pointer, std::nullptr_t>
+ inline std::compare_three_way_result_t<typename unique_ptr<T, D>::pointer, std::nullptr_t> operator<=>(const unique_ptr<T, D>& a, std::nullptr_t)
+ {
+ return a.get() <=> nullptr;
+ }
+#else
template <typename T, typename D>
inline bool operator==(std::nullptr_t, const unique_ptr<T, D>& a) EA_NOEXCEPT
{
@@ -663,6 +664,7 @@ namespace eastl
{
return static_cast<bool>(a);
}
+#endif
template <typename T, typename D>
inline bool operator<(const unique_ptr<T, D>& a, std::nullptr_t)
diff --git a/EASTL/include/EASTL/utility.h b/EASTL/include/EASTL/utility.h
index a91ce8c..1e6b922 100644
--- a/EASTL/include/EASTL/utility.h
+++ b/EASTL/include/EASTL/utility.h
@@ -10,6 +10,8 @@
#include <EASTL/internal/config.h>
#include <EASTL/type_traits.h>
#include <EASTL/iterator.h>
+#include <EASTL/numeric_limits.h>
+#include <EASTL/compare.h>
#include <EASTL/internal/functional_base.h>
#include <EASTL/internal/move_help.h>
#include <EABase/eahave.h>
@@ -352,6 +354,90 @@ namespace eastl
}
+ #if defined(EA_COMPILER_CPP20_ENABLED)
+ ///////////////////////////////////////////////////////////////////////
+ /// Safe Integral Comparisons
+ ///
+ template <typename T, typename U>
+ EA_CONSTEXPR bool cmp_equal(const T x, const U y) EA_NOEXCEPT
+ {
+ // Assert types are not chars, bools, etc.
+ static_assert(eastl::is_integral_v<T> && !eastl::is_same_v<eastl::remove_cv_t<T>, bool> && !eastl::is_same_v<eastl::remove_cv_t<T>, char>);
+ static_assert(eastl::is_integral_v<U> && !eastl::is_same_v<eastl::remove_cv_t<U>, bool> && !eastl::is_same_v<eastl::remove_cv_t<U>, char>);
+
+ using UT = eastl::make_unsigned_t<T>;
+ using UU = eastl::make_unsigned_t<U>;
+
+ if constexpr (eastl::is_signed_v<T> == eastl::is_signed_v<U>)
+ {
+ return x == y;
+ }
+ else if (eastl::is_signed_v<T>)
+ {
+ return (x < 0) ? false : UT(x) == y;
+ }
+ else
+ {
+ return (y < 0) ? false : x == UU(y);
+ }
+ }
+
+
+ template <typename T, typename U>
+ EA_CONSTEXPR bool cmp_not_equal(const T x, const U y) EA_NOEXCEPT
+ { return !eastl::cmp_equal(x, y); }
+
+
+ template <typename T, typename U>
+ EA_CONSTEXPR bool cmp_less(const T x, const U y) EA_NOEXCEPT
+ {
+ static_assert(eastl::is_integral_v<T> && !eastl::is_same_v<eastl::remove_cv_t<T>, bool> && !eastl::is_same_v<eastl::remove_cv_t<T>, char>);
+ static_assert(eastl::is_integral_v<U> && !eastl::is_same_v<eastl::remove_cv_t<U>, bool> && !eastl::is_same_v<eastl::remove_cv_t<U>, char>);
+
+ using UT = eastl::make_unsigned_t<T>;
+ using UU = eastl::make_unsigned_t<U>;
+
+ if constexpr (eastl::is_signed_v<T> == eastl::is_signed_v<U>)
+ {
+ return x < y;
+ }
+ else if (eastl::is_signed_v<T>)
+ {
+ return (x < 0) ? true : UT(x) < y;
+ }
+ else
+ {
+ return (y < 0) ? false : x < UU(y);
+ }
+ }
+
+
+ template <typename T, typename U>
+ EA_CONSTEXPR bool cmp_greater(const T x, const U y) EA_NOEXCEPT
+ { return eastl::cmp_less(y, x); }
+
+
+ template <typename T, typename U>
+ EA_CONSTEXPR bool cmp_less_equal(const T x, const U y) EA_NOEXCEPT
+ { return !eastl::cmp_greater(x, y); }
+
+
+ template <typename T, typename U>
+ EA_CONSTEXPR bool cmp_greater_equal(const T x, const U y) EA_NOEXCEPT
+ { return !eastl::cmp_less(x, y); }
+
+
+ template <typename T, typename U>
+ EA_CONSTEXPR bool in_range(const U x) EA_NOEXCEPT
+ {
+ static_assert(eastl::is_integral_v<T> && !eastl::is_same_v<eastl::remove_cv_t<T>, bool> && !eastl::is_same_v<eastl::remove_cv_t<T>, char>);
+ static_assert(eastl::is_integral_v<U> && !eastl::is_same_v<eastl::remove_cv_t<U>, bool> && !eastl::is_same_v<eastl::remove_cv_t<U>, char>);
+
+ return eastl::cmp_greater_equal(x, eastl::numeric_limits<T>::min()) && eastl::cmp_less_equal(x, eastl::numeric_limits<T>::max());
+ }
+ #endif
+
+
///////////////////////////////////////////////////////////////////////
/// pair_first_construct
///
@@ -360,7 +446,7 @@ namespace eastl
struct pair_first_construct_t {};
EA_CONSTEXPR pair_first_construct_t pair_first_construct = pair_first_construct_t();
-
+
///////////////////////////////////////////////////////////////////////
/// pair
///
@@ -630,7 +716,17 @@ namespace eastl
return ((a.first == b.first) && (a.second == b.second));
}
-
+ #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T1, typename T2>
+ EA_CONSTEXPR inline std::common_comparison_category_t<synth_three_way_result<T1>, synth_three_way_result<T2>> operator<=>(const pair<T1, T2>& a, const pair<T1, T2>& b)
+ {
+ if (auto result = synth_three_way{}(a.first, b.first); result != 0)
+ {
+ return result;
+ }
+ return synth_three_way{}(a.second, b.second);
+ }
+ #else
template <typename T1, typename T2>
EA_CPP14_CONSTEXPR inline bool operator<(const pair<T1, T2>& a, const pair<T1, T2>& b)
{
@@ -668,7 +764,7 @@ namespace eastl
{
return !(b < a);
}
-
+ #endif
diff --git a/EASTL/include/EASTL/variant.h b/EASTL/include/EASTL/variant.h
index 6e77928..a7af97b 100644
--- a/EASTL/include/EASTL/variant.h
+++ b/EASTL/include/EASTL/variant.h
@@ -224,11 +224,15 @@ namespace eastl
struct monostate {};
// 20.7.8, monostate relational operators
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ EA_CONSTEXPR std::strong_ordering operator<=>(monostate, monostate) EA_NOEXCEPT { return std::strong_ordering::equal; }
+#else
EA_CONSTEXPR bool operator> (monostate, monostate) EA_NOEXCEPT { return false; }
EA_CONSTEXPR bool operator< (monostate, monostate) EA_NOEXCEPT { return false; }
EA_CONSTEXPR bool operator!=(monostate, monostate) EA_NOEXCEPT { return false; }
EA_CONSTEXPR bool operator<=(monostate, monostate) EA_NOEXCEPT { return true; }
EA_CONSTEXPR bool operator>=(monostate, monostate) EA_NOEXCEPT { return true; }
+#endif
EA_CONSTEXPR bool operator==(monostate, monostate) EA_NOEXCEPT { return true; }
// 20.7.11, hash support
@@ -1434,7 +1438,6 @@ namespace eastl
//
struct variant_relational_comparison
{
-
template <typename Compare, size_t I, typename Variant>
static EA_CONSTEXPR bool invoke_relational_visitor(const Variant& lhs, const Variant& rhs)
{
@@ -1457,6 +1460,29 @@ namespace eastl
return call_index<Compare>(lhs, rhs, eastl::make_index_sequence<eastl::variant_size_v<eastl::decay_t<Variant>>>());
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename Compare, size_t I, typename Variant>
+ static EA_CONSTEXPR std::compare_three_way_result_t<Variant> invoke_relational_visitor_three_way(const Variant& lhs, const Variant& rhs)
+ {
+ return eastl::invoke(Compare{}, eastl::get<I>(lhs), eastl::get<I>(rhs));
+ }
+
+ template <typename Compare, typename Variant, size_t... VariantArgIndices>
+ static EA_CONSTEXPR std::compare_three_way_result_t<Variant> call_index_three_way(const Variant& lhs, const Variant& rhs, eastl::index_sequence<VariantArgIndices...>)
+ {
+ using invoke_relational_visitor_func_ptr = std::compare_three_way_result_t<Variant> (*)(const Variant&, const Variant&);
+
+ EA_CONSTEXPR invoke_relational_visitor_func_ptr visitors[] = {static_cast<invoke_relational_visitor_func_ptr>(&invoke_relational_visitor_three_way<Compare, VariantArgIndices, Variant>)...};
+
+ return visitors[lhs.index()](lhs, rhs);
+ }
+
+ template <typename Compare, typename Variant>
+ static EA_CONSTEXPR std::compare_three_way_result_t<Variant> call_three_way(const Variant& lhs, const Variant& rhs)
+ {
+ return call_index_three_way<Compare>(lhs, rhs, eastl::make_index_sequence<eastl::variant_size_v<eastl::decay_t<Variant>>>());
+ }
+#endif
};
template <typename Compare, typename Variant>
@@ -1465,6 +1491,14 @@ namespace eastl
return variant_relational_comparison::call<Compare>(lhs, rhs);
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename Compare, typename Variant>
+ static EA_CONSTEXPR std::compare_three_way_result_t<Variant> CompareVariantRelationalThreeWay(const Variant& lhs, const Variant& rhs)
+ {
+ return variant_relational_comparison::call_three_way<Compare>(lhs, rhs);
+ }
+#endif
+
} // namespace internal
@@ -1533,6 +1567,20 @@ namespace eastl
return internal::CompareVariantRelational<eastl::greater_equal<>>(lhs, rhs);
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <class... Types> requires (std::three_way_comparable<Types> && ...)
+ EA_CONSTEXPR std::common_comparison_category_t<std::compare_three_way_result_t<Types>...> operator<=>(const variant<Types...>& lhs, const variant<Types...>& rhs)
+ {
+ if (lhs.valueless_by_exception() && rhs.valueless_by_exception()) return std::strong_ordering::equal;
+ if (lhs.valueless_by_exception()) return std::strong_ordering::less;
+ if (rhs.valueless_by_exception()) return std::strong_ordering::greater;
+ if (auto result = (lhs.index() <=> rhs.index()); result != 0) return result;
+
+ return internal::CompareVariantRelationalThreeWay<std::compare_three_way>(lhs, rhs);
+
+ }
+#endif
+
} // namespace eastl
EA_RESTORE_VC_WARNING()
diff --git a/EASTL/include/EASTL/vector.h b/EASTL/include/EASTL/vector.h
index 1736a78..b6ca8dc 100644
--- a/EASTL/include/EASTL/vector.h
+++ b/EASTL/include/EASTL/vector.h
@@ -1058,8 +1058,9 @@ namespace eastl
{
if(mpEnd == internalCapacityPtr())
{
- const size_type newSize = (size_type)(mpEnd - mpBegin) + 1;
- reserve(newSize);
+ const size_type nPrevSize = size_type(mpEnd - mpBegin);
+ const size_type nNewSize = GetNewCapacity(nPrevSize);
+ DoGrow(nNewSize);
}
return mpEnd++;
@@ -1982,7 +1983,13 @@ namespace eastl
return ((a.size() == b.size()) && eastl::equal(a.begin(), a.end(), b.begin()));
}
-
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T, typename Allocator>
+ inline synth_three_way_result<T> operator<=>(const vector<T, Allocator>& a, const vector<T, Allocator>& b)
+ {
+ return eastl::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end(), synth_three_way{});
+ }
+#else
template <typename T, typename Allocator>
inline bool operator!=(const vector<T, Allocator>& a, const vector<T, Allocator>& b)
{
@@ -2016,7 +2023,7 @@ namespace eastl
{
return !(a < b);
}
-
+#endif
template <typename T, typename Allocator>
inline void swap(vector<T, Allocator>& a, vector<T, Allocator>& b) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(a.swap(b)))
@@ -2032,17 +2039,39 @@ namespace eastl
// https://en.cppreference.com/w/cpp/container/vector/erase2
///////////////////////////////////////////////////////////////////////
template <class T, class Allocator, class U>
- void erase(vector<T, Allocator>& c, const U& value)
+ typename vector<T, Allocator>::size_type erase(vector<T, Allocator>& c, const U& value)
{
// Erases all elements that compare equal to value from the container.
- c.erase(eastl::remove(c.begin(), c.end(), value), c.end());
+ auto origEnd = c.end();
+ auto newEnd = eastl::remove(c.begin(), origEnd, value);
+ auto numRemoved = eastl::distance(newEnd, origEnd);
+ c.erase(newEnd, origEnd);
+
+ // Note: This is technically a lossy conversion when size_type
+ // is 32bits and ptrdiff_t is 64bits (could happen on 64bit
+ // systems when EASTL_SIZE_T_32BIT is set). In practice this
+ // is fine because if EASTL_SIZE_T_32BIT is set then the vector
+ // should not have more elements than fit in a uint32_t and so
+ // the distance here should fit in a size_type.
+ return static_cast<typename vector<T, Allocator>::size_type>(numRemoved);
}
template <class T, class Allocator, class Predicate>
- void erase_if(vector<T, Allocator>& c, Predicate predicate)
+ typename vector<T, Allocator>::size_type erase_if(vector<T, Allocator>& c, Predicate predicate)
{
// Erases all elements that satisfy the predicate pred from the container.
- c.erase(eastl::remove_if(c.begin(), c.end(), predicate), c.end());
+ auto origEnd = c.end();
+ auto newEnd = eastl::remove_if(c.begin(), origEnd, predicate);
+ auto numRemoved = eastl::distance(newEnd, origEnd);
+ c.erase(newEnd, origEnd);
+
+ // Note: This is technically a lossy conversion when size_type
+ // is 32bits and ptrdiff_t is 64bits (could happen on 64bit
+ // systems when EASTL_SIZE_T_32BIT is set). In practice this
+ // is fine because if EASTL_SIZE_T_32BIT is set then the vector
+ // should not have more elements than fit in a uint32_t and so
+ // the distance here should fit in a size_type.
+ return static_cast<typename vector<T, Allocator>::size_type>(numRemoved);
}
} // namespace eastl
diff --git a/EASTL/source/assert.cpp b/EASTL/source/assert.cpp
index a4734af..63b444a 100644
--- a/EASTL/source/assert.cpp
+++ b/EASTL/source/assert.cpp
@@ -7,7 +7,9 @@
#include <EASTL/string.h>
#include <EABase/eabase.h>
-#if defined(EA_PLATFORM_MICROSOFT)
+#if defined(EA_PLATFORM_WINDOWS_KERNEL)
+ #include <Wdm.h>
+#elif defined(EA_PLATFORM_MICROSOFT)
EA_DISABLE_ALL_VC_WARNINGS();
#if defined(EA_COMPILER_MSVC)
#include <crtdbg.h>
@@ -66,7 +68,9 @@ namespace eastl
EASTL_API void AssertionFailureFunctionDefault(const char* pExpression, void* /*pContext*/)
{
#if EASTL_ASSERT_ENABLED
- #if defined(EA_PLATFORM_MICROSOFT)
+ #if defined(EA_PLATFORM_WINDOWS_KERNEL)
+ DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "%s", pExpression);
+ #elif defined(EA_PLATFORM_MICROSOFT)
printf("%s\n", pExpression); // Write the message to stdout
if( ::IsDebuggerPresent())
{
diff --git a/EASTL/source/numeric_limits.cpp b/EASTL/source/numeric_limits.cpp
index 4eed54e..90b1d75 100644
--- a/EASTL/source/numeric_limits.cpp
+++ b/EASTL/source/numeric_limits.cpp
@@ -197,6 +197,32 @@
EA_CONSTEXPR_OR_CONST bool numeric_limits<wchar_t>::has_denorm_loss;
EA_CONSTEXPR_OR_CONST bool numeric_limits<wchar_t>::is_iec559;
+ // char8_t
+ #if defined(EA_CHAR8_UNIQUE) && EA_CHAR8_UNIQUE // If char8_t is a true unique type (as called for by the C++20 Standard)
+ EA_CONSTEXPR_OR_CONST bool numeric_limits<char8_t>::is_specialized;
+ EA_CONSTEXPR_OR_CONST int numeric_limits<char8_t>::digits;
+ EA_CONSTEXPR_OR_CONST int numeric_limits<char8_t>::digits10;
+ EA_CONSTEXPR_OR_CONST bool numeric_limits<char8_t>::is_signed;
+ EA_CONSTEXPR_OR_CONST bool numeric_limits<char8_t>::is_integer;
+ EA_CONSTEXPR_OR_CONST bool numeric_limits<char8_t>::is_exact;
+ EA_CONSTEXPR_OR_CONST int numeric_limits<char8_t>::radix;
+ EA_CONSTEXPR_OR_CONST int numeric_limits<char8_t>::min_exponent;
+ EA_CONSTEXPR_OR_CONST int numeric_limits<char8_t>::min_exponent10;
+ EA_CONSTEXPR_OR_CONST int numeric_limits<char8_t>::max_exponent;
+ EA_CONSTEXPR_OR_CONST int numeric_limits<char8_t>::max_exponent10;
+ EA_CONSTEXPR_OR_CONST bool numeric_limits<char8_t>::is_bounded;
+ EA_CONSTEXPR_OR_CONST bool numeric_limits<char8_t>::is_modulo;
+ EA_CONSTEXPR_OR_CONST bool numeric_limits<char8_t>::traps;
+ EA_CONSTEXPR_OR_CONST bool numeric_limits<char8_t>::tinyness_before;
+ EA_CONSTEXPR_OR_CONST float_round_style numeric_limits<char8_t>::round_style;
+ EA_CONSTEXPR_OR_CONST bool numeric_limits<char8_t>::has_infinity;
+ EA_CONSTEXPR_OR_CONST bool numeric_limits<char8_t>::has_quiet_NaN;
+ EA_CONSTEXPR_OR_CONST bool numeric_limits<char8_t>::has_signaling_NaN;
+ EA_CONSTEXPR_OR_CONST float_denorm_style numeric_limits<char8_t>::has_denorm;
+ EA_CONSTEXPR_OR_CONST bool numeric_limits<char8_t>::has_denorm_loss;
+ EA_CONSTEXPR_OR_CONST bool numeric_limits<char8_t>::is_iec559;
+ #endif
+
// char16_t
#if EA_CHAR16_NATIVE // If char16_t is a true unique type (as called for by the C++11 Standard)...
EA_CONSTEXPR_OR_CONST bool numeric_limits<char16_t>::is_specialized;
diff --git a/EASTL/test/CMakeLists.txt b/EASTL/test/CMakeLists.txt
index 3fac51f..ff16189 100644
--- a/EASTL/test/CMakeLists.txt
+++ b/EASTL/test/CMakeLists.txt
@@ -17,6 +17,9 @@ add_definitions(-D_SCL_SECURE_NO_WARNINGS)
add_definitions(-DEASTL_OPENSOURCE=1)
add_definitions(-D_CHAR16T)
add_definitions(-DEASTL_THREAD_SUPPORT_AVAILABLE=0)
+if (EASTL_STD_ITERATOR_CATEGORY_ENABLED)
+ add_definitions(-DEASTL_STD_ITERATOR_CATEGORY_ENABLED=1)
+endif()
#-------------------------------------------------------------------------------------------
# Compiler Flags
diff --git a/EASTL/test/source/EASTLTest.h b/EASTL/test/source/EASTLTest.h
index 1908f5f..fca6b2c 100644
--- a/EASTL/test/source/EASTLTest.h
+++ b/EASTL/test/source/EASTLTest.h
@@ -1261,6 +1261,8 @@ public:
activeAllocatedMemory = 0;
}
+ virtual ~CountingAllocator() = default;
+
static uint64_t activeAllocCount;
static uint64_t totalAllocCount;
static uint64_t totalDeallocCount;
diff --git a/EASTL/test/source/TestAlgorithm.cpp b/EASTL/test/source/TestAlgorithm.cpp
index 142d45e..a0f64da 100644
--- a/EASTL/test/source/TestAlgorithm.cpp
+++ b/EASTL/test/source/TestAlgorithm.cpp
@@ -1509,6 +1509,82 @@ int TestAlgorithm()
EATEST_VERIFY( b);
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ {
+ // <compairison_category> lexicographical_compare_three_way(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, Compare compare)
+
+ int intArray1[6] = {0, 1, 2, 3, 4, 5};
+ int intArray2[6] = {0, 1, 2, 3, 4, 6};
+ int intArray3[5] = {0, 1, 2, 3, 4};
+ int intArray4[5] = {4, 3, 2, 1, 0};
+
+ // strong ordering
+ auto compare_strong = [](int first, int second)
+ {
+ return (first < second) ? std::strong_ordering::less :
+ (first > second) ? std::strong_ordering::greater :
+ std::strong_ordering::equal;
+ };
+
+ auto b = lexicographical_compare_three_way(intArray1, intArray1 + 6, intArray2, intArray2 + 6, compare_strong);
+ EATEST_VERIFY(b == std::strong_ordering::less);
+ b = lexicographical_compare_three_way(intArray3, intArray3 + 5, intArray2, intArray2 + 6, compare_strong);
+ EATEST_VERIFY(b == std::strong_ordering::less);
+ b = lexicographical_compare_three_way(intArray3, intArray3 + 5, intArray2, intArray2 + 6, synth_three_way{});
+ EATEST_VERIFY(b == std::strong_ordering::less);
+
+ b = lexicographical_compare_three_way(intArray2, intArray2 + 6, intArray1, intArray1 + 6, compare_strong);
+ EATEST_VERIFY(b == std::strong_ordering::greater);
+ b = lexicographical_compare_three_way(intArray2, intArray2 + 6, intArray1, intArray1 + 6, synth_three_way{});
+ EATEST_VERIFY(b == std::strong_ordering::greater);
+
+ b = lexicographical_compare_three_way(intArray1, intArray1 + 6, intArray3, intArray3 + 5, compare_strong);
+ EATEST_VERIFY(b == std::strong_ordering::greater);
+ b = lexicographical_compare_three_way(intArray1, intArray1 + 6, intArray3, intArray3 + 5, synth_three_way{});
+ EATEST_VERIFY(b == std::strong_ordering::greater);
+
+ b = lexicographical_compare_three_way(intArray1, intArray1, intArray2, intArray2, compare_strong); // Test empty range.
+ EATEST_VERIFY(b == std::strong_ordering::equal);
+ b = lexicographical_compare_three_way(intArray1, intArray1, intArray2, intArray2, synth_three_way{}); // Test empty range.
+ EATEST_VERIFY(b == std::strong_ordering::equal);
+
+ // weak ordering
+ auto compare_weak = [](int first, int second)
+ {
+ return (first < second) ? std::weak_ordering::less :
+ (first > second) ? std::weak_ordering::greater :
+ std::weak_ordering::equivalent;
+ };
+
+ auto c = lexicographical_compare_three_way(intArray3, intArray3 + 5, intArray4, intArray4 + 5, compare_weak);
+ EATEST_VERIFY(c == std::weak_ordering::less);
+ c = lexicographical_compare_three_way(intArray4, intArray4 + 5, intArray3, intArray3 + 5, compare_weak);
+ EATEST_VERIFY(c == std::weak_ordering::greater);
+ c = lexicographical_compare_three_way(intArray3, intArray3 + 5, intArray4, intArray4 + 5, synth_three_way{});
+ EATEST_VERIFY(c == std::weak_ordering::less);
+ c = lexicographical_compare_three_way(intArray4, intArray4 + 5, intArray3, intArray3 + 5, synth_three_way{});
+ EATEST_VERIFY(c == std::weak_ordering::greater);
+ }
+
+ {
+ EATEST_VERIFY(synth_three_way{}(1, 1) == std::strong_ordering::equal);
+ EATEST_VERIFY(synth_three_way{}(2, 1) == std::strong_ordering::greater);
+ EATEST_VERIFY(synth_three_way{}(1, 2) == std::strong_ordering::less);
+
+ struct weak_struct
+ {
+ int val;
+ inline std::weak_ordering operator<=>(const weak_struct& b) const
+ {
+ return val <=> b.val;
+ }
+ };
+
+ EATEST_VERIFY(synth_three_way{}(weak_struct{1}, weak_struct{2}) == std::weak_ordering::less);
+ EATEST_VERIFY(synth_three_way{}(weak_struct{2}, weak_struct{1}) == std::weak_ordering::greater);
+ EATEST_VERIFY(synth_three_way{}(weak_struct{1}, weak_struct{1}) == std::weak_ordering::equivalent);
+ }
+#endif
{
// ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last, const T& value)
@@ -1815,7 +1891,164 @@ int TestAlgorithm()
}
- {
+ {
+ // ForwardIterator apply_and_remove(ForwardIterator first, ForwardIterator last, Function function, const T&
+ // value) ForwardIterator apply_and_remove_if(ForwardIterator first, ForwardIterator last, Function function,
+ // Predicate predicate)
+
+ // Test for empty range and full container range
+ {
+ int intArray[12] = {0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1};
+ vector<int> output;
+ auto func = [&output](int a) { output.push_back(a); };
+ int* pInt = apply_and_remove(intArray, intArray, func, 1);
+ EATEST_VERIFY(pInt == intArray);
+ EATEST_VERIFY(VerifySequence(intArray, intArray + 12, int(), "apply_and_remove", 0, 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, -1));
+ EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove", -1));
+ pInt = apply_and_remove(intArray, intArray + 12, func, 1);
+ EATEST_VERIFY(pInt == intArray + 6);
+ EATEST_VERIFY(VerifySequence(intArray, intArray + 6, int(), "apply_and_remove", 0, 0, 0, 0, 0, 0, -1));
+ EATEST_VERIFY(
+ VerifySequence(output.begin(), output.end(), int(), "apply_and_remove", 1, 1, 1, 1, 1, 1, -1));
+ }
+
+ // Test for no match on empty range and full container range
+ {
+ int intArray[12] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3};
+ vector<int> output;
+ auto func = [&output](int a) { output.push_back(a); };
+ int* pInt = apply_and_remove(intArray, intArray, func, 1);
+ EATEST_VERIFY(pInt == intArray);
+ EATEST_VERIFY(VerifySequence(intArray, intArray + 12, int(), "apply_and_remove", 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, -1));
+ EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove", -1));
+ pInt = apply_and_remove(intArray, intArray + 12, func, 1);
+ EATEST_VERIFY(pInt == intArray + 12);
+ EATEST_VERIFY(VerifySequence(intArray, intArray + 12, int(), "apply_and_remove", 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, -1));
+ EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove", -1));
+ }
+
+ // Test for empty range and full container range
+ {
+ int intArray[12] = {0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1};
+ vector<int> output;
+ auto func = [&output](int a) { output.push_back(a); };
+ int* pInt = apply_and_remove_if(intArray, intArray, func, bind2nd(equal_to<int>(), (int)1));
+ EATEST_VERIFY(pInt == intArray);
+ EATEST_VERIFY(VerifySequence(intArray, intArray + 12, int(), "apply_and_remove_if", 0, 0, 1, 1, 0, 0, 1, 1,
+ 0, 0, 1, 1, -1));
+ EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove_if", -1));
+ pInt = apply_and_remove_if(intArray, intArray + 12, func, bind2nd(equal_to<int>(), (int)1));
+ EATEST_VERIFY(pInt == intArray + 6);
+ EATEST_VERIFY(VerifySequence(intArray, intArray + 6, int(), "apply_and_remove_if", 0, 0, 0, 0, 0, 0, -1));
+ EATEST_VERIFY(
+ VerifySequence(output.begin(), output.end(), int(), "apply_and_remove_if", 1, 1, 1, 1, 1, 1, -1));
+ }
+
+ // Test for no match on empty range and full container range
+ {
+ int intArray[12] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3};
+ vector<int> output;
+ auto func = [&output](int a) { output.push_back(a); };
+ int* pInt = apply_and_remove_if(intArray, intArray, func, bind2nd(equal_to<int>(), (int)1));
+ EATEST_VERIFY(pInt == intArray);
+ EATEST_VERIFY(VerifySequence(intArray, intArray + 12, int(), "apply_and_remove_if", 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, -1));
+ EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove_if", -1));
+ pInt = apply_and_remove_if(intArray, intArray + 12, func, bind2nd(equal_to<int>(), (int)1));
+ EATEST_VERIFY(pInt == intArray + 12);
+ EATEST_VERIFY(VerifySequence(intArray, intArray + 12, int(), "apply_and_remove_if", 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, -1));
+ EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove_if", -1));
+ }
+
+ auto even = [](int a) { return (a % 2) == 0; };
+ // Test to verify that the remaining element have stable ordering
+ {
+ int intArray[12] = {7, 8, 2, 3, 4, 5, 6, 0, 1, 9, 10, 11};
+ vector<int> output;
+ auto func = [&output](int a) { output.push_back(a); };
+ int* pInt = apply_and_remove_if(intArray, intArray + 12, func, even);
+ EATEST_VERIFY(pInt == intArray + 6);
+ EATEST_VERIFY(VerifySequence(intArray, intArray + 6, int(), "apply_and_remove_if", 7, 3, 5, 1, 9, 11, -1));
+ EATEST_VERIFY(
+ VerifySequence(output.begin(), output.end(), int(), "apply_and_remove_if", 8, 2, 4, 6, 0, 10, -1));
+ }
+ {
+ int intArray[12] = {7, 8, 0, 0, 4, 5, 6, 0, 1, 9, 0, 11};
+ vector<int> output;
+ auto func = [&output](int a) { output.push_back(a); };
+ int* pInt = apply_and_remove(intArray, intArray + 12, func, 0);
+ EATEST_VERIFY(pInt == intArray + 8);
+ EATEST_VERIFY(
+ VerifySequence(intArray, intArray + 8, int(), "apply_and_remove", 7, 8, 4, 5, 6, 1, 9, 11, -1));
+ EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove", 0, 0, 0, 0, -1));
+ }
+
+ // Tests on a list (i.e. non-contiguous memory container)
+ {
+ list<int> intList = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+ vector<int> output;
+ auto func = [&output](int a) { output.push_back(a); };
+ auto listIter = apply_and_remove_if(intList.begin(), intList.begin(), func, even);
+ EATEST_VERIFY(listIter == intList.begin());
+ EATEST_VERIFY(VerifySequence(intList.begin(), intList.end(), int(), "apply_and_remove_if", 0, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, -1));
+ EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove_if", -1));
+ listIter = apply_and_remove_if(intList.begin(), intList.end(), func, even);
+ EATEST_VERIFY(listIter == next(intList.begin(), 6));
+ EATEST_VERIFY(
+ VerifySequence(intList.begin(), listIter, int(), "apply_and_remove_if", 1, 3, 5, 7, 9, 11, -1));
+ EATEST_VERIFY(
+ VerifySequence(output.begin(), output.end(), int(), "apply_and_remove_if", 0, 2, 4, 6, 8, 10, -1));
+ }
+ {
+ list<int> intList = {0, 4, 2, 3, 4, 5, 6, 4, 4, 4, 10, 11};
+ vector<int> output;
+ auto func = [&output](int a) { output.push_back(a); };
+ auto listIter = apply_and_remove(intList.begin(), intList.begin(), func, 4);
+ EATEST_VERIFY(listIter == intList.begin());
+ EATEST_VERIFY(VerifySequence(intList.begin(), intList.end(), int(), "apply_and_remove", 0, 4, 2, 3, 4, 5, 6,
+ 4, 4, 4, 10, 11, -1));
+ EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove", -1));
+ listIter = apply_and_remove(intList.begin(), intList.end(), func, 4);
+ EATEST_VERIFY(listIter == next(intList.begin(), 7));
+ EATEST_VERIFY(
+ VerifySequence(intList.begin(), listIter, int(), "apply_and_remove", 0, 2, 3, 5, 6, 10, 11, -1));
+ EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove", 4, 4, 4, 4, 4, -1));
+ }
+
+ // Tests on a part of a container
+ {
+ vector<int> intVector = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+ vector<int> output;
+ auto func = [&output](int a) { output.push_back(a); };
+ auto vectorIter = apply_and_remove_if(next(intVector.begin(), 3), prev(intVector.end(), 2), func, even);
+ EATEST_VERIFY(vectorIter == next(intVector.begin(), 7));
+ EATEST_VERIFY(
+ VerifySequence(intVector.begin(), vectorIter, int(), "apply_and_remove_if", 0, 1, 2, 3, 5, 7, 9, -1));
+ EATEST_VERIFY(
+ VerifySequence(prev(intVector.end(), 2), intVector.end(), int(), "apply_and_remove_if", 10, 11, -1));
+ EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove_if", 4, 6, 8, -1));
+ }
+ {
+ vector<int> intVector = {5, 1, 5, 3, 4, 5, 5, 7, 8, 5, 10, 5};
+ vector<int> output;
+ auto func = [&output](int a) { output.push_back(a); };
+ auto vectorIter = apply_and_remove(next(intVector.begin(), 2), prev(intVector.end(), 3), func, 5);
+ EATEST_VERIFY(vectorIter == next(intVector.begin(), 6));
+ EATEST_VERIFY(
+ VerifySequence(intVector.begin(), vectorIter, int(), "apply_and_remove", 5, 1, 3, 4, 7, 8, -1));
+ EATEST_VERIFY(
+ VerifySequence(prev(intVector.end(), 3), intVector.end(), int(), "apply_and_remove", 5, 10, 5, -1));
+ EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove", 5, 5, 5, -1));
+ }
+ }
+
+
+ {
// OutputIterator replace_copy(InputIterator first, InputIterator last, OutputIterator result, const T& old_value, const T& new_value)
// OutputIterator replace_copy_if(InputIterator first, InputIterator last, OutputIterator result, Predicate predicate, const T& new_value)
diff --git a/EASTL/test/source/TestAllocator.cpp b/EASTL/test/source/TestAllocator.cpp
index 85f5adf..2a28c07 100644
--- a/EASTL/test/source/TestAllocator.cpp
+++ b/EASTL/test/source/TestAllocator.cpp
@@ -151,6 +151,8 @@ static int TestFixedAllocator()
{
EATEST_VERIFY(buffer1[i].mValue == TEST_VALUE);
}
+
+ intList1.clear();
}
{ // fixed_allocator_with_overflow
diff --git a/EASTL/test/source/TestArray.cpp b/EASTL/test/source/TestArray.cpp
index 3db95b9..ca05b67 100644
--- a/EASTL/test/source/TestArray.cpp
+++ b/EASTL/test/source/TestArray.cpp
@@ -125,6 +125,22 @@ int TestArray()
VERIFY(!(a >= c));
VERIFY(!(a > c));
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ VERIFY( (a <=> b) == 0);
+ VERIFY(!((a <=> b) != 0));
+ VERIFY(!((a <=> b) < 0));
+ VERIFY( (a <=> b) <= 0);
+ VERIFY( (a <=> b) >= 0);
+ VERIFY(!((a <=> b) > 0));
+
+ VERIFY(!((a <=> c) == 0));
+ VERIFY( (a <=> c) != 0);
+ VERIFY( (a <=> c) < 0);
+ VERIFY( (a <=> c) <= 0);
+ VERIFY(!((a <=> c) >= 0));
+ VERIFY(!((a <=> c) > 0));
+#endif
+
// deduction guides
#ifdef __cpp_deduction_guides
array deduced {1,2,3,4,5};
@@ -132,6 +148,37 @@ int TestArray()
static_assert(eastl::is_same_v<decltype(deduced)::value_type, int>, "deduced array value_type mismatch");
VERIFY(deduced.size() == 5);
#endif
+
+ // structured binding
+
+ {
+ eastl::array<int, 5> aCopy = a;
+ auto&& [a0, a1, a2, a3, a4] = aCopy;
+
+ VERIFY(a0 == aCopy[0]);
+ VERIFY(a1 == aCopy[1]);
+ VERIFY(a2 == aCopy[2]);
+ VERIFY(a3 == aCopy[3]);
+ VERIFY(a4 == aCopy[4]);
+
+ a0 = 100;
+ VERIFY(aCopy[0] == 100);
+
+ a4 = 0;
+ VERIFY(aCopy[4] == 0);
+
+ // The deduced type may or may not be a reference type; it is an aliased type,
+ // as per https://en.cppreference.com/w/cpp/language/structured_binding:
+ // > Like a reference, a structured binding is an alias to an existing object. Unlike a reference,
+ // the type of a structured binding does not have to be a reference type.
+ // Any reference specifier is thus removed to check only the type & its const qualifier
+ static_assert(eastl::is_same_v<eastl::remove_reference_t<decltype(a0)>, int>);
+
+ const eastl::array<int, 5> aConstCopy = a;
+ auto&& [aConst0, aConst1, aConst2, aConst3, aConst4] = aConstCopy;
+
+ static_assert(eastl::is_same_v<eastl::remove_reference_t<decltype(aConst0)>, const int>);
+ }
}
// constexpr tests
diff --git a/EASTL/test/source/TestChrono.cpp b/EASTL/test/source/TestChrono.cpp
index 6a698e9..a56b934 100644
--- a/EASTL/test/source/TestChrono.cpp
+++ b/EASTL/test/source/TestChrono.cpp
@@ -89,12 +89,15 @@ int TestDuration()
microseconds us = 2 * ms; // 6000 microseconds constructed from 3 milliseconds
VERIFY(us.count() == 6000);
+
+ microseconds us2 = ms * 2; // 6000 microseconds constructed from 3 milliseconds
+ VERIFY(us2.count() == 6000);
- microseconds us2 = us / 2;
- VERIFY(us2.count() == 3000);
+ microseconds us3 = us / 2;
+ VERIFY(us3.count() == 3000);
- microseconds us3 = us % 2;
- VERIFY(us3.count() == 0);
+ microseconds us4 = us % 2;
+ VERIFY(us4.count() == 0);
}
}
diff --git a/EASTL/test/source/TestDeque.cpp b/EASTL/test/source/TestDeque.cpp
index 99076ff..e3f4ab6 100644
--- a/EASTL/test/source/TestDeque.cpp
+++ b/EASTL/test/source/TestDeque.cpp
@@ -1063,29 +1063,61 @@ int TestDeque()
{
eastl::deque<int> d = {1, 2, 3, 4, 5, 6, 7, 8, 9};
- eastl::erase(d, 2);
+ auto numErased = eastl::erase(d, 2);
VERIFY((d == eastl::deque<int>{1, 3, 4, 5, 6, 7, 8, 9}));
+ VERIFY(numErased == 1);
- eastl::erase(d, 7);
+ numErased = eastl::erase(d, 7);
VERIFY((d == eastl::deque<int>{1, 3, 4, 5, 6, 8, 9}));
+ VERIFY(numErased == 1);
- eastl::erase(d, 9);
+ numErased = eastl::erase(d, 9);
VERIFY((d == eastl::deque<int>{1, 3, 4, 5, 6, 8}));
+ VERIFY(numErased == 1);
- eastl::erase(d, 5);
+ numErased = eastl::erase(d, 5);
VERIFY((d == eastl::deque<int>{1, 3, 4, 6, 8}));
+ VERIFY(numErased == 1);
- eastl::erase(d, 3);
+ numErased = eastl::erase(d, 3);
VERIFY((d == eastl::deque<int>{1, 4, 6, 8}));
+ VERIFY(numErased == 1);
}
{
eastl::deque<int> d = {1, 2, 3, 4, 5, 6, 7, 8, 9};
- eastl::erase_if(d, [](auto i) { return i % 2 == 0; });
+ auto numErased = eastl::erase_if(d, [](auto i) { return i % 2 == 0; });
VERIFY((d == eastl::deque<int>{1, 3, 5, 7, 9}));
+ VERIFY(numErased == 4);
}
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+
+ { // Test <=>
+ eastl::deque<int> d1 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+ eastl::deque<int> d2 = {9, 8, 7, 6, 5, 4, 3, 2, 1};
+ eastl::deque<int> d3 = {1, 2, 3, 4, 5};
+ eastl::deque<int> d4 = {10};
+
+ VERIFY(d1 != d2);
+ VERIFY(d1 < d2);
+ VERIFY(d1 != d3);
+ VERIFY(d1 > d3);
+ VERIFY(d4 > d1);
+ VERIFY(d4 > d2);
+ VERIFY(d4 > d3);
+
+ VERIFY((d1 <=> d2) != 0);
+ VERIFY((d1 <=> d2) < 0);
+ VERIFY((d1 <=> d3) != 0);
+ VERIFY((d1 <=> d3) > 0);
+ VERIFY((d4 <=> d1) > 0);
+ VERIFY((d4 <=> d2) > 0);
+ VERIFY((d4 <=> d3) > 0);
+ }
+#endif
+
return nErrorCount;
}
diff --git a/EASTL/test/source/TestExtra.cpp b/EASTL/test/source/TestExtra.cpp
index 03f7b41..52fbd62 100644
--- a/EASTL/test/source/TestExtra.cpp
+++ b/EASTL/test/source/TestExtra.cpp
@@ -66,6 +66,7 @@ namespace eastl
#include <EASTL/string.h>
#include <EASTL/hash_set.h>
#include <EASTL/random.h>
+#include <EASTL/bit.h>
#include <EASTL/core_allocator_adapter.h>
#include <EASTL/bonus/call_traits.h>
#include <EASTL/bonus/compressed_pair.h>
@@ -292,7 +293,6 @@ static int TestQueue()
EATEST_VERIFY(!(toListQueue < toListQueue2));
EATEST_VERIFY(!(toListQueue > toListQueue2));
-
// bool empty() const;
// size_type size() const;
EATEST_VERIFY(toListQueue.empty());
@@ -356,6 +356,103 @@ static int TestQueue()
EATEST_VERIFY(intQueue.front() == 5);
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ {
+ // queue(const Sequence& x = Sequence());
+ queue<TestObject, list<TestObject>> toListQueue;
+ queue<TestObject, list<TestObject>> toListQueue2;
+
+
+ // global operators
+ EATEST_VERIFY( ((toListQueue <=> toListQueue2) == 0));
+ EATEST_VERIFY(!((toListQueue <=> toListQueue2) != 0));
+ EATEST_VERIFY( ((toListQueue <=> toListQueue2) <= 0));
+ EATEST_VERIFY( ((toListQueue <=> toListQueue2) >= 0));
+ EATEST_VERIFY(!((toListQueue <=> toListQueue2) < 0));
+ EATEST_VERIFY(!((toListQueue <=> toListQueue2) > 0));
+
+ // bool empty() const;
+ // size_type size() const;
+ EATEST_VERIFY(toListQueue.empty());
+ EATEST_VERIFY(toListQueue.size() == 0);
+
+ // Verify toListQueue > toListQueue2
+ toListQueue.push(TestObject(0));
+ toListQueue.push(TestObject(1));
+ toListQueue2.push(TestObject(0));
+
+ EATEST_VERIFY(!((toListQueue <=> toListQueue2) == 0));
+ EATEST_VERIFY( ((toListQueue <=> toListQueue2) != 0));
+ EATEST_VERIFY( ((toListQueue <=> toListQueue2) >= 0));
+ EATEST_VERIFY(!((toListQueue <=> toListQueue2) <= 0));
+ EATEST_VERIFY( ((toListQueue <=> toListQueue2) > 0));
+ EATEST_VERIFY(!((toListQueue <=> toListQueue2) < 0));
+
+ // Verify toListQueue2 > toListQueue by element size
+ toListQueue2.push(TestObject(3));
+ EATEST_VERIFY(!((toListQueue <=> toListQueue2) == 0));
+ EATEST_VERIFY( ((toListQueue <=> toListQueue2) != 0));
+ EATEST_VERIFY( ((toListQueue <=> toListQueue2) <= 0));
+ EATEST_VERIFY(!((toListQueue <=> toListQueue2) >= 0));
+ EATEST_VERIFY( ((toListQueue <=> toListQueue2) < 0));
+ EATEST_VERIFY(!((toListQueue <=> toListQueue2) > 0));
+
+ queue<TestObject, list<TestObject>> toListQueue3;
+ queue<TestObject, list<TestObject>> toListQueue4;
+
+ for (int i = 0; i < 10; i++)
+ {
+ toListQueue3.push(TestObject(i));
+ if (i < 5)
+ toListQueue4.push(TestObject(i));
+ }
+
+ // Verify toListQueue4 is a strict subset of toListQueue3
+ EATEST_VERIFY(!((toListQueue3 <=> toListQueue4) == 0));
+ EATEST_VERIFY( ((toListQueue3 <=> toListQueue4) != 0));
+ EATEST_VERIFY( ((toListQueue3 <=> toListQueue4) >= 0));
+ EATEST_VERIFY(!((toListQueue3 <=> toListQueue4) <= 0));
+ EATEST_VERIFY( ((toListQueue3 <=> toListQueue4) > 0));
+ EATEST_VERIFY(!((toListQueue3 <=> toListQueue4) < 0));
+
+ // Verify that even thoughn toListQueue4 has a smaller size, it's lexicographically larger
+ toListQueue4.push(TestObject(11));
+ EATEST_VERIFY(!((toListQueue3 <=> toListQueue4) == 0));
+ EATEST_VERIFY( ((toListQueue3 <=> toListQueue4) != 0));
+ EATEST_VERIFY( ((toListQueue3 <=> toListQueue4) <= 0));
+ EATEST_VERIFY(!((toListQueue3 <=> toListQueue4) >= 0));
+ EATEST_VERIFY( ((toListQueue3 <=> toListQueue4) < 0));
+ EATEST_VERIFY(!((toListQueue3 <=> toListQueue4) > 0));
+
+ }
+
+ {
+ queue<TestObject, list<TestObject>> toListQueue1;
+ queue<TestObject, list<TestObject>> toListQueue2;
+ queue<TestObject, list<TestObject>> toListQueue3;
+
+ for (int i = 0; i < 10; i++)
+ {
+ toListQueue1.push(TestObject(i));
+ toListQueue2.push(TestObject(9-i));
+ if (i < 5)
+ toListQueue3.push(TestObject(i));
+ }
+
+ struct weak_ordering_queue
+ {
+ queue<TestObject, list<TestObject>> queue;
+ inline std::weak_ordering operator<=>(const weak_ordering_queue& b) const { return queue <=> b.queue; }
+ };
+
+ EATEST_VERIFY(synth_three_way{}(weak_ordering_queue{toListQueue1}, weak_ordering_queue{toListQueue2}) == std::weak_ordering::less);
+ EATEST_VERIFY(synth_three_way{}(weak_ordering_queue{toListQueue3}, weak_ordering_queue{toListQueue1}) == std::weak_ordering::less);
+ EATEST_VERIFY(synth_three_way{}(weak_ordering_queue{toListQueue2}, weak_ordering_queue{toListQueue1}) == std::weak_ordering::greater);
+ EATEST_VERIFY(synth_three_way{}(weak_ordering_queue{toListQueue2}, weak_ordering_queue{toListQueue3}) == std::weak_ordering::greater);
+ EATEST_VERIFY(synth_three_way{}(weak_ordering_queue{toListQueue1}, weak_ordering_queue{toListQueue1}) == std::weak_ordering::equivalent);
+ }
+ #endif
+
{
vector<TestObject> toVector;
for(int i = 0; i < 100; i++)
@@ -620,7 +717,6 @@ static int TestStack()
EATEST_VERIFY(!(toListStack < toListStack2));
EATEST_VERIFY(!(toListStack > toListStack2));
-
// void push(const value_type& value);
// reference top();
// const_reference top() const;
@@ -665,6 +761,101 @@ static int TestStack()
#endif
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ {
+ // stack(const Sequence& x = Sequence());
+ stack<TestObject, list<TestObject> > toListStack;
+ stack<TestObject, list<TestObject> > toListStack2;
+
+ // bool empty() const;
+ // size_type size() const;
+ EATEST_VERIFY(toListStack.empty());
+ EATEST_VERIFY(toListStack.size() == 0);
+
+
+ // global operators
+ EATEST_VERIFY( ((toListStack <=> toListStack2) == 0));
+ EATEST_VERIFY(!((toListStack <=> toListStack2) != 0));
+ EATEST_VERIFY( ((toListStack <=> toListStack2) <= 0));
+ EATEST_VERIFY( ((toListStack <=> toListStack2) >= 0));
+ EATEST_VERIFY(!((toListStack <=> toListStack2) < 0));
+ EATEST_VERIFY(!((toListStack <=> toListStack2) > 0));
+
+ toListStack.push(TestObject(0));
+ toListStack.push(TestObject(1));
+ toListStack2.push(TestObject(0));
+
+ EATEST_VERIFY(!((toListStack <=> toListStack2) == 0));
+ EATEST_VERIFY( ((toListStack <=> toListStack2) != 0));
+ EATEST_VERIFY( ((toListStack <=> toListStack2) >= 0));
+ EATEST_VERIFY(!((toListStack <=> toListStack2) <= 0));
+ EATEST_VERIFY( ((toListStack <=> toListStack2) > 0));
+ EATEST_VERIFY(!((toListStack <=> toListStack2) < 0));
+
+ // Verify toListStack2 > toListStack by element size
+ toListStack2.push(TestObject(3));
+ EATEST_VERIFY(!((toListStack <=> toListStack2) == 0));
+ EATEST_VERIFY( ((toListStack <=> toListStack2) != 0));
+ EATEST_VERIFY( ((toListStack <=> toListStack2) <= 0));
+ EATEST_VERIFY(!((toListStack <=> toListStack2) >= 0));
+ EATEST_VERIFY( ((toListStack <=> toListStack2) < 0));
+ EATEST_VERIFY(!((toListStack <=> toListStack2) > 0));
+
+ stack<TestObject, list<TestObject> > toListStack3;
+ stack<TestObject, list<TestObject> > toListStack4;
+
+ for (int i = 0; i < 10; i++)
+ {
+ toListStack3.push(TestObject(i));
+ if (i < 5)
+ toListStack4.push(TestObject(i));
+ }
+
+ // Verify toListStack4 is a strict subset of toListStack3
+ EATEST_VERIFY(!((toListStack3 <=> toListStack4) == 0));
+ EATEST_VERIFY( ((toListStack3 <=> toListStack4) != 0));
+ EATEST_VERIFY( ((toListStack3 <=> toListStack4) >= 0));
+ EATEST_VERIFY(!((toListStack3 <=> toListStack4) <= 0));
+ EATEST_VERIFY( ((toListStack3 <=> toListStack4) > 0));
+ EATEST_VERIFY(!((toListStack3 <=> toListStack4) < 0));
+
+ // Verify that even thoughn toListQueue4 has a smaller size, it's lexicographically larger
+ toListStack4.push(TestObject(11));
+ EATEST_VERIFY(!((toListStack3 <=> toListStack4) == 0));
+ EATEST_VERIFY( ((toListStack3 <=> toListStack4) != 0));
+ EATEST_VERIFY( ((toListStack3 <=> toListStack4) <= 0));
+ EATEST_VERIFY(!((toListStack3 <=> toListStack4) >= 0));
+ EATEST_VERIFY( ((toListStack3 <=> toListStack4) < 0));
+ EATEST_VERIFY(!((toListStack3 <=> toListStack4) > 0));
+ }
+
+ {
+ stack<TestObject, list<TestObject> > toListStack1;
+ stack<TestObject, list<TestObject> > toListStack2;
+ stack<TestObject, list<TestObject> > toListStack3;
+
+ for (int i = 0; i < 10; i++)
+ {
+ toListStack1.push(TestObject(i));
+ toListStack2.push(TestObject(9-i));
+ if (i < 5)
+ toListStack3.push(TestObject(i));
+ }
+
+ struct weak_ordering_stack
+ {
+ stack<TestObject, list<TestObject> > stack;
+ inline std::weak_ordering operator<=>(const weak_ordering_stack& b) const { return stack <=> b.stack; }
+ };
+
+ EATEST_VERIFY(synth_three_way{}(weak_ordering_stack{toListStack1}, weak_ordering_stack{toListStack2}) == std::weak_ordering::less);
+ EATEST_VERIFY(synth_three_way{}(weak_ordering_stack{toListStack3}, weak_ordering_stack{toListStack1}) == std::weak_ordering::less);
+ EATEST_VERIFY(synth_three_way{}(weak_ordering_stack{toListStack2}, weak_ordering_stack{toListStack1}) == std::weak_ordering::greater);
+ EATEST_VERIFY(synth_three_way{}(weak_ordering_stack{toListStack2}, weak_ordering_stack{toListStack3}) == std::weak_ordering::greater);
+ EATEST_VERIFY(synth_three_way{}(weak_ordering_stack{toListStack1}, weak_ordering_stack{toListStack1}) == std::weak_ordering::equivalent);
+ }
+#endif
+
{
vector<TestObject> toVector;
@@ -862,6 +1053,281 @@ static int TestNumeric()
return nErrorCount;
}
+#if defined(EA_COMPILER_CPP20_ENABLED)
+template <typename T>
+static constexpr int SignedIntMidpoint()
+{
+ int nErrorCount = 0;
+
+ EATEST_VERIFY(eastl::midpoint(T(0), T(0)) == T(0));
+ EATEST_VERIFY(eastl::midpoint(T(0), T(2)) == T(1));
+ EATEST_VERIFY(eastl::midpoint(T(0), T(4)) == T(2));
+ EATEST_VERIFY(eastl::midpoint(T(0), T(8)) == T(4));
+ EATEST_VERIFY(eastl::midpoint(T(2), T(0)) == T(1));
+ EATEST_VERIFY(eastl::midpoint(T(4), T(0)) == T(2));
+ EATEST_VERIFY(eastl::midpoint(T(8), T(0)) == T(4));
+
+ EATEST_VERIFY(eastl::midpoint(T(1), T(1)) == T(1));
+ EATEST_VERIFY(eastl::midpoint(T(1), T(3)) == T(2));
+ EATEST_VERIFY(eastl::midpoint(T(3), T(1)) == T(2));
+ EATEST_VERIFY(eastl::midpoint(T(2), T(6)) == T(4));
+ EATEST_VERIFY(eastl::midpoint(T(6), T(2)) == T(4));
+
+ EATEST_VERIFY(eastl::midpoint(T(-1), T(-1)) == T(-1));
+ EATEST_VERIFY(eastl::midpoint(T(-1), T(-3)) == T(-2));
+ EATEST_VERIFY(eastl::midpoint(T(-3), T(-1)) == T(-2));
+ EATEST_VERIFY(eastl::midpoint(T(-2), T(-6)) == T(-4));
+ EATEST_VERIFY(eastl::midpoint(T(-6), T(-2)) == T(-4));
+
+ EATEST_VERIFY(eastl::midpoint(T(-0), T(0)) == T(0));
+ EATEST_VERIFY(eastl::midpoint(T(0), T(-0)) == T(0));
+ EATEST_VERIFY(eastl::midpoint(T(-0), T(-0)) == T(0));
+ EATEST_VERIFY(eastl::midpoint(T(-1), T(1)) == T(0));
+ EATEST_VERIFY(eastl::midpoint(T(-10), T(10)) == T(0));
+ EATEST_VERIFY(eastl::midpoint(T(-3), T(7)) == T(2));
+ EATEST_VERIFY(eastl::midpoint(T(-7), T(3)) == T(-2));
+ EATEST_VERIFY(eastl::midpoint(T(-2), T(6)) == T(2));
+ EATEST_VERIFY(eastl::midpoint(T(-6), T(2)) == T(-2));
+ EATEST_VERIFY(eastl::midpoint(T(2), T(-6)) == T(-2));
+ EATEST_VERIFY(eastl::midpoint(T(6), T(-2)) == T(2));
+
+ // If an odd sum, midpoint should round towards the LHS operand.
+ EATEST_VERIFY(eastl::midpoint(T(0), T(5)) == T(2));
+ EATEST_VERIFY(eastl::midpoint(T(5), T(0)) == T(3));
+ EATEST_VERIFY(eastl::midpoint(T(1), T(4)) == T(2));
+ EATEST_VERIFY(eastl::midpoint(T(4), T(1)) == T(3));
+ EATEST_VERIFY(eastl::midpoint(T(7), T(10)) == T(8));
+ EATEST_VERIFY(eastl::midpoint(T(10), T(7)) == T(9));
+ EATEST_VERIFY(eastl::midpoint(T(-1), T(2)) == T(0));
+ EATEST_VERIFY(eastl::midpoint(T(2), T(-1)) == T(1));
+ EATEST_VERIFY(eastl::midpoint(T(-5), T(4)) == T(-1));
+ EATEST_VERIFY(eastl::midpoint(T(4), T(-5)) == T(0));
+
+ // Test absolute limits
+ constexpr T MIN = eastl::numeric_limits<T>::min();
+ constexpr T MAX = eastl::numeric_limits<T>::max();
+
+ EATEST_VERIFY(eastl::midpoint(MIN, MIN) == MIN);
+ EATEST_VERIFY(eastl::midpoint(MAX, MAX) == MAX);
+ EATEST_VERIFY(eastl::midpoint(MIN, MAX) == T(-1));
+ EATEST_VERIFY(eastl::midpoint(MAX, MIN) == T(0));
+ EATEST_VERIFY(eastl::midpoint(MIN, T(0)) == MIN / 2);
+ EATEST_VERIFY(eastl::midpoint(T(0), MIN) == MIN / 2);
+ EATEST_VERIFY(eastl::midpoint(MAX, T(0)) == (MAX / 2) + 1);
+ EATEST_VERIFY(eastl::midpoint(T(0), MAX) == (MAX / 2));
+
+ EATEST_VERIFY(eastl::midpoint(MIN, T(10)) == (MIN / 2) + 5);
+ EATEST_VERIFY(eastl::midpoint(T(10), MIN) == (MIN / 2) + 5);
+ EATEST_VERIFY(eastl::midpoint(MAX, T(10)) == (MAX / 2) + 5 + 1);
+ EATEST_VERIFY(eastl::midpoint(T(10), MAX) == (MAX / 2) + 5);
+ EATEST_VERIFY(eastl::midpoint(MIN, T(-10)) == (MIN / 2) - 5);
+ EATEST_VERIFY(eastl::midpoint(T(-10), MIN) == (MIN / 2) - 5);
+ EATEST_VERIFY(eastl::midpoint(MAX, T(-10)) == (MAX / 2) - 5 + 1);
+ EATEST_VERIFY(eastl::midpoint(T(-10), MAX) == (MAX / 2) - 5);
+
+ return nErrorCount;
+}
+
+template <typename T>
+static constexpr int UnsignedIntMidpoint()
+{
+ int nErrorCount = 0;
+
+ EATEST_VERIFY(eastl::midpoint(T(0), T(0)) == T(0));
+ EATEST_VERIFY(eastl::midpoint(T(0), T(2)) == T(1));
+ EATEST_VERIFY(eastl::midpoint(T(0), T(4)) == T(2));
+ EATEST_VERIFY(eastl::midpoint(T(0), T(8)) == T(4));
+ EATEST_VERIFY(eastl::midpoint(T(2), T(0)) == T(1));
+ EATEST_VERIFY(eastl::midpoint(T(4), T(0)) == T(2));
+ EATEST_VERIFY(eastl::midpoint(T(8), T(0)) == T(4));
+
+ EATEST_VERIFY(eastl::midpoint(T(1), T(1)) == T(1));
+ EATEST_VERIFY(eastl::midpoint(T(1), T(3)) == T(2));
+ EATEST_VERIFY(eastl::midpoint(T(3), T(1)) == T(2));
+ EATEST_VERIFY(eastl::midpoint(T(2), T(6)) == T(4));
+ EATEST_VERIFY(eastl::midpoint(T(6), T(2)) == T(4));
+
+ // If an odd sum, midpoint should round towards the LHS operand.
+ EATEST_VERIFY(eastl::midpoint(T(0), T(5)) == T(2));
+ EATEST_VERIFY(eastl::midpoint(T(5), T(0)) == T(3));
+ EATEST_VERIFY(eastl::midpoint(T(1), T(4)) == T(2));
+ EATEST_VERIFY(eastl::midpoint(T(4), T(1)) == T(3));
+ EATEST_VERIFY(eastl::midpoint(T(7), T(10)) == T(8));
+ EATEST_VERIFY(eastl::midpoint(T(10), T(7)) == T(9));
+
+ // Test absolute limits
+ constexpr T MIN = eastl::numeric_limits<T>::min();
+ constexpr T MAX = eastl::numeric_limits<T>::max();
+
+ EATEST_VERIFY(eastl::midpoint(MIN, MIN) == MIN);
+ EATEST_VERIFY(eastl::midpoint(MAX, MAX) == MAX);
+ EATEST_VERIFY(eastl::midpoint(MIN, MAX) == MAX / 2);
+ EATEST_VERIFY(eastl::midpoint(MAX, MIN) == (MAX / 2) + 1);
+ EATEST_VERIFY(eastl::midpoint(MIN, T(0)) == T(0));
+ EATEST_VERIFY(eastl::midpoint(T(0), MIN) == T(0));
+
+ EATEST_VERIFY(eastl::midpoint(MIN, T(10)) == (MIN / 2) + 5);
+ EATEST_VERIFY(eastl::midpoint(T(10), MIN) == (MIN / 2) + 5);
+ EATEST_VERIFY(eastl::midpoint(MAX, T(10)) == (MAX / 2) + 5 + 1);
+ EATEST_VERIFY(eastl::midpoint(T(10), MAX) == (MAX / 2) + 5);
+
+ return nErrorCount;
+}
+
+template <typename T>
+static constexpr int FloatMidpoint()
+{
+ // for use with floats, double, long doubles.
+ int nErrorCount = 0;
+ EATEST_VERIFY(eastl::midpoint(T(0.0), T(0.0)) == T(0.0));
+ EATEST_VERIFY(eastl::midpoint(T(0.0), T(2.0)) == T(1.0));
+ EATEST_VERIFY(eastl::midpoint(T(0.0), T(4.0)) == T(2.0));
+ EATEST_VERIFY(eastl::midpoint(T(2.0), T(0.0)) == T(1.0));
+ EATEST_VERIFY(eastl::midpoint(T(4.0), T(0.0)) == T(2.0));
+
+ EATEST_VERIFY(eastl::midpoint(T(0.5), T(0.5)) == T(0.5));
+ EATEST_VERIFY(eastl::midpoint(T(0.0), T(0.5)) == T(0.25));
+ EATEST_VERIFY(eastl::midpoint(T(0.5), T(0.0)) == T(0.25));
+ EATEST_VERIFY(eastl::midpoint(T(0.5), T(1.0)) == T(0.75));
+ EATEST_VERIFY(eastl::midpoint(T(1.0), T(0.5)) == T(0.75));
+
+ EATEST_VERIFY(eastl::midpoint(T(-0.0), T(0.0)) == T(0.0));
+ EATEST_VERIFY(eastl::midpoint(T(0.0), T(-0.0)) == T(0.0));
+ EATEST_VERIFY(eastl::midpoint(T(-0.0), T(-0.0)) == T(0.0));
+ EATEST_VERIFY(eastl::midpoint(T(-1.0), T(2.0)) == T(0.5));
+ EATEST_VERIFY(eastl::midpoint(T(-2.0), T(1)) == T(-0.5));
+ EATEST_VERIFY(eastl::midpoint(T(-3.0), T(6.0)) == T(1.5));
+ EATEST_VERIFY(eastl::midpoint(T(-6.0), T(3.0)) == T(-1.5));
+
+ // Test absolute limits
+ const T MIN = eastl::numeric_limits<T>::min();
+ const T MAX = eastl::numeric_limits<T>::max();
+
+ EATEST_VERIFY(eastl::midpoint(MIN, MIN) == MIN);
+ EATEST_VERIFY(eastl::midpoint(MAX, MAX) == MAX);
+ EATEST_VERIFY(eastl::midpoint(MIN, MAX) == MAX / 2);
+ EATEST_VERIFY(eastl::midpoint(MAX, MIN) == MAX / 2);
+ EATEST_VERIFY(eastl::midpoint(-MAX, MIN) == -MAX / 2);
+
+ EATEST_VERIFY(eastl::midpoint(MIN, T(9.0)) == T(4.5));
+ EATEST_VERIFY(eastl::midpoint(MIN, T(-9.0)) == T(-4.5));
+ EATEST_VERIFY(eastl::midpoint(T(9.0), MIN) == T(4.5));
+ EATEST_VERIFY(eastl::midpoint(T(-9.0), MIN) == T(-4.5));
+ EATEST_VERIFY(eastl::midpoint(MAX, T(9.0)) == MAX / 2 + T(4.5));
+ EATEST_VERIFY(eastl::midpoint(MAX, T(-9.0)) == MAX / 2 - T(4.5));
+ EATEST_VERIFY(eastl::midpoint(T(9.0), MAX) == MAX / 2 + T(4.5));
+ EATEST_VERIFY(eastl::midpoint(T(-9.0), MAX) == MAX / 2 - T(4.5));
+
+ return nErrorCount;
+}
+
+template <typename T>
+static constexpr int PointerMidpoint()
+{
+ int nErrorCount = 0;
+
+ const T ARR[100] = {};
+
+ EATEST_VERIFY(eastl::midpoint(ARR, ARR) == ARR);
+ EATEST_VERIFY(eastl::midpoint(ARR, ARR + 100) == ARR + 50);
+ EATEST_VERIFY(eastl::midpoint(ARR + 100, ARR) == ARR + 50);
+ EATEST_VERIFY(eastl::midpoint(ARR, ARR + 25) == ARR + 12);
+ EATEST_VERIFY(eastl::midpoint(ARR + 25, ARR) == ARR + 13);
+ EATEST_VERIFY(eastl::midpoint(ARR, ARR + 13) == ARR + 6);
+ EATEST_VERIFY(eastl::midpoint(ARR + 13, ARR) == ARR + 7);
+ EATEST_VERIFY(eastl::midpoint(ARR + 50, ARR + 100) == ARR + 75);
+ EATEST_VERIFY(eastl::midpoint(ARR + 100, ARR + 50) == ARR + 75);
+
+ return nErrorCount;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// TestMidpoint
+//
+static int TestMidpoint()
+{
+ int nErrorCount = 0;
+
+ // template <typename T>
+ // constexpr eastl::enable_if_t<eastl::is_arithmetic_v<T> && !eastl::is_same_v<eastl::remove_cv_t<T>, bool>, T>
+ // midpoint(const T lhs, const T rhs) EA_NOEXCEPT
+ nErrorCount += SignedIntMidpoint<int>();
+ nErrorCount += SignedIntMidpoint<char>();
+ nErrorCount += SignedIntMidpoint<short>();
+ nErrorCount += SignedIntMidpoint<long>();
+ nErrorCount += SignedIntMidpoint<long long>();
+
+ nErrorCount += UnsignedIntMidpoint<unsigned int>();
+ nErrorCount += UnsignedIntMidpoint<unsigned char>();
+ nErrorCount += UnsignedIntMidpoint<unsigned short>();
+ nErrorCount += UnsignedIntMidpoint<unsigned long>();
+ nErrorCount += UnsignedIntMidpoint<unsigned long long>();
+
+ nErrorCount += FloatMidpoint<float>();
+ nErrorCount += FloatMidpoint<double>();
+ nErrorCount += FloatMidpoint<long double>();
+
+ // template <typename T>
+ // constexpr eastl::enable_if_t<eastl::is_object_v<T>, const T*> midpoint(const T* lhs, const T* rhs)
+ nErrorCount += PointerMidpoint<int>();
+ nErrorCount += PointerMidpoint<char>();
+ nErrorCount += PointerMidpoint<short>();
+ nErrorCount += PointerMidpoint<float>();
+ nErrorCount += PointerMidpoint<double>();
+ nErrorCount += PointerMidpoint<long double>();
+
+ return nErrorCount;
+}
+
+
+template <typename T>
+static constexpr int FloatLerp()
+{
+ int nErrorCount = 0;
+
+ EATEST_VERIFY(eastl::lerp(T(0.0), T(0.0), T(0.0)) == T(0.0));
+ EATEST_VERIFY(eastl::lerp(T(1.0), T(0.0), T(0.0)) == T(1.0));
+ EATEST_VERIFY(eastl::lerp(T(-1.0), T(0.0), T(0.0)) == T(-1.0));
+ EATEST_VERIFY(eastl::lerp(T(0.0), T(1.0), T(0.0)) == T(0.0));
+ EATEST_VERIFY(eastl::lerp(T(0.0), T(-1.0), T(0.0)) == T(0.0));
+ EATEST_VERIFY(eastl::lerp(T(-1.0), T(1.0), T(1.0)) == T(1.0));
+ EATEST_VERIFY(eastl::lerp(T(1.0), T(-1.0), T(1.0)) == T(-1.0));
+ EATEST_VERIFY(eastl::lerp(T(-1.0), T(1.0), T(0.5)) == T(0.0));
+ EATEST_VERIFY(eastl::lerp(T(1.0), T(-1.0), T(0.5)) == T(0.0));
+ EATEST_VERIFY(eastl::lerp(T(5.0), T(5.0), T(0.5)) == T(5.0));
+ EATEST_VERIFY(eastl::lerp(T(-5.0), T(-5.0), T(0.5)) == T(-5.0));
+ EATEST_VERIFY(eastl::lerp(T(1.0), T(2.0), T(1.0)) == T(2.0));
+ EATEST_VERIFY(eastl::lerp(T(2.0), T(1.0), T(1.0)) == T(1.0));
+ EATEST_VERIFY(eastl::lerp(T(1.0), T(2.0), T(1.0)) == T(2.0));
+ EATEST_VERIFY(eastl::lerp(T(1.0), T(2.0), T(2.0)) == T(3.0));
+ EATEST_VERIFY(eastl::lerp(T(2.0), T(1.0), T(2.0)) == T(0.0));
+ EATEST_VERIFY(eastl::lerp(T(1.0), T(-2.0), T(2.0)) == T(-5.0));
+ EATEST_VERIFY(eastl::lerp(T(-1.0), T(2.0), T(2.0)) == T(5.0));
+ EATEST_VERIFY(eastl::lerp(T(-1.5), T(1.5), T(0.75)) == T(0.75));
+ EATEST_VERIFY(eastl::lerp(T(0.125), T(1.75), T(0.25)) == T(0.53125));
+ EATEST_VERIFY(eastl::lerp(T(-0.125), T(-1.75), T(0.5)) == T(-0.9375));
+ EATEST_VERIFY(eastl::lerp(T(-0.125), T(1.5), T(2.5)) == T(3.9375));
+
+ return nErrorCount;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// TestLerp
+//
+static int TestLerp()
+{
+ int nErrorCount = 0;
+
+ // template <class T>
+ // constexpr T lerp(const T a, const T b, const T t) EA_NOEXCEPT
+ nErrorCount += FloatLerp<float>();
+ nErrorCount += FloatLerp<double>();
+ nErrorCount += FloatLerp<long double>();
+
+ return nErrorCount;
+}
+#endif
///////////////////////////////////////////////////////////////////////////////
@@ -914,7 +1380,142 @@ static int TestAdaptors()
return nErrorCount;
}
+#if defined(EA_COMPILER_CPP20_ENABLED)
+template <typename T>
+int TestHasSingleBit()
+{
+ int nErrorCount = 0;
+
+ VERIFY(eastl::has_single_bit(T(0)) == false);
+ VERIFY(eastl::has_single_bit(T(1)) == true);
+ VERIFY(eastl::has_single_bit(T(2)) == true);
+ VERIFY(eastl::has_single_bit(T(3)) == false);
+
+ VERIFY(eastl::has_single_bit(eastl::numeric_limits<T>::min()) == false);
+ VERIFY(eastl::has_single_bit(eastl::numeric_limits<T>::max()) == false);
+ for (int i = 4; i < eastl::numeric_limits<T>::digits; i++)
+ {
+ T power_of_two = static_cast<T>(T(1U) << i);
+ VERIFY(eastl::has_single_bit(power_of_two));
+ VERIFY(eastl::has_single_bit(static_cast<T>(power_of_two - 1)) == false);
+ }
+
+ return nErrorCount;
+}
+
+template <typename T>
+static int TestBitCeil()
+{
+ int nErrorCount = 0;
+
+ VERIFY(eastl::bit_ceil(T(0)) == T(1));
+ VERIFY(eastl::bit_ceil(T(1)) == T(1));
+ VERIFY(eastl::bit_ceil(T(2)) == T(2));
+ VERIFY(eastl::bit_ceil(T(3)) == T(4));
+
+ EA_CONSTEXPR auto DIGITS = eastl::numeric_limits<T>::digits;
+ EA_CONSTEXPR auto MIN = eastl::numeric_limits<T>::min();
+ EA_CONSTEXPR auto MAX = static_cast<T>(T(1) << (DIGITS - 1));
+
+ VERIFY(eastl::bit_ceil(MAX) == MAX);
+ VERIFY(eastl::bit_ceil(static_cast<T>(MAX - 1)) == MAX);
+ VERIFY(eastl::bit_ceil(MIN) == T(1));
+
+ for (int i = 4; i < eastl::numeric_limits<T>::digits; i++)
+ {
+ T power_of_two = static_cast<T>(T(1U) << i);
+ VERIFY(eastl::bit_ceil(power_of_two) == power_of_two);
+ VERIFY(eastl::bit_ceil(static_cast<T>(power_of_two - 1)) == power_of_two);
+ }
+
+ return nErrorCount;
+}
+
+template <typename T>
+static int TestBitFloor()
+{
+ int nErrorCount = 0;
+ VERIFY(eastl::bit_floor(T(0)) == T(0));
+ VERIFY(eastl::bit_floor(T(1)) == T(1));
+ VERIFY(eastl::bit_floor(T(2)) == T(2));
+ VERIFY(eastl::bit_floor(T(3)) == T(2));
+
+ EA_CONSTEXPR auto DIGITS = eastl::numeric_limits<T>::digits;
+ EA_CONSTEXPR auto MIN = eastl::numeric_limits<T>::min();
+ EA_CONSTEXPR auto MAX = eastl::numeric_limits<T>::max();
+
+ VERIFY(eastl::bit_floor(MAX) == T(1) << (DIGITS - 1));
+ VERIFY(eastl::bit_floor(MIN) == T(0));
+
+ for (int i = 4; i < eastl::numeric_limits<T>::digits; i++)
+ {
+ T power_of_two = static_cast<T>(T(1U) << i);
+ VERIFY(eastl::bit_floor(power_of_two) == power_of_two);
+ VERIFY(eastl::bit_floor(static_cast<T>(power_of_two + 1)) == power_of_two);
+ }
+ return nErrorCount;
+}
+
+template <typename T>
+static int TestBitWidth()
+{
+ int nErrorCount = 0;
+
+ VERIFY(eastl::bit_width(T(0)) == T(0));
+ VERIFY(eastl::bit_width(T(1)) == T(1));
+ VERIFY(eastl::bit_width(T(2)) == T(2));
+ VERIFY(eastl::bit_width(T(3)) == T(2));
+
+ EA_CONSTEXPR auto DIGITS = eastl::numeric_limits<T>::digits;
+ EA_CONSTEXPR auto MIN = eastl::numeric_limits<T>::min();
+ EA_CONSTEXPR auto MAX = eastl::numeric_limits<T>::max();
+
+ VERIFY(eastl::bit_width(MIN) == 0);
+ VERIFY(eastl::bit_width(MAX) == DIGITS);
+
+ for (int i = 4; i < eastl::numeric_limits<T>::digits; i++)
+ {
+ T power_of_two = static_cast<T>(T(1U) << i);
+ VERIFY(eastl::bit_width(power_of_two) == static_cast<T>(i + 1));
+ }
+
+ return nErrorCount;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// TestPowerofTwo
+//
+static int TestPowerOfTwo()
+{
+ int nErrorCount = 0;
+ nErrorCount += TestHasSingleBit<unsigned int>();
+ nErrorCount += TestHasSingleBit<unsigned char>();
+ nErrorCount += TestHasSingleBit<unsigned short>();
+ nErrorCount += TestHasSingleBit<unsigned long>();
+ nErrorCount += TestHasSingleBit<unsigned long long>();
+
+ nErrorCount += TestBitCeil<unsigned int>();
+ nErrorCount += TestBitCeil<unsigned char>();
+ nErrorCount += TestBitCeil<unsigned short>();
+ nErrorCount += TestBitCeil<unsigned long>();
+ nErrorCount += TestBitCeil<unsigned long long>();
+
+ nErrorCount += TestBitFloor<unsigned int>();
+ nErrorCount += TestBitFloor<unsigned char>();
+ nErrorCount += TestBitFloor<unsigned short>();
+ nErrorCount += TestBitFloor<unsigned long>();
+ nErrorCount += TestBitFloor<unsigned long long>();
+
+ nErrorCount += TestBitWidth<unsigned int>();
+ nErrorCount += TestBitWidth<unsigned char>();
+ nErrorCount += TestBitWidth<unsigned short>();
+ nErrorCount += TestBitWidth<unsigned long>();
+ nErrorCount += TestBitWidth<unsigned long long>();
+
+ return nErrorCount;
+}
+#endif
///////////////////////////////////////////////////////////////////////////////
// TestExtra
@@ -931,6 +1532,11 @@ int TestExtra()
nErrorCount += TestCallTraits();
nErrorCount += TestNumeric();
nErrorCount += TestAdaptors();
+#if defined(EA_COMPILER_CPP20_ENABLED)
+ nErrorCount += TestMidpoint();
+ nErrorCount += TestLerp();
+ nErrorCount += TestPowerOfTwo();
+#endif
return nErrorCount;
}
diff --git a/EASTL/test/source/TestFixedString.cpp b/EASTL/test/source/TestFixedString.cpp
index a7f7bd9..8528dc7 100644
--- a/EASTL/test/source/TestFixedString.cpp
+++ b/EASTL/test/source/TestFixedString.cpp
@@ -131,6 +131,58 @@ int TestFixedSubstring()
EATEST_VERIFY(str == "");
}
+
+ {
+ // Check that copies/moves don't become independent strings.
+ // They should all point to the same sub-string.
+ string str = "hello world";
+ fixed_substring<char> sub(str, 2, 5);
+
+ EATEST_VERIFY(sub.size() == 5);
+ EATEST_VERIFY(sub[0] == 'l');
+ EATEST_VERIFY(sub == "llo w");
+
+ vector<fixed_substring<char>> v;
+ for (eastl_size_t i = 0; i < 1000; ++i) {
+ v.push_back(sub);
+ }
+
+ sub[0] = 'g';
+ EATEST_VERIFY(str == "heglo world");
+ EATEST_VERIFY(sub == "glo w");
+
+ for (const auto& s : v){
+ EATEST_VERIFY(s == "glo w");
+ }
+
+ // copy construct
+ fixed_substring<char> sub2 = sub;
+
+ // copy assign
+ fixed_substring<char> sub3;
+ sub3 = sub;
+
+ // move construct
+ fixed_substring<char> sub4 = eastl::move(sub);
+
+ // move assign
+ fixed_substring<char> sub_again(str, 2, 5);
+ fixed_substring<char> sub5;
+ sub5 = eastl::move(sub_again);
+
+ EATEST_VERIFY(sub2 == "glo w");
+ EATEST_VERIFY(sub3 == "glo w");
+ EATEST_VERIFY(sub4 == "glo w");
+ EATEST_VERIFY(sub5 == "glo w");
+
+ str[5] = 'g';
+ EATEST_VERIFY(sub2 == "glogw");
+ EATEST_VERIFY(sub3 == "glogw");
+ EATEST_VERIFY(sub4 == "glogw");
+ EATEST_VERIFY(sub5 == "glogw");
+
+ }
+
return nErrorCount;
}
diff --git a/EASTL/test/source/TestFunctional.cpp b/EASTL/test/source/TestFunctional.cpp
index 63b3516..1e25200 100644
--- a/EASTL/test/source/TestFunctional.cpp
+++ b/EASTL/test/source/TestFunctional.cpp
@@ -1491,5 +1491,39 @@ struct TestInvokeResult
};
template struct eastl::invoke_result<decltype(&TestInvokeResult::f), TestInvokeResult, void>;
+
static_assert(!eastl::is_invocable<decltype(&TestInvokeResult::f), TestInvokeResult, void>::value, "incorrect value for is_invocable");
+static_assert(!eastl::is_invocable<decltype(&TestInvokeResult::f), TestInvokeResult, int, int>::value, "incorrect value for is_invocable");
static_assert(eastl::is_invocable<decltype(&TestInvokeResult::f), TestInvokeResult, int>::value, "incorrect value for is_invocable");
+
+static_assert(!eastl::is_invocable_r<int, decltype(&TestInvokeResult::f), TestInvokeResult, void>::value, "incorrect value for is_invocable_r");
+static_assert(!eastl::is_invocable_r<void, decltype(&TestInvokeResult::f), TestInvokeResult, int, int>::value, "incorrect value for is_invocable_r");
+static_assert(eastl::is_invocable_r<void, decltype(&TestInvokeResult::f), TestInvokeResult, int>::value, "incorrect value for is_invocable_r");
+static_assert(eastl::is_invocable_r<int, decltype(&TestInvokeResult::f), TestInvokeResult, int>::value, "incorrect value for is_invocable_r");
+
+struct TestCallableInvokeResult
+{
+ int operator()(int i) {return i;}
+};
+
+template struct eastl::invoke_result<TestCallableInvokeResult, void>;
+
+static_assert(!eastl::is_invocable<TestCallableInvokeResult, void>::value, "incorrect value for is_invocable");
+static_assert(!eastl::is_invocable<TestCallableInvokeResult, int, int>::value, "incorrect value for is_invocable");
+static_assert(eastl::is_invocable<TestCallableInvokeResult, int>::value, "incorrect value for is_invocable");
+
+static_assert(!eastl::is_invocable_r<int, TestCallableInvokeResult, void>::value, "incorrect value for is_invocable_r");
+static_assert(!eastl::is_invocable_r<void, TestCallableInvokeResult, int, int>::value, "incorrect value for is_invocable_r");
+static_assert(eastl::is_invocable_r<void, TestCallableInvokeResult, int>::value, "incorrect value for is_invocable_r");
+static_assert(eastl::is_invocable_r<int, TestCallableInvokeResult, int>::value, "incorrect value for is_invocable_r");
+
+typedef decltype(eastl::ref(eastl::declval<TestCallableInvokeResult&>())) TestCallableRefInvokeResult;
+
+static_assert(!eastl::is_invocable<TestCallableRefInvokeResult, void>::value, "incorrect value for is_invocable");
+static_assert(!eastl::is_invocable<TestCallableRefInvokeResult, int, int>::value, "incorrect value for is_invocable");
+static_assert(eastl::is_invocable<TestCallableRefInvokeResult, int>::value, "incorrect value for is_invocable");
+
+static_assert(!eastl::is_invocable_r<int, TestCallableRefInvokeResult, void>::value, "incorrect value for is_invocable_r");
+static_assert(!eastl::is_invocable_r<void, TestCallableRefInvokeResult, int, int>::value, "incorrect value for is_invocable_r");
+static_assert(eastl::is_invocable_r<void, TestCallableRefInvokeResult, int>::value, "incorrect value for is_invocable_r");
+static_assert(eastl::is_invocable_r<int, TestCallableRefInvokeResult, int>::value, "incorrect value for is_invocable_r");
diff --git a/EASTL/test/source/TestHash.cpp b/EASTL/test/source/TestHash.cpp
index 9c9bf9d..1bcf996 100644
--- a/EASTL/test/source/TestHash.cpp
+++ b/EASTL/test/source/TestHash.cpp
@@ -746,14 +746,16 @@ int TestHash()
{ // hash_set erase_if
hash_set<int> m = {0, 1, 2, 3, 4};
- eastl::erase_if(m, [](auto i) { return i % 2 == 0; });
+ auto numErased = eastl::erase_if(m, [](auto i) { return i % 2 == 0; });
VERIFY((m == hash_set<int>{1, 3}));
+ VERIFY(numErased == 3);
}
{ // hash_multiset erase_if
hash_multiset<int> m = {0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 4};
- eastl::erase_if(m, [](auto i) { return i % 2 == 0; });
+ auto numErased = eastl::erase_if(m, [](auto i) { return i % 2 == 0; });
VERIFY((m == hash_multiset<int>{1, 1, 1, 3}));
+ VERIFY(numErased == 12);
}
@@ -943,15 +945,17 @@ int TestHash()
{ // hash_map erase_if
hash_map<int, int> m = {{0, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}};
- eastl::erase_if(m, [](auto p) { return p.first % 2 == 0; });
+ auto numErased = eastl::erase_if(m, [](auto p) { return p.first % 2 == 0; });
VERIFY((m == hash_map<int, int>{{1, 1}, {3, 3}}));
+ VERIFY(numErased == 3);
}
{ // hash_multimap erase_if
hash_multimap<int, int> m = {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {2, 2},
{2, 2}, {2, 2}, {2, 2}, {3, 3}, {3, 3}, {4, 4}};
- eastl::erase_if(m, [](auto p) { return p.first % 2 == 0; });
+ auto numErased = eastl::erase_if(m, [](auto p) { return p.first % 2 == 0; });
VERIFY((m == hash_multimap<int, int>{{1, 1}, {3, 3}, {3, 3}}));
+ VERIFY(numErased == 9);
}
diff --git a/EASTL/test/source/TestIterator.cpp b/EASTL/test/source/TestIterator.cpp
index 02aa1d4..b6c6f76 100644
--- a/EASTL/test/source/TestIterator.cpp
+++ b/EASTL/test/source/TestIterator.cpp
@@ -4,6 +4,7 @@
#include "EASTLTest.h"
+#include <EASTL/deque.h>
#include <EASTL/iterator.h>
#include <EASTL/vector.h>
#include <EASTL/set.h>
@@ -21,6 +22,8 @@ EA_DISABLE_ALL_VC_WARNINGS()
#include <string.h>
EA_RESTORE_ALL_VC_WARNINGS()
+template <class T>
+using detect_iterator_traits_reference = typename eastl::iterator_traits<T>::reference;
// This is used below, though is currently disabled as documented below.
struct IListNode : public eastl::intrusive_list_node{};
@@ -181,7 +184,7 @@ int TestIterator_moveIterator()
// Check that we support iterators yielding plain value (typically a proxy-iterator).
struct FakeProxyIterator
{
- using iterator_category = eastl::forward_iterator_tag;
+ using iterator_category = EASTL_ITC_NS::forward_iterator_tag;
using difference_type = ptrdiff_t;
using value_type = int;
using pointer = int; // Note that we are yielding by value.
@@ -250,6 +253,34 @@ int TestIterator()
}
{
+ // Regression bug with assign/insert combined with reverse iterator.
+ eastl::vector<int> a;
+ for (int i = 0; i < 10; ++i) {
+ a.push_back(i);
+ }
+
+ eastl::deque<int> d;
+ d.assign(a.rbegin(), a.rend());
+ for (int i = 0; i < 10; ++i) {
+ EATEST_VERIFY(a[i] == d[a.size() - i - 1]);
+ }
+ d.insert(d.end(), a.rbegin(), a.rend());
+ for (int i = 0; i < 10; ++i) {
+ EATEST_VERIFY(a[i] == d[d.size() - i - 1]);
+ }
+
+ eastl::vector<int> b;
+ b.assign(a.rbegin(), a.rend());
+ for (int i = 0; i < 10; ++i) {
+ EATEST_VERIFY(a[i] == b[a.size() - i - 1]);
+ }
+ b.insert(b.end(), a.rbegin(), a.rend());
+ for (int i = 0; i < 10; ++i) {
+ EATEST_VERIFY(a[i] == b[b.size() - i - 1]);
+ }
+ }
+
+ {
// move_iterator
// move_iterator<Iterator> make_move_iterator(Iterator mi)
typedef eastl::vector<eastl::string> StringArray;
@@ -421,13 +452,17 @@ int TestIterator()
{
// is_iterator_wrapper
- static_assert((eastl::is_iterator_wrapper<void>::value == false), "is_iterator_wrapper failure");
- static_assert((eastl::is_iterator_wrapper<int>::value == false), "is_iterator_wrapper failure");
- static_assert((eastl::is_iterator_wrapper<int*>::value == false), "is_iterator_wrapper failure");
- static_assert((eastl::is_iterator_wrapper<eastl::array<char>*>::value == false), "is_iterator_wrapper failure");
- static_assert((eastl::is_iterator_wrapper<eastl::vector<char> >::value == false), "is_iterator_wrapper failure");
- static_assert((eastl::is_iterator_wrapper<eastl::generic_iterator<int*> >::value == true), "is_iterator_wrapper failure");
- static_assert((eastl::is_iterator_wrapper<eastl::move_iterator<eastl::array<int>::iterator> >::value == true), "is_iterator_wrapper failure");
+ static_assert((eastl::is_iterator_wrapper<void>::value == false), "is_iterator_wrapper failure");
+ static_assert((eastl::is_iterator_wrapper<int>::value == false), "is_iterator_wrapper failure");
+ static_assert((eastl::is_iterator_wrapper<int*>::value == false), "is_iterator_wrapper failure");
+ static_assert((eastl::is_iterator_wrapper<eastl::array<int>::iterator>::value == false), "is_iterator_wrapper failure");
+ static_assert((eastl::is_iterator_wrapper<eastl::array<char>*>::value == false), "is_iterator_wrapper failure");
+ static_assert((eastl::is_iterator_wrapper<eastl::vector<char> >::value == false), "is_iterator_wrapper failure");
+ static_assert((eastl::is_iterator_wrapper<eastl::generic_iterator<int*> >::value == true), "is_iterator_wrapper failure");
+ static_assert((eastl::is_iterator_wrapper<eastl::move_iterator<eastl::array<int>::iterator> >::value == true), "is_iterator_wrapper failure");
+ static_assert((eastl::is_iterator_wrapper<eastl::reverse_iterator<eastl::array<int>::iterator> >::value == false), "is_iterator_wrapper failure");
+ static_assert((eastl::is_iterator_wrapper<eastl::reverse_iterator<int*> >::value == false), "is_iterator_wrapper failure");
+ static_assert((eastl::is_iterator_wrapper<eastl::reverse_iterator<eastl::move_iterator<int*>> >::value == true), "is_iterator_wrapper failure");
}
@@ -455,6 +490,61 @@ int TestIterator()
intVector[0] = 20;
EATEST_VERIFY(*itVector == 20);
static_assert((eastl::is_same<decltype(eastl::unwrap_iterator(miIntVector)), eastl::vector<int>::iterator>::value == true), "unwrap_iterator failure");
+
+ eastl::reverse_iterator<eastl::vector<int>::iterator> riIntVector = intVector.rbegin();
+ eastl::reverse_iterator<eastl::vector<int>::iterator> riUnwrapped = eastl::unwrap_iterator(riIntVector);
+ EATEST_VERIFY(*riUnwrapped == 19);
+ static_assert((eastl::is_same<decltype(eastl::unwrap_iterator(riIntVector)), eastl::reverse_iterator<eastl::vector<int>::iterator>>::value == true), "unwrap_iterator failure");
+
+ eastl::reverse_iterator<eastl::move_iterator<eastl::vector<int>::iterator>> rimiIntVec(miIntVector);
+ static_assert((eastl::is_same<decltype(eastl::unwrap_iterator(rimiIntVec)), eastl::reverse_iterator<eastl::vector<int>::iterator>>::value == true), "unwrap_iterator failure");
+
+ eastl::reverse_iterator<eastl::generic_iterator<int*>> rigiIntArray(giIntArray);
+ static_assert((eastl::is_same<decltype(eastl::unwrap_iterator(rigiIntArray)), eastl::reverse_iterator<int*>>::value == true), "unwrap_iterator failure");
+
+ eastl::deque<int> intDeque(3);
+ eastl::deque<int>::iterator begin = intDeque.begin();
+ eastl::generic_iterator<eastl::deque<int>::iterator> giWrappedBegin(begin);
+ static_assert((eastl::is_same<decltype(eastl::unwrap_iterator(giWrappedBegin)), eastl::deque<int>::iterator>::value == true), "unwrap_iterator failure");
+
+ eastl::deque<int>::iterator unwrappedBegin = eastl::unwrap_iterator(giWrappedBegin);
+ EATEST_VERIFY(begin == unwrappedBegin);
+ }
+
+ {
+ // unwrap_generic_iterator
+ int intArray[2] = {0, 1};
+ eastl::generic_iterator<int*> giIntArray(intArray);
+ int* pInt = eastl::unwrap_generic_iterator(giIntArray);
+ EATEST_VERIFY(*pInt == 0);
+ static_assert((eastl::is_same<decltype(eastl::unwrap_generic_iterator(giIntArray)), int*>::value == true), "unwrap_iterator failure");
+
+ eastl::move_iterator<int*> miIntArray(intArray);
+ static_assert((eastl::is_same<decltype(eastl::unwrap_generic_iterator(miIntArray)), eastl::move_iterator<int*>>::value == true), "unwrap_iterator failure");
+
+ eastl::vector<int> intVector(1, 1);
+ eastl::generic_iterator<eastl::vector<int>::iterator> giVectorInt(intVector.begin());
+ eastl::vector<int>::iterator it = unwrap_generic_iterator(giVectorInt);
+ EATEST_VERIFY(*it == 1);
+ static_assert((eastl::is_same<decltype(eastl::unwrap_generic_iterator(giVectorInt)), eastl::vector<int>::iterator>::value == true), "unwrap_iterator failure");
+ }
+
+ {
+ // unwrap_move_iterator
+ int intArray[2] = {0, 1};
+ eastl::move_iterator<int*> miIntArray(intArray);
+ int* pInt = eastl::unwrap_move_iterator(miIntArray);
+ EATEST_VERIFY(*pInt == 0);
+ static_assert((eastl::is_same<decltype(eastl::unwrap_move_iterator(miIntArray)), int*>::value == true), "unwrap_iterator failure");
+
+ eastl::generic_iterator<int*> giIntArray(intArray);
+ static_assert((eastl::is_same<decltype(eastl::unwrap_move_iterator(giIntArray)), eastl::generic_iterator<int*>>::value == true), "unwrap_iterator failure");
+
+ eastl::vector<int> intVector(1, 1);
+ eastl::move_iterator<eastl::vector<int>::iterator> miVectorInt(intVector.begin());
+ eastl::vector<int>::iterator it = unwrap_move_iterator(miVectorInt);
+ EATEST_VERIFY(*it == 1);
+ static_assert((eastl::is_same<decltype(eastl::unwrap_move_iterator(miVectorInt)), eastl::vector<int>::iterator>::value == true), "unwrap_iterator failure");
}
{
@@ -468,6 +558,11 @@ int TestIterator()
EATEST_VERIFY(dist == 3);
}
+ {
+ // Regression test that ensure N3844 is working correctly.
+ static_assert(!eastl::is_detected<detect_iterator_traits_reference, int>::value, "detecting iterator_traits<int> should SFINAE gracefully.");
+ }
+
return nErrorCount;
}
diff --git a/EASTL/test/source/TestList.cpp b/EASTL/test/source/TestList.cpp
index 8a5e057..001b79a 100644
--- a/EASTL/test/source/TestList.cpp
+++ b/EASTL/test/source/TestList.cpp
@@ -975,20 +975,115 @@ int TestList()
{
eastl::list<int> l = {1, 2, 3, 4, 5, 6, 7, 8, 9};
- eastl::erase(l, 3);
- eastl::erase(l, 5);
- eastl::erase(l, 7);
+ auto numErased = eastl::erase(l, 3);
+ VERIFY(numErased == 1);
+ numErased = eastl::erase(l, 5);
+ VERIFY(numErased == 1);
+ numErased = eastl::erase(l, 7);
+ VERIFY(numErased == 1);
VERIFY((l == eastl::list<int>{1, 2, 4, 6, 8, 9}));
}
{
eastl::list<int> l = {1, 2, 3, 4, 5, 6, 7, 8, 9};
- eastl::erase_if(l, [](auto i) { return i % 2 == 0; });
+ auto numErased = eastl::erase_if(l, [](auto i) { return i % 2 == 0; });
VERIFY((l == eastl::list<int>{1, 3, 5, 7, 9}));
+ VERIFY(numErased == 4);
}
}
+ { // Test global operators
+ {
+ eastl::list<int> list1 = {0, 1, 2, 3, 4, 5};
+ eastl::list<int> list2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ eastl::list<int> list3 = {5, 6, 7, 8};
+
+ VERIFY(list1 == list1);
+ VERIFY(!(list1 != list1));
+
+ VERIFY(list1 != list2);
+ VERIFY(list2 != list3);
+ VERIFY(list1 != list3);
+
+ VERIFY(list1 < list2);
+ VERIFY(list1 <= list2);
+
+ VERIFY(list2 > list1);
+ VERIFY(list2 >= list1);
+
+ VERIFY(list3 > list1);
+ VERIFY(list3 > list2);
+ }
+
+ // three way comparison operator
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ {
+ eastl::list<int> list1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ eastl::list<int> list2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+
+ // Verify equality between list1 and list2
+ VERIFY((list1 <=> list2) == 0);
+ VERIFY(!((list1 <=> list2) != 0));
+ VERIFY((list1 <=> list2) <= 0);
+ VERIFY((list1 <=> list2) >= 0);
+ VERIFY(!((list1 <=> list2) < 0));
+ VERIFY(!((list1 <=> list2) > 0));
+
+ list1.push_back(100); // Make list1 less than list2.
+ list2.push_back(101);
+
+ // Verify list1 < list2
+ VERIFY(!((list1 <=> list2) == 0));
+ VERIFY((list1 <=> list2) != 0);
+ VERIFY((list1 <=> list2) <= 0);
+ VERIFY(!((list1 <=> list2) >= 0));
+ VERIFY(((list1 <=> list2) < 0));
+ VERIFY(!((list1 <=> list2) > 0));
+
+ for (int i = 0; i < 3; i++) // Make the length of list2 less than list1
+ list2.pop_back();
+
+ // Verify list2.size() < list1.size() and list2 is a subset of list1
+ VERIFY(!((list1 <=> list2) == 0));
+ VERIFY((list1 <=> list2) != 0);
+ VERIFY((list1 <=> list2) >= 0);
+ VERIFY(!((list1 <=> list2) <= 0));
+ VERIFY(((list1 <=> list2) > 0));
+ VERIFY(!((list1 <=> list2) < 0));
+ }
+
+ {
+ eastl::list<int> list1 = {1, 2, 3, 4, 5, 6, 7};
+ eastl::list<int> list2 = {7, 6, 5, 4, 3, 2, 1};
+ eastl::list<int> list3 = {1, 2, 3, 4};
+
+ struct weak_ordering_list
+ {
+ eastl::list<int> list;
+ inline std::weak_ordering operator<=>(const weak_ordering_list& b) const { return list <=> b.list; }
+ };
+
+ VERIFY(synth_three_way{}(weak_ordering_list{list1}, weak_ordering_list{list2}) == std::weak_ordering::less);
+ VERIFY(synth_three_way{}(weak_ordering_list{list3}, weak_ordering_list{list1}) == std::weak_ordering::less);
+ VERIFY(synth_three_way{}(weak_ordering_list{list2}, weak_ordering_list{list1}) == std::weak_ordering::greater);
+ VERIFY(synth_three_way{}(weak_ordering_list{list2}, weak_ordering_list{list3}) == std::weak_ordering::greater);
+ VERIFY(synth_three_way{}(weak_ordering_list{list1}, weak_ordering_list{list1}) == std::weak_ordering::equivalent);
+
+ struct strong_ordering_list
+ {
+ eastl::list<int> list;
+ inline std::strong_ordering operator<=>(const strong_ordering_list& b) const { return list <=> b.list; }
+ };
+
+ VERIFY(synth_three_way{}(strong_ordering_list{list1}, strong_ordering_list{list2}) == std::strong_ordering::less);
+ VERIFY(synth_three_way{}(strong_ordering_list{list3}, strong_ordering_list{list1}) == std::strong_ordering::less);
+ VERIFY(synth_three_way{}(strong_ordering_list{list2}, strong_ordering_list{list1}) == std::strong_ordering::greater);
+ VERIFY(synth_three_way{}(strong_ordering_list{list2}, strong_ordering_list{list3}) == std::strong_ordering::greater);
+ VERIFY(synth_three_way{}(strong_ordering_list{list1}, strong_ordering_list{list1}) == std::strong_ordering::equal);
+ }
+#endif
+ }
return nErrorCount;
}
diff --git a/EASTL/test/source/TestMap.cpp b/EASTL/test/source/TestMap.cpp
index e2eef2f..0df8c88 100644
--- a/EASTL/test/source/TestMap.cpp
+++ b/EASTL/test/source/TestMap.cpp
@@ -147,15 +147,23 @@ int TestMap()
{
typedef eastl::map<int, int> IntIntMap;
IntIntMap map1;
+ map1[1] = 1;
+ map1[3] = 3;
#if EASTL_EXCEPTIONS_ENABLED
EATEST_VERIFY_THROW(map1.at(0));
+ EATEST_VERIFY_THROW(map1.at(2));
+ EATEST_VERIFY_THROW(map1.at(4));
#endif
- map1[0]=1;
+ map1[0] = 1;
#if EASTL_EXCEPTIONS_ENABLED
EATEST_VERIFY_NOTHROW(map1.at(0));
+ EATEST_VERIFY_NOTHROW(map1.at(1));
+ EATEST_VERIFY_NOTHROW(map1.at(3));
#endif
EATEST_VERIFY(map1.at(0) == 1);
+ EATEST_VERIFY(map1.at(1) == 1);
+ EATEST_VERIFY(map1.at(3) == 3);
const IntIntMap map2;
const IntIntMap map3(map1);
@@ -223,16 +231,65 @@ int TestMap()
{ // Test erase_if
eastl::map<int, int> m = {{0, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}};
- eastl::erase_if(m, [](auto p) { return p.first % 2 == 0; });
+ auto numErased = eastl::erase_if(m, [](auto p) { return p.first % 2 == 0; });
VERIFY((m == eastl::map<int, int>{{1, 1},{3, 3}}));
+ VERIFY(numErased == 3);
}
{ // Test erase_if
eastl::multimap<int, int> m = {{0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {2, 2}, {3, 3}, {4, 4}, {4, 4}, {4, 4}};
- eastl::erase_if(m, [](auto p) { return p.first % 2 == 0; });
- VERIFY((m == eastl::multimap<int, int>{{1, 1}, {1, 1}, {3, 3}}));
+ auto numErased = eastl::erase_if(m, [](auto p) { return p.first % 2 == 0; });
+ VERIFY((m == eastl::multimap<int, int>{{1, 1}, {1, 1}, {3, 3}}));;
+ VERIFY(numErased == 7);
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ { // Test map <=>
+ eastl::map<int, int> m1 = {{0, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}};
+ eastl::map<int, int> m2 = {{4, 4}, {3, 3}, {2, 2}, {1, 1}, {0, 0}};
+ eastl::map<int, int> m3 = {{0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}};
+ eastl::map<int, int> m4 = {{1, 0}, {3, 2}, {5, 4}, {7, 6}, {9, 8}};
+ eastl::map<int, int> m5 = {{0, 1}, {2, 3}, {4, 5}};
+
+ VERIFY(m1 == m2);
+ VERIFY(m1 != m3);
+ VERIFY(m3 != m4);
+ VERIFY(m3 < m4);
+ VERIFY(m5 < m4);
+ VERIFY(m5 < m3);
+
+
+ VERIFY((m1 <=> m2) == 0);
+ VERIFY((m1 <=> m3) != 0);
+ VERIFY((m3 <=> m4) != 0);
+ VERIFY((m3 <=> m4) < 0);
+ VERIFY((m5 <=> m4) < 0);
+ VERIFY((m5 <=> m3) < 0);
+ }
+
+ { // Test multimap <=>
+ eastl::multimap<int, int> m1 = {{0, 0}, {0, 0}, {1, 1}, {1, 1}, {2, 2}, {2, 2}, {3, 3}, {3, 3}, {4, 4}, {4, 4}};
+ eastl::multimap<int, int> m2 = {{0, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}, {4, 4}, {3, 3}, {2, 2}, {1, 1}, {0, 0}};
+ eastl::multimap<int, int> m3 = {{0, 1}, {2, 3}, {4, 5}, {0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}};
+ eastl::multimap<int, int> m4 = {{1, 0}, {3, 2}, {5, 4}, {1, 0}, {3, 2}, {5, 4}, {7, 6}, {9, 8}};
+ eastl::multimap<int, int> m5 = {{10, 11}, {10, 11}};
+
+ VERIFY(m1 == m2);
+ VERIFY(m1 != m3);
+ VERIFY(m3 != m4);
+ VERIFY(m3 < m4);
+ VERIFY(m5 > m4);
+ VERIFY(m5 > m3);
+
+ VERIFY((m1 <=> m2) == 0);
+ VERIFY((m1 <=> m3) != 0);
+ VERIFY((m3 <=> m4) != 0);
+ VERIFY((m3 <=> m4) < 0);
+ VERIFY((m5 <=> m4) > 0);
+ VERIFY((m5 <=> m3) > 0);
+ }
+#endif
+
return nErrorCount;
}
diff --git a/EASTL/test/source/TestMap.h b/EASTL/test/source/TestMap.h
index 09353cd..8d480cf 100644
--- a/EASTL/test/source/TestMap.h
+++ b/EASTL/test/source/TestMap.h
@@ -1248,11 +1248,18 @@ int TestMapCpp17()
VERIFY(toMap.size() == 1);
}
+ auto ctorCount = TestObject::sTOCtorCount;
+
{ // verify duplicate not inserted
auto result = toMap.try_emplace(7, mapped_type(7)); // test fwding to copy-ctor
VERIFY(!result.second);
VERIFY(result.first->second == mapped_type(7));
VERIFY(toMap.size() == 1);
+
+ // we explicitly constructed an element for the parameter
+ // and one for the VERIFY check
+ ctorCount += 2;
+ VERIFY(ctorCount == TestObject::sTOCtorCount);
}
{ // verify duplicate not inserted
@@ -1261,6 +1268,9 @@ int TestMapCpp17()
VERIFY(result->first == 7);
VERIFY(result->second == mapped_type(7));
VERIFY(toMap.size() == 1);
+ // we explicitly constructed an element for the VERIFY check
+ ++ctorCount;
+ VERIFY(ctorCount == TestObject::sTOCtorCount);
}
{ // verify duplicate not inserted
@@ -1269,20 +1279,36 @@ int TestMapCpp17()
VERIFY(result->first == 7);
VERIFY(result->second == mapped_type(7));
VERIFY(toMap.size() == 1);
+
+ // we explicitly constructed an element for the parameter
+ // and one for the VERIFY check
+ ctorCount += 2;
+ VERIFY(ctorCount == TestObject::sTOCtorCount);
}
{
{
- auto result = toMap.try_emplace(8, 8);
+ auto result = toMap.try_emplace(8, 8);
+ // emplacing a new value should call exactly one constructor,
+ // when the value is constructed in place inside the container.
+ ++ctorCount;
VERIFY(result.second);
VERIFY(result.first->second == mapped_type(8));
+ // One more constructor for the temporary in the VERIFY
+ ++ctorCount;
VERIFY(toMap.size() == 2);
+ VERIFY(ctorCount == TestObject::sTOCtorCount);
}
{
- auto result = toMap.try_emplace(9, mapped_type(9));
+ auto result = toMap.try_emplace(9, mapped_type(9));
VERIFY(result.second);
VERIFY(result.first->second == mapped_type(9));
VERIFY(toMap.size() == 3);
+ // one more constructor for the temporary argument,
+ // one for moving it to the container, and one for the VERIFY
+ ctorCount += 3;
+ VERIFY(ctorCount == TestObject::sTOCtorCount);
+
}
}
}
diff --git a/EASTL/test/source/TestMemory.cpp b/EASTL/test/source/TestMemory.cpp
index 4e25738..77caf9f 100644
--- a/EASTL/test/source/TestMemory.cpp
+++ b/EASTL/test/source/TestMemory.cpp
@@ -133,6 +133,23 @@ eastl::late_constructed<LCTestObject, false, true> gLCTestObjectFalseTrue;
eastl::late_constructed<LCTestObject, false, false> gLCTestObjectFalseFalse;
eastl::late_constructed<LCTestObject, true, false> gLCTestObjectTrueFalse;
+struct TypeWithPointerTraits {};
+
+namespace eastl
+{
+ template <>
+ struct pointer_traits<TypeWithPointerTraits>
+ {
+ // Note: only parts of the traits we are interested to test are defined here.
+ static const int* to_address(TypeWithPointerTraits)
+ {
+ return &a;
+ }
+
+ inline static constexpr int a = 42;
+ };
+}
+
///////////////////////////////////////////////////////////////////////////////
// TestMemory
@@ -684,6 +701,33 @@ int TestMemory()
}
}
+ // to_address
+ {
+ // Normal pointers.
+ int a;
+ int* ptrA = &a;
+ EATEST_VERIFY(ptrA == to_address(ptrA));
+
+ // Smart pointer.
+ struct MockSmartPointer
+ {
+ const int* operator->() const
+ {
+ return &a;
+ }
+
+ int a = 42;
+ };
+
+ MockSmartPointer sp;
+ EATEST_VERIFY(&sp.a == to_address(sp));
+
+ // Type with specialized pointer_traits.
+ TypeWithPointerTraits t;
+ const int* result = to_address(t);
+ EATEST_VERIFY(result != nullptr && *result == 42);
+ }
+
{
// Test that align handles integral overflow correctly and returns NULL.
void* ptr;
diff --git a/EASTL/test/source/TestNumericLimits.cpp b/EASTL/test/source/TestNumericLimits.cpp
index 440715b..1964442 100644
--- a/EASTL/test/source/TestNumericLimits.cpp
+++ b/EASTL/test/source/TestNumericLimits.cpp
@@ -64,6 +64,11 @@ int TestNumericLimits()
EATEST_VERIFY(eastl::numeric_limits<wchar_t>::is_bounded);
EATEST_VERIFY(eastl::numeric_limits<wchar_t>::max() != 0);
+ #if defined(EA_CHAR8_UNIQUE) && EA_CHAR8_UNIQUE
+ EATEST_VERIFY(eastl::numeric_limits<char8_t>::is_bounded);
+ EATEST_VERIFY(eastl::numeric_limits<char8_t>::max() != 0);
+ #endif
+
EATEST_VERIFY(eastl::numeric_limits<char16_t>::is_bounded);
EATEST_VERIFY(eastl::numeric_limits<char16_t>::max() != 0);
diff --git a/EASTL/test/source/TestOptional.cpp b/EASTL/test/source/TestOptional.cpp
index b4934a7..36307ad 100644
--- a/EASTL/test/source/TestOptional.cpp
+++ b/EASTL/test/source/TestOptional.cpp
@@ -18,12 +18,17 @@ struct IntStruct
int data;
};
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+auto operator<=>(const IntStruct& lhs, const IntStruct& rhs) { return lhs.data <=> rhs.data; }
+#else
bool operator<(const IntStruct& lhs, const IntStruct& rhs)
{ return lhs.data < rhs.data; }
+#endif
bool operator==(const IntStruct& lhs, const IntStruct& rhs)
{ return lhs.data == rhs.data; }
+
/////////////////////////////////////////////////////////////////////////////
struct destructor_test
{
@@ -476,6 +481,43 @@ int TestOptional()
VERIFY(o >= nullopt);
}
+ #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ {
+ optional<IntStruct> o(in_place, 10);
+ optional<IntStruct> e;
+
+ VERIFY((o <=> IntStruct(42)) < 0);
+ VERIFY((o <=> IntStruct(2)) >= 0);
+ VERIFY((o <=> IntStruct(10)) >= 0);
+ VERIFY((e <=> o) < 0);
+ VERIFY((e <=> IntStruct(10)) < 0);
+
+ VERIFY((o <=> IntStruct(4)) > 0);
+ VERIFY(o <=> IntStruct(42) <= 0);
+
+ VERIFY((o <=> IntStruct(4)) >= 0);
+ VERIFY((o <=> IntStruct(10)) >= 0);
+ VERIFY((IntStruct(4) <=> o) <= 0);
+ VERIFY((IntStruct(10) <=> o) <= 0);
+
+ VERIFY((o <=> IntStruct(10)) == 0);
+ VERIFY((o->data <=> IntStruct(10).data) == 0);
+
+ VERIFY((o <=> IntStruct(11)) != 0);
+ VERIFY((o->data <=> IntStruct(11).data) != 0);
+
+ VERIFY((e <=> nullopt) == 0);
+ VERIFY((nullopt <=> e) == 0);
+
+ VERIFY((o <=> nullopt) != 0);
+ VERIFY((nullopt <=> o) != 0);
+ VERIFY((nullopt <=> o) < 0);
+ VERIFY((o <=> nullopt) > 0);
+ VERIFY((nullopt <=> o) <= 0);
+ VERIFY((o <=> nullopt) >= 0);
+ }
+ #endif
+
// hash
{
{
diff --git a/EASTL/test/source/TestSList.cpp b/EASTL/test/source/TestSList.cpp
index d73f2bc..94a4d3a 100644
--- a/EASTL/test/source/TestSList.cpp
+++ b/EASTL/test/source/TestSList.cpp
@@ -795,36 +795,134 @@ int TestSList()
{
slist<int> l = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- eastl::erase(l, 5);
+ auto numErased = eastl::erase(l, 5);
VERIFY((l == slist<int>{0, 1, 2, 3, 4, 6, 7, 8, 9}));
+ VERIFY(numErased == 1);
- eastl::erase(l, 7);
+ numErased = eastl::erase(l, 7);
VERIFY((l == slist<int>{0, 1, 2, 3, 4, 6, 8, 9}));
+ VERIFY(numErased == 1);
- eastl::erase(l, 2);
+ numErased = eastl::erase(l, 2);
VERIFY((l == slist<int>{0, 1, 3, 4, 6, 8, 9}));
+ VERIFY(numErased == 1);
- eastl::erase(l, 0);
+ numErased = eastl::erase(l, 0);
VERIFY((l == slist<int>{1, 3, 4, 6, 8, 9}));
+ VERIFY(numErased == 1);
- eastl::erase(l, 4);
+ numErased = eastl::erase(l, 4);
VERIFY((l == slist<int>{1, 3, 6, 8, 9}));
+ VERIFY(numErased == 1);
}
{
slist<int> l = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- eastl::erase_if(l, [](auto e) { return e % 2 == 0; });
+ auto numErased = eastl::erase_if(l, [](auto e) { return e % 2 == 0; });
VERIFY((l == slist<int>{1, 3, 5, 7, 9}));
+ VERIFY(numErased == 5);
- eastl::erase_if(l, [](auto e) { return e == 5; });
+ numErased = eastl::erase_if(l, [](auto e) { return e == 5; });
VERIFY((l == slist<int>{1, 3, 7, 9}));
+ VERIFY(numErased == 1);
- eastl::erase_if(l, [](auto e) { return e % 3 == 0; });
+ numErased = eastl::erase_if(l, [](auto e) { return e % 3 == 0; });
VERIFY((l == slist<int>{1, 7}));
+ VERIFY(numErased == 2);
}
}
+ { // Test global operators
+ {
+ slist<int> list1 = {0, 1, 2, 3, 4, 5};
+ slist<int> list2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ slist<int> list3 = {5, 6, 7, 8};
+
+ VERIFY(list1 == list1);
+ VERIFY(!(list1 != list1));
+
+ VERIFY(list1 != list2);
+ VERIFY(list2 != list3);
+ VERIFY(list1 != list3);
+
+ VERIFY(list1 < list2);
+ VERIFY(list1 <= list2);
+
+ VERIFY(list2 > list1);
+ VERIFY(list2 >= list1);
+
+ VERIFY(list3 > list1);
+ VERIFY(list3 > list2);
+ }
+
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ {
+ slist<int> list1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ slist<int> list2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ slist<int> list3 = {-1, 0, 1, 2, 3, 4, 5};
+
+ // Verify equality between list1 and list2
+ VERIFY((list1 <=> list2) == 0);
+ VERIFY(!((list1 <=> list2) != 0));
+ VERIFY((list1 <=> list2) <= 0);
+ VERIFY((list1 <=> list2) >= 0);
+ VERIFY(!((list1 <=> list2) < 0));
+ VERIFY(!((list1 <=> list2) > 0));
+
+ list1.push_front(-2); // Make list1 less than list2.
+ list2.push_front(-1);
+
+ // Verify list1 < list2
+ VERIFY(!((list1 <=> list2) == 0));
+ VERIFY((list1 <=> list2) != 0);
+ VERIFY((list1 <=> list2) <= 0);
+ VERIFY(!((list1 <=> list2) >= 0));
+ VERIFY(((list1 <=> list2) < 0));
+ VERIFY(!((list1 <=> list2) > 0));
+
+
+ // Verify list3.size() < list2.size() and list3 is a subset of list2
+ VERIFY(!((list3 <=> list2) == 0));
+ VERIFY((list3 <=> list2) != 0);
+ VERIFY((list3 <=> list2) <= 0);
+ VERIFY(!((list3 <=> list2) >= 0));
+ VERIFY(((list3 <=> list2) < 0));
+ VERIFY(!((list3 <=> list2) > 0));
+ }
+
+ {
+ slist<int> list1 = {1, 2, 3, 4, 5, 6, 7};
+ slist<int> list2 = {7, 6, 5, 4, 3, 2, 1};
+ slist<int> list3 = {1, 2, 3, 4};
+
+ struct weak_ordering_slist
+ {
+ slist<int> slist;
+ inline std::weak_ordering operator<=>(const weak_ordering_slist& b) const { return slist <=> b.slist; }
+ };
+
+ VERIFY(synth_three_way{}(weak_ordering_slist{list1}, weak_ordering_slist{list2}) == std::weak_ordering::less);
+ VERIFY(synth_three_way{}(weak_ordering_slist{list3}, weak_ordering_slist{list1}) == std::weak_ordering::less);
+ VERIFY(synth_three_way{}(weak_ordering_slist{list2}, weak_ordering_slist{list1}) == std::weak_ordering::greater);
+ VERIFY(synth_three_way{}(weak_ordering_slist{list2}, weak_ordering_slist{list3}) == std::weak_ordering::greater);
+ VERIFY(synth_three_way{}(weak_ordering_slist{list1}, weak_ordering_slist{list1}) == std::weak_ordering::equivalent);
+
+ struct strong_ordering_slist
+ {
+ slist<int> slist;
+ inline std::strong_ordering operator<=>(const strong_ordering_slist& b) const { return slist <=> b.slist; }
+ };
+
+ VERIFY(synth_three_way{}(strong_ordering_slist{list1}, strong_ordering_slist{list2}) == std::strong_ordering::less);
+ VERIFY(synth_three_way{}(strong_ordering_slist{list3}, strong_ordering_slist{list1}) == std::strong_ordering::less);
+ VERIFY(synth_three_way{}(strong_ordering_slist{list2}, strong_ordering_slist{list1}) == std::strong_ordering::greater);
+ VERIFY(synth_three_way{}(strong_ordering_slist{list2}, strong_ordering_slist{list3}) == std::strong_ordering::greater);
+ VERIFY(synth_three_way{}(strong_ordering_slist{list1}, strong_ordering_slist{list1}) == std::strong_ordering::equal);
+ }
+#endif
+ }
+
return nErrorCount;
}
diff --git a/EASTL/test/source/TestSet.cpp b/EASTL/test/source/TestSet.cpp
index 1adc12f..9a590c2 100644
--- a/EASTL/test/source/TestSet.cpp
+++ b/EASTL/test/source/TestSet.cpp
@@ -162,16 +162,60 @@ int TestSet()
{ // set erase_if tests
set<int> s = {0, 1, 2, 3, 4};
- eastl::erase_if(s, [](auto i) { return i % 2 == 0;});
+ auto numErased = eastl::erase_if(s, [](auto i) { return i % 2 == 0;});
VERIFY((s == set<int>{1,3}));
+ VERIFY(numErased == 3);
}
{ // multiset erase_if tests
multiset<int> s = {0, 0, 0, 0, 0, 1, 1, 1, 2, 3, 3, 3, 4};
- eastl::erase_if(s, [](auto i) { return i % 2 == 0;});
+ auto numErased = eastl::erase_if(s, [](auto i) { return i % 2 == 0;});
VERIFY((s == multiset<int>{1, 1, 1, 3, 3, 3}));
+ VERIFY(numErased == 7);
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ { // Test set <=>
+ set<int> s1 = {0, 1, 2, 3, 4};
+ set<int> s2 = {4, 3, 2, 1, 0};
+ set<int> s3 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+ set<int> s4 = {1, 2, 3, 4, 5, 6};
+ set<int> s5 = {9};
+
+ VERIFY(s1 == s2);
+ VERIFY(s1 != s3);
+ VERIFY(s3 > s4);
+ VERIFY(s5 > s4);
+ VERIFY(s5 > s3);
+
+ VERIFY((s1 <=> s2) == 0);
+ VERIFY((s1 <=> s3) != 0);
+ VERIFY((s3 <=> s4) > 0);
+ VERIFY((s5 <=> s4) > 0);
+ VERIFY((s5 <=> s3) > 0);
+ }
+
+ { // Test multiset <=>
+ multiset<int> s1 = {0, 0, 0, 1, 1, 2, 3, 3, 4};
+ multiset<int> s2 = {4, 3, 3, 2, 1, 1, 0, 0, 0};
+ multiset<int> s3 = {1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9};
+ multiset<int> s4 = {1, 1, 2, 2, 3, 4, 5, 5, 6};
+ multiset<int> s5 = {9};
+
+ VERIFY(s1 == s2);
+ VERIFY(s1 != s3);
+ VERIFY(s3 > s4);
+ VERIFY(s5 > s4);
+ VERIFY(s5 > s3);
+
+ VERIFY((s1 <=> s2) == 0);
+ VERIFY((s1 <=> s3) != 0);
+ VERIFY((s3 <=> s4) > 0);
+ VERIFY((s5 <=> s4) > 0);
+ VERIFY((s5 <=> s3) > 0);
+ }
+#endif
+
{
// user reported regression: ensure container elements are NOT
// moved from during the eastl::set construction process.
diff --git a/EASTL/test/source/TestSmartPtr.cpp b/EASTL/test/source/TestSmartPtr.cpp
index dc94b96..8052392 100644
--- a/EASTL/test/source/TestSmartPtr.cpp
+++ b/EASTL/test/source/TestSmartPtr.cpp
@@ -8,6 +8,7 @@
#include "GetTypeName.h"
#include <EAStdC/EAString.h>
#include <EAStdC/EAStopwatch.h>
+#include <EASTL/atomic.h>
#include <EASTL/core_allocator_adapter.h>
#include <EASTL/core_allocator.h>
#include <EASTL/intrusive_ptr.h>
@@ -800,6 +801,38 @@ static int Test_unique_ptr()
}
#endif
+ #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ {
+ unique_ptr<int> pT1(new int(5));
+ unique_ptr<int> pT2(new int(10));
+ unique_ptr<int> pT3(new int(0));
+
+ EATEST_VERIFY((pT1 <=> pT2) != 0);
+ EATEST_VERIFY((pT2 <=> pT1) != 0);
+
+ EATEST_VERIFY((pT1 <=> pT2) < 0);
+ EATEST_VERIFY((pT1 <=> pT2) <= 0);
+ EATEST_VERIFY((pT2 <=> pT1) > 0);
+ EATEST_VERIFY((pT2 <=> pT1) >= 0);
+
+ EATEST_VERIFY((pT3 <=> pT1) < 0);
+ EATEST_VERIFY((pT3 <=> pT2) < 0);
+ EATEST_VERIFY((pT1 <=> pT3) > 0);
+ EATEST_VERIFY((pT2 <=> pT3) > 0);
+
+ unique_ptr<A> pT4(new A(5));
+ unique_ptr<A> pT5(new A(10));
+
+ EATEST_VERIFY((pT4 <=> pT5) != 0);
+ EATEST_VERIFY((pT5 <=> pT4) != 0);
+
+ EATEST_VERIFY((pT4 <=> pT5) < 0);
+ EATEST_VERIFY((pT4 <=> pT5) <= 0);
+ EATEST_VERIFY((pT5 <=> pT4) > 0);
+ EATEST_VERIFY((pT5 <=> pT4) >= 0);
+ }
+ #endif
+
// ToDo: Test move assignment between two convertible types with an is_assignable deleter_type
//{
// struct Base {};
@@ -1351,7 +1384,7 @@ static int Test_shared_ptr()
{
EA::Thread::ThreadParameters mThreadParams;
EA::Thread::Thread mThread;
- volatile bool mbShouldContinue;
+ eastl::atomic<bool> mbShouldContinue;
int mnErrorCount;
eastl::shared_ptr<TestObject>* mpSPTO;
eastl::weak_ptr<TestObject>* mpWPTO;
@@ -1364,7 +1397,7 @@ static int Test_shared_ptr()
{
int& nErrorCount = mnErrorCount; // declare nErrorCount so that EATEST_VERIFY can work, as it depends on it being declared.
- while(mbShouldContinue)
+ while(mbShouldContinue.load(eastl::memory_order_relaxed))
{
EA::UnitTest::ThreadSleepRandom(1, 10);
@@ -1419,7 +1452,7 @@ static int Test_shared_ptr_thread()
EA::UnitTest::ThreadSleep(2000);
for(size_t i = 0; i < EAArrayCount(thread); i++)
- thread[i].mbShouldContinue = false;
+ thread[i].mbShouldContinue.store(false, eastl::memory_order_relaxed);
for(size_t i = 0; i < EAArrayCount(thread); i++)
{
diff --git a/EASTL/test/source/TestSort.cpp b/EASTL/test/source/TestSort.cpp
index 2d0116f..114a73b 100644
--- a/EASTL/test/source/TestSort.cpp
+++ b/EASTL/test/source/TestSort.cpp
@@ -177,8 +177,22 @@ namespace eastl
return x;
}
};
+
+ struct TestNoLessOperator
+ {
+ int i {};
+ };
} // namespace Internal
+ template <>
+ struct less<Internal::TestNoLessOperator>
+ {
+ bool operator()(const Internal::TestNoLessOperator& lhs, const Internal::TestNoLessOperator& rhs) const noexcept
+ {
+ return lhs.i < rhs.i;
+ }
+ };
+
} // namespace eastl
int TestSort()
@@ -630,6 +644,13 @@ int TestSort()
radix_sort<uint32_t*, identity_extract_radix_key<uint32_t>>(begin(input), end(input), buffer);
EATEST_VERIFY(is_sorted(begin(input), end(input)));
}
+ {
+ // Test case for bug where the last histogram bucket was not being cleared to zero
+ uint32_t input[] = { 0xff00, 0xff };
+ uint32_t buffer[EAArrayCount(input)];
+ radix_sort<uint32_t*, identity_extract_radix_key<uint32_t>>(begin(input), end(input), buffer);
+ EATEST_VERIFY(is_sorted(begin(input), end(input)));
+ }
}
{
@@ -793,7 +814,7 @@ int TestSort()
}
{
- // EATEST_VERIFY deque sorting can compile.
+ // Test checking that deque sorting can compile.
deque<int> intDeque;
vector<int> intVector;
@@ -801,6 +822,25 @@ int TestSort()
stable_sort(intVector.begin(), intVector.end());
}
+ {
+ // Test checking that sorting containers having elements of a type without an operator< compiles correctly
+
+ vector<TestNoLessOperator> noLessVector;
+
+ stable_sort(noLessVector.begin(), noLessVector.end());
+ bubble_sort(noLessVector.begin(), noLessVector.end());
+ shaker_sort(noLessVector.begin(), noLessVector.end());
+ insertion_sort(noLessVector.begin(), noLessVector.end());
+ selection_sort(noLessVector.begin(), noLessVector.end());
+ shell_sort(noLessVector.begin(), noLessVector.end());
+ comb_sort(noLessVector.begin(), noLessVector.end());
+ heap_sort(noLessVector.begin(), noLessVector.end());
+ merge_sort(noLessVector.begin(), noLessVector.end(), *get_default_allocator(nullptr));
+ quick_sort(noLessVector.begin(), noLessVector.end());
+
+ vector<TestNoLessOperator> buffer;
+ tim_sort_buffer(noLessVector.begin(), noLessVector.end(), buffer.data());
+}
{
// Test sorting of a container of pointers to objects as opposed to a container of objects themselves.
diff --git a/EASTL/test/source/TestString.inl b/EASTL/test/source/TestString.inl
index 08fb924..3a59e68 100644
--- a/EASTL/test/source/TestString.inl
+++ b/EASTL/test/source/TestString.inl
@@ -2024,19 +2024,25 @@ int TEST_STRING_NAME()
// test eastl::erase
{
StringType str(LITERAL("abcdefghijklmnopqrstuvwxyz"));
- eastl::erase(str, LITERAL('a'));
- eastl::erase(str, LITERAL('f'));
- eastl::erase(str, LITERAL('l'));
- eastl::erase(str, LITERAL('w'));
- eastl::erase(str, LITERAL('y'));
+ auto numErased = eastl::erase(str, LITERAL('a'));
+ VERIFY(numErased == 1);
+ numErased = eastl::erase(str, LITERAL('f'));
+ VERIFY(numErased == 1);
+ numErased = eastl::erase(str, LITERAL('l'));
+ VERIFY(numErased == 1);
+ numErased = eastl::erase(str, LITERAL('w'));
+ VERIFY(numErased == 1);
+ numErased = eastl::erase(str, LITERAL('y'));
+ VERIFY(numErased == 1);
VERIFY(str == LITERAL("bcdeghijkmnopqrstuvxz"));
}
// test eastl::erase_if
{
StringType str(LITERAL("abcdefghijklmnopqrstuvwxyz"));
- eastl::erase_if(str, [](auto c) { return c == LITERAL('a') || c == LITERAL('v'); });
+ auto numErased = eastl::erase_if(str, [](auto c) { return c == LITERAL('a') || c == LITERAL('v'); });
VERIFY(str == LITERAL("bcdefghijklmnopqrstuwxyz"));
+ VERIFY(numErased == 2);
}
// template<> struct hash<eastl::string>;
@@ -2064,6 +2070,28 @@ int TEST_STRING_NAME()
VERIFY(LocalHash(sw2) == LocalHash(sw3));
}
+ // test <=> operator
+ #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ {
+ StringType sw1(LITERAL("Test String "));
+ StringType sw2(LITERAL("Test String 1"));
+ StringType sw3(LITERAL("Test String 2"));
+ StringType sw4(LITERAL("abcdef"));
+
+ VERIFY((sw1 <=> sw2) != 0);
+ VERIFY((sw1 <=> sw3) != 0);
+ VERIFY((sw2 <=> sw3) != 0);
+ VERIFY((sw1 <=> sw2) < 0);
+ VERIFY((sw1 <=> sw3) < 0);
+ VERIFY((sw2 <=> sw2) == 0);
+ VERIFY((sw2 <=> sw3) < 0);
+ VERIFY((sw2 <=> sw4) < 0);
+ VERIFY((sw4 <=> sw2) > 0);
+ VERIFY((sw4 <=> sw3) > 0);
+ VERIFY((sw3 <=> sw2) > 0);
+ }
+ #endif
+
return nErrorCount;
}
diff --git a/EASTL/test/source/TestStringView.cpp b/EASTL/test/source/TestStringView.cpp
index 835488c..23e6e51 100644
--- a/EASTL/test/source/TestStringView.cpp
+++ b/EASTL/test/source/TestStringView.cpp
@@ -5,6 +5,7 @@
#include "EASTLTest.h"
#include <EABase/eabase.h>
#include <EASTL/numeric_limits.h>
+#include <EASTL/string.h>
#include <EASTL/string_view.h>
// Verify char8_t support is present if the test build requested it.
@@ -78,12 +79,18 @@ int TestStringView()
static_assert(eastl::is_same_v<decltype(U"abcdef"_sv), eastl::u32string_view>, "string_view literal type mismatch");
static_assert(eastl::is_same_v<decltype(L"abcdef"_sv), eastl::wstring_view>, "string_view literal type mismatch");
- // TODO: Need to resolve this. Not sure why on Clang the user literal 'operator ""sv' can't be found.
- // VERIFY("cplusplus"sv.compare("cplusplus") == 0);
- // VERIFY(L"cplusplus"sv.compare(L"cplusplus") == 0);
- // VERIFY(u"cplusplus"sv.compare(u"cplusplus") == 0);
- // VERIFY(U"cplusplus"sv.compare(U"cplusplus") == 0);
- // VERIFY(u8"cplusplus"sv.compare(u8"cplusplus") == 0);
+
+ VERIFY("cplusplus"sv.compare("cplusplus") == 0);
+ VERIFY(L"cplusplus"sv.compare(L"cplusplus") == 0);
+ VERIFY(u"cplusplus"sv.compare(u"cplusplus") == 0);
+ VERIFY(U"cplusplus"sv.compare(U"cplusplus") == 0);
+ VERIFY(u8"cplusplus"sv.compare(u8"cplusplus") == 0);
+
+ static_assert(eastl::is_same_v<decltype("abcdef"sv), eastl::string_view>, "string_view literal type mismatch");
+ static_assert(eastl::is_same_v<decltype(u8"abcdef"sv), eastl::u8string_view>, "string_view literal type mismatch");
+ static_assert(eastl::is_same_v<decltype(u"abcdef"sv), eastl::u16string_view>, "string_view literal type mismatch");
+ static_assert(eastl::is_same_v<decltype(U"abcdef"sv), eastl::u32string_view>, "string_view literal type mismatch");
+ static_assert(eastl::is_same_v<decltype(L"abcdef"sv), eastl::wstring_view>, "string_view literal type mismatch");
}
#endif
diff --git a/EASTL/test/source/TestStringView.inl b/EASTL/test/source/TestStringView.inl
index 14472fb..cd4214e 100644
--- a/EASTL/test/source/TestStringView.inl
+++ b/EASTL/test/source/TestStringView.inl
@@ -5,6 +5,8 @@
template<typename StringViewT>
int TEST_STRING_NAME()
{
+ using StringT = eastl::basic_string<typename StringViewT::value_type>;
+
int nErrorCount = 0;
{
// EA_CONSTEXPR basic_string_view()
@@ -476,6 +478,84 @@ int TEST_STRING_NAME()
VERIFY(sw1 <= sw2);
VERIFY(sw2 > sw1);
VERIFY(sw2 >= sw1);
+
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ VERIFY((sw1 <=> StringViewT(LITERAL("AAAAABBBBBCCCDDDDDEEEEEFFFGGH"))) == 0);
+ VERIFY((sw1 <=> StringViewT(LITERAL("abcdefghijklmnopqrstuvwxyz"))) != 0);
+ VERIFY((sw1 <=> sw2) < 0);
+ VERIFY((sw1 <=> sw2) <= 0);
+ VERIFY((sw2 <=> sw1) > 0);
+ VERIFY((sw2 <=> sw1) >= 0);
+#endif
+ }
+
+ {
+ auto s = LITERAL("Hello, World");
+ StringViewT sv(s);
+
+ VERIFY(s == sv);
+ VERIFY(sv == s);
+
+ VERIFY(s <= sv);
+ VERIFY(sv <= s);
+ VERIFY(s >= sv);
+ VERIFY(sv >= s);
+ VERIFY(!(s != sv));
+ VERIFY(!(sv != s));
+ VERIFY(!(s < sv));
+ VERIFY(!(sv < s));
+ VERIFY(!(s > sv));
+ VERIFY(!(sv > s));
+
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ VERIFY((s <=> sv) == 0);
+ VERIFY((sv <=> s) == 0);
+
+ VERIFY((s <=> sv) <= 0);
+ VERIFY((sv <=> s) <= 0);
+ VERIFY((s <=> sv) >= 0);
+ VERIFY((sv <=> s) >= 0);
+ VERIFY(!((s <=> sv) != 0));
+ VERIFY(!((sv <=> s) != 0));
+ VERIFY(!((s <=> sv) > 0));
+ VERIFY(!((sv <=> s) < 0));
+#endif
+ }
+
+ // Regression comparison operators should work between basic_string_view and basic_string.
+ // The idea is that type_identity_t on some overloads will force basic_string::operator basic_string_view() to kick in.
+ {
+ StringT s(LITERAL("Hello, Stockholm"));
+ StringViewT sv(s);
+
+ VERIFY(s == sv);
+ VERIFY(sv == s);
+
+ // All the operators bellow used to not work.
+ VERIFY(s <= sv);
+ VERIFY(sv <= s);
+ VERIFY(s >= sv);
+ VERIFY(sv >= s);
+ VERIFY(!(s != sv));
+ VERIFY(!(sv != s));
+ VERIFY(!(s < sv));
+ VERIFY(!(sv < s));
+ VERIFY(!(s > sv));
+ VERIFY(!(sv > s));
+
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ VERIFY((s <=> sv) == 0);
+ VERIFY((sv <=> s) == 0);
+
+ VERIFY((s <=> sv) <= 0);
+ VERIFY((sv <=> s) <= 0);
+ VERIFY((s <=> sv) >= 0);
+ VERIFY((sv <=> s) >= 0);
+ VERIFY(!((s <=> sv) != 0));
+ VERIFY(!((sv <=> s) != 0));
+ VERIFY(!((s <=> sv) > 0));
+ VERIFY(!((sv <=> s) < 0));
+#endif
}
// template<> struct hash<std::string_view>;
diff --git a/EASTL/test/source/TestTuple.cpp b/EASTL/test/source/TestTuple.cpp
index 8c1b48a..6a7647e 100644
--- a/EASTL/test/source/TestTuple.cpp
+++ b/EASTL/test/source/TestTuple.cpp
@@ -227,11 +227,27 @@ int TestTuple()
EATEST_VERIFY(aTuple != aDefaultInitTuple);
EATEST_VERIFY(aDefaultInitTuple < aTuple);
+ #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ EATEST_VERIFY((aTuple <=> anotherTuple) == 0);
+ EATEST_VERIFY((aTuple <=> anotherTuple) >= 0);
+ EATEST_VERIFY((anotherTuple <=> aTuple) >= 0);
+ EATEST_VERIFY((aTuple <=> aDefaultInitTuple) != 0);
+ EATEST_VERIFY((aDefaultInitTuple <=> aTuple) < 0);
+ #endif
+
tuple<int, int, int> lesserTuple(1, 2, 3);
tuple<int, int, int> greaterTuple(1, 2, 4);
EATEST_VERIFY(lesserTuple < greaterTuple && !(greaterTuple < lesserTuple) && greaterTuple > lesserTuple &&
!(lesserTuple > greaterTuple));
+ #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ EATEST_VERIFY((lesserTuple <=> greaterTuple) != 0);
+ EATEST_VERIFY((lesserTuple <=> greaterTuple) < 0);
+ EATEST_VERIFY((lesserTuple <=> greaterTuple) <= 0);
+ EATEST_VERIFY((greaterTuple <=> lesserTuple) > 0);
+ EATEST_VERIFY((greaterTuple <=> lesserTuple) >= 0);
+ #endif
+
tuple<int, float, TestObject> valTup(2, 2.0f, TestObject(2));
tuple<int&, float&, TestObject&> refTup(valTup);
tuple<const int&, const float&, const TestObject&> constRefTup(valTup);
@@ -272,6 +288,20 @@ int TestTuple()
}
{
+ // Test construction of tuple containing r-value references
+ int x = 42;
+ TestObject object{1337};
+
+ tuple<int&&, TestObject&&> aTupleWithRValueReference(eastl::move(x), eastl::move(object));
+ static_assert(is_same<decltype(get<0>(aTupleWithRValueReference)), int&>::value, "wrong return type for get when using r-value reference.");
+ static_assert(is_same<decltype(get<1>(aTupleWithRValueReference)), TestObject&>::value, "wrong return type for get when using r-value reference.");
+ EATEST_VERIFY(get<0>(aTupleWithRValueReference) == 42);
+ EATEST_VERIFY(get<1>(aTupleWithRValueReference).mX == 1337);
+
+ static_assert(!is_constructible<decltype(aTupleWithRValueReference), int&, TestObject&>::value, "it shouldn't be possible to assign r-value references with l-values.");
+ }
+
+ {
// Tuple helpers
// make_tuple
@@ -481,6 +511,27 @@ int TestTuple()
#endif
}
+ // Compilation test to make sure that we can handle reference to forward-declared types
+ {
+ struct ForwardDeclared;
+
+ auto fill_tuple = [](ForwardDeclared& f) {
+ eastl::tuple<ForwardDeclared&, const ForwardDeclared&> t{f, f};
+ return t;
+ };
+
+ struct ForwardDeclared
+ {
+ int x;
+ };
+
+ ForwardDeclared f{666};
+ auto t = fill_tuple(f);
+
+ EATEST_VERIFY(get<0>(t).x == 666);
+ EATEST_VERIFY(get<1>(t).x == 666);
+ }
+
#ifndef EA_COMPILER_NO_STRUCTURED_BINDING
// tuple structured bindings test
{
diff --git a/EASTL/test/source/TestTypeTraits.cpp b/EASTL/test/source/TestTypeTraits.cpp
index 0353be9..2670e24 100644
--- a/EASTL/test/source/TestTypeTraits.cpp
+++ b/EASTL/test/source/TestTypeTraits.cpp
@@ -173,15 +173,16 @@ struct NonPod2
virtual void Function(){}
};
-#if EASTL_VARIABLE_TEMPLATES_ENABLED
- struct HasIncrementOperator { HasIncrementOperator& operator++() { return *this; } };
+struct HasIncrementOperator { HasIncrementOperator& operator++() { return *this; } };
- template<typename, typename = eastl::void_t<>>
- struct has_increment_operator : eastl::false_type {};
+template <class T>
+using has_increment_operator_detection = decltype(++eastl::declval<T>());
- template <typename T>
- struct has_increment_operator<T, eastl::void_t<decltype(++eastl::declval<T>())>> : eastl::true_type {};
-#endif
+template<typename, typename = eastl::void_t<>>
+struct has_increment_operator_using_void_t : eastl::false_type {};
+
+template <typename T>
+struct has_increment_operator_using_void_t<T, eastl::void_t<has_increment_operator_detection<T>>> : eastl::true_type {};
// We use this for the is_copy_constructible test in order to verify that
@@ -359,13 +360,19 @@ struct NonPolymorphic1
void Function(){}
};
+// Disable the following warning:
+// warning: ‘struct Abstract’ has virtual functions and accessible non-virtual destructor [-Wnon-virtual-dtor]
+// We explicitly want this class not to have a virtual destructor to test our type traits.
+EA_DISABLE_VC_WARNING(4265)
+EA_DISABLE_CLANG_WARNING(-Wnon-virtual-dtor)
+EA_DISABLE_GCC_WARNING(-Wnon-virtual-dtor)
struct Abstract
{
- #if defined(EA_COMPILER_GNUC) // GCC warns about this, so we include it for this class, even though for this compiler it partly defeats the purpose of its usage.
- virtual ~Abstract(){}
- #endif
virtual void Function() = 0;
};
+EA_RESTORE_GCC_WARNING()
+EA_RESTORE_CLANG_WARNING()
+EA_RESTORE_VC_WARNING()
struct AbstractWithDtor
{
@@ -542,6 +549,7 @@ int TestTypeTraits()
EATEST_VERIFY(GetType(is_integral<float>()) == false);
static_assert(is_integral<bool>::value, "is_integral failure");
+ static_assert(is_integral<char8_t>::value, "is_integral failure");
static_assert(is_integral<char16_t>::value, "is_integral failure");
static_assert(is_integral<char32_t>::value, "is_integral failure");
static_assert(is_integral<char>::value, "is_integral failure");
@@ -616,6 +624,42 @@ int TestTypeTraits()
EATEST_VERIFY(GetType(is_array<uint32_t*>()) == false);
+ //is_bounded_array
+ static_assert(is_bounded_array<Array>::value == true, "is_bounded_array failure");
+ EATEST_VERIFY(GetType(is_bounded_array<Array>()) == true);
+
+ static_assert(is_bounded_array<ArrayConst>::value == true, "is_bounded_array failure");
+ EATEST_VERIFY(GetType(is_bounded_array<ArrayConst>()) == true);
+
+ static_assert(is_bounded_array<int>::value == false, "is_bounded_array failure");
+ static_assert(is_bounded_array<int[32]>::value == true, "is_bounded_array failure");
+ static_assert(is_bounded_array<int[]>::value == false, "is_bounded_array failure");
+
+ static_assert(is_bounded_array<uint32_t>::value == false, "is_bounded_array failure");
+ EATEST_VERIFY(GetType(is_bounded_array<uint32_t>()) == false);
+
+ static_assert(is_bounded_array<uint32_t*>::value == false, "is_bounded_array failure");
+ EATEST_VERIFY(GetType(is_bounded_array<uint32_t*>()) == false);
+
+
+ //is_unbounded_array
+ static_assert(is_unbounded_array<Array>::value == false, "is_unbounded_array failure");
+ EATEST_VERIFY(GetType(is_unbounded_array<Array>()) == false);
+
+ static_assert(is_unbounded_array<ArrayConst>::value == false, "is_unbounded_array failure");
+ EATEST_VERIFY(GetType(is_unbounded_array<ArrayConst>()) == false);
+
+ static_assert(is_unbounded_array<int>::value == false, "is_unbounded_array failure");
+ static_assert(is_unbounded_array<int[32]>::value == false, "is_unbounded_array failure");
+ static_assert(is_unbounded_array<int[]>::value == true, "is_unbounded_array failure");
+
+ static_assert(is_unbounded_array<uint32_t>::value == false, "is_unbounded_array failure");
+ EATEST_VERIFY(GetType(is_unbounded_array<uint32_t>()) == false);
+
+ static_assert(is_unbounded_array<uint32_t*>::value == false, "is_unbounded_array failure");
+ EATEST_VERIFY(GetType(is_unbounded_array<uint32_t*>()) == false);
+
+
// is_reference
static_assert(is_reference<Class&>::value == true, "is_reference failure");
EATEST_VERIFY(GetType(is_reference<Class&>()) == true);
@@ -640,6 +684,10 @@ int TestTypeTraits()
static_assert(is_member_function_pointer<int>::value == false, "is_member_function_pointer failure");
static_assert(is_member_function_pointer<int(Class::*)>::value == false, "is_member_function_pointer failure");
static_assert(is_member_function_pointer<int(Class::*)()>::value == true, "is_member_function_pointer failure");
+ static_assert(is_member_function_pointer<int(Class::*)(...)>::value == true, "is_member_function_pointer failure");
+ static_assert(is_member_function_pointer<int(Class::*)() noexcept>::value == true, "is_member_function_pointer failure");
+ static_assert(is_member_function_pointer<int(Class::*)() &>::value == true, "is_member_function_pointer failure");
+ static_assert(is_member_function_pointer<int(Class::*)() &&>::value == true, "is_member_function_pointer failure");
// is_member_object_pointer
@@ -652,6 +700,9 @@ int TestTypeTraits()
static_assert(is_member_pointer<int>::value == false, "is_member_pointer failure");
static_assert(is_member_pointer<int(Class::*)>::value == true, "is_member_pointer failure");
static_assert(is_member_pointer<int(Class::*)()>::value == true, "is_member_pointer failure");
+ static_assert(is_member_pointer<int(Class::* const)>::value == true, "is_member_pointer failure");
+ static_assert(is_member_pointer<int(Class::* volatile)>::value == true, "is_member_pointer failure");
+ static_assert(is_member_pointer<int(Class::* const volatile)>::value == true, "is_member_pointer failure");
// is_pointer
@@ -719,7 +770,7 @@ int TestTypeTraits()
// is_function
static_assert(is_function<void>::value == false, "is_function failure");
static_assert(is_function<FunctionVoidVoid>::value == true, "is_function failure");
- static_assert(is_function<FunctionVoidVoid&>::value == false, "is_function failure");
+ static_assert(is_function<FunctionVoidVoid&>::value == false, "is_function failure");
static_assert(is_function<FunctionIntVoid>::value == true, "is_function failure");
static_assert(is_function<FunctionIntFloat>::value == true, "is_function failure");
static_assert(is_function<FunctionVoidVoidPtr>::value == false, "is_function failure");
@@ -731,6 +782,16 @@ int TestTypeTraits()
// typedef int PrintfConst(const char*, ...) const;
static_assert(is_function<int (const char*, ...)>::value == true, "is_function failure"); // This is the signature of printf.
#endif
+
+ static_assert(is_function<int (float)>::value == true, "is_function failure");
+ static_assert(is_function<int (float) const>::value == true, "is_function failure");
+ static_assert(is_function<int(float) volatile>::value == true, "is_function failure");
+ static_assert(is_function<int(float) const volatile>::value == true, "is_function failure");
+ static_assert(is_function<int(float)&>::value == true, "is_function failure");
+ static_assert(is_function<int(float)&&>::value == true, "is_function failure");
+ static_assert(is_function<int(float) noexcept>::value == true, "is_function failure");
+ static_assert(is_function<FunctionIntFloat &>::value == false, "is_function failure"); // reference to function, not a l-value reference qualified function
+ static_assert(is_function<FunctionIntFloat &&>::value == false, "is_function failure");
static_assert(is_function_v<void> == false, "is_function failure");
static_assert(is_function_v<FunctionVoidVoid> == true, "is_function failure");
@@ -820,6 +881,8 @@ int TestTypeTraits()
static_assert(is_const<ConstVolatileIntReference>::value == false, "is_const failure"); // Note here that the int is const, not the reference to the int.
EATEST_VERIFY(GetType(is_const<ConstVolatileIntReference>()) == false);
+ static_assert(is_const<void() const>::value == false, "is_const failure");
+ EATEST_VERIFY(GetType(is_const<void() const>()) == false);
// is_volatile
static_assert(is_volatile<Int>::value == false, "is_volatile failure");
@@ -843,6 +906,9 @@ int TestTypeTraits()
static_assert(is_volatile<ConstVolatileIntReference>::value == false, "is_volatile failure"); // Note here that the int is volatile, not the reference to the int.
EATEST_VERIFY(GetType(is_volatile<ConstVolatileIntReference>()) == false);
+ static_assert(is_volatile<void() const>::value == false, "is_volatile failure");
+ EATEST_VERIFY(GetType(is_volatile<void() const>()) == false);
+
// 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...
@@ -1067,7 +1133,24 @@ int TestTypeTraits()
static_assert(is_signed<double>::value == true, "is_signed failure ");
static_assert(is_signed_v<double> == true, "is_signed failure ");
EATEST_VERIFY(GetType(is_signed<double>()) == true);
-
+
+ static_assert(is_signed<char16_t>::value == false, "is_signed failure ");
+ static_assert(is_signed_v<char16_t> == false, "is_signed failure ");
+ EATEST_VERIFY(GetType(is_signed<char16_t>()) == false);
+
+ static_assert(is_signed<char32_t>::value == false, "is_signed failure ");
+ static_assert(is_signed_v<char32_t> == false, "is_signed failure ");
+ EATEST_VERIFY(GetType(is_signed<char32_t>()) == false);
+
+#if EASTL_GCC_STYLE_INT128_SUPPORTED
+ static_assert(is_signed<__int128_t>::value == true, "is_signed failure ");
+ static_assert(is_signed_v<__int128_t> == true, "is_signed failure ");
+ EATEST_VERIFY(GetType(is_signed<__int128_t>()) == true);
+
+ static_assert(is_signed<__uint128_t>::value == false, "is_signed failure ");
+ static_assert(is_signed_v<__uint128_t> == false, "is_signed failure ");
+ EATEST_VERIFY(GetType(is_signed<__uint128_t>()) == false);
+#endif
// is_unsigned
static_assert(is_unsigned<unsigned int>::value == true, "is_unsigned failure ");
@@ -1082,9 +1165,9 @@ int TestTypeTraits()
static_assert(is_unsigned_v<int32_t> == false, "is_unsigned failure ");
EATEST_VERIFY(GetType(is_unsigned<int32_t>()) == false);
- static_assert(is_unsigned<bool>::value == false, "is_unsigned failure ");
- static_assert(is_unsigned_v<bool> == false, "is_unsigned failure ");
- EATEST_VERIFY(GetType(is_unsigned<bool>()) == false);
+ static_assert(is_unsigned<bool>::value == true, "is_unsigned failure ");
+ static_assert(is_unsigned_v<bool> == true, "is_unsigned failure ");
+ EATEST_VERIFY(GetType(is_unsigned<bool>()) == true);
static_assert(is_unsigned<float>::value == false, "is_unsigned failure ");
static_assert(is_unsigned_v<float> == false, "is_unsigned failure ");
@@ -1093,6 +1176,24 @@ int TestTypeTraits()
static_assert(is_unsigned<double>::value == false, "is_unsigned failure ");
static_assert(is_unsigned_v<double> == false, "is_unsigned failure ");
EATEST_VERIFY(GetType(is_unsigned<double>()) == false);
+
+ static_assert(is_unsigned<char16_t>::value == true, "is_unsigned failure ");
+ static_assert(is_unsigned_v<char16_t> == true, "is_unsigned failure ");
+ EATEST_VERIFY(GetType(is_unsigned<char16_t>()) == true);
+
+ static_assert(is_unsigned<char32_t>::value == true, "is_unsigned failure ");
+ static_assert(is_unsigned_v<char32_t> == true, "is_unsigned failure ");
+ EATEST_VERIFY(GetType(is_unsigned<char32_t>()) == true);
+
+#if EASTL_GCC_STYLE_INT128_SUPPORTED
+ static_assert(is_unsigned<__int128_t>::value == false, "is_unsigned failure ");
+ static_assert(is_unsigned_v<__int128_t> == false, "is_unsigned failure ");
+ EATEST_VERIFY(GetType(is_unsigned<__int128_t>()) == false);
+
+ static_assert(is_unsigned<__uint128_t>::value == true, "is_unsigned failure ");
+ static_assert(is_unsigned_v<__uint128_t> == true, "is_unsigned failure ");
+ EATEST_VERIFY(GetType(is_unsigned<__uint128_t>()) == true);
+#endif
// is_lvalue_reference
@@ -1252,6 +1353,7 @@ int TestTypeTraits()
// is_trivially_copyable
static_assert(is_trivially_copyable<void>::value == false, "is_trivially_copyable failure");
+ EATEST_VERIFY(GetType(is_trivially_copyable<void>()) == false);
static_assert(is_trivially_copyable<int>::value == true, "is_trivially_copyable failure");
static_assert(is_trivially_copyable<int*>::value == true, "is_trivially_copyable failure");
static_assert(is_trivially_copyable<int[]>::value == true, "is_trivially_copyable failure");
@@ -1395,14 +1497,16 @@ int TestTypeTraits()
// is_destructible
static_assert(is_destructible<int>::value == true, "is_destructible failure");
+ static_assert(is_destructible<int&>::value == true, "is_destructible failure");
+ static_assert(is_destructible<int&&>::value == true, "is_destructible failure");
static_assert(is_destructible<char>::value == true, "is_destructible failure");
static_assert(is_destructible<char*>::value == true, "is_destructible failure");
static_assert(is_destructible<PodA>::value == true, "is_destructible failure");
static_assert(is_destructible<void>::value == false, "is_destructible failure");
static_assert(is_destructible<int[3]>::value == true, "is_destructible failure");
static_assert(is_destructible<int[]>::value == false, "is_destructible failure"); // You can't call operator delete on this class.
- static_assert(is_destructible<Abstract>::value == false, "is_destructible failure"); // You can't call operator delete on this class.
- static_assert(is_destructible<AbstractWithDtor>::value == false, "is_destructible failure"); // You can't call operator delete on this class.
+ static_assert(is_destructible<Abstract>::value == true, "is_destructible failure");
+ static_assert(is_destructible<AbstractWithDtor>::value == true, "is_destructible failure");
#if !defined(EA_COMPILER_NO_DELETED_FUNCTIONS)
static_assert(is_destructible<DeletedDtor>::value == false, "is_destructible failure"); // You can't call operator delete on this class.
#endif
@@ -1420,18 +1524,25 @@ int TestTypeTraits()
static_assert(is_trivially_destructible<PodA>::value == true, "is_trivially_destructible failure");
static_assert(is_trivially_destructible<int[3]>::value == true, "is_trivially_destructible failure");
static_assert(is_trivially_destructible<int[]>::value == false, "is_trivially_destructible failure");
- static_assert(is_trivially_destructible<Abstract>::value == false, "is_trivially_destructible failure");
- static_assert(is_trivially_destructible<AbstractWithDtor>::value == false, "is_trivially_destructible failure");
+ static_assert(is_trivially_destructible<Abstract>::value == true, "is_trivially_destructible failure");
+ static_assert(is_trivially_destructible<AbstractWithDtor>::value == false, "is_trivially_destructible failure"); // Having a user-defined destructor make it non-trivial.
+ #if !defined(EA_COMPILER_NO_DELETED_FUNCTIONS)
static_assert(is_trivially_destructible<DeletedDtor>::value == false, "is_trivially_destructible failure");
+ #endif
static_assert(is_trivially_destructible<NonPod2>::value == false, "is_trivially_destructible failure"); // This case differs from is_destructible, because we have a declared destructor.
#endif
// is_nothrow_destructible
static_assert(is_nothrow_destructible<int>::value == true, "is_nothrow_destructible failure");
- static_assert(is_nothrow_destructible<int&>::value == true, "is_nothrow_destructible failure");
- static_assert(is_nothrow_destructible<int&&>::value == true, "is_nothrow_destructible failure");
+ static_assert(is_nothrow_destructible<int&>::value == true, "is_nothrow_destructible failure");
+ static_assert(is_nothrow_destructible<int&&>::value == true, "is_nothrow_destructible failure");
static_assert(is_nothrow_destructible<void>::value == false, "is_nothrow_destructible failure");
+ static_assert(is_nothrow_destructible<Abstract>::value == true, "is_nothrow_destructible failure");
+ static_assert(is_nothrow_destructible<AbstractWithDtor>::value == true, "is_nothrow_destructible failure");
+ #if !defined(EA_COMPILER_NO_DELETED_FUNCTIONS)
+ static_assert(is_nothrow_destructible<DeletedDtor>::value == false, "is_nothrow_destructible failure"); // You can't call operator delete on this class.
+ #endif
#if EASTL_TYPE_TRAIT_is_nothrow_destructible_CONFORMANCE
static_assert(is_nothrow_destructible<NonPod2>::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]
static_assert(is_nothrow_destructible<NoThrowDestructible>::value == true, "is_nothrow_destructible failure");
@@ -1669,7 +1780,7 @@ int TestTypeTraits()
static_assert(eastl::is_same_v<unsigned long, eastl::make_unsigned<unsigned long>::type>);
static_assert(eastl::is_same_v<unsigned long long, eastl::make_unsigned<unsigned long long>::type>);
- #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG))
+ #if EASTL_GCC_STYLE_INT128_SUPPORTED
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>);
@@ -1680,13 +1791,18 @@ int TestTypeTraits()
// Char tests
static_assert(sizeof(char) == sizeof(eastl::make_signed<char>::type));
static_assert(sizeof(wchar_t) == sizeof(eastl::make_signed<wchar_t>::type));
+ static_assert(sizeof(char8_t) == sizeof(eastl::make_signed<char8_t>::type));
static_assert(sizeof(char16_t) == sizeof(eastl::make_signed<char16_t>::type));
static_assert(sizeof(char32_t) == sizeof(eastl::make_signed<char32_t>::type));
static_assert(sizeof(char) == sizeof(eastl::make_unsigned<char>::type));
static_assert(sizeof(wchar_t) == sizeof(eastl::make_unsigned<wchar_t>::type));
+ static_assert(sizeof(char8_t) == sizeof(eastl::make_unsigned<char8_t>::type));
static_assert(sizeof(char16_t) == sizeof(eastl::make_unsigned<char16_t>::type));
static_assert(sizeof(char32_t) == sizeof(eastl::make_unsigned<char32_t>::type));
+ static_assert(eastl::is_same_v<signed char, eastl::make_signed<char8_t>::type>);
+ static_assert(eastl::is_same_v<unsigned char, eastl::make_unsigned<char8_t>::type>);
+
// Enum tests
enum EnumUCharSize : unsigned char {};
enum EnumUShortSize : unsigned short {};
@@ -1833,6 +1949,28 @@ int TestTypeTraits()
yValue = 3;
EATEST_VERIFY(yValue == 3);
+ // ref to T
+ // -> T*
+ static_assert(is_same_v<add_pointer_t<int&>, int*>, "add_pointer failure");
+ static_assert(is_same_v<add_pointer_t<int(&)()>, int(*)()>, "add_pointer failure");
+
+ // object type (a (possibly cv-qualified) type other than function type, reference type or void), or
+ // a function type that is not cv- or ref-qualified, or a (possibly cv-qualified) void type
+ // -> T*
+ static_assert(is_same_v<add_pointer_t<int>, int*>, "add_pointer failure");
+ static_assert(is_same_v<add_pointer_t<int*>, int**>, "add_pointer failure");
+ static_assert(is_same_v<add_pointer_t<int()>, int(*)()>, "add_pointer failure");
+ static_assert(is_same_v<add_pointer_t<void>, void*>, "add_pointer failure");
+ static_assert(is_same_v<add_pointer_t<const void>, const void*>, "add_pointer failure");
+ static_assert(is_same_v<add_pointer_t<volatile void>, volatile void*>, "add_pointer failure");
+ static_assert(is_same_v<add_pointer_t<const volatile void>, const volatile void*>, "add_pointer failure");
+
+ // otherwise (cv- or ref-qualified function type)
+ // -> T
+ static_assert(is_same_v<add_pointer_t<int() const>, int() const>, "add_pointer failure");
+ static_assert(is_same_v<add_pointer_t<int() volatile>, int() volatile>, "add_pointer failure");
+ static_assert(is_same_v<add_pointer_t<int() const volatile>, int() const volatile>, "add_pointer failure");
+
// remove_extent
// If T is an array of some type X, provides the member typedef type equal to X, otherwise
// type is T. Note that if T is a multidimensional array, only the first dimension is removed.
@@ -1846,6 +1984,55 @@ int TestTypeTraits()
static_assert((eastl::is_same<Int2, int>::value == true), "remove_all_extents/is_same failure");
}
+ // add_lvalue_reference
+ {
+ // function type with no cv- or ref-qualifier
+ // -> T&
+ static_assert(is_same_v<add_lvalue_reference_t<void()>, void(&)()>, "add_lvalue_reference failure");
+
+ // object type (a (possibly cv-qualified) type other than function type, reference type or void)
+ // -> T&
+ static_assert(is_same_v<add_lvalue_reference_t<int>, int&>, "add_lvalue_reference failure");
+ static_assert(is_same_v<add_lvalue_reference_t<const int>, const int&>, "add_lvalue_reference failure");
+
+ // if T is an rvalue reference (to some type U)
+ // -> U&
+ static_assert(is_same_v<add_lvalue_reference_t<int&&>, int&>, "add_lvalue_reference failure");
+
+ // otherwise (cv- or ref-qualified function type, or reference type, or (possibly cv-qualified) void)
+ // -> T
+ static_assert(is_same_v<add_lvalue_reference_t<void() const>, void() const>, "add_lvalue_reference failure");
+ static_assert(is_same_v<add_lvalue_reference_t<void()&>, void()&>, "add_lvalue_reference failure");
+ static_assert(is_same_v<add_lvalue_reference_t<void()&&>, void()&&>, "add_lvalue_reference failure");
+ static_assert(is_same_v<add_lvalue_reference_t<int&>, int&>, "add_lvalue_reference failure");
+ static_assert(is_same_v<add_lvalue_reference_t<const int&>, const int&>, "add_lvalue_reference failure");
+ static_assert(is_same_v<add_lvalue_reference_t<void>, void>, "add_lvalue_reference failure");
+ static_assert(is_same_v<add_lvalue_reference_t<const void>, const void>, "add_lvalue_reference failure");
+ }
+
+ // add_rvalue_reference
+ {
+ // function type with no cv- or ref-qualifier
+ // -> T&&
+ static_assert(is_same_v<add_rvalue_reference_t<void()>, void(&&)()>, "add_rvalue_reference failure");
+
+ // object type (a (possibly cv-qualified) type other than function type, reference type or void)
+ // -> T&&
+ static_assert(is_same_v<add_rvalue_reference_t<int>, int&&>, "add_rvalue_reference failure");
+ static_assert(is_same_v<add_rvalue_reference_t<const int>, const int&&>, "add_rvalue_reference failure");
+
+ // otherwise (cv- or ref-qualified function type, or reference type, or (possibly cv-qualified) void)
+ // -> T
+ static_assert(is_same_v<add_rvalue_reference_t<void() const>, void() const>, "add_rvalue_reference failure");
+ static_assert(is_same_v<add_rvalue_reference_t<void()&>, void()&>, "add_rvalue_reference failure");
+ static_assert(is_same_v<add_rvalue_reference_t<void()&&>, void()&&>, "add_rvalue_reference failure");
+ static_assert(is_same_v<add_rvalue_reference_t<int&>, int&>, "add_rvalue_reference failure");
+ static_assert(is_same_v<add_rvalue_reference_t<int&&>, int&&>, "add_rvalue_reference failure");
+ static_assert(is_same_v<add_rvalue_reference_t<const int&>, const int&>, "add_rvalue_reference failure");
+ static_assert(is_same_v<add_rvalue_reference_t<void>, void>, "add_rvalue_reference failure");
+ static_assert(is_same_v<add_rvalue_reference_t<const void>, const void>, "add_rvalue_reference failure");
+ }
+
// decay
{
@@ -1979,26 +2166,71 @@ int TestTypeTraits()
}
// void_t
- #if EASTL_VARIABLE_TEMPLATES_ENABLED
{
{
- static_assert(is_same_v<void_t<void>, void>, "void_t failure");
- static_assert(is_same_v<void_t<int>, void>, "void_t failure");
- static_assert(is_same_v<void_t<short>, void>, "void_t failure");
- static_assert(is_same_v<void_t<long>, void>, "void_t failure");
- static_assert(is_same_v<void_t<long long>, void>, "void_t failure");
- static_assert(is_same_v<void_t<ClassEmpty>, void>, "void_t failure");
- static_assert(is_same_v<void_t<ClassNonEmpty>, void>, "void_t failure");
- static_assert(is_same_v<void_t<vector<int>>, void>, "void_t failure");
+ static_assert(is_same<void_t<void>, void>::value, "void_t failure");
+ static_assert(is_same<void_t<int>, void>::value, "void_t failure");
+ static_assert(is_same<void_t<short>, void>::value, "void_t failure");
+ static_assert(is_same<void_t<long>, void>::value, "void_t failure");
+ static_assert(is_same<void_t<long long>, void>::value, "void_t failure");
+ static_assert(is_same<void_t<ClassEmpty>, void>::value, "void_t failure");
+ static_assert(is_same<void_t<ClassNonEmpty>, void>::value, "void_t failure");
+ static_assert(is_same<void_t<vector<int>>, void>::value, "void_t failure");
}
// new sfinae mechansim test
{
- static_assert(has_increment_operator<HasIncrementOperator>::value, "void_t sfinae failure");
- static_assert(!has_increment_operator<ClassEmpty>::value, "void_t sfinae failure");
+ static_assert(has_increment_operator_using_void_t<HasIncrementOperator>::value, "void_t sfinae failure");
+ static_assert(!has_increment_operator_using_void_t<ClassEmpty>::value, "void_t sfinae failure");
}
}
+
+ // detected idiom
+ {
+ static_assert(is_detected<has_increment_operator_detection, HasIncrementOperator>::value, "is_detected failure.");
+ static_assert(!is_detected<has_increment_operator_detection, ClassEmpty>::value, "is_detected failure.");
+
+ static_assert(is_same<detected_t<has_increment_operator_detection, HasIncrementOperator>, HasIncrementOperator&>::value, "is_detected_t failure.");
+ static_assert(is_same<detected_t<has_increment_operator_detection, ClassEmpty>, nonesuch>::value, "is_detected_t failure.");
+
+ using detected_or_positive_result = detected_or<float, has_increment_operator_detection, HasIncrementOperator>;
+ using detected_or_negative_result = detected_or<float, has_increment_operator_detection, ClassEmpty>;
+ static_assert(detected_or_positive_result::value_t::value, "detected_or failure.");
+ static_assert(!detected_or_negative_result::value_t::value, "detected_or failure.");
+ static_assert(is_same<detected_or_positive_result::type, HasIncrementOperator&>::value, "detected_or failure.");
+ static_assert(is_same<detected_or_negative_result::type, float>::value, "detected_or failure.");
+
+ static_assert(is_same<detected_or_t<float, has_increment_operator_detection, HasIncrementOperator>, HasIncrementOperator&>::value, "detected_or_t failure.");
+ static_assert(is_same<detected_or_t<float, has_increment_operator_detection, ClassEmpty>, float>::value, "detected_or_t failure.");
+
+ static_assert(is_detected_exact<HasIncrementOperator&, has_increment_operator_detection, HasIncrementOperator>::value, "is_detected_exact failure.");
+ static_assert(!is_detected_exact<float, has_increment_operator_detection, HasIncrementOperator>::value, "is_detected_exact failure.");
+ static_assert(is_detected_exact<nonesuch, has_increment_operator_detection, ClassEmpty>::value, "is_detected_exact failure.");
+ static_assert(!is_detected_exact<float, has_increment_operator_detection, ClassEmpty>::value, "is_detected_exact failure.");
+
+ static_assert(is_detected_convertible<HasIncrementOperator&, has_increment_operator_detection, HasIncrementOperator>::value, "is_detected_convertible failure.");
+ static_assert(is_detected_convertible<HasIncrementOperator, has_increment_operator_detection, HasIncrementOperator>::value, "is_detected_convertible failure.");
+ static_assert(!is_detected_convertible<float, has_increment_operator_detection, HasIncrementOperator>::value, "is_detected_convertible failure.");
+ static_assert(!is_detected_convertible<nonesuch, has_increment_operator_detection, ClassEmpty>::value, "is_detected_convertible failure.");
+ static_assert(!is_detected_convertible<float, has_increment_operator_detection, ClassEmpty>::value, "is_detected_convertible failure.");
+
+
+ #if EASTL_VARIABLE_TEMPLATES_ENABLED
+ static_assert(is_detected_v<has_increment_operator_detection, HasIncrementOperator>, "is_detected_v failure.");
+ static_assert(!is_detected_v<has_increment_operator_detection, ClassEmpty>, "is_detected_v failure.");
+
+ static_assert(is_detected_exact_v<HasIncrementOperator&, has_increment_operator_detection, HasIncrementOperator>, "is_detected_exact_v failure.");
+ static_assert(!is_detected_exact_v<float, has_increment_operator_detection, HasIncrementOperator>, "is_detected_exact_v failure.");
+ static_assert(is_detected_exact_v<nonesuch, has_increment_operator_detection, ClassEmpty>, "is_detected_exact_v failure.");
+ static_assert(!is_detected_exact_v<float, has_increment_operator_detection, ClassEmpty>, "is_detected_exact_v failure.");
+
+ static_assert(is_detected_convertible_v<HasIncrementOperator&, has_increment_operator_detection, HasIncrementOperator>, "is_detected_convertible_v failure.");
+ static_assert(is_detected_convertible_v<HasIncrementOperator, has_increment_operator_detection, HasIncrementOperator>, "is_detected_convertible_v failure.");
+ static_assert(!is_detected_convertible_v<float, has_increment_operator_detection, HasIncrementOperator>, "is_detected_convertible_v failure.");
+ static_assert(!is_detected_convertible_v<nonesuch, has_increment_operator_detection, ClassEmpty>, "is_detected_convertible_v failure.");
+ static_assert(!is_detected_convertible_v<float, has_increment_operator_detection, ClassEmpty>, "is_detected_convertible_v failure.");
#endif
+ }
// conjunction
{
@@ -2160,8 +2392,10 @@ int TestTypeTraits()
static_assert(!is_aggregate_v<NotAggregrate>, "is_aggregate failure");
}
- #ifndef EA_COMPILER_MSVC
- // NOTE(rparolin): MSVC is incorrectly categorizing the aggregate type in this test-case.
+ #if defined(EA_COMPILER_CPP11_ENABLED) && !defined(EA_COMPILER_CPP14_ENABLED)
+ // See https://en.cppreference.com/w/cpp/language/aggregate_initialization
+ // In C++11 the requirement was added to aggregate types that no default member initializers exist,
+ // however this requirement was removed in C++14.
{
struct NotAggregrate { int data = 42; }; // default member initializer
static_assert(!is_aggregate_v<NotAggregrate>, "is_aggregate failure");
diff --git a/EASTL/test/source/TestUtility.cpp b/EASTL/test/source/TestUtility.cpp
index 363f409..e9027e5 100644
--- a/EASTL/test/source/TestUtility.cpp
+++ b/EASTL/test/source/TestUtility.cpp
@@ -108,7 +108,7 @@ static int TestUtilityPair()
EATEST_VERIFY((p2.first == 0) && (p2.second == 1.f));
pair<const char*, int> p3 = eastl::make_pair("a", 1);
- EATEST_VERIFY((EA::StdC::Strcmp(p3.first, "a") == 0) && (p2.second == 1));
+ EATEST_VERIFY((EA::StdC::Strcmp(p3.first, "a") == 0) && (p3.second == 1));
pair<const char*, int> p4 = eastl::make_pair<const char*, int>("a", 1);
EATEST_VERIFY((EA::StdC::Strcmp(p4.first, "a") == 0) && (p4.second == 1));
@@ -116,6 +116,20 @@ static int TestUtilityPair()
pair<int, const char*> p5 = eastl::make_pair<int, const char*>(1, "b");
EATEST_VERIFY((p5.first == 1) && (EA::StdC::Strcmp(p5.second, "b") == 0));
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ pair<int, int> p6 = eastl::make_pair<int, int>(1, 2);
+ pair<int, int> p7 = eastl::make_pair<int, int>(2, 1);
+ pair<int, int> p8 = eastl::make_pair<int, int>(7, 8);
+ pair<int, int> p9 = eastl::make_pair<int, int>(10, 1);
+
+ EATEST_VERIFY( (p6 <=> p7) != 0);
+ EATEST_VERIFY( (p6 <=> p6) == 0);
+ EATEST_VERIFY( (p7 <=> p8) < 0);
+ EATEST_VERIFY( (p7 <=> p8) <= 0);
+ EATEST_VERIFY( (p9 <=> p8) > 0);
+ EATEST_VERIFY( (p9 <=> p8) >= 0);
+#endif
+
#if !defined(EA_COMPILER_NO_AUTO)
auto p60 = eastl::make_pair("a", "b"); // Different strings of same length of 1.
EATEST_VERIFY((EA::StdC::Strcmp(p60.first, "a") == 0) && (EA::StdC::Strcmp(p60.second, "b") == 0));
@@ -495,13 +509,15 @@ static int TestUtilityIntegerSequence()
using namespace eastl;
int nErrorCount = 0;
#if EASTL_VARIADIC_TEMPLATES_ENABLED
-// Android clang chokes with an internal compiler error on make_integer_sequence
-#if !defined(EA_PLATFORM_ANDROID)
+
EATEST_VERIFY((integer_sequence<int, 0, 1, 2, 3, 4>::size() == 5));
EATEST_VERIFY((make_integer_sequence<int, 5>::size() == 5));
-#endif
+ static_assert(is_same<make_integer_sequence<int, 5>, integer_sequence<int, 0, 1, 2, 3, 4>>::value);
+
EATEST_VERIFY((index_sequence<0, 1, 2, 3, 4>::size() == 5));
EATEST_VERIFY((make_index_sequence<5>::size() == 5));
+ static_assert(is_same<make_index_sequence<5>, index_sequence<0, 1, 2, 3, 4>>::value);
+ static_assert(is_same<make_index_sequence<5>, integer_sequence<size_t, 0, 1, 2, 3, 4>>::value);
#endif // EASTL_VARIADIC_TEMPLATES_ENABLED
return nErrorCount;
@@ -614,6 +630,271 @@ static int TestUtilityExchange()
return nErrorCount;
}
+#if defined(EA_COMPILER_CPP20_ENABLED)
+template <typename T>
+static int TestCmpCommon()
+{
+ int nErrorCount = 0;
+
+ EATEST_VERIFY(eastl::cmp_equal(T(0), T(0)));
+ EATEST_VERIFY(eastl::cmp_equal(T(1), T(1)));
+ EATEST_VERIFY(eastl::cmp_equal(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::min()));
+ EATEST_VERIFY(eastl::cmp_equal(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::max()));
+ EATEST_VERIFY(!eastl::cmp_equal(T(0), T(1)));
+ EATEST_VERIFY(!eastl::cmp_equal(T(1), T(0)));
+ if (eastl::is_signed_v<T>)
+ {
+ EATEST_VERIFY(eastl::cmp_equal(T(-1), T(-1)));
+ EATEST_VERIFY(!eastl::cmp_equal(T(-1), T(-2)));
+ EATEST_VERIFY(!eastl::cmp_equal(T(-2), T(-1)));
+ }
+
+ EATEST_VERIFY(eastl::cmp_not_equal(T(1), T(0)));
+ EATEST_VERIFY(eastl::cmp_not_equal(T(0), T(1)));
+ EATEST_VERIFY(eastl::cmp_not_equal(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::max()));
+ EATEST_VERIFY(eastl::cmp_not_equal(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::min()));
+ if (eastl::is_signed_v<T>)
+ {
+ EATEST_VERIFY(!eastl::cmp_not_equal(T(-1), T(-1)));
+ EATEST_VERIFY(eastl::cmp_not_equal(T(-1), T(-2)));
+ EATEST_VERIFY(eastl::cmp_not_equal(T(-2), T(-1)));
+ }
+
+ EATEST_VERIFY(eastl::cmp_less(T(0), T(1)));
+ EATEST_VERIFY(eastl::cmp_less(T(5), T(10)));
+ EATEST_VERIFY(!eastl::cmp_less(T(0), T(0)));
+ EATEST_VERIFY(!eastl::cmp_less(T(1), T(0)));
+ EATEST_VERIFY(eastl::cmp_less(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::max()));
+ EATEST_VERIFY(!eastl::cmp_less(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::min()));
+ EATEST_VERIFY(!eastl::cmp_less(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::max()));
+ EATEST_VERIFY(!eastl::cmp_less(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::min()));
+ if (eastl::is_signed_v<T>)
+ {
+ EATEST_VERIFY(!eastl::cmp_less(T(-1), T(-1)));
+ EATEST_VERIFY(!eastl::cmp_less(T(-1), T(-2)));
+ EATEST_VERIFY(eastl::cmp_less(T(-2), T(-1)));
+ }
+
+ EATEST_VERIFY(eastl::cmp_less_equal(T(0), T(1)));
+ EATEST_VERIFY(eastl::cmp_less_equal(T(5), T(10)));
+ EATEST_VERIFY(eastl::cmp_less_equal(T(0), T(0)));
+ EATEST_VERIFY(eastl::cmp_less_equal(T(1), T(1)));
+ EATEST_VERIFY(!eastl::cmp_less_equal(T(1), T(0)));
+ EATEST_VERIFY(eastl::cmp_less_equal(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::max()));
+ EATEST_VERIFY(eastl::cmp_less_equal(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::min()));
+ EATEST_VERIFY(eastl::cmp_less_equal(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::max()));
+ EATEST_VERIFY(!eastl::cmp_less_equal(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::min()));
+ if (eastl::is_signed_v<T>)
+ {
+ EATEST_VERIFY(eastl::cmp_less_equal(T(-1), T(-1)));
+ EATEST_VERIFY(!eastl::cmp_less_equal(T(-1), T(-2)));
+ EATEST_VERIFY(eastl::cmp_less_equal(T(-2), T(-1)));
+ }
+
+ EATEST_VERIFY(eastl::cmp_greater(T(1), T(0)));
+ EATEST_VERIFY(eastl::cmp_greater(T(10), T(5)));
+ EATEST_VERIFY(!eastl::cmp_greater(T(0), T(0)));
+ EATEST_VERIFY(!eastl::cmp_greater(T(0), T(1)));
+ EATEST_VERIFY(eastl::cmp_greater(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::min()));
+ EATEST_VERIFY(!eastl::cmp_greater(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::min()));
+ EATEST_VERIFY(!eastl::cmp_greater(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::max()));
+ EATEST_VERIFY(!eastl::cmp_greater(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::max()));
+ if (eastl::is_signed_v<T>)
+ {
+ EATEST_VERIFY(!eastl::cmp_greater(T(-1), T(-1)));
+ EATEST_VERIFY(eastl::cmp_greater(T(-1), T(-2)));
+ EATEST_VERIFY(!eastl::cmp_greater(T(-2), T(-1)));
+ }
+
+ EATEST_VERIFY(eastl::cmp_greater_equal(T(1), T(0)));
+ EATEST_VERIFY(eastl::cmp_greater_equal(T(10), T(5)));
+ EATEST_VERIFY(eastl::cmp_greater_equal(T(0), T(0)));
+ EATEST_VERIFY(!eastl::cmp_greater_equal(T(0), T(1)));
+ EATEST_VERIFY(eastl::cmp_greater_equal(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::min()));
+ EATEST_VERIFY(eastl::cmp_greater_equal(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::min()));
+ EATEST_VERIFY(eastl::cmp_greater_equal(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::max()));
+ EATEST_VERIFY(!eastl::cmp_greater_equal(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::max()));
+ if (eastl::is_signed_v<T>)
+ {
+ EATEST_VERIFY(eastl::cmp_greater_equal(T(-1), T(-1)));
+ EATEST_VERIFY(eastl::cmp_greater_equal(T(-1), T(-2)));
+ EATEST_VERIFY(!eastl::cmp_greater_equal(T(-2), T(-1)));
+ }
+
+ return nErrorCount;
+}
+
+template <typename T, typename U>
+static int TestUtilityCmpEql(const T x, const U y)
+{
+ int nErrorCount = 0;
+
+ EATEST_VERIFY(eastl::cmp_equal(T(x), U(y)));
+ EATEST_VERIFY(eastl::cmp_equal(U(y), T(x)));
+ EATEST_VERIFY(!eastl::cmp_not_equal(T(x), U(y)));
+ EATEST_VERIFY(!eastl::cmp_not_equal(U(y), T(x)));
+
+ return nErrorCount;
+}
+
+template <typename T, typename U>
+static int TestUtilityCmpLess(const T x, const U y)
+{
+ int nErrorCount = 0;
+
+ EATEST_VERIFY(eastl::cmp_less(T(x), U(y)));
+ EATEST_VERIFY(!eastl::cmp_less(U(y), T(x)));
+
+ EATEST_VERIFY(!eastl::cmp_greater_equal(T(x), U(y)));
+ EATEST_VERIFY(eastl::cmp_greater_equal(U(y), T(x)));
+
+ return nErrorCount;
+}
+
+template <typename T, typename U>
+static int TestUtilityCmpGreater(const T x, const U y)
+{
+ int nErrorCount = 0;
+
+ EATEST_VERIFY(eastl::cmp_greater(T(x), U(y)));
+ EATEST_VERIFY(!eastl::cmp_greater(U(y), T(x)));
+
+ EATEST_VERIFY(!eastl::cmp_less_equal(T(x), U(y)));
+ EATEST_VERIFY(eastl::cmp_less_equal(U(y), T(x)));
+
+ return nErrorCount;
+}
+
+template <typename T, typename U>
+static int TestUtilityCmpLessEq(const T x, const U y)
+{
+ int nErrorCount = 0;
+
+ EATEST_VERIFY(eastl::cmp_less_equal(T(x), U(y)));
+ EATEST_VERIFY(eastl::cmp_less(T(x), U(y)) || eastl::cmp_equal(T(x), U(y)));
+
+ EATEST_VERIFY(eastl::cmp_greater_equal(U(y), T(x)));
+
+ return nErrorCount;
+}
+
+template <typename T, typename U>
+static int TestUtilityCmpGreaterEq(const T x, const U y)
+{
+ int nErrorCount = 0;
+
+ EATEST_VERIFY(eastl::cmp_greater_equal(T(x), U(y)));
+ EATEST_VERIFY(eastl::cmp_greater(T(x), U(y)) || eastl::cmp_equal(T(x), U(y)));
+
+ EATEST_VERIFY(eastl::cmp_less_equal(U(y), T(x)));
+
+ return nErrorCount;
+}
+
+static int TestUtilityIntegralComp()
+{
+ int nErrorCount = 0;
+
+ // Test integral comparisons among same types
+ nErrorCount += TestCmpCommon<int>();
+ nErrorCount += TestCmpCommon<short>();
+ nErrorCount += TestCmpCommon<long>();
+ nErrorCount += TestCmpCommon<long long>();
+
+ nErrorCount += TestCmpCommon<unsigned int>();
+ nErrorCount += TestCmpCommon<unsigned short>();
+ nErrorCount += TestCmpCommon<unsigned long>();
+ nErrorCount += TestCmpCommon<unsigned long long>();
+
+ // Test integral comparison among different types
+ nErrorCount += TestUtilityCmpEql(int(0), short(0));
+ nErrorCount += TestUtilityCmpEql(short(2), long(2));
+ nErrorCount += TestUtilityCmpEql(short(3), unsigned long(3));
+ nErrorCount += TestUtilityCmpEql(int(-5), long long(-5));
+ nErrorCount += TestUtilityCmpEql(short(-100), long long(-100));
+ nErrorCount += TestUtilityCmpEql(unsigned int(100), long(100));
+ nErrorCount += TestUtilityCmpEql(unsigned long long(100), int(100));
+
+ nErrorCount += TestUtilityCmpLess(int(0), long long(1));
+ nErrorCount += TestUtilityCmpLess(int(-1), unsigned long(1));
+ nErrorCount += TestUtilityCmpLess(short(-100), long long(100));
+ nErrorCount += TestUtilityCmpLess(eastl::numeric_limits<long>::min(), short(0));
+ nErrorCount += TestUtilityCmpLess(short(0), eastl::numeric_limits<int>::max());
+ nErrorCount += TestUtilityCmpLess(eastl::numeric_limits<unsigned short>::min(), eastl::numeric_limits<int>::max());
+ nErrorCount += TestUtilityCmpLess(eastl::numeric_limits<short>::max(), eastl::numeric_limits<long>::max());
+ nErrorCount += TestUtilityCmpLess(eastl::numeric_limits<int>::max(), eastl::numeric_limits<long long>::max());
+ nErrorCount += TestUtilityCmpLess(int(-100), unsigned int(0));
+ nErrorCount += TestUtilityCmpLess(eastl::numeric_limits<int>::min(), eastl::numeric_limits<unsigned int>::min());
+
+ nErrorCount += TestUtilityCmpGreater(int(1), short(0));
+ nErrorCount += TestUtilityCmpGreater(unsigned long(1), int(-1));
+ nErrorCount += TestUtilityCmpGreater(unsigned long long(100), short(-100));
+ nErrorCount += TestUtilityCmpGreater(short(0), eastl::numeric_limits<short>::min());
+ nErrorCount += TestUtilityCmpGreater(eastl::numeric_limits<long>::max(), unsigned short(5));
+ nErrorCount += TestUtilityCmpGreater(eastl::numeric_limits<long>::max(), eastl::numeric_limits<int>::min());
+ nErrorCount += TestUtilityCmpGreater(eastl::numeric_limits<int>::max(), eastl::numeric_limits<short>::max());
+ nErrorCount += TestUtilityCmpGreater(eastl::numeric_limits<long long>::max(), eastl::numeric_limits<int>::max());
+ nErrorCount += TestUtilityCmpGreater(unsigned int(0), int(-100));
+ nErrorCount += TestUtilityCmpGreater(eastl::numeric_limits<unsigned int>::min(), eastl::numeric_limits<int>::min());
+
+ nErrorCount += TestUtilityCmpLessEq(int(0), short(1));
+ nErrorCount += TestUtilityCmpLessEq(int(-1), long long(-1));
+ nErrorCount += TestUtilityCmpLessEq(short(-100), unsigned long long(100));
+ nErrorCount += TestUtilityCmpLessEq(short(-100), long long(-100));
+ nErrorCount += TestUtilityCmpLessEq(eastl::numeric_limits<int>::min(), short(0));
+ nErrorCount += TestUtilityCmpLessEq(short(0), eastl::numeric_limits<int>::max());
+ nErrorCount += TestUtilityCmpLessEq(eastl::numeric_limits<short>::min(), eastl::numeric_limits<short>::min());
+ nErrorCount += TestUtilityCmpLessEq(eastl::numeric_limits<int>::max(), eastl::numeric_limits<int>::max());
+ nErrorCount += TestUtilityCmpLessEq(eastl::numeric_limits<int>::max(), eastl::numeric_limits<long long>::max());
+ nErrorCount += TestUtilityCmpLessEq(int(50), unsigned int(50));
+ nErrorCount += TestUtilityCmpLessEq(eastl::numeric_limits<int>::min(), eastl::numeric_limits<unsigned int>::min());
+
+ nErrorCount += TestUtilityCmpGreaterEq(int(1), short(1));
+ nErrorCount += TestUtilityCmpGreaterEq(long long(-1), int(-1));
+ nErrorCount += TestUtilityCmpGreaterEq(long long(-100), short(-100));
+ nErrorCount += TestUtilityCmpGreaterEq(short(0), long(0));
+ nErrorCount += TestUtilityCmpGreaterEq(eastl::numeric_limits<long>::max(), eastl::numeric_limits<long>::max());
+ nErrorCount += TestUtilityCmpGreaterEq(eastl::numeric_limits<int>::max(), eastl::numeric_limits<short>::min());
+ nErrorCount += TestUtilityCmpGreaterEq(eastl::numeric_limits<int>::max(), eastl::numeric_limits<short>::max());
+ nErrorCount += TestUtilityCmpGreaterEq(eastl::numeric_limits<long long>::max(), eastl::numeric_limits<int>::max());
+ nErrorCount += TestUtilityCmpGreaterEq(unsigned int(0), int(0));
+ nErrorCount += TestUtilityCmpGreaterEq(eastl::numeric_limits<unsigned int>::min(), eastl::numeric_limits<int>::min());
+
+ // Test in_range
+ EATEST_VERIFY(eastl::in_range<int>(0));
+ EATEST_VERIFY(eastl::in_range<int>(eastl::numeric_limits<int>::min()));
+ EATEST_VERIFY(eastl::in_range<int>(eastl::numeric_limits<int>::max()));
+ EATEST_VERIFY(eastl::in_range<unsigned int>(0));
+ EATEST_VERIFY(eastl::in_range<unsigned int>(eastl::numeric_limits<unsigned int>::min()));
+ EATEST_VERIFY(eastl::in_range<unsigned int>(eastl::numeric_limits<unsigned int>::max()));
+ EATEST_VERIFY(!eastl::in_range<unsigned int>(-1));
+ EATEST_VERIFY(!eastl::in_range<int>(eastl::numeric_limits<unsigned int>::max()));
+ EATEST_VERIFY(!eastl::in_range<unsigned int>(eastl::numeric_limits<int>::min()));
+
+ EATEST_VERIFY(eastl::in_range<short>(100));
+ EATEST_VERIFY(eastl::in_range<short>(eastl::numeric_limits<short>::min()));
+ EATEST_VERIFY(eastl::in_range<short>(eastl::numeric_limits<short>::max()));
+ EATEST_VERIFY(eastl::in_range<unsigned short>(100));
+ EATEST_VERIFY(eastl::in_range<unsigned short>(eastl::numeric_limits<unsigned short>::min()));
+ EATEST_VERIFY(eastl::in_range<unsigned short>(eastl::numeric_limits<unsigned short>::max()));
+ EATEST_VERIFY(!eastl::in_range<unsigned short>(-1));
+ EATEST_VERIFY(!eastl::in_range<short>(eastl::numeric_limits<unsigned int>::max()));
+ EATEST_VERIFY(!eastl::in_range<unsigned short>(eastl::numeric_limits<int>::min()));
+
+ EATEST_VERIFY(eastl::in_range<long>(50));
+ EATEST_VERIFY(eastl::in_range<long>(eastl::numeric_limits<long>::min()));
+ EATEST_VERIFY(eastl::in_range<long>(eastl::numeric_limits<long>::max()));
+ EATEST_VERIFY(eastl::in_range<unsigned long>(50));
+ EATEST_VERIFY(eastl::in_range<unsigned long>(eastl::numeric_limits<unsigned long>::min()));
+ EATEST_VERIFY(eastl::in_range<unsigned long>(eastl::numeric_limits<unsigned long>::max()));
+ EATEST_VERIFY(!eastl::in_range<unsigned long>(-1));
+ EATEST_VERIFY(!eastl::in_range<long>(eastl::numeric_limits<unsigned int>::max()));
+ EATEST_VERIFY(!eastl::in_range<unsigned long>(eastl::numeric_limits<int>::min()));
+
+ return nErrorCount;
+}
+#endif
+
///////////////////////////////////////////////////////////////////////////////
// TestUtility
//
@@ -627,6 +908,8 @@ int TestUtility()
nErrorCount += TestUtilityMove();
nErrorCount += TestUtilityIntegerSequence();
nErrorCount += TestUtilityExchange();
-
+#if defined(EA_COMPILER_CPP20_ENABLED)
+ nErrorCount += TestUtilityIntegralComp();
+#endif
return nErrorCount;
}
diff --git a/EASTL/test/source/TestVariant.cpp b/EASTL/test/source/TestVariant.cpp
index a8197e5..2a78a89 100644
--- a/EASTL/test/source/TestVariant.cpp
+++ b/EASTL/test/source/TestVariant.cpp
@@ -7,6 +7,7 @@
#include <EASTL/string.h>
#include <EASTL/algorithm.h>
#include <EASTL/sort.h>
+#include <EASTL/bonus/overloaded.h>
#ifdef EA_COMPILER_CPP14_ENABLED
#include "ConceptImpls.h"
@@ -291,7 +292,7 @@ int TestVariantHoldsAlternative()
VERIFY(!holds_alternative<long>(v)); // Verify that a query for a T not in the variant typelist returns false.
VERIFY(!holds_alternative<string>(v)); // Verify that a query for a T not in the variant typelist returns false.
- VERIFY(!holds_alternative<int>(v)); // variant does not hold an int
+ VERIFY(!holds_alternative<int>(v)); // variant does not hold an int
VERIFY(!holds_alternative<short>(v)); // variant does not hold a short
}
@@ -377,7 +378,7 @@ int TestVariantValuelessByException()
VERIFY(!v.valueless_by_exception());
}
- // TODO(rparolin): review exception safety for variant types
+ // TODO(rparolin): review exception safety for variant types
//
// {
// #if EASTL_EXCEPTIONS_ENABLED
@@ -563,12 +564,12 @@ int TestVariantSwap()
v1.swap(v2);
- VERIFY(get<int>(v1) == 24);
+ VERIFY(get<int>(v1) == 24);
VERIFY(get<int>(v2) == 42);
v1.swap(v2);
- VERIFY(get<int>(v1) == 42);
+ VERIFY(get<int>(v1) == 42);
VERIFY(get<int>(v2) == 24);
}
@@ -576,13 +577,13 @@ int TestVariantSwap()
variant<string> v1 = "Hello";
variant<string> v2 = "World";
- VERIFY(get<string>(v1) == "Hello");
+ VERIFY(get<string>(v1) == "Hello");
VERIFY(get<string>(v2) == "World");
v1.swap(v2);
VERIFY(get<string>(v1) == "World");
- VERIFY(get<string>(v2) == "Hello");
+ VERIFY(get<string>(v2) == "Hello");
}
return nErrorCount;
@@ -657,7 +658,7 @@ EA_NO_INLINE int TestVariantVisitNoInline(const eastl::variant<int, bool, unsign
struct MyVisitor
{
MyVisitor() = delete;
- MyVisitor(bool& b) : mVisited(b) {}
+ MyVisitor(bool& visited) : mVisited(visited) {};
void operator()(int) { mVisited = true; }
void operator()(bool) { mVisited = true; }
@@ -666,7 +667,7 @@ EA_NO_INLINE int TestVariantVisitNoInline(const eastl::variant<int, bool, unsign
bool& mVisited;
};
- eastl::visit(MyVisitor{bVisited}, v);
+ eastl::visit(MyVisitor(bVisited), v);
EATEST_VERIFY(bVisited);
@@ -682,7 +683,7 @@ EA_NO_INLINE int TestVariantVisit2NoInline(const eastl::variant<int, bool>& v0,
struct MyVisitor
{
MyVisitor() = delete;
- MyVisitor(bool& b) : mVisited(b) {}
+ MyVisitor(bool& visited) : mVisited(visited) {};
void operator()(int, int) { mVisited = true; }
void operator()(bool, int) { mVisited = true; }
@@ -692,7 +693,7 @@ EA_NO_INLINE int TestVariantVisit2NoInline(const eastl::variant<int, bool>& v0,
bool& mVisited;
};
- eastl::visit(MyVisitor{bVisited}, v0, v1);
+ eastl::visit(MyVisitor(bVisited), v0, v1);
EATEST_VERIFY(bVisited);
@@ -708,7 +709,7 @@ EA_NO_INLINE int TestVariantVisit3tNoInline(const eastl::variant<int, bool>& v0,
struct MyVisitor
{
MyVisitor() = delete;
- MyVisitor(bool& b) : mVisited(b) {}
+ MyVisitor(bool& visited) : mVisited(visited) {};
void operator()(int, int, int) { mVisited = true; }
void operator()(bool, int, int) { mVisited = true; }
@@ -723,38 +724,101 @@ EA_NO_INLINE int TestVariantVisit3tNoInline(const eastl::variant<int, bool>& v0,
bool& mVisited;
};
- eastl::visit(MyVisitor{bVisited}, v0, v1, v2);
+ eastl::visit(MyVisitor(bVisited), v0, v1, v2);
EATEST_VERIFY(bVisited);
return nErrorCount;
}
-int TestVariantVisitor()
+int TestVariantVisitorOverloaded()
{
using namespace eastl;
int nErrorCount = 0;
using v_t = variant<int, string, double, long>;
+ v_t arr[] = {42, "jean", 42.0, 42L};
+ v_t v{42.0};
+
+
+ #ifdef __cpp_deduction_guides
+ {
+ int count = 0;
+
+ for (auto& e : arr)
+ {
+ eastl::visit(
+ overloaded{
+ [&](int) { count++; },
+ [&](string) { count++; },
+ [&](double) { count++; },
+ [&](long) { count++; }},
+ e
+ );
+ }
+
+ VERIFY(count == EAArrayCount(arr));
+ }
+
+ {
+ double visitedValue = 0.0f;
+
+ eastl::visit(
+ overloaded{
+ [](int) { },
+ [](string) { },
+ [&](double d) { visitedValue = d; },
+ [](long) { }},
+ v
+ );
+
+ VERIFY(visitedValue == 42.0f);
+ }
+
+ #endif
+
+ {
+ int count = 0;
+
+ for (auto& e : arr)
+ {
+ eastl::visit(
+ eastl::make_overloaded(
+ [&](int) { count++; },
+ [&](string) { count++; },
+ [&](double) { count++; },
+ [&](long) { count++; }),
+ e
+ );
+ }
- // TODO(rparolin): When we have a C++17 compiler
- //
- // template deduction guides test
- // template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
- // template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
+ VERIFY(count == EAArrayCount(arr));
+ }
+
+ {
+ double visitedValue = 0.0f;
- // {
- // v_t arr[] = {42, "rob", 42.0, 42L};
+ eastl::visit(
+ eastl::make_overloaded(
+ [](int) { },
+ [](string) { },
+ [&](double d) { visitedValue = d; },
+ [](long) { }),
+ v
+ );
- // int count = 0;
- // for (auto& e : arr)
- // {
- // eastl::visit(overloaded{[&](int) { count++; },
- // [&](string) { count++; },
- // [&](double) { count++; },
- // [&](long) { count++; }}, e);
- // }
- // }
+ VERIFY(visitedValue == 42.0f);
+ }
+
+ return nErrorCount;
+}
+
+int TestVariantVisitor()
+{
+ using namespace eastl;
+ int nErrorCount = 0;
+
+ using v_t = variant<int, string, double, long>;
{
v_t arr[] = {42, "hello", 42.0, 42L};
@@ -982,7 +1046,7 @@ int TestVariantVisitor()
struct MultipleVisitor
{
MultipleVisitor() = delete;
- MultipleVisitor(bool& b) : mVisited(b) {}
+ MultipleVisitor(bool& visited) : mVisited(visited) {};
void operator()(int, int) { mVisited = true; }
void operator()(int, bool) {}
@@ -992,11 +1056,11 @@ int TestVariantVisitor()
bool& mVisited;
};
- visit(MultipleVisitor{bVisited}, v0, v1);
+ visit(MultipleVisitor(bVisited), v0, v1);
EATEST_VERIFY(bVisited);
bVisited = false;
- visit<void>(MultipleVisitor{bVisited}, v0, v1);
+ visit<void>(MultipleVisitor(bVisited), v0, v1);
EATEST_VERIFY(bVisited);
}
@@ -1742,6 +1806,7 @@ int TestVariant()
nErrorCount += TestVariantEmplace();
nErrorCount += TestVariantRelOps();
nErrorCount += TestVariantInplaceCtors();
+ nErrorCount += TestVariantVisitorOverloaded();
nErrorCount += TestVariantVisitor();
nErrorCount += TestVariantAssignment();
nErrorCount += TestVariantMoveOnly();
@@ -1756,13 +1821,3 @@ int TestVariant()
#else
int TestVariant() { return 0; }
#endif
-
-
-
-
-
-
-
-
-
-
diff --git a/EASTL/test/source/TestVector.cpp b/EASTL/test/source/TestVector.cpp
index 0fe719d..69cdb52 100644
--- a/EASTL/test/source/TestVector.cpp
+++ b/EASTL/test/source/TestVector.cpp
@@ -1258,6 +1258,84 @@ int TestVector()
EATEST_VERIFY(!(intArray1 > intArray2));
}
+ // three way comparison operator
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ {
+ using namespace eastl;
+
+ vector<int> intArray1(10);
+ vector<int> intArray2(10);
+
+ for (i = 0; i < intArray1.size(); i++)
+ {
+ intArray1[i] = (int)i; // Make intArray1 equal to intArray2.
+ intArray2[i] = (int)i;
+ }
+
+ // Verify equality between intArray1 and intArray2
+ EATEST_VERIFY((intArray1 <=> intArray2) == 0);
+ EATEST_VERIFY(!((intArray1 <=> intArray2) != 0));
+ EATEST_VERIFY((intArray1 <=> intArray2) <= 0);
+ EATEST_VERIFY((intArray1 <=> intArray2) >= 0);
+ EATEST_VERIFY(!((intArray1 <=> intArray2) < 0));
+ EATEST_VERIFY(!((intArray1 <=> intArray2) > 0));
+
+ intArray1.push_back(100); // Make intArray1 less than intArray2.
+ intArray2.push_back(101);
+
+ // Verify intArray1 < intArray2
+ EATEST_VERIFY(!((intArray1 <=> intArray2) == 0));
+ EATEST_VERIFY((intArray1 <=> intArray2) != 0);
+ EATEST_VERIFY((intArray1 <=> intArray2) <= 0);
+ EATEST_VERIFY(!((intArray1 <=> intArray2) >= 0));
+ EATEST_VERIFY(((intArray1 <=> intArray2) < 0));
+ EATEST_VERIFY(!((intArray1 <=> intArray2) > 0));
+
+ for (i = 0; i < 3; i++) // Make the length of intArray2 less than intArray1
+ intArray2.pop_back();
+
+ // Verify intArray2.size() < intArray1.size() and intArray2 is a subset of intArray1
+ EATEST_VERIFY(!((intArray1 <=> intArray2) == 0));
+ EATEST_VERIFY((intArray1 <=> intArray2) != 0);
+ EATEST_VERIFY((intArray1 <=> intArray2) >= 0);
+ EATEST_VERIFY(!((intArray1 <=> intArray2) <= 0));
+ EATEST_VERIFY(((intArray1 <=> intArray2) > 0));
+ EATEST_VERIFY(!((intArray1 <=> intArray2) < 0));
+ }
+
+ {
+ using namespace eastl;
+
+ vector<int> intArray1 = {1, 2, 3, 4, 5, 6, 7};
+ vector<int> intArray2 = {7, 6, 5, 4, 3, 2, 1};
+ vector<int> intArray3 = {1, 2, 3, 4};
+
+ struct weak_ordering_vector
+ {
+ vector<int> vec;
+ inline std::weak_ordering operator<=>(const weak_ordering_vector& b) const { return vec <=> b.vec; }
+ };
+
+ EATEST_VERIFY(synth_three_way{}(weak_ordering_vector{intArray1}, weak_ordering_vector{intArray2}) == std::weak_ordering::less);
+ EATEST_VERIFY(synth_three_way{}(weak_ordering_vector{intArray3}, weak_ordering_vector{intArray1}) == std::weak_ordering::less);
+ EATEST_VERIFY(synth_three_way{}(weak_ordering_vector{intArray2}, weak_ordering_vector{intArray1}) == std::weak_ordering::greater);
+ EATEST_VERIFY(synth_three_way{}(weak_ordering_vector{intArray2}, weak_ordering_vector{intArray3}) == std::weak_ordering::greater);
+ EATEST_VERIFY(synth_three_way{}(weak_ordering_vector{intArray1}, weak_ordering_vector{intArray1}) == std::weak_ordering::equivalent);
+
+ struct strong_ordering_vector
+ {
+ vector<int> vec;
+ inline std::strong_ordering operator<=>(const strong_ordering_vector& b) const { return vec <=> b.vec; }
+ };
+
+ EATEST_VERIFY(synth_three_way{}(strong_ordering_vector{intArray1}, strong_ordering_vector{intArray2}) == std::strong_ordering::less);
+ EATEST_VERIFY(synth_three_way{}(strong_ordering_vector{intArray3}, strong_ordering_vector{intArray1}) == std::strong_ordering::less);
+ EATEST_VERIFY(synth_three_way{}(strong_ordering_vector{intArray2}, strong_ordering_vector{intArray1}) == std::strong_ordering::greater);
+ EATEST_VERIFY(synth_three_way{}(strong_ordering_vector{intArray2}, strong_ordering_vector{intArray3}) == std::strong_ordering::greater);
+ EATEST_VERIFY(synth_three_way{}(strong_ordering_vector{intArray1}, strong_ordering_vector{intArray1}) == std::strong_ordering::equal);
+ }
+#endif
+
{
using namespace eastl;
@@ -1317,7 +1395,7 @@ int TestVector()
eastl::vector<TestObject> toTest;
// InputIterator
- demoted_iterator<TestObject*, eastl::forward_iterator_tag> toInput(&to);
+ demoted_iterator<TestObject*, EASTL_ITC_NS::forward_iterator_tag> toInput(&to);
toTest.assign(toInput, toInput);
// ForwardIterator
@@ -1637,7 +1715,7 @@ int TestVector()
{
struct iterator
{
- typedef eastl::input_iterator_tag iterator_category;
+ typedef EASTL_ITC_NS::input_iterator_tag iterator_category;
typedef int value_type;
typedef ptrdiff_t difference_type;
typedef int* pointer;
@@ -1718,20 +1796,24 @@ int TestVector()
{
eastl::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9};
- eastl::erase(v, 5);
+ auto numErased = eastl::erase(v, 5);
VERIFY((v == eastl::vector<int> {1, 2, 3, 4, 6, 7, 8, 9}));
+ VERIFY(numErased == 1);
- eastl::erase(v, 2);
+ numErased = eastl::erase(v, 2);
VERIFY((v == eastl::vector<int> {1, 3, 4, 6, 7, 8, 9}));
+ VERIFY(numErased == 1);
- eastl::erase(v, 9);
+ numErased = eastl::erase(v, 9);
VERIFY((v == eastl::vector<int> {1, 3, 4, 6, 7, 8}));
+ VERIFY(numErased == 1);
}
{
eastl::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9};
- eastl::erase_if(v, [](auto i) { return i % 2 == 0; });
+ auto numErased = eastl::erase_if(v, [](auto i) { return i % 2 == 0; });
VERIFY((v == eastl::vector<int>{1, 3, 5, 7, 9}));
+ VERIFY(numErased == 4);
}
}
diff --git a/EASTL/test/source/main.cpp b/EASTL/test/source/main.cpp
index 8ce7c1b..132bab1 100644
--- a/EASTL/test/source/main.cpp
+++ b/EASTL/test/source/main.cpp
@@ -145,7 +145,7 @@ int EAMain(int argc, char* argv[])
testSuite.AddTest("VectorSet", TestVectorSet);
testSuite.AddTest("AtomicBasic", TestAtomicBasic);
testSuite.AddTest("AtomicAsm", TestAtomicAsm);
- testSuite.AddTest("TestBitcast", TestBitcast);
+ testSuite.AddTest("Bitcast", TestBitcast);
nErrorCount += testSuite.Run();