From cc509ef9c9af63d9ca1152b2726e64f731e514b1 Mon Sep 17 00:00:00 2001 From: "dmytro.ivanchykhin" Date: Sat, 2 Apr 2022 21:10:30 +0300 Subject: [PATCH 01/31] switching to the latest version of Foundation and IIBMalloc modules and adding arm64 processor --- library/src/iibmalloc | 2 +- library/src/safe_ptr_common.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/src/iibmalloc b/library/src/iibmalloc index 0b11de5..15d2e03 160000 --- a/library/src/iibmalloc +++ b/library/src/iibmalloc @@ -1 +1 @@ -Subproject commit 0b11de51ba2fbdea0f478de9ce839288f991c633 +Subproject commit 15d2e03eaa5af2c360f635ab0bd3b472a1b1ccbc diff --git a/library/src/safe_ptr_common.h b/library/src/safe_ptr_common.h index b8d88d9..f104561 100644 --- a/library/src/safe_ptr_common.h +++ b/library/src/safe_ptr_common.h @@ -46,7 +46,7 @@ #endif -#if defined NODECPP_X64 && !defined NODECPP_NOT_USING_IIBMALLOC +#if ((defined NODECPP_X64) || (defined NODECPP_ARM64)) && (!defined NODECPP_NOT_USING_IIBMALLOC) #define NODECPP_USE_IIBMALLOC #else #define NODECPP_USE_NEW_DELETE_ALLOC From 2116c792cc3a32fc68afb826b5838c5b1c7b9eb5 Mon Sep 17 00:00:00 2001 From: "dmytro.ivanchykhin" Date: Mon, 11 Apr 2022 10:42:27 +0300 Subject: [PATCH 02/31] switching to the latest version of IIBMalloc module --- library/src/iibmalloc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/iibmalloc b/library/src/iibmalloc index 15d2e03..84dc304 160000 --- a/library/src/iibmalloc +++ b/library/src/iibmalloc @@ -1 +1 @@ -Subproject commit 15d2e03eaa5af2c360f635ab0bd3b472a1b1ccbc +Subproject commit 84dc304f79d6b5b1de889709d600dcaebea77eba From 5f7e8697936dc2b2567ae6bc938d6e0df33fa94e Mon Sep 17 00:00:00 2001 From: Marcos Bracco Date: Fri, 22 Apr 2022 12:43:05 -0300 Subject: [PATCH 03/31] Remove easlt::atomic because of build errors --- library/3rdparty/EASTL-3.17.03.diff | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/library/3rdparty/EASTL-3.17.03.diff b/library/3rdparty/EASTL-3.17.03.diff index 4c75b0a..991c11e 100644 --- a/library/3rdparty/EASTL-3.17.03.diff +++ b/library/3rdparty/EASTL-3.17.03.diff @@ -102,6 +102,23 @@ index ad20e4d..84d0445 100644 /// dummy_allocator /// /// Defines an allocator which does nothing. It returns NULL from allocate calls. +diff --git a/include/EASTL/internal/atomic/atomic_integral.h b/include/EASTL/internal/atomic/atomic_integral.h +index 060b5b8..9f01c25 100644 +--- a/include/EASTL/internal/atomic/atomic_integral.h ++++ b/include/EASTL/internal/atomic/atomic_integral.h +@@ -326,9 +326,9 @@ namespace internal + EASTL_ATOMIC_INTEGRAL_WIDTH_SPECIALIZE(8, 64) + #endif + +-#if defined(EASTL_ATOMIC_HAS_128BIT) +- EASTL_ATOMIC_INTEGRAL_WIDTH_SPECIALIZE(16, 128) +-#endif ++// #if defined(EASTL_ATOMIC_HAS_128BIT) ++// EASTL_ATOMIC_INTEGRAL_WIDTH_SPECIALIZE(16, 128) ++// #endif + + + } // namespace internal diff --git a/include/EASTL/internal/hashtable.h b/include/EASTL/internal/hashtable.h index 21767f3..772203c 100644 --- a/include/EASTL/internal/hashtable.h From ef6c75008dc204cfc5c72c902dcca0bd5502247c Mon Sep 17 00:00:00 2001 From: Marcos Bracco Date: Fri, 22 Apr 2022 12:53:33 -0300 Subject: [PATCH 04/31] added ci scripts --- .../containers/EASTL-benchmark/CMakeLists.txt | 2 +- library/tools/ci-clang11.sh | 16 ++++++++++++ library/tools/ci-gcc10.sh | 16 ++++++++++++ library/tools/ci-vs2019.bat | 15 +++++++++++ library/tools/ci-vs2022.bat | 15 +++++++++++ library/tools/teamcity-ninja-windows.bat | 26 ------------------- 6 files changed, 63 insertions(+), 27 deletions(-) create mode 100644 library/tools/ci-clang11.sh create mode 100644 library/tools/ci-gcc10.sh create mode 100644 library/tools/ci-vs2019.bat create mode 100644 library/tools/ci-vs2022.bat delete mode 100644 library/tools/teamcity-ninja-windows.bat diff --git a/library/test/containers/EASTL-benchmark/CMakeLists.txt b/library/test/containers/EASTL-benchmark/CMakeLists.txt index 340c214..f721cf9 100644 --- a/library/test/containers/EASTL-benchmark/CMakeLists.txt +++ b/library/test/containers/EASTL-benchmark/CMakeLists.txt @@ -28,5 +28,5 @@ target_link_libraries(SafeMemoryBenchmarks safememory) #------------------------------------------------------------------------------------------- # Run Unit tests and verify the results. #------------------------------------------------------------------------------------------- -add_test(SafeMemoryBenchmarksRun SafeMemoryBenchmarks) +# add_test(SafeMemoryBenchmarksRun SafeMemoryBenchmarks) diff --git a/library/tools/ci-clang11.sh b/library/tools/ci-clang11.sh new file mode 100644 index 0000000..8e577ce --- /dev/null +++ b/library/tools/ci-clang11.sh @@ -0,0 +1,16 @@ +#!/bin/sh +set -ev + +rm -Rf library/build/clang11 +mkdir -p library/build/clang11 +cd library/build/clang11 + +export CC=clang-11 +export CXX=clang++-11 + +cmake -DCMAKE_BUILD_TYPE=Release -DSAFEMEMORY_TEST=ON -G "Unix Makefiles" ../.. + +cmake --build . + +ctest --output-on-failure + diff --git a/library/tools/ci-gcc10.sh b/library/tools/ci-gcc10.sh new file mode 100644 index 0000000..492aa8d --- /dev/null +++ b/library/tools/ci-gcc10.sh @@ -0,0 +1,16 @@ +#!/bin/sh +set -ev + +rm -Rf library/build/gcc10 +mkdir -p library/build/gcc10 +cd library/build/gcc10 + +export CC=gcc-10 +export CXX=g++-10 + +cmake -DCMAKE_BUILD_TYPE=Release -DSAFEMEMORY_TEST=ON -G "Unix Makefiles" ../.. + +cmake --build . + +ctest --output-on-failure + diff --git a/library/tools/ci-vs2019.bat b/library/tools/ci-vs2019.bat new file mode 100644 index 0000000..c88447c --- /dev/null +++ b/library/tools/ci-vs2019.bat @@ -0,0 +1,15 @@ +rem script to build with Visual Studio +rem run from root as 'tools\ci-msvc2019' + +rmdir /S /Q library\build\vs2019 +mkdir library\build\vs2019 +cd library\build\vs2019 + +cmake -DSAFEMEMORY_TEST=ON -G "Visual Studio 16 2019" ..\.. +@if ERRORLEVEL 1 exit /b %ERRORLEVEL% + +cmake --build . --config Release +@if ERRORLEVEL 1 exit /b %ERRORLEVEL% + +ctest --output-on-failure -C Release +@if ERRORLEVEL 1 exit /b %ERRORLEVEL% diff --git a/library/tools/ci-vs2022.bat b/library/tools/ci-vs2022.bat new file mode 100644 index 0000000..4a42e4a --- /dev/null +++ b/library/tools/ci-vs2022.bat @@ -0,0 +1,15 @@ +rem script to build with Visual Studio +rem run from root as 'tools\ci-msvc2022' + +rmdir /S /Q library\build\vs2022 +mkdir library\build\vs2022 +cd library\build\vs2022 + +cmake -DSAFEMEMORY_TEST=ON -G "Visual Studio 17 2022" ..\.. +@if ERRORLEVEL 1 exit /b %ERRORLEVEL% + +cmake --build . --config Release +@if ERRORLEVEL 1 exit /b %ERRORLEVEL% + +ctest --output-on-failure -C Release +@if ERRORLEVEL 1 exit /b %ERRORLEVEL% diff --git a/library/tools/teamcity-ninja-windows.bat b/library/tools/teamcity-ninja-windows.bat deleted file mode 100644 index a71ae8d..0000000 --- a/library/tools/teamcity-ninja-windows.bat +++ /dev/null @@ -1,26 +0,0 @@ -rem Build script used by teamcity CI -rem This script requires a properly configured environment, in particular -rem vcvars64.bat from Visual Studio and sccache.exe and ninja.exe in the path - -if not exist "build\" ( - mkdir build -) - -cd build - -if not exist "teamcity\" ( - mkdir teamcity -) - -cd teamcity - -cmake -DCMAKE_CXX_COMPILER_LAUNCHER="sccache" -DCMAKE_BUILD_TYPE=Release -G Ninja ..\.. -@if ERRORLEVEL 1 exit /b %ERRORLEVEL% - -cmake --build . -@if ERRORLEVEL 1 exit /b %ERRORLEVEL% - -ctest --output-on-failure -@if ERRORLEVEL 1 exit /b %ERRORLEVEL% - -cd ..\.. From c9e37b01ae539a6a4880e6a7718b2e864d23e798 Mon Sep 17 00:00:00 2001 From: Marcos Bracco Date: Fri, 22 Apr 2022 13:04:20 -0300 Subject: [PATCH 05/31] eastl::atomic 128 bits has build error on VS2022 --- .../EASTL/include/EASTL/internal/atomic/atomic_integral.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_integral.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_integral.h index 060b5b8..9f01c25 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_integral.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_integral.h @@ -326,9 +326,9 @@ namespace internal EASTL_ATOMIC_INTEGRAL_WIDTH_SPECIALIZE(8, 64) #endif -#if defined(EASTL_ATOMIC_HAS_128BIT) - EASTL_ATOMIC_INTEGRAL_WIDTH_SPECIALIZE(16, 128) -#endif +// #if defined(EASTL_ATOMIC_HAS_128BIT) +// EASTL_ATOMIC_INTEGRAL_WIDTH_SPECIALIZE(16, 128) +// #endif } // namespace internal From 8e35cf79bacdeedb920d8c7f91fa1c00f138a133 Mon Sep 17 00:00:00 2001 From: Marcos Bracco Date: Mon, 25 Apr 2022 14:14:58 -0300 Subject: [PATCH 06/31] bug fix --- library/src/safe_ptr_impl.h | 2 ++ library/src/safe_ptr_no_checks.h | 1 + 2 files changed, 3 insertions(+) diff --git a/library/src/safe_ptr_impl.h b/library/src/safe_ptr_impl.h index 0f9759e..43805f8 100644 --- a/library/src/safe_ptr_impl.h +++ b/library/src/safe_ptr_impl.h @@ -32,6 +32,8 @@ #include "memory_safety.h" #include "../include/nodecpp_error/nodecpp_error.h" #include "safe_memory_error.h" +#include "iibmalloc/src/iibmalloc.h" + #ifdef NODECPP_MEMORY_SAFETY_DBG_ADD_PTR_LIFECYCLE_INFO #include #endif // NODECPP_MEMORY_SAFETY_DBG_ADD_PTR_LIFECYCLE_INFO diff --git a/library/src/safe_ptr_no_checks.h b/library/src/safe_ptr_no_checks.h index 843e58e..dc99c67 100644 --- a/library/src/safe_ptr_no_checks.h +++ b/library/src/safe_ptr_no_checks.h @@ -30,6 +30,7 @@ #include "safe_ptr_common.h" #include "memory_safety.h" +#include "iibmalloc/src/iibmalloc.h" // forward declaration namespace safememory { From e4213d1b63882f8575b76c3b2e77a81effd282f5 Mon Sep 17 00:00:00 2001 From: Marcos Bracco Date: Tue, 3 May 2022 19:33:30 -0300 Subject: [PATCH 07/31] update iibmalloc --- library/src/iibmalloc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/iibmalloc b/library/src/iibmalloc index 84dc304..3ce1fca 160000 --- a/library/src/iibmalloc +++ b/library/src/iibmalloc @@ -1 +1 @@ -Subproject commit 84dc304f79d6b5b1de889709d600dcaebea77eba +Subproject commit 3ce1fca7139ebabacacc4e75d1baa491c6e8a968 From e5c31dabffecf20a3ecdb072abe5f0dfbe32f0bc Mon Sep 17 00:00:00 2001 From: "dmytro.ivanchykhin" Date: Wed, 4 May 2022 10:29:50 +0300 Subject: [PATCH 08/31] switching to the latest version of Foundation and IIBMalloc modules; fixes inspired by enabling /analyze option for msvc --- library/include/safememory/array.h | 2 +- .../safememory/detail/array_iterator.h | 2 +- .../safememory/detail/dezombiefy_iterators.h | 4 +- .../safememory/detail/hashtable_iterator.h | 2 +- .../detail/soft_ptr_with_zero_offset.h | 12 ++-- library/src/iibmalloc | 2 +- library/src/safe_ptr_impl.h | 24 +++---- library/src/safe_ptr_no_checks.h | 18 ++--- library/test/build/TestSafePointers.vcxproj | 72 ++++++++++++------- 9 files changed, 81 insertions(+), 57 deletions(-) diff --git a/library/include/safememory/array.h b/library/include/safememory/array.h index 4673ac5..2bcfd1f 100644 --- a/library/include/safememory/array.h +++ b/library/include/safememory/array.h @@ -133,7 +133,7 @@ struct array eastl::uninitialized_copy_ptr(other.begin_unsafe(), other.end_unsafe(), begin_unsafe()); } - array(array&& other) { + array(array&& other) noexcept { eastl::uninitialized_move_ptr(other.begin_unsafe(), other.end_unsafe(), begin_unsafe()); } diff --git a/library/include/safememory/detail/array_iterator.h b/library/include/safememory/detail/array_iterator.h index 9ef8c5b..fcccbc6 100644 --- a/library/include/safememory/detail/array_iterator.h +++ b/library/include/safememory/detail/array_iterator.h @@ -236,7 +236,7 @@ class array_heap_safe_iterator array_heap_safe_iterator(const array_heap_safe_iterator& ri) = default; array_heap_safe_iterator& operator=(const array_heap_safe_iterator& ri) = default; - array_heap_safe_iterator(array_heap_safe_iterator&& ri) = default; + array_heap_safe_iterator(array_heap_safe_iterator&& ri) noexcept = default; array_heap_safe_iterator& operator=(array_heap_safe_iterator&& ri) = default; /// allow non-const to const constructor diff --git a/library/include/safememory/detail/dezombiefy_iterators.h b/library/include/safememory/detail/dezombiefy_iterators.h index ce3f9ee..603a084 100644 --- a/library/include/safememory/detail/dezombiefy_iterators.h +++ b/library/include/safememory/detail/dezombiefy_iterators.h @@ -75,7 +75,7 @@ class iterator_registry { iterator_registry(const iterator_registry&) {} //don't copy registry - iterator_registry(iterator_registry&& other) { + iterator_registry(iterator_registry&& other) noexcept { // don't copy registry other.invalidateAllIterators(); } @@ -91,7 +91,7 @@ class iterator_registry { return *this; } - iterator_registry& operator=(iterator_registry&& other) { + iterator_registry& operator=(iterator_registry&& other) noexcept { if(this == std::addressof(other)) return *this; diff --git a/library/include/safememory/detail/hashtable_iterator.h b/library/include/safememory/detail/hashtable_iterator.h index 058bf30..f2f24ab 100644 --- a/library/include/safememory/detail/hashtable_iterator.h +++ b/library/include/safememory/detail/hashtable_iterator.h @@ -75,7 +75,7 @@ namespace safememory::detail { hashtable_stack_only_iterator(const this_type&) = default; hashtable_stack_only_iterator& operator=(const hashtable_stack_only_iterator& ri) = default; - hashtable_stack_only_iterator(hashtable_stack_only_iterator&& ri) = default; + hashtable_stack_only_iterator(hashtable_stack_only_iterator&& ri) noexcept = default; hashtable_stack_only_iterator& operator=(hashtable_stack_only_iterator&& ri) = default; ~hashtable_stack_only_iterator() = default; diff --git a/library/include/safememory/detail/soft_ptr_with_zero_offset.h b/library/include/safememory/detail/soft_ptr_with_zero_offset.h index 055b795..d01b17e 100644 --- a/library/include/safememory/detail/soft_ptr_with_zero_offset.h +++ b/library/include/safememory/detail/soft_ptr_with_zero_offset.h @@ -107,12 +107,12 @@ class soft_ptr_with_zero_offset_base return *this; } - soft_ptr_with_zero_offset_base( soft_ptr_with_zero_offset_base&& other ) { + soft_ptr_with_zero_offset_base( soft_ptr_with_zero_offset_base&& other ) noexcept { // mb: copy is actually more light weight than move, and we don't need real move ptr.copy_from(other.ptr); } - soft_ptr_with_zero_offset_base& operator=( soft_ptr_with_zero_offset_base&& other ) { + soft_ptr_with_zero_offset_base& operator=( soft_ptr_with_zero_offset_base&& other ) noexcept { // mb: copy is actually more light weight than move, and we don't need real move if(this == std::addressof(other)) return *this; @@ -181,8 +181,8 @@ class soft_ptr_with_zero_offset_impl : public soft_ptr_with_zero_offset_base soft_ptr_with_zero_offset_impl( const soft_ptr_with_zero_offset_impl& ) = default; soft_ptr_with_zero_offset_impl& operator=( const soft_ptr_with_zero_offset_impl& ) = default; - soft_ptr_with_zero_offset_impl( soft_ptr_with_zero_offset_impl&& ) = default; - soft_ptr_with_zero_offset_impl& operator=( soft_ptr_with_zero_offset_impl&& ) = default; + soft_ptr_with_zero_offset_impl( soft_ptr_with_zero_offset_impl&& ) noexcept = default; + soft_ptr_with_zero_offset_impl& operator=( soft_ptr_with_zero_offset_impl&& ) noexcept = default; soft_ptr_with_zero_offset_impl( std::nullptr_t ) {} soft_ptr_with_zero_offset_impl& operator=( std::nullptr_t ) { reset(); return *this; } @@ -241,8 +241,8 @@ class soft_ptr_with_zero_offset_impl> : public soft_ptr_with_z soft_ptr_with_zero_offset_impl( const soft_ptr_with_zero_offset_impl& other ) = default; soft_ptr_with_zero_offset_impl& operator=( const soft_ptr_with_zero_offset_impl& other ) = default; - soft_ptr_with_zero_offset_impl( soft_ptr_with_zero_offset_impl&& other ) = default; - soft_ptr_with_zero_offset_impl& operator=( soft_ptr_with_zero_offset_impl&& other ) = default; + soft_ptr_with_zero_offset_impl( soft_ptr_with_zero_offset_impl&& other ) noexcept = default; + soft_ptr_with_zero_offset_impl& operator=( soft_ptr_with_zero_offset_impl&& other ) noexcept = default; soft_ptr_with_zero_offset_impl( std::nullptr_t ) { } soft_ptr_with_zero_offset_impl& operator=( std::nullptr_t ){ reset(); return *this; } diff --git a/library/src/iibmalloc b/library/src/iibmalloc index 0b11de5..f7f5e64 160000 --- a/library/src/iibmalloc +++ b/library/src/iibmalloc @@ -1 +1 @@ -Subproject commit 0b11de51ba2fbdea0f478de9ce839288f991c633 +Subproject commit f7f5e64d3e447b72db9a59e07b0e95f1a7360609 diff --git a/library/src/safe_ptr_impl.h b/library/src/safe_ptr_impl.h index 0f9759e..250bd28 100644 --- a/library/src/safe_ptr_impl.h +++ b/library/src/safe_ptr_impl.h @@ -680,7 +680,7 @@ class owning_ptr_base_impl } owning_ptr_base_impl( const owning_ptr_base_impl& other ) = delete; owning_ptr_base_impl& operator = ( const owning_ptr_base_impl& other ) = delete; - owning_ptr_base_impl( owning_ptr_base_impl&& other ) + owning_ptr_base_impl( owning_ptr_base_impl&& other ) noexcept { #ifdef NODECPP_MEMORY_SAFETY_DBG_ADD_PTR_LIFECYCLE_INFO creationInfo = std::move( other.creationInfo ); @@ -694,7 +694,7 @@ class owning_ptr_base_impl other.dbgCheckValidity(); dbgCheckValidity(); } - owning_ptr_base_impl& operator = ( owning_ptr_base_impl&& other ) + owning_ptr_base_impl& operator = ( owning_ptr_base_impl&& other ) noexcept { if ( this == &other ) return *this; #ifdef NODECPP_MEMORY_SAFETY_DBG_ADD_PTR_LIFECYCLE_INFO @@ -909,13 +909,13 @@ class owning_ptr_impl : public owning_ptr_base_impl owning_ptr_impl( make_owning_t mo, T* t_ ) : owning_ptr_base_impl( mo, t_ ) {} owning_ptr_impl() : owning_ptr_base_impl() {} owning_ptr_impl( const owning_ptr_impl& other ) = delete; - owning_ptr_impl( owning_ptr_impl&& other ) : owning_ptr_base_impl( std::move(other) ) {} + owning_ptr_impl( owning_ptr_impl&& other ) noexcept : owning_ptr_base_impl( std::move(other) ) {} template owning_ptr_impl( owning_ptr_impl&& other ) : owning_ptr_base_impl( std::move(other) ) {} owning_ptr_impl( std::nullptr_t nulp ) : owning_ptr_base_impl( nulp ) {} owning_ptr_impl& operator = ( const owning_ptr_impl& other ) = delete; - owning_ptr_impl& operator = ( owning_ptr_impl&& other ) { + owning_ptr_impl& operator = ( owning_ptr_impl&& other ) noexcept { if ( this == &other ) return *this; owning_ptr_base_impl::operator = ( std::move( other ) ); return *this; @@ -1343,7 +1343,7 @@ class soft_ptr_base_impl } - soft_ptr_base_impl( soft_ptr_base_impl&& other ) + soft_ptr_base_impl( soft_ptr_base_impl&& other ) noexcept { if ( this == &other ) return; #ifdef NODECPP_MEMORY_SAFETY_ON_DEMAND @@ -1390,7 +1390,7 @@ class soft_ptr_base_impl #endif // NODECPP_MEMORY_SAFETY_DBG_ADD_PTR_LIFECYCLE_INFO } - soft_ptr_base_impl& operator = ( soft_ptr_base_impl&& other ) + soft_ptr_base_impl& operator = ( soft_ptr_base_impl&& other ) noexcept { // TODO+++: revise if ( this == &other ) return *this; @@ -1906,9 +1906,9 @@ class soft_ptr_impl : public soft_ptr_base_impl } - soft_ptr_impl( soft_ptr_impl&& other ) : soft_ptr_base_impl( std::move(other) ) {} + soft_ptr_impl( soft_ptr_impl&& other ) noexcept : soft_ptr_base_impl( std::move(other) ) {} - soft_ptr_impl& operator = ( soft_ptr_impl&& other ) + soft_ptr_impl& operator = ( soft_ptr_impl&& other ) noexcept { if ( this == &other ) return *this; soft_ptr_base_impl::operator = ( std::move(other) ); @@ -2148,9 +2148,9 @@ class soft_ptr_impl : public soft_ptr_base_impl } - soft_ptr_impl( soft_ptr_impl&& other ) : soft_ptr_base_impl( std::move(other) ) {} + soft_ptr_impl( soft_ptr_impl&& other ) noexcept : soft_ptr_base_impl( std::move(other) ) {} - soft_ptr_impl& operator = ( soft_ptr_impl&& other ) + soft_ptr_impl& operator = ( soft_ptr_impl&& other ) noexcept { if ( this == &other ) return *this; soft_ptr_base_impl::operator = ( std::move(other) ); @@ -2302,10 +2302,10 @@ class soft_this_ptr2_impl soft_this_ptr2_impl() : cbPtr(getCbPtr()) {} soft_this_ptr2_impl(const soft_this_ptr2_impl&) : cbPtr(getCbPtr()) {} - soft_this_ptr2_impl(soft_this_ptr2_impl&&) : cbPtr(getCbPtr()) {} + soft_this_ptr2_impl(soft_this_ptr2_impl&&) noexcept : cbPtr(getCbPtr()) {} soft_this_ptr2_impl& operator=(const soft_this_ptr2_impl&) { return *this; } - soft_this_ptr2_impl& operator=(soft_this_ptr2_impl&&) { return *this; } + soft_this_ptr2_impl& operator=(soft_this_ptr2_impl&&) noexcept { return *this; } ~soft_this_ptr2_impl() = default; diff --git a/library/src/safe_ptr_no_checks.h b/library/src/safe_ptr_no_checks.h index 843e58e..10f92b6 100644 --- a/library/src/safe_ptr_no_checks.h +++ b/library/src/safe_ptr_no_checks.h @@ -101,8 +101,8 @@ class owning_ptr_base_no_checks owning_ptr_base_no_checks() { implReset(); } owning_ptr_base_no_checks( owning_ptr_base_no_checks& other ) = delete; owning_ptr_base_no_checks& operator = ( owning_ptr_base_no_checks& other ) = delete; - owning_ptr_base_no_checks( owning_ptr_base_no_checks&& other ) {implFromOtherBasePtr(other.t_); other.implReset(); } - owning_ptr_base_no_checks& operator = ( owning_ptr_base_no_checks&& other ) + owning_ptr_base_no_checks( owning_ptr_base_no_checks&& other ) noexcept {implFromOtherBasePtr(other.t_); other.implReset(); } + owning_ptr_base_no_checks& operator = ( owning_ptr_base_no_checks&& other ) noexcept { if ( this == &other ) return *this; implFromOtherBasePtr( other.t_ ); @@ -241,13 +241,13 @@ class owning_ptr_no_checks : public owning_ptr_base_no_checks owning_ptr_no_checks( make_owning_t mo, T* t_ ) : owning_ptr_base_no_checks( mo, t_ ) {} owning_ptr_no_checks() : owning_ptr_base_no_checks() {} owning_ptr_no_checks( owning_ptr_no_checks& other ) = delete; - owning_ptr_no_checks( owning_ptr_no_checks&& other ) : owning_ptr_base_no_checks( std::move(other) ) {} + owning_ptr_no_checks( owning_ptr_no_checks&& other ) noexcept : owning_ptr_base_no_checks( std::move(other) ) {} template owning_ptr_no_checks( owning_ptr_no_checks&& other ) : owning_ptr_base_no_checks( std::move(other) ) {} owning_ptr_no_checks( std::nullptr_t nulp ) : owning_ptr_base_no_checks( nulp ) {} owning_ptr_no_checks& operator = ( owning_ptr_no_checks& other ) = delete; - owning_ptr_no_checks& operator = ( owning_ptr_no_checks&& other ) { + owning_ptr_no_checks& operator = ( owning_ptr_no_checks&& other ) noexcept { if ( this == &other ) return *this; owning_ptr_base_no_checks::operator = ( std::move( other ) ); return *this; @@ -318,7 +318,7 @@ class soft_ptr_base_no_checks friend class safememory::detail::soft_ptr_helper; - T* t; + T* t = nullptr; soft_ptr_base_no_checks(fbc_ptr_t, T* t_) { t = t_; } // to be used for only types annotaded as [[nodecpp::owning_only]] @@ -344,9 +344,9 @@ class soft_ptr_base_no_checks soft_ptr_base_no_checks( const soft_ptr_base_impl& other ) { t = other.getDereferencablePtr(); } soft_ptr_base_no_checks& operator = ( const soft_ptr_base_impl& other ) { t = other.getDereferencablePtr(); return *this; } - soft_ptr_base_no_checks( soft_ptr_base_no_checks&& other ) { t = other.t; other.t = nullptr; } + soft_ptr_base_no_checks( soft_ptr_base_no_checks&& other ) noexcept { t = other.t; other.t = nullptr; } - soft_ptr_base_no_checks& operator = ( soft_ptr_base_no_checks&& other ) { if ( this == &other ) return *this; t = other.t; other.t = nullptr; return *this; } + soft_ptr_base_no_checks& operator = ( soft_ptr_base_no_checks&& other ) noexcept { if ( this == &other ) return *this; t = other.t; other.t = nullptr; return *this; } template soft_ptr_base_no_checks( const owning_ptr_no_checks& owner, T* t_ ) { t = t_; } @@ -622,9 +622,9 @@ class soft_ptr_no_checks : public soft_ptr_base_no_checks } - soft_ptr_no_checks( soft_ptr_no_checks&& other ) : soft_ptr_base_no_checks( std::move(other) ) {} + soft_ptr_no_checks( soft_ptr_no_checks&& other ) noexcept : soft_ptr_base_no_checks( std::move(other) ) {} - soft_ptr_no_checks& operator = ( soft_ptr_no_checks&& other ) + soft_ptr_no_checks& operator = ( soft_ptr_no_checks&& other ) noexcept { if ( this == &other ) return *this; soft_ptr_base_no_checks::operator = ( std::move(other) ); diff --git a/library/test/build/TestSafePointers.vcxproj b/library/test/build/TestSafePointers.vcxproj index c01e108..b403531 100644 --- a/library/test/build/TestSafePointers.vcxproj +++ b/library/test/build/TestSafePointers.vcxproj @@ -51,6 +51,16 @@ + + + + + + + + + + true true @@ -65,6 +75,7 @@ true true + @@ -88,6 +99,7 @@ + @@ -233,51 +245,51 @@ true - ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;$(IncludePath);../../include + ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;$(IncludePath);../../include;../../3rdparty/EASTL/include;../../3rdparty/EABase/include/Common true - ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;$(IncludePath);../../include + ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;$(IncludePath);../../include;../../3rdparty/EASTL/include;../../3rdparty/EABase/include/Common true - ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;$(IncludePath);../../include + ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;$(IncludePath);../../include;../../3rdparty/EASTL/include;../../3rdparty/EABase/include/Common true - ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;../../include;$(IncludePath);../../include + ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;../../include;$(IncludePath);../../include;../../3rdparty/EASTL/include;../../3rdparty/EABase/include/Common true - ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;../../include;$(IncludePath);../../include + ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;../../include;$(IncludePath);../../include;../../3rdparty/EASTL/include;../../3rdparty/EABase/include/Common true - ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;$(IncludePath);../../include + ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;$(IncludePath);../../include;../../3rdparty/EASTL/include;../../3rdparty/EABase/include/Common false - ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;$(IncludePath);../../include + ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;$(IncludePath);../../include;../../3rdparty/EASTL/include;../../3rdparty/EABase/include/Common false - ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;$(IncludePath);../../include + ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;$(IncludePath);../../include;../../3rdparty/EASTL/include;../../3rdparty/EABase/include/Common false - ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;$(IncludePath);../../include + ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;$(IncludePath);../../include;../../3rdparty/EASTL/include;../../3rdparty/EABase/include/Common false - ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;$(IncludePath);../../include + ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;$(IncludePath);../../include;../../3rdparty/EASTL/include;../../3rdparty/EASTL/include;../../3rdparty/EABase/include/Common false - ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;$(IncludePath);../../include + ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;$(IncludePath);../../include;../../3rdparty/EASTL/include;../../3rdparty/EABase/include/Common false - ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;$(IncludePath);../../include + ../../src/iibmalloc/src;../../src;../../src/iibmalloc/src/foundation/include;../../src/iibmalloc/src/foundation/3rdparty/fmt/include;$(IncludePath);../../include;../../3rdparty/EASTL/include;../../3rdparty/EABase/include/Common @@ -285,9 +297,10 @@ Level3 Disabled true - _CRT_SECURE_NO_WARNINGS;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=SAFE;NODECPP_SAFE_PTR_DEBUG_MODE;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;EASTL_EASTDC_VSNPRINTF=0;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=SAFE;NODECPP_SAFE_PTR_DEBUG_MODE;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 + /analyze %(AdditionalOptions) Console @@ -300,9 +313,10 @@ Level3 Disabled true - _CRT_SECURE_NO_WARNINGS;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=SAFE;NODECPP_SAFE_PTR_DEBUG_MODE;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;EASTL_EASTDC_VSNPRINTF=0;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=SAFE;NODECPP_SAFE_PTR_DEBUG_MODE;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 + /analyze %(AdditionalOptions) Console @@ -315,9 +329,10 @@ Level3 Disabled true - _CRT_SECURE_NO_WARNINGS;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=SAFE;NODECPP_SAFE_PTR_DEBUG_MODE;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;EASTL_EASTDC_VSNPRINTF=0;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=SAFE;NODECPP_SAFE_PTR_DEBUG_MODE;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 + /analyze %(AdditionalOptions) Console @@ -330,9 +345,10 @@ Level3 Disabled true - _CRT_SECURE_NO_WARNINGS;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=0;NODECPP_SAFE_PTR_USE_ON_STACK_OPTIMIZATION;NODECPP_SAFE_PTR_DEBUG_MODE;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;EASTL_EASTDC_VSNPRINTF=0;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=0;NODECPP_SAFE_PTR_USE_ON_STACK_OPTIMIZATION;NODECPP_SAFE_PTR_DEBUG_MODE;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 + /analyze %(AdditionalOptions) Console @@ -345,9 +361,10 @@ Level3 Disabled true - _CRT_SECURE_NO_WARNINGS;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=1;NODECPP_SAFE_PTR_USE_ON_STACK_OPTIMIZATION;NODECPP_SAFE_PTR_DEBUG_MODE;NODECPP_MEMORY_SAFETY_DBG_ADD_PTR_LIFECYCLE_INFO;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;EASTL_EASTDC_VSNPRINTF=0;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=1;NODECPP_SAFE_PTR_USE_ON_STACK_OPTIMIZATION;NODECPP_SAFE_PTR_DEBUG_MODE;NODECPP_MEMORY_SAFETY_DBG_ADD_PTR_LIFECYCLE_INFO;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 + /analyze %(AdditionalOptions) Console @@ -360,9 +377,10 @@ Level3 Disabled true - _CRT_SECURE_NO_WARNINGS;NODECPP_USE_GENERIC_STRUCTS;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=1;NODECPP_SAFE_PTR_DEBUG_MODE;NODECPP_MEMORY_SAFETY_DBG_ADD_DESTRUCTION_INFO;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;EASTL_EASTDC_VSNPRINTF=0;NODECPP_USE_GENERIC_STRUCTS;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=1;NODECPP_SAFE_PTR_DEBUG_MODE;NODECPP_MEMORY_SAFETY_DBG_ADD_DESTRUCTION_INFO;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 + /analyze %(AdditionalOptions) Console @@ -377,9 +395,10 @@ true true true - _CRT_SECURE_NO_WARNINGS;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=SAFE;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;EASTL_EASTDC_VSNPRINTF=0;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=SAFE;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 + /analyze %(AdditionalOptions) Console @@ -396,9 +415,10 @@ true true true - _CRT_SECURE_NO_WARNINGS;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=SAFE;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;EASTL_EASTDC_VSNPRINTF=0;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=SAFE;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 + /analyze %(AdditionalOptions) Console @@ -415,9 +435,10 @@ true true true - _CRT_SECURE_NO_WARNINGS;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=SAFE;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;EASTL_EASTDC_VSNPRINTF=0;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=SAFE;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 + /analyze %(AdditionalOptions) Console @@ -434,9 +455,10 @@ true true true - _CRT_SECURE_NO_WARNINGS;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=0;NODECPP_SAFE_PTR_USE_ON_STACK_OPTIMIZATION;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;EASTL_EASTDC_VSNPRINTF=0;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=0;NODECPP_SAFE_PTR_USE_ON_STACK_OPTIMIZATION;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 + /analyze %(AdditionalOptions) Console @@ -453,9 +475,10 @@ true true true - _CRT_SECURE_NO_WARNINGS;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=1;NODECPP_MEMORY_SAFETY_DBG_ADD_PTR_LIFECYCLE_INFO;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;EASTL_EASTDC_VSNPRINTF=0;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=1;NODECPP_MEMORY_SAFETY_DBG_ADD_PTR_LIFECYCLE_INFO;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 + /analyze %(AdditionalOptions) Console @@ -472,9 +495,10 @@ true true true - _CRT_SECURE_NO_WARNINGS;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=0;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;EASTL_EASTDC_VSNPRINTF=0;NODECPP_MEMORY_SAFETY_EXCLUSIONS="../test/safety_exclusions.h";NODECPP_MEMORY_SAFETY=0;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 + /analyze %(AdditionalOptions) Console From df4f079c2b2ed551f0287e71d1a0487b28c98321 Mon Sep 17 00:00:00 2001 From: Marcos Bracco Date: Thu, 5 May 2022 09:59:51 -0300 Subject: [PATCH 09/31] reverted 'noexcept' move ctor because of zombie exceptions --- library/include/safememory/array.h | 2 +- .../safememory/detail/array_iterator.h | 2 +- .../safememory/detail/dezombiefy_iterators.h | 4 +-- .../safememory/detail/hashtable_iterator.h | 2 +- .../detail/soft_ptr_with_zero_offset.h | 12 ++++----- library/src/safe_ptr_impl.h | 26 +++++++++---------- library/src/safe_ptr_no_checks.h | 16 ++++++------ 7 files changed, 32 insertions(+), 32 deletions(-) diff --git a/library/include/safememory/array.h b/library/include/safememory/array.h index 2bcfd1f..4673ac5 100644 --- a/library/include/safememory/array.h +++ b/library/include/safememory/array.h @@ -133,7 +133,7 @@ struct array eastl::uninitialized_copy_ptr(other.begin_unsafe(), other.end_unsafe(), begin_unsafe()); } - array(array&& other) noexcept { + array(array&& other) { eastl::uninitialized_move_ptr(other.begin_unsafe(), other.end_unsafe(), begin_unsafe()); } diff --git a/library/include/safememory/detail/array_iterator.h b/library/include/safememory/detail/array_iterator.h index fcccbc6..9ef8c5b 100644 --- a/library/include/safememory/detail/array_iterator.h +++ b/library/include/safememory/detail/array_iterator.h @@ -236,7 +236,7 @@ class array_heap_safe_iterator array_heap_safe_iterator(const array_heap_safe_iterator& ri) = default; array_heap_safe_iterator& operator=(const array_heap_safe_iterator& ri) = default; - array_heap_safe_iterator(array_heap_safe_iterator&& ri) noexcept = default; + array_heap_safe_iterator(array_heap_safe_iterator&& ri) = default; array_heap_safe_iterator& operator=(array_heap_safe_iterator&& ri) = default; /// allow non-const to const constructor diff --git a/library/include/safememory/detail/dezombiefy_iterators.h b/library/include/safememory/detail/dezombiefy_iterators.h index 603a084..ce3f9ee 100644 --- a/library/include/safememory/detail/dezombiefy_iterators.h +++ b/library/include/safememory/detail/dezombiefy_iterators.h @@ -75,7 +75,7 @@ class iterator_registry { iterator_registry(const iterator_registry&) {} //don't copy registry - iterator_registry(iterator_registry&& other) noexcept { + iterator_registry(iterator_registry&& other) { // don't copy registry other.invalidateAllIterators(); } @@ -91,7 +91,7 @@ class iterator_registry { return *this; } - iterator_registry& operator=(iterator_registry&& other) noexcept { + iterator_registry& operator=(iterator_registry&& other) { if(this == std::addressof(other)) return *this; diff --git a/library/include/safememory/detail/hashtable_iterator.h b/library/include/safememory/detail/hashtable_iterator.h index f2f24ab..058bf30 100644 --- a/library/include/safememory/detail/hashtable_iterator.h +++ b/library/include/safememory/detail/hashtable_iterator.h @@ -75,7 +75,7 @@ namespace safememory::detail { hashtable_stack_only_iterator(const this_type&) = default; hashtable_stack_only_iterator& operator=(const hashtable_stack_only_iterator& ri) = default; - hashtable_stack_only_iterator(hashtable_stack_only_iterator&& ri) noexcept = default; + hashtable_stack_only_iterator(hashtable_stack_only_iterator&& ri) = default; hashtable_stack_only_iterator& operator=(hashtable_stack_only_iterator&& ri) = default; ~hashtable_stack_only_iterator() = default; diff --git a/library/include/safememory/detail/soft_ptr_with_zero_offset.h b/library/include/safememory/detail/soft_ptr_with_zero_offset.h index d01b17e..055b795 100644 --- a/library/include/safememory/detail/soft_ptr_with_zero_offset.h +++ b/library/include/safememory/detail/soft_ptr_with_zero_offset.h @@ -107,12 +107,12 @@ class soft_ptr_with_zero_offset_base return *this; } - soft_ptr_with_zero_offset_base( soft_ptr_with_zero_offset_base&& other ) noexcept { + soft_ptr_with_zero_offset_base( soft_ptr_with_zero_offset_base&& other ) { // mb: copy is actually more light weight than move, and we don't need real move ptr.copy_from(other.ptr); } - soft_ptr_with_zero_offset_base& operator=( soft_ptr_with_zero_offset_base&& other ) noexcept { + soft_ptr_with_zero_offset_base& operator=( soft_ptr_with_zero_offset_base&& other ) { // mb: copy is actually more light weight than move, and we don't need real move if(this == std::addressof(other)) return *this; @@ -181,8 +181,8 @@ class soft_ptr_with_zero_offset_impl : public soft_ptr_with_zero_offset_base soft_ptr_with_zero_offset_impl( const soft_ptr_with_zero_offset_impl& ) = default; soft_ptr_with_zero_offset_impl& operator=( const soft_ptr_with_zero_offset_impl& ) = default; - soft_ptr_with_zero_offset_impl( soft_ptr_with_zero_offset_impl&& ) noexcept = default; - soft_ptr_with_zero_offset_impl& operator=( soft_ptr_with_zero_offset_impl&& ) noexcept = default; + soft_ptr_with_zero_offset_impl( soft_ptr_with_zero_offset_impl&& ) = default; + soft_ptr_with_zero_offset_impl& operator=( soft_ptr_with_zero_offset_impl&& ) = default; soft_ptr_with_zero_offset_impl( std::nullptr_t ) {} soft_ptr_with_zero_offset_impl& operator=( std::nullptr_t ) { reset(); return *this; } @@ -241,8 +241,8 @@ class soft_ptr_with_zero_offset_impl> : public soft_ptr_with_z soft_ptr_with_zero_offset_impl( const soft_ptr_with_zero_offset_impl& other ) = default; soft_ptr_with_zero_offset_impl& operator=( const soft_ptr_with_zero_offset_impl& other ) = default; - soft_ptr_with_zero_offset_impl( soft_ptr_with_zero_offset_impl&& other ) noexcept = default; - soft_ptr_with_zero_offset_impl& operator=( soft_ptr_with_zero_offset_impl&& other ) noexcept = default; + soft_ptr_with_zero_offset_impl( soft_ptr_with_zero_offset_impl&& other ) = default; + soft_ptr_with_zero_offset_impl& operator=( soft_ptr_with_zero_offset_impl&& other ) = default; soft_ptr_with_zero_offset_impl( std::nullptr_t ) { } soft_ptr_with_zero_offset_impl& operator=( std::nullptr_t ){ reset(); return *this; } diff --git a/library/src/safe_ptr_impl.h b/library/src/safe_ptr_impl.h index aec3867..f2ab90e 100644 --- a/library/src/safe_ptr_impl.h +++ b/library/src/safe_ptr_impl.h @@ -682,7 +682,7 @@ class owning_ptr_base_impl } owning_ptr_base_impl( const owning_ptr_base_impl& other ) = delete; owning_ptr_base_impl& operator = ( const owning_ptr_base_impl& other ) = delete; - owning_ptr_base_impl( owning_ptr_base_impl&& other ) noexcept + owning_ptr_base_impl( owning_ptr_base_impl&& other ) { #ifdef NODECPP_MEMORY_SAFETY_DBG_ADD_PTR_LIFECYCLE_INFO creationInfo = std::move( other.creationInfo ); @@ -696,7 +696,7 @@ class owning_ptr_base_impl other.dbgCheckValidity(); dbgCheckValidity(); } - owning_ptr_base_impl& operator = ( owning_ptr_base_impl&& other ) noexcept + owning_ptr_base_impl& operator = ( owning_ptr_base_impl&& other ) { if ( this == &other ) return *this; #ifdef NODECPP_MEMORY_SAFETY_DBG_ADD_PTR_LIFECYCLE_INFO @@ -911,13 +911,13 @@ class owning_ptr_impl : public owning_ptr_base_impl owning_ptr_impl( make_owning_t mo, T* t_ ) : owning_ptr_base_impl( mo, t_ ) {} owning_ptr_impl() : owning_ptr_base_impl() {} owning_ptr_impl( const owning_ptr_impl& other ) = delete; - owning_ptr_impl( owning_ptr_impl&& other ) noexcept : owning_ptr_base_impl( std::move(other) ) {} + owning_ptr_impl( owning_ptr_impl&& other ) : owning_ptr_base_impl( std::move(other) ) {} template owning_ptr_impl( owning_ptr_impl&& other ) : owning_ptr_base_impl( std::move(other) ) {} owning_ptr_impl( std::nullptr_t nulp ) : owning_ptr_base_impl( nulp ) {} owning_ptr_impl& operator = ( const owning_ptr_impl& other ) = delete; - owning_ptr_impl& operator = ( owning_ptr_impl&& other ) noexcept { + owning_ptr_impl& operator = ( owning_ptr_impl&& other ) { if ( this == &other ) return *this; owning_ptr_base_impl::operator = ( std::move( other ) ); return *this; @@ -1345,7 +1345,7 @@ class soft_ptr_base_impl } - soft_ptr_base_impl( soft_ptr_base_impl&& other ) noexcept + soft_ptr_base_impl( soft_ptr_base_impl&& other ) { if ( this == &other ) return; #ifdef NODECPP_MEMORY_SAFETY_ON_DEMAND @@ -1392,7 +1392,7 @@ class soft_ptr_base_impl #endif // NODECPP_MEMORY_SAFETY_DBG_ADD_PTR_LIFECYCLE_INFO } - soft_ptr_base_impl& operator = ( soft_ptr_base_impl&& other ) noexcept + soft_ptr_base_impl& operator = ( soft_ptr_base_impl&& other ) { // TODO+++: revise if ( this == &other ) return *this; @@ -1908,9 +1908,9 @@ class soft_ptr_impl : public soft_ptr_base_impl } - soft_ptr_impl( soft_ptr_impl&& other ) noexcept : soft_ptr_base_impl( std::move(other) ) {} + soft_ptr_impl( soft_ptr_impl&& other ) : soft_ptr_base_impl( std::move(other) ) {} - soft_ptr_impl& operator = ( soft_ptr_impl&& other ) noexcept + soft_ptr_impl& operator = ( soft_ptr_impl&& other ) { if ( this == &other ) return *this; soft_ptr_base_impl::operator = ( std::move(other) ); @@ -2150,9 +2150,9 @@ class soft_ptr_impl : public soft_ptr_base_impl } - soft_ptr_impl( soft_ptr_impl&& other ) noexcept : soft_ptr_base_impl( std::move(other) ) {} + soft_ptr_impl( soft_ptr_impl&& other ) : soft_ptr_base_impl( std::move(other) ) {} - soft_ptr_impl& operator = ( soft_ptr_impl&& other ) noexcept + soft_ptr_impl& operator = ( soft_ptr_impl&& other ) { if ( this == &other ) return *this; soft_ptr_base_impl::operator = ( std::move(other) ); @@ -2287,7 +2287,7 @@ class soft_this_ptr2_impl { FirstControlBlock* cbPtr = nullptr; - static FirstControlBlock* getCbPtr() noexcept { + static FirstControlBlock* getCbPtr() { if(thg_stackPtrForMakeOwningCall == NODECPP_SECOND_NULLPTR) return nullptr; #ifdef NODECPP_MEMORY_SAFETY_ON_DEMAND @@ -2304,10 +2304,10 @@ class soft_this_ptr2_impl soft_this_ptr2_impl() : cbPtr(getCbPtr()) {} soft_this_ptr2_impl(const soft_this_ptr2_impl&) : cbPtr(getCbPtr()) {} - soft_this_ptr2_impl(soft_this_ptr2_impl&&) noexcept : cbPtr(getCbPtr()) {} + soft_this_ptr2_impl(soft_this_ptr2_impl&&) : cbPtr(getCbPtr()) {} soft_this_ptr2_impl& operator=(const soft_this_ptr2_impl&) { return *this; } - soft_this_ptr2_impl& operator=(soft_this_ptr2_impl&&) noexcept { return *this; } + soft_this_ptr2_impl& operator=(soft_this_ptr2_impl&&) { return *this; } ~soft_this_ptr2_impl() = default; diff --git a/library/src/safe_ptr_no_checks.h b/library/src/safe_ptr_no_checks.h index 3abdd5a..4e1dd300 100644 --- a/library/src/safe_ptr_no_checks.h +++ b/library/src/safe_ptr_no_checks.h @@ -102,8 +102,8 @@ class owning_ptr_base_no_checks owning_ptr_base_no_checks() { implReset(); } owning_ptr_base_no_checks( owning_ptr_base_no_checks& other ) = delete; owning_ptr_base_no_checks& operator = ( owning_ptr_base_no_checks& other ) = delete; - owning_ptr_base_no_checks( owning_ptr_base_no_checks&& other ) noexcept {implFromOtherBasePtr(other.t_); other.implReset(); } - owning_ptr_base_no_checks& operator = ( owning_ptr_base_no_checks&& other ) noexcept + owning_ptr_base_no_checks( owning_ptr_base_no_checks&& other ) {implFromOtherBasePtr(other.t_); other.implReset(); } + owning_ptr_base_no_checks& operator = ( owning_ptr_base_no_checks&& other ) { if ( this == &other ) return *this; implFromOtherBasePtr( other.t_ ); @@ -242,13 +242,13 @@ class owning_ptr_no_checks : public owning_ptr_base_no_checks owning_ptr_no_checks( make_owning_t mo, T* t_ ) : owning_ptr_base_no_checks( mo, t_ ) {} owning_ptr_no_checks() : owning_ptr_base_no_checks() {} owning_ptr_no_checks( owning_ptr_no_checks& other ) = delete; - owning_ptr_no_checks( owning_ptr_no_checks&& other ) noexcept : owning_ptr_base_no_checks( std::move(other) ) {} + owning_ptr_no_checks( owning_ptr_no_checks&& other ) : owning_ptr_base_no_checks( std::move(other) ) {} template owning_ptr_no_checks( owning_ptr_no_checks&& other ) : owning_ptr_base_no_checks( std::move(other) ) {} owning_ptr_no_checks( std::nullptr_t nulp ) : owning_ptr_base_no_checks( nulp ) {} owning_ptr_no_checks& operator = ( owning_ptr_no_checks& other ) = delete; - owning_ptr_no_checks& operator = ( owning_ptr_no_checks&& other ) noexcept { + owning_ptr_no_checks& operator = ( owning_ptr_no_checks&& other ) { if ( this == &other ) return *this; owning_ptr_base_no_checks::operator = ( std::move( other ) ); return *this; @@ -345,9 +345,9 @@ class soft_ptr_base_no_checks soft_ptr_base_no_checks( const soft_ptr_base_impl& other ) { t = other.getDereferencablePtr(); } soft_ptr_base_no_checks& operator = ( const soft_ptr_base_impl& other ) { t = other.getDereferencablePtr(); return *this; } - soft_ptr_base_no_checks( soft_ptr_base_no_checks&& other ) noexcept { t = other.t; other.t = nullptr; } + soft_ptr_base_no_checks( soft_ptr_base_no_checks&& other ) { t = other.t; other.t = nullptr; } - soft_ptr_base_no_checks& operator = ( soft_ptr_base_no_checks&& other ) noexcept { if ( this == &other ) return *this; t = other.t; other.t = nullptr; return *this; } + soft_ptr_base_no_checks& operator = ( soft_ptr_base_no_checks&& other ) { if ( this == &other ) return *this; t = other.t; other.t = nullptr; return *this; } template soft_ptr_base_no_checks( const owning_ptr_no_checks& owner, T* t_ ) { t = t_; } @@ -623,9 +623,9 @@ class soft_ptr_no_checks : public soft_ptr_base_no_checks } - soft_ptr_no_checks( soft_ptr_no_checks&& other ) noexcept : soft_ptr_base_no_checks( std::move(other) ) {} + soft_ptr_no_checks( soft_ptr_no_checks&& other ) : soft_ptr_base_no_checks( std::move(other) ) {} - soft_ptr_no_checks& operator = ( soft_ptr_no_checks&& other ) noexcept + soft_ptr_no_checks& operator = ( soft_ptr_no_checks&& other ) { if ( this == &other ) return *this; soft_ptr_base_no_checks::operator = ( std::move(other) ); From 948e842c2721bac298232470066eb665f538bfa0 Mon Sep 17 00:00:00 2001 From: Marcos Bracco Date: Tue, 17 May 2022 10:34:14 -0300 Subject: [PATCH 10/31] update iibmalloc --- library/src/iibmalloc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/iibmalloc b/library/src/iibmalloc index f7f5e64..e70d38a 160000 --- a/library/src/iibmalloc +++ b/library/src/iibmalloc @@ -1 +1 @@ -Subproject commit f7f5e64d3e447b72db9a59e07b0e95f1a7360609 +Subproject commit e70d38ae94edcb971f3479df319a608f831cc0d4 From 0e99f7995dfc12f70a0975d1d50e30ec32732d85 Mon Sep 17 00:00:00 2001 From: Marcos Bracco Date: Tue, 17 May 2022 11:53:51 -0300 Subject: [PATCH 11/31] update iibmalloc --- library/src/iibmalloc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/iibmalloc b/library/src/iibmalloc index e70d38a..90dae10 160000 --- a/library/src/iibmalloc +++ b/library/src/iibmalloc @@ -1 +1 @@ -Subproject commit e70d38ae94edcb971f3479df319a608f831cc0d4 +Subproject commit 90dae107dd3b74ff2af2da709896f3162cb3cfa2 From 3ed7dee951adf79bc5d9805d48c653029c33885f Mon Sep 17 00:00:00 2001 From: Marcos Bracco Date: Tue, 17 May 2022 13:03:27 -0300 Subject: [PATCH 12/31] silence reversed-operator warning --- library/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index d038b03..56f3b18 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -120,6 +120,7 @@ if (SAFEMEMORY_TEST) target_compile_options(test_safememory PRIVATE -Wno-missing-braces) target_compile_options(test_safememory PRIVATE -Wno-reinterpret-base-class) target_compile_options(test_safememory PRIVATE -Wno-deprecated-declarations) + target_compile_options(test_safememory PRIVATE -Wno-ambiguous-reversed-operator) endif() target_link_libraries(test_safememory safememory) From 0ddf4241af26f855d25363367876c95293f55983 Mon Sep 17 00:00:00 2001 From: Marcos Bracco Date: Wed, 18 May 2022 14:02:10 -0300 Subject: [PATCH 13/31] add clang-13 build script --- library/tools/ci-clang13.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 library/tools/ci-clang13.sh diff --git a/library/tools/ci-clang13.sh b/library/tools/ci-clang13.sh new file mode 100644 index 0000000..24bfbf0 --- /dev/null +++ b/library/tools/ci-clang13.sh @@ -0,0 +1,16 @@ +#!/bin/sh +set -ev + +rm -Rf library/build/clang13 +mkdir -p library/build/clang13 +cd library/build/clang13 + +export CC=clang-13 +export CXX=clang++-13 + +cmake -DCMAKE_BUILD_TYPE=Release -DSAFEMEMORY_TEST=ON -G "Unix Makefiles" ../.. + +cmake --build . + +ctest --output-on-failure + From 958445552112051780b9e387300c332823d128a0 Mon Sep 17 00:00:00 2001 From: Marcos Bracco Date: Thu, 19 May 2022 10:57:40 -0300 Subject: [PATCH 14/31] update iibmalloc --- library/src/iibmalloc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/iibmalloc b/library/src/iibmalloc index 90dae10..82dd7b6 160000 --- a/library/src/iibmalloc +++ b/library/src/iibmalloc @@ -1 +1 @@ -Subproject commit 90dae107dd3b74ff2af2da709896f3162cb3cfa2 +Subproject commit 82dd7b6ea71b27632ba4205a50b038a5294ece1b From 50feb97915919d69af92014f16b9c98dd2f686fa Mon Sep 17 00:00:00 2001 From: Marcos Bracco Date: Thu, 19 May 2022 14:29:34 -0300 Subject: [PATCH 15/31] update iibmalloc --- library/src/iibmalloc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/iibmalloc b/library/src/iibmalloc index 82dd7b6..c415688 160000 --- a/library/src/iibmalloc +++ b/library/src/iibmalloc @@ -1 +1 @@ -Subproject commit 82dd7b6ea71b27632ba4205a50b038a5294ece1b +Subproject commit c41568881bb13aeea8d562155f892fcdc9f2375c From fb5d6486d98b34f306566ce1661ad1c81f519339 Mon Sep 17 00:00:00 2001 From: Marcos Bracco Date: Wed, 25 May 2022 14:51:22 -0300 Subject: [PATCH 16/31] update iibmalloc --- library/src/iibmalloc | 2 +- library/src/safe_ptr_impl.h | 4 ++-- library/src/startup_checks.h | 2 +- library/test/test_safe_pointers.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/src/iibmalloc b/library/src/iibmalloc index c415688..a6a0e21 160000 --- a/library/src/iibmalloc +++ b/library/src/iibmalloc @@ -1 +1 @@ -Subproject commit c41568881bb13aeea8d562155f892fcdc9f2375c +Subproject commit a6a0e211b15c5c9704b0a47e56fb3ac4124b2594 diff --git a/library/src/safe_ptr_impl.h b/library/src/safe_ptr_impl.h index f2ab90e..1657ac7 100644 --- a/library/src/safe_ptr_impl.h +++ b/library/src/safe_ptr_impl.h @@ -1049,13 +1049,13 @@ class soft_ptr_base_impl friend class safememory::detail::soft_ptr_helper; #ifdef NODECPP_SAFE_PTR_DEBUG_MODE -#ifdef NODECPP_X64 +#if defined(NODECPP_X64) || defined(NODECPP_ARM64) using PointersT = nodecpp::platform::ptrwithdatastructsdefs::generic_allocated_ptr_and_ptr_and_data_and_flags_<3,32,1>; #else using PointersT = nodecpp::platform::ptrwithdatastructsdefs::generic_allocated_ptr_and_ptr_and_data_and_flags_<2,26,1>; #endif #else -#ifdef NODECPP_X64 +#if defined(NODECPP_X64) || defined(NODECPP_ARM64) using PointersT = nodecpp::platform::allocated_ptr_and_ptr_and_data_and_flags<3,32,1>; #else using PointersT = nodecpp::platform::allocated_ptr_and_ptr_and_data_and_flags<2,26,1>; diff --git a/library/src/startup_checks.h b/library/src/startup_checks.h index dc857b5..d2b1f47 100644 --- a/library/src/startup_checks.h +++ b/library/src/startup_checks.h @@ -50,7 +50,7 @@ namespace dummy_objects { NODECPP_FORCEINLINE uint32_t rng32() { uint64_t ret = seedVal * 0xd989bcacc137dcd5ull; seedVal ^= seedVal >> 11; seedVal ^= seedVal << 31; seedVal ^= seedVal >> 18; return uint32_t(ret >> 32ull); } NODECPP_FORCEINLINE uint64_t rng64() { uint64_t ret = rng32(); ret <<= 32; return ret + rng32(); } NODECPP_FORCEINLINE uint64_t rng64NoNull() { uint64_t ret; do { ret = rng32(); ret <<= 32; ret += rng32(); } while (ret == 0); return ret; } -#ifdef NODECPP_X64 +#if defined(NODECPP_X64) || defined(NODECPP_ARM64) NODECPP_FORCEINLINE size_t rng() { return rng64(); } NODECPP_FORCEINLINE size_t rngNoNull() { return rng64NoNull(); } #elif ( defined NODECPP_X86 ) diff --git a/library/test/test_safe_pointers.cpp b/library/test/test_safe_pointers.cpp index bfd061b..d5502ba 100644 --- a/library/test/test_safe_pointers.cpp +++ b/library/test/test_safe_pointers.cpp @@ -947,7 +947,7 @@ int testWithLest( int argc, char * argv[] ) void test__allocated_ptr_and_ptr_and_data_and_flags() { -#ifdef NODECPP_X64 +#if defined(NODECPP_X64) || defined(NODECPP_ARM64) constexpr size_t maxData = 32; #else constexpr size_t maxData = 26; From 818f5ff78bccfa803b4abd55fa494afe889184a6 Mon Sep 17 00:00:00 2001 From: Marcos Bracco Date: Wed, 25 May 2022 17:05:01 -0300 Subject: [PATCH 17/31] update iibmalloc --- library/src/iibmalloc | 2 +- library/tools/ci-android-r23b.sh | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 library/tools/ci-android-r23b.sh diff --git a/library/src/iibmalloc b/library/src/iibmalloc index a6a0e21..cc13ac8 160000 --- a/library/src/iibmalloc +++ b/library/src/iibmalloc @@ -1 +1 @@ -Subproject commit a6a0e211b15c5c9704b0a47e56fb3ac4124b2594 +Subproject commit cc13ac84ca1279bbad31d9dd7db708b34eb0f3b7 diff --git a/library/tools/ci-android-r23b.sh b/library/tools/ci-android-r23b.sh new file mode 100644 index 0000000..afd5c3b --- /dev/null +++ b/library/tools/ci-android-r23b.sh @@ -0,0 +1,16 @@ +#!/bin/sh +set -ev + +rm -Rf library/build/android-r23b +mkdir -p library/build/android-r23b +cd library/build/android-r23b + +# env variable ANDROID_NDK should point to the root folder where NDKs are installed + +cmake -DCMAKE_BUILD_TYPE=Release -DSAFEMEMORY_TEST=ON -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-23 -DANDROID_NDK=${ANDROID_NDK}/android-ndk-r23b -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/android-ndk-r23b/build/cmake/android.toolchain.cmake -G Ninja ../.. + +cmake --build . + +# is cross compile, don't run tests here +# ctest --output-on-failure + From bcc8baa5d6e59edfb85eb333883087facb560f87 Mon Sep 17 00:00:00 2001 From: Marcos Bracco Date: Thu, 26 May 2022 22:33:44 -0300 Subject: [PATCH 18/31] update iibmalloc --- library/src/iibmalloc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/iibmalloc b/library/src/iibmalloc index cc13ac8..45e500a 160000 --- a/library/src/iibmalloc +++ b/library/src/iibmalloc @@ -1 +1 @@ -Subproject commit cc13ac84ca1279bbad31d9dd7db708b34eb0f3b7 +Subproject commit 45e500a240574d2cad6bd50de3b097d7c522e8b6 From a7e3ceabbb06525cdb3c621dc41b3d7cc0dc6b86 Mon Sep 17 00:00:00 2001 From: Marcos Bracco Date: Mon, 30 May 2022 19:26:44 -0300 Subject: [PATCH 19/31] update android build script --- library/test/containers/EASTL-test/main.cpp | 3 +++ library/tools/ci-android-r23b.sh | 16 ---------------- library/tools/ci-android-r23c.bat | 18 ++++++++++++++++++ 3 files changed, 21 insertions(+), 16 deletions(-) delete mode 100644 library/tools/ci-android-r23b.sh create mode 100644 library/tools/ci-android-r23c.bat diff --git a/library/test/containers/EASTL-test/main.cpp b/library/test/containers/EASTL-test/main.cpp index 16c732e..be8f4ad 100644 --- a/library/test/containers/EASTL-test/main.cpp +++ b/library/test/containers/EASTL-test/main.cpp @@ -128,6 +128,9 @@ int main(int argc, char* argv[]) nodecpp::iibmalloc::setCurrneAllocator(formerAlloc); #endif + if(nErrorCount == 0) + printf("Done.\n"); + return nErrorCount; } diff --git a/library/tools/ci-android-r23b.sh b/library/tools/ci-android-r23b.sh deleted file mode 100644 index afd5c3b..0000000 --- a/library/tools/ci-android-r23b.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -set -ev - -rm -Rf library/build/android-r23b -mkdir -p library/build/android-r23b -cd library/build/android-r23b - -# env variable ANDROID_NDK should point to the root folder where NDKs are installed - -cmake -DCMAKE_BUILD_TYPE=Release -DSAFEMEMORY_TEST=ON -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-23 -DANDROID_NDK=${ANDROID_NDK}/android-ndk-r23b -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/android-ndk-r23b/build/cmake/android.toolchain.cmake -G Ninja ../.. - -cmake --build . - -# is cross compile, don't run tests here -# ctest --output-on-failure - diff --git a/library/tools/ci-android-r23c.bat b/library/tools/ci-android-r23c.bat new file mode 100644 index 0000000..26420d1 --- /dev/null +++ b/library/tools/ci-android-r23c.bat @@ -0,0 +1,18 @@ +rem script to build with Visual Studio +rem run from root as 'tools\ci-msvc2019' + +rmdir /S /Q library\build\android-r23c +mkdir library\build\android-r23c +cd library\build\android-r23c + +rem env variable ANDROID_SDK_HOME should point to the root Sdk folder + +cmake -DSAFEMEMORY_TEST=ON -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI=arm64-v8a -DANDROID_NDK=%ANDROID_SDK_HOME%\ndk\23.2.8568313 -DCMAKE_TOOLCHAIN_FILE=%ANDROID_SDK_HOME%\ndk\23.2.8568313\build\cmake\android.toolchain.cmake -G Ninja ..\.. +@if ERRORLEVEL 1 exit /b %ERRORLEVEL% + +cmake --build . +@if ERRORLEVEL 1 exit /b %ERRORLEVEL% + +rem we don't test here, since we must deploy on (virtual) device +rem ctest --output-on-failure -C Release +rem @if ERRORLEVEL 1 exit /b %ERRORLEVEL% From 9d6bbdc2ec56a7efcac3a9d77feac070bec3303e Mon Sep 17 00:00:00 2001 From: "dmytro.ivanchykhin" Date: Thu, 5 Jan 2023 17:26:40 +0200 Subject: [PATCH 20/31] switching to the latest version of IIBMalloc module --- library/src/iibmalloc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/iibmalloc b/library/src/iibmalloc index c415688..20afcf4 160000 --- a/library/src/iibmalloc +++ b/library/src/iibmalloc @@ -1 +1 @@ -Subproject commit c41568881bb13aeea8d562155f892fcdc9f2375c +Subproject commit 20afcf4d4e7308b7612e6cc72e1e85be2f9ba63f From 0ee1045e0d45a9b01e403ef704cc252726c2b843 Mon Sep 17 00:00:00 2001 From: Marcos Bracco Date: Mon, 6 Feb 2023 16:53:06 -0300 Subject: [PATCH 21/31] update EASTL to version 3.18.00 --- library/3rdparty/EABase-EASTL.md | 2 +- library/3rdparty/EASTL-3.18.00.diff | 2861 +++++++++++++++++++++++ library/3rdparty/clone-EABase-EASTL.bat | 4 +- library/3rdparty/clone-EABase-EASTL.sh | 4 +- 4 files changed, 2866 insertions(+), 5 deletions(-) create mode 100644 library/3rdparty/EASTL-3.18.00.diff diff --git a/library/3rdparty/EABase-EASTL.md b/library/3rdparty/EABase-EASTL.md index bde5a45..c923169 100644 --- a/library/3rdparty/EABase-EASTL.md +++ b/library/3rdparty/EABase-EASTL.md @@ -5,7 +5,7 @@ Both libraries, `3rdparty/EABase` and `3rdparty/EASTL` have been cloned _by-valu **EABase** folder is by-value clone of [https://github.com/electronicarts/EABase.git] initially done at tag `2.09.06`. -**EASTL** folder is by-value clone of [https://github.com/electronicarts/EASTL] initially done at tag `3.17.03` and patched with `EASTL-3.17.03.diff`. +**EASTL** folder is by-value clone of [https://github.com/electronicarts/EASTL] initially done at tag `3.18.00` and patched with `EASTL-3.18.00.diff`. It is done with `clone-EABase-EASLT.sh` or `clone-EABase-EASTL.bat` scripts. diff --git a/library/3rdparty/EASTL-3.18.00.diff b/library/3rdparty/EASTL-3.18.00.diff new file mode 100644 index 0000000..7e66fae --- /dev/null +++ b/library/3rdparty/EASTL-3.18.00.diff @@ -0,0 +1,2861 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index e8700dc..bba15ff 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -20,7 +20,7 @@ include(CommonCppFlags) + # Library definition + #------------------------------------------------------------------------------------------- + file(GLOB EASTL_SOURCES "source/*.cpp") +-add_library(EASTL ${EASTL_SOURCES}) ++add_library(EASTL STATIC ${EASTL_SOURCES}) + + if(EASTL_BUILD_BENCHMARK) + add_subdirectory(benchmark) +diff --git a/include/EASTL/allocator.h b/include/EASTL/allocator.h +index ad20e4d..84d0445 100644 +--- a/include/EASTL/allocator.h ++++ b/include/EASTL/allocator.h +@@ -64,6 +64,78 @@ namespace eastl + const char* get_name() const; + void set_name(const char* pName); + ++ //////// safememory methods and aliases below //////// ++ ++ template ++ using pointer = T*; ++ ++ template ++ using array_pointer = T*; ++ ++ template ++ T* allocate_array(eastl_size_t count, int flags = 0) { ++ //TODO use aligned allocate ++ return (T*)allocate(count * sizeof(T), flags); ++ } ++ ++ template ++ T* allocate_array_zeroed(eastl_size_t count, int flags = 0) { ++ //TODO use aligned allocate ++ auto arr = (T*)allocate(count * sizeof(T), flags); ++ memset(arr, 0, count * sizeof(T)); ++ return arr; ++ } ++ ++ template ++ void deallocate_array(T* p, eastl_size_t count) { ++ deallocate(p, count * sizeof(T)); ++ } ++ ++ template ++ T* allocate_node() { ++ return (T*)allocate(sizeof(T), 0); ++ } ++ ++ template ++ void deallocate_node(T* p) { ++ deallocate(p, sizeof(T)); ++ } ++ ++ template ++ static T* to_raw(T* p) { ++ return p; ++ } ++ ++ template ++ static int make_raii(T* p) { ++ return 0; ++ } ++ ++ static void force_changes_in_dtor(const void*) {} ++ ++ //////// hashtable special values //////// ++ template ++ static T* get_hashtable_sentinel() { ++ return reinterpret_cast((void*)uintptr_t(~0)); ++ } ++ ++ template ++ static T* get_empty_hashtable() { ++ extern EASTL_API void* gpEmptyBucketArray[2]; ++ return reinterpret_cast(&gpEmptyBucketArray[0]); ++ } ++ ++ template ++ static bool is_hashtable_sentinel(const T* p) { ++ return p == get_hashtable_sentinel(); ++ } ++ ++ template ++ static bool is_empty_hashtable(const T* a) { ++ return a == get_empty_hashtable(); ++ } ++ ++ + protected: + #if EASTL_NAME_ENABLED + const char* mpName; // Debug name, used to track memory. +@@ -74,7 +146,6 @@ namespace eastl + bool operator!=(const allocator& a, const allocator& b); + + +- + /// dummy_allocator + /// + /// Defines an allocator which does nothing. It returns NULL from allocate calls. +diff --git a/include/EASTL/internal/atomic/atomic_integral.h b/include/EASTL/internal/atomic/atomic_integral.h +index bcf7c17..96858de 100644 +--- a/include/EASTL/internal/atomic/atomic_integral.h ++++ b/include/EASTL/internal/atomic/atomic_integral.h +@@ -326,9 +326,9 @@ namespace internal + EASTL_ATOMIC_INTEGRAL_WIDTH_SPECIALIZE(8, 64) + #endif + +-#if defined(EASTL_ATOMIC_HAS_128BIT) +- EASTL_ATOMIC_INTEGRAL_WIDTH_SPECIALIZE(16, 128) +-#endif ++// #if defined(EASTL_ATOMIC_HAS_128BIT) ++// EASTL_ATOMIC_INTEGRAL_WIDTH_SPECIALIZE(16, 128) ++// #endif + + + } // namespace internal +diff --git a/include/EASTL/internal/hashtable.h b/include/EASTL/internal/hashtable.h +index a9347b1..9f56ed2 100644 +--- a/include/EASTL/internal/hashtable.h ++++ b/include/EASTL/internal/hashtable.h +@@ -103,34 +103,34 @@ namespace eastl + /// store a hash code in the node to speed up hash calculations + /// and comparisons in some cases. + /// +- template ++ template + struct hash_node; + + EA_DISABLE_VC_WARNING(4625 4626) // "copy constructor / assignment operator could not be generated because a base class copy constructor is inaccessible or deleted" + #ifdef EA_COMPILER_MSVC_2015 + EA_DISABLE_VC_WARNING(5026) // disable warning: "move constructor was implicitly defined as deleted" + #endif +- template +- struct hash_node ++ template ++ struct hash_node + { + hash_node() = default; + hash_node(const hash_node&) = default; + hash_node(hash_node&&) = default; + + Value mValue; +- hash_node* mpNext; ++ typename Allocator::template pointer mpNext; + eastl_size_t mnHashCode; // See config.h for the definition of eastl_size_t, which defaults to size_t. + } EASTL_MAY_ALIAS; + +- template +- struct hash_node ++ template ++ struct hash_node + { + hash_node() = default; + hash_node(const hash_node&) = default; + hash_node(hash_node&&) = default; + + Value mValue; +- hash_node* mpNext; ++ typename Allocator::template pointer mpNext; + } EASTL_MAY_ALIAS; + + #ifdef EA_COMPILER_MSVC_2015 +@@ -161,8 +161,8 @@ namespace eastl + }; + } + +- static_assert(Internal::has_hashcode_member>::value, "contains a mnHashCode member"); +- static_assert(!Internal::has_hashcode_member>::value, "doesn't contain a mnHashCode member"); ++ // static_assert(Internal::has_hashcode_member>::value, "contains a mnHashCode member"); ++ // static_assert(!Internal::has_hashcode_member>::value, "doesn't contain a mnHashCode member"); + + // convenience macros to increase the readability of the code paths that must SFINAE on if the 'hash_node' + // contains the cached hashed value or not. +@@ -179,16 +179,22 @@ namespace eastl + /// We define a base class here because it is shared by both const and + /// non-const iterators. + /// +- template ++ template + struct node_iterator_base + { +- typedef hash_node node_type; ++ typedef hash_node node_type; ++ typedef typename Allocator::template pointer pointer_type; + +- node_type* mpNode; ++ pointer_type mpNode; + +- node_iterator_base(node_type* pNode) ++ node_iterator_base(pointer_type pNode) + : mpNode(pNode) { } + ++ ~node_iterator_base() { ++ mpNode = nullptr; ++ Allocator::force_changes_in_dtor(this); ++ } ++ + void increment() + { mpNode = mpNode->mpNext; } + }; +@@ -202,12 +208,12 @@ namespace eastl + /// The bConst parameter defines if the iterator is a const_iterator + /// or an iterator. + /// +- template +- struct node_iterator : public node_iterator_base ++ template ++ struct node_iterator : public node_iterator_base + { + public: +- typedef node_iterator_base base_type; +- typedef node_iterator this_type; ++ typedef node_iterator_base base_type; ++ typedef node_iterator this_type; + typedef typename base_type::node_type node_type; + typedef Value value_type; + typedef typename type_select::type pointer; +@@ -216,10 +222,10 @@ namespace eastl + typedef EASTL_ITC_NS::forward_iterator_tag iterator_category; + + public: +- explicit node_iterator(node_type* pNode = NULL) ++ explicit node_iterator(typename base_type::pointer_type pNode = NULL) + : base_type(pNode) { } + +- node_iterator(const node_iterator& x) ++ node_iterator(const node_iterator& x) + : base_type(x.mpNode) { } + + reference operator*() const +@@ -248,33 +254,41 @@ namespace eastl + /// We define a base class here because it is shared by both const and + /// non-const iterators. + /// +- template ++ template + struct hashtable_iterator_base + { + public: +- typedef hashtable_iterator_base this_type; +- typedef hash_node node_type; ++ typedef hashtable_iterator_base this_type; ++ typedef hash_node node_type; ++ typedef typename Allocator::template pointer pointer_type; + + protected: ++ + template + friend class hashtable; + +- template ++ template + friend struct hashtable_iterator; + +- template +- friend bool operator==(const hashtable_iterator_base&, const hashtable_iterator_base&); ++ template ++ friend bool operator==(const hashtable_iterator_base&, const hashtable_iterator_base&); + +- template +- friend bool operator!=(const hashtable_iterator_base&, const hashtable_iterator_base&); ++ template ++ friend bool operator!=(const hashtable_iterator_base&, const hashtable_iterator_base&); + +- node_type* mpNode; // Current node within current bucket. +- node_type** mpBucket; // Current bucket. ++ pointer_type mpNode; // Current node within current bucket. ++ pointer_type* mpBucket; // Current bucket. + + public: +- hashtable_iterator_base(node_type* pNode, node_type** pBucket) ++ hashtable_iterator_base(const pointer_type& pNode, pointer_type* pBucket) + : mpNode(pNode), mpBucket(pBucket) { } + ++ ~hashtable_iterator_base() { ++ mpNode = nullptr; ++ mpBucket = nullptr; ++ Allocator::force_changes_in_dtor(this); ++ } ++ + void increment_bucket() + { + ++mpBucket; +@@ -306,13 +320,13 @@ namespace eastl + /// The bConst parameter defines if the iterator is a const_iterator + /// or an iterator. + /// +- template +- struct hashtable_iterator : public hashtable_iterator_base ++ template ++ struct hashtable_iterator : public hashtable_iterator_base + { + public: +- typedef hashtable_iterator_base base_type; +- typedef hashtable_iterator this_type; +- typedef hashtable_iterator this_type_non_const; ++ typedef hashtable_iterator_base base_type; ++ typedef hashtable_iterator this_type; ++ typedef hashtable_iterator this_type_non_const; + typedef typename base_type::node_type node_type; + typedef Value value_type; + typedef typename type_select::type pointer; +@@ -320,16 +334,29 @@ namespace eastl + typedef ptrdiff_t difference_type; + typedef EASTL_ITC_NS::forward_iterator_tag iterator_category; + ++ typedef typename base_type::pointer_type pointer_type; ++ + public: +- hashtable_iterator(node_type* pNode = NULL, node_type** pBucket = NULL) ++ hashtable_iterator(const pointer_type& pNode = NULL, pointer_type* pBucket = NULL) + : base_type(pNode, pBucket) { } + +- hashtable_iterator(node_type** pBucket) ++ hashtable_iterator(pointer_type* pBucket) + : base_type(*pBucket, pBucket) { } + + hashtable_iterator(const this_type_non_const& x) + : base_type(x.mpNode, x.mpBucket) { } + ++ hashtable_iterator& operator=(const this_type_non_const& x) ++ { ++ if(this != static_cast(&x)) ++ { ++ base_type::mpNode = x.mpNode; ++ base_type::mpBucket = x.mpBucket; ++ } ++ ++ return *this; ++ } ++ + reference operator*() const + { return base_type::mpNode->mValue; } + +@@ -342,9 +369,11 @@ namespace eastl + hashtable_iterator operator++(int) + { hashtable_iterator temp(*this); base_type::increment(); return temp; } + +- const node_type* get_node() const ++ const pointer_type& get_node() const + { return base_type::mpNode; } + ++ pointer_type* get_bucket() const ++ { return base_type::mpBucket; } + }; // hashtable_iterator + + +@@ -511,7 +540,7 @@ namespace eastl + /// objects here, for convenience. + /// + template ++ typename H1, typename H2, typename H, bool bCacheHashCode, typename Allocator> + struct hash_code_base; + + +@@ -520,8 +549,8 @@ namespace eastl + /// Specialization: ranged hash function, no caching hash codes. + /// H1 and H2 are provided but ignored. We define a dummy hash code type. + /// +- template +- struct hash_code_base ++ template ++ struct hash_code_base + { + protected: + ExtractKey mExtractKey; // To do: Make this member go away entirely, as it never has any data. +@@ -560,16 +589,16 @@ namespace eastl + bucket_index_t bucket_index(const Key& key, hash_code_t, uint32_t nBucketCount) const + { return (bucket_index_t)mRangedHash(key, nBucketCount); } + +- bucket_index_t bucket_index(const hash_node* pNode, uint32_t nBucketCount) const ++ bucket_index_t bucket_index(const hash_node* pNode, uint32_t nBucketCount) const + { return (bucket_index_t)mRangedHash(mExtractKey(pNode->mValue), nBucketCount); } + +- bool compare(const Key& key, hash_code_t, hash_node* pNode) const ++ bool compare(const Key& key, hash_code_t, hash_node* pNode) const + { return mEqual(key, mExtractKey(pNode->mValue)); } + +- void copy_code(hash_node*, const hash_node*) const ++ void copy_code(hash_node*, const hash_node*) const + { } // Nothing to do. + +- void set_code(hash_node* pDest, hash_code_t c) const ++ void set_code(hash_node* pDest, hash_code_t c) const + { + EA_UNUSED(pDest); + EA_UNUSED(c); +@@ -596,8 +625,8 @@ namespace eastl + /// This combination is meaningless, so we provide only a declaration + /// and no definition. + /// +- template +- struct hash_code_base; ++ template ++ struct hash_code_base; + + + +@@ -607,8 +636,8 @@ namespace eastl + /// no caching of hash codes. H is provided but ignored. + /// Provides typedef and accessor required by TR1. + /// +- template +- struct hash_code_base ++ template ++ struct hash_code_base + { + protected: + ExtractKey mExtractKey; +@@ -634,7 +663,7 @@ namespace eastl + protected: + typedef size_t hash_code_t; + typedef uint32_t bucket_index_t; +- typedef hash_node node_type; ++ typedef hash_node node_type; + + hash_code_base(const ExtractKey& ex, const Equal& eq, const H1& h1, const H2& h2, const default_ranged_hash&) + : mExtractKey(ex), mEqual(eq), m_h1(h1), m_h2(h2) { } +@@ -678,8 +707,8 @@ namespace eastl + /// caching hash codes. H is provided but ignored. + /// Provides typedef and accessor required by TR1. + /// +- template +- struct hash_code_base ++ template ++ struct hash_code_base + { + protected: + ExtractKey mExtractKey; +@@ -705,7 +734,7 @@ namespace eastl + protected: + typedef uint32_t hash_code_t; + typedef uint32_t bucket_index_t; +- typedef hash_node node_type; ++ typedef hash_node node_type; + + hash_code_base(const ExtractKey& ex, const Equal& eq, const H1& h1, const H2& h2, const default_ranged_hash&) + : mExtractKey(ex), mEqual(eq), m_h1(h1), m_h2(h2) { } +@@ -826,13 +855,13 @@ namespace eastl + typename RehashPolicy, bool bCacheHashCode, bool bMutableIterators, bool bUniqueKeys> + class hashtable + : public rehash_base >, +- public hash_code_base ++ public hash_code_base + { + public: + typedef Key key_type; + typedef Value value_type; + typedef typename ExtractKey::result_type mapped_type; +- typedef hash_code_base hash_code_base_type; ++ typedef hash_code_base hash_code_base_type; + typedef typename hash_code_base_type::hash_code_t hash_code_t; + typedef Allocator allocator_type; + typedef Equal key_equal; +@@ -840,11 +869,13 @@ namespace eastl + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to size_t. + typedef value_type& reference; + typedef const value_type& const_reference; +- typedef node_iterator local_iterator; +- typedef node_iterator const_local_iterator; +- typedef hashtable_iterator iterator; +- typedef hashtable_iterator const_iterator; +- typedef hash_node node_type; ++ typedef node_iterator local_iterator; ++ typedef node_iterator const_local_iterator; ++ typedef hashtable_iterator iterator; ++ typedef hashtable_iterator const_iterator; ++ typedef hash_node node_type; ++ typedef typename allocator_type::template pointer node_pointer; ++ typedef typename allocator_type::template array_pointer bucket_array_type; + typedef typename type_select, iterator>::type insert_return_type; + typedef hashtable this_type; +@@ -873,7 +904,7 @@ namespace eastl + }; + + protected: +- node_type** mpBucketArray; ++ bucket_array_type mpBucketArray; + size_type mnBucketCount; + size_type mnElementCount; + RehashPolicy mRehashPolicy; // To do: Use base class optimization to make this go away. +@@ -910,7 +941,7 @@ namespace eastl + + iterator begin() EA_NOEXCEPT + { +- iterator i(mpBucketArray); ++ iterator i(allocator_type::to_raw(mpBucketArray)); + if(!i.mpNode) + i.increment_bucket(); + return i; +@@ -918,7 +949,7 @@ namespace eastl + + const_iterator begin() const EA_NOEXCEPT + { +- const_iterator i(mpBucketArray); ++ const_iterator i(allocator_type::to_raw(mpBucketArray)); + if(!i.mpNode) + i.increment_bucket(); + return i; +@@ -1034,7 +1065,7 @@ namespace eastl + + // Non-standard extension + template // See comments below for the const value_type& equivalent to this function. +- insert_return_type insert(hash_code_t c, node_type* pNodeNew, P&& otherValue); ++ insert_return_type insert(hash_code_t c, node_pointer pNodeNew, P&& otherValue); + + // We provide a version of insert which lets the caller directly specify the hash value and + // a potential node to insert if needed. This allows for less thread contention in the case +@@ -1045,7 +1076,7 @@ namespace eastl + // to another call to insert. pNodeNew need not be assigned the value by the caller, as the insert + // function will assign value to pNodeNew upon insertion into the hash table. pNodeNew may be + // created by the user with the allocate_uninitialized_node function, and freed by the free_uninitialized_node function. +- insert_return_type insert(hash_code_t c, node_type* pNodeNew, const value_type& value); ++ insert_return_type insert(hash_code_t c, node_pointer pNodeNew, const value_type& value); + + template eastl::pair insert_or_assign(const key_type& k, M&& obj); + template eastl::pair insert_or_assign(key_type&& k, M&& obj); +@@ -1053,8 +1084,8 @@ namespace eastl + template iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); + + // Used to allocate and free memory used by insert(const value_type& value, hash_code_t c, node_type* pNodeNew). +- node_type* allocate_uninitialized_node(); +- void free_uninitialized_node(node_type* pNode); ++ node_pointer allocate_uninitialized_node(); ++ void free_uninitialized_node(node_pointer pNode); + + iterator erase(const_iterator position); + iterator erase(const_iterator first, const_iterator last); +@@ -1114,7 +1145,7 @@ namespace eastl + + const size_type n = (size_type)bucket_index(c, (uint32_t)mnBucketCount); + +- node_type* const pNode = DoFindNode(mpBucketArray[n], c); ++ node_pointer const pNode = DoFindNode(mpBucketArray[n], c); + + return pNode ? iterator(pNode, mpBucketArray + n) : + iterator(mpBucketArray + mnBucketCount); // iterator(mpBucketArray + mnBucketCount) == end() +@@ -1130,7 +1161,7 @@ namespace eastl + + const size_type n = (size_type)bucket_index(c, (uint32_t)mnBucketCount); + +- node_type* const pNode = DoFindNode(mpBucketArray[n], c); ++ node_pointer const pNode = DoFindNode(mpBucketArray[n], c); + + return pNode ? + const_iterator(pNode, mpBucketArray + n) : +@@ -1141,7 +1172,7 @@ namespace eastl + { + const size_type n = (size_type)bucket_index(c, (uint32_t)mnBucketCount); + +- node_type* const pNode = DoFindNode(mpBucketArray[n], k, c); ++ node_pointer const pNode = DoFindNode(mpBucketArray[n], k, c); + return pNode ? iterator(pNode, mpBucketArray + n) : iterator(mpBucketArray + mnBucketCount); // iterator(mpBucketArray + mnBucketCount) == end() + } + +@@ -1149,7 +1180,7 @@ namespace eastl + { + const size_type n = (size_type)bucket_index(c, (uint32_t)mnBucketCount); + +- node_type* const pNode = DoFindNode(mpBucketArray[n], k, c); ++ node_pointer const pNode = DoFindNode(mpBucketArray[n], k, c); + return pNode ? const_iterator(pNode, mpBucketArray + n) : const_iterator(mpBucketArray + mnBucketCount); // iterator(mpBucketArray + mnBucketCount) == end() + } + +@@ -1192,13 +1223,13 @@ namespace eastl + return irt; + } + +- node_type* DoAllocateNodeFromKey(const key_type& key); +- node_type* DoAllocateNodeFromKey(key_type&& key); +- void DoFreeNode(node_type* pNode); +- void DoFreeNodes(node_type** pBucketArray, size_type); ++ node_pointer DoAllocateNodeFromKey(const key_type& key); ++ node_pointer DoAllocateNodeFromKey(key_type&& key); ++ void DoFreeNode(node_pointer pNode); ++ void DoFreeNodes(bucket_array_type pBucketArray, size_type); + +- node_type** DoAllocateBuckets(size_type n); +- void DoFreeBuckets(node_type** pBucketArray, size_type n); ++ bucket_array_type DoAllocateBuckets(size_type n); ++ void DoFreeBuckets(bucket_array_type pBucketArray, size_type n); + + template + eastl::pair DoInsertValue(BoolConstantT, Args&&... args); +@@ -1211,7 +1242,7 @@ namespace eastl + eastl::pair DoInsertValueExtra(BoolConstantT, + const key_type& k, + hash_code_t c, +- node_type* pNodeNew, ++ node_pointer pNodeNew, + value_type&& value, + ENABLE_IF_TRUETYPE(BoolConstantT) = nullptr); + +@@ -1224,7 +1255,7 @@ namespace eastl + iterator DoInsertValueExtra(BoolConstantT, + const key_type& k, + hash_code_t c, +- node_type* pNodeNew, ++ node_pointer pNodeNew, + value_type&& value, + DISABLE_IF_TRUETYPE(BoolConstantT) = nullptr); + +@@ -1236,7 +1267,7 @@ namespace eastl + eastl::pair DoInsertValueExtra(BoolConstantT, + const key_type& k, + hash_code_t c, +- node_type* pNodeNew, ++ node_pointer pNodeNew, + const value_type& value, + ENABLE_IF_TRUETYPE(BoolConstantT) = nullptr); + +@@ -1249,7 +1280,7 @@ namespace eastl + iterator DoInsertValueExtra(BoolConstantT, + const key_type& k, + hash_code_t c, +- node_type* pNodeNew, ++ node_pointer pNodeNew, + const value_type& value, + DISABLE_IF_TRUETYPE(BoolConstantT) = nullptr); + +@@ -1257,9 +1288,9 @@ namespace eastl + iterator DoInsertValue(BoolConstantT, const value_type& value, DISABLE_IF_TRUETYPE(BoolConstantT) = nullptr); + + template +- node_type* DoAllocateNode(Args&&... args); +- node_type* DoAllocateNode(value_type&& value); +- node_type* DoAllocateNode(const value_type& value); ++ node_pointer DoAllocateNode(Args&&... args); ++ node_pointer DoAllocateNode(value_type&& value); ++ node_pointer DoAllocateNode(const value_type& value); + + // DoInsertKey is supposed to get hash_code_t c = get_hash_code(key). + // it is done in case application has it's own hashset/hashmap-like containter, where hash code is for some reason known prior the insert +@@ -1277,7 +1308,7 @@ namespace eastl + iterator DoInsertKey(false_type, key_type&& key) { return DoInsertKey(false_type(), eastl::move(key), get_hash_code(key)); } + + void DoRehash(size_type nBucketCount); +- node_type* DoFindNode(node_type* pNode, const key_type& k, hash_code_t c) const; ++ node_pointer DoFindNode(node_pointer pNode, const key_type& k, hash_code_t c) const; + + template + ENABLE_IF_HAS_HASHCODE(T, node_type) DoFindNode(T* pNode, hash_code_t c) const +@@ -1291,7 +1322,7 @@ namespace eastl + } + + template +- node_type* DoFindNodeT(node_type* pNode, const U& u, BinaryPredicate predicate) const; ++ node_pointer DoFindNodeT(node_pointer pNode, const U& u, BinaryPredicate predicate) const; + + }; // class hashtable + +@@ -1303,12 +1334,12 @@ namespace eastl + // node_iterator_base + /////////////////////////////////////////////////////////////////////// + +- template +- inline bool operator==(const node_iterator_base& a, const node_iterator_base& b) ++ template ++ inline bool operator==(const node_iterator_base& a, const node_iterator_base& b) + { return a.mpNode == b.mpNode; } + +- template +- inline bool operator!=(const node_iterator_base& a, const node_iterator_base& b) ++ template ++ inline bool operator!=(const node_iterator_base& a, const node_iterator_base& b) + { return a.mpNode != b.mpNode; } + + +@@ -1318,12 +1349,12 @@ namespace eastl + // hashtable_iterator_base + /////////////////////////////////////////////////////////////////////// + +- template +- inline bool operator==(const hashtable_iterator_base& a, const hashtable_iterator_base& b) ++ template ++ inline bool operator==(const hashtable_iterator_base& a, const hashtable_iterator_base& b) + { return a.mpNode == b.mpNode; } + +- template +- inline bool operator!=(const hashtable_iterator_base& a, const hashtable_iterator_base& b) ++ template ++ inline bool operator!=(const hashtable_iterator_base& a, const hashtable_iterator_base& b) + { return a.mpNode != b.mpNode; } + + +@@ -1339,7 +1370,7 @@ namespace eastl + ::hashtable(size_type nBucketCount, const H1& h1, const H2& h2, const H& h, + const Eq& eq, const EK& ek, const allocator_type& allocator) + : rehash_base(), +- hash_code_base(ek, eq, h1, h2, h), ++ hash_code_base(ek, eq, h1, h2, h), + mnBucketCount(0), + mnElementCount(0), + mRehashPolicy(), +@@ -1364,7 +1395,7 @@ namespace eastl + const H1& h1, const H2& h2, const H& h, + const Eq& eq, const EK& ek, const allocator_type& allocator) + : rehash_base(), +- hash_code_base(ek, eq, h1, h2, h), ++ hash_code_base(ek, eq, h1, h2, h), + //mnBucketCount(0), // This gets re-assigned below. + mnElementCount(0), + mRehashPolicy(), +@@ -1406,7 +1437,7 @@ namespace eastl + typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU> + hashtable::hashtable(const this_type& x) + : rehash_base(x), +- hash_code_base(x), ++ hash_code_base(x), + mnBucketCount(x.mnBucketCount), + mnElementCount(x.mnElementCount), + mRehashPolicy(x.mRehashPolicy), +@@ -1422,13 +1453,13 @@ namespace eastl + #endif + for(size_type i = 0; i < x.mnBucketCount; ++i) + { +- node_type* pNodeSource = x.mpBucketArray[i]; +- node_type** ppNodeDest = mpBucketArray + i; ++ node_pointer pNodeSource = x.mpBucketArray[i]; ++ node_pointer* ppNodeDest = mpBucketArray + i; + + while(pNodeSource) + { + *ppNodeDest = DoAllocateNode(pNodeSource->mValue); +- copy_code(*ppNodeDest, pNodeSource); ++ copy_code(allocator_type::to_raw(*ppNodeDest), allocator_type::to_raw(pNodeSource)); + ppNodeDest = &(*ppNodeDest)->mpNext; + pNodeSource = pNodeSource->mpNext; + } +@@ -1456,7 +1487,7 @@ namespace eastl + typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU> + hashtable::hashtable(this_type&& x) + : rehash_base(x), +- hash_code_base(x), ++ hash_code_base(x), + mnBucketCount(0), + mnElementCount(0), + mRehashPolicy(x.mRehashPolicy), +@@ -1471,7 +1502,7 @@ namespace eastl + typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU> + hashtable::hashtable(this_type&& x, const allocator_type& allocator) + : rehash_base(x), +- hash_code_base(x), ++ hash_code_base(x), + mnBucketCount(0), + mnElementCount(0), + mRehashPolicy(x.mRehashPolicy), +@@ -1564,21 +1595,25 @@ namespace eastl + { + clear(); + DoFreeBuckets(mpBucketArray, mnBucketCount); ++ reset_lose_memory(); ++ allocator_type::force_changes_in_dtor(this); + } + + + template +- typename hashtable::node_type* ++ typename hashtable::node_pointer + hashtable::DoAllocateNodeFromKey(const key_type& key) + { +- node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++ node_pointer const pNode = mAllocator.template allocate_node(); + EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif ++ auto raii = allocator_type::make_raii(pNode); + ::new(eastl::addressof(pNode->mValue)) value_type(pair_first_construct, key); + pNode->mpNext = NULL; + return pNode; +@@ -1586,7 +1621,8 @@ namespace eastl + } + catch(...) + { +- EASTLFree(mAllocator, pNode, sizeof(node_type)); ++// EASTLFree(mAllocator, pNode, sizeof(node_type)); ++ mAllocator.deallocate_node(pNode); + throw; + } + #endif +@@ -1595,16 +1631,18 @@ namespace eastl + + template +- typename hashtable::node_type* ++ typename hashtable::node_pointer + hashtable::DoAllocateNodeFromKey(key_type&& key) + { +- node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++ node_pointer const pNode = mAllocator.template allocate_node(); + EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif ++ auto raii = allocator_type::make_raii(pNode); + ::new(eastl::addressof(pNode->mValue)) value_type(pair_first_construct, eastl::move(key)); + pNode->mpNext = NULL; + return pNode; +@@ -1612,7 +1650,8 @@ namespace eastl + } + catch(...) + { +- EASTLFree(mAllocator, pNode, sizeof(node_type)); ++ // EASTLFree(mAllocator, pNode, sizeof(node_type)); ++ mAllocator.deallocate_node(pNode); + throw; + } + #endif +@@ -1621,24 +1660,25 @@ namespace eastl + + template +- inline void hashtable::DoFreeNode(node_type* pNode) ++ inline void hashtable::DoFreeNode(node_pointer pNode) + { + pNode->~node_type(); +- EASTLFree(mAllocator, pNode, sizeof(node_type)); ++ // EASTLFree(mAllocator, pNode, sizeof(node_type)); ++ mAllocator.deallocate_node(pNode); + } + + + + template +- void hashtable::DoFreeNodes(node_type** pNodeArray, size_type n) ++ void hashtable::DoFreeNodes(bucket_array_type pNodeArray, size_type n) + { + for(size_type i = 0; i < n; ++i) + { +- node_type* pNode = pNodeArray[i]; ++ node_pointer pNode = pNodeArray[i]; + while(pNode) + { +- node_type* const pTempNode = pNode; ++ node_pointer const pTempNode = pNode; + pNode = pNode->mpNext; + DoFreeNode(pTempNode); + } +@@ -1650,17 +1690,18 @@ namespace eastl + + template +- typename hashtable::node_type** ++ typename hashtable::bucket_array_type + hashtable::DoAllocateBuckets(size_type n) + { + // We allocate one extra bucket to hold a sentinel, an arbitrary + // non-null pointer. Iterator increment relies on this. + EASTL_ASSERT(n > 1); // We reserve an mnBucketCount of 1 for the shared gpEmptyBucketArray. + EASTL_CT_ASSERT(kHashtableAllocFlagBuckets == 0x00400000); // Currently we expect this to be so, because the allocator has a copy of this enum. +- node_type** const pBucketArray = (node_type**)EASTLAllocAlignedFlags(mAllocator, (n + 1) * sizeof(node_type*), EASTL_ALIGN_OF(node_type*), 0, kHashtableAllocFlagBuckets); ++// node_type** const pBucketArray = (node_type**)EASTLAllocAlignedFlags(mAllocator, (n + 1) * sizeof(node_type*), EASTL_ALIGN_OF(node_type*), 0, kHashtableAllocFlagBuckets); ++ bucket_array_type const pBucketArray = mAllocator.template allocate_array_zeroed(n + 1, kHashtableAllocFlagBuckets); + //eastl::fill(pBucketArray, pBucketArray + n, (node_type*)NULL); +- memset(pBucketArray, 0, n * sizeof(node_type*)); +- pBucketArray[n] = reinterpret_cast((uintptr_t)~0); ++ //memset(pBucketArray, 0, n * sizeof(node_pointer)); ++ pBucketArray[n] = allocator_type::template get_hashtable_sentinel(); + return pBucketArray; + } + +@@ -1668,13 +1709,14 @@ namespace eastl + + template +- inline void hashtable::DoFreeBuckets(node_type** pBucketArray, size_type n) ++ inline void hashtable::DoFreeBuckets(bucket_array_type pBucketArray, size_type n) + { + // If n <= 1, then pBucketArray is from the shared gpEmptyBucketArray. We don't test + // for pBucketArray == &gpEmptyBucketArray because one library have a different gpEmptyBucketArray + // than another but pass a hashtable to another. So we go by the size. + if(n > 1) +- EASTLFree(mAllocator, pBucketArray, (n + 1) * sizeof(node_type*)); // '+1' because DoAllocateBuckets allocates nBucketCount + 1 buckets in order to have a NULL sentinel at the end. ++ // EASTLFree(mAllocator, pBucketArray, (n + 1) * sizeof(node_type*)); // '+1' because DoAllocateBuckets allocates nBucketCount + 1 buckets in order to have a NULL sentinel at the end. ++ mAllocator.deallocate_array(pBucketArray, n + 1); + } + + +@@ -1682,9 +1724,9 @@ namespace eastl + typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU> + void hashtable::swap(this_type& x) + { +- hash_code_base::base_swap(x); // hash_code_base has multiple implementations, so we let them handle the swap. ++ hash_code_base::base_swap(x); // hash_code_base has multiple implementations, so we let them handle the swap. + eastl::swap(mRehashPolicy, x.mRehashPolicy); +- EASTL_MACRO_SWAP(node_type**, mpBucketArray, x.mpBucketArray); ++ EASTL_MACRO_SWAP(bucket_array_type, mpBucketArray, x.mpBucketArray); + eastl::swap(mnBucketCount, x.mnBucketCount); + eastl::swap(mnElementCount, x.mnElementCount); + +@@ -1717,7 +1759,7 @@ namespace eastl + const hash_code_t c = get_hash_code(k); + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + +- node_type* const pNode = DoFindNode(mpBucketArray[n], k, c); ++ node_pointer const pNode = DoFindNode(mpBucketArray[n], k, c); + return pNode ? iterator(pNode, mpBucketArray + n) : iterator(mpBucketArray + mnBucketCount); // iterator(mpBucketArray + mnBucketCount) == end() + } + +@@ -1731,7 +1773,7 @@ namespace eastl + const hash_code_t c = get_hash_code(k); + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + +- node_type* const pNode = DoFindNode(mpBucketArray[n], k, c); ++ node_pointer const pNode = DoFindNode(mpBucketArray[n], k, c); + return pNode ? const_iterator(pNode, mpBucketArray + n) : const_iterator(mpBucketArray + mnBucketCount); // iterator(mpBucketArray + mnBucketCount) == end() + } + +@@ -1746,7 +1788,7 @@ namespace eastl + const hash_code_t c = (hash_code_t)uhash(other); + const size_type n = (size_type)(c % mnBucketCount); // This assumes we are using the mod range policy. + +- node_type* const pNode = DoFindNodeT(mpBucketArray[n], other, predicate); ++ node_pointer const pNode = DoFindNodeT(mpBucketArray[n], other, predicate); + return pNode ? iterator(pNode, mpBucketArray + n) : iterator(mpBucketArray + mnBucketCount); // iterator(mpBucketArray + mnBucketCount) == end() + } + +@@ -1761,7 +1803,7 @@ namespace eastl + const hash_code_t c = (hash_code_t)uhash(other); + const size_type n = (size_type)(c % mnBucketCount); // This assumes we are using the mod range policy. + +- node_type* const pNode = DoFindNodeT(mpBucketArray[n], other, predicate); ++ node_pointer const pNode = DoFindNodeT(mpBucketArray[n], other, predicate); + return pNode ? const_iterator(pNode, mpBucketArray + n) : const_iterator(mpBucketArray + mnBucketCount); // iterator(mpBucketArray + mnBucketCount) == end() + } + +@@ -1820,7 +1862,7 @@ namespace eastl + hashtable::find_range_by_hash(hash_code_t c) const + { + const size_type start = (size_type)bucket_index(c, (uint32_t)mnBucketCount); +- node_type* const pNodeStart = mpBucketArray[start]; ++ node_pointer const pNodeStart = mpBucketArray[start]; + + if (pNodeStart) + { +@@ -1843,7 +1885,7 @@ namespace eastl + hashtable::find_range_by_hash(hash_code_t c) + { + const size_type start = (size_type)bucket_index(c, (uint32_t)mnBucketCount); +- node_type* const pNodeStart = mpBucketArray[start]; ++ node_pointer const pNodeStart = mpBucketArray[start]; + + if (pNodeStart) + { +@@ -1871,9 +1913,9 @@ namespace eastl + + // To do: Make a specialization for bU (unique keys) == true and take + // advantage of the fact that the count will always be zero or one in that case. +- for(node_type* pNode = mpBucketArray[n]; pNode; pNode = pNode->mpNext) ++ for(node_pointer pNode = mpBucketArray[n]; pNode; pNode = pNode->mpNext) + { +- if(compare(k, c, pNode)) ++ if(compare(k, c, allocator_type::to_raw(pNode))) + ++result; + } + return result; +@@ -1889,16 +1931,16 @@ namespace eastl + { + const hash_code_t c = get_hash_code(k); + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); +- node_type** head = mpBucketArray + n; +- node_type* pNode = DoFindNode(*head, k, c); ++ node_pointer* head = mpBucketArray + n; ++ node_pointer pNode = DoFindNode(*head, k, c); + + if(pNode) + { +- node_type* p1 = pNode->mpNext; ++ node_pointer p1 = pNode->mpNext; + + for(; p1; p1 = p1->mpNext) + { +- if(!compare(k, c, p1)) ++ if(!compare(k, c, allocator_type::to_raw(p1))) + break; + } + +@@ -1926,16 +1968,16 @@ namespace eastl + { + const hash_code_t c = get_hash_code(k); + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); +- node_type** head = mpBucketArray + n; +- node_type* pNode = DoFindNode(*head, k, c); ++ node_pointer* head = mpBucketArray + n; ++ node_pointer pNode = DoFindNode(*head, k, c); + + if(pNode) + { +- node_type* p1 = pNode->mpNext; ++ node_pointer p1 = pNode->mpNext; + + for(; p1; p1 = p1->mpNext) + { +- if(!compare(k, c, p1)) ++ if(!compare(k, c, allocator_type::to_raw(p1))) + break; + } + +@@ -1956,12 +1998,12 @@ namespace eastl + + template +- inline typename hashtable::node_type* +- hashtable::DoFindNode(node_type* pNode, const key_type& k, hash_code_t c) const ++ inline typename hashtable::node_pointer ++ hashtable::DoFindNode(node_pointer pNode, const key_type& k, hash_code_t c) const + { + for(; pNode; pNode = pNode->mpNext) + { +- if(compare(k, c, pNode)) ++ if(compare(k, c, allocator_type::to_raw(pNode))) + return pNode; + } + return NULL; +@@ -1972,8 +2014,8 @@ namespace eastl + template + template +- inline typename hashtable::node_type* +- hashtable::DoFindNodeT(node_type* pNode, const U& other, BinaryPredicate predicate) const ++ inline typename hashtable::node_pointer ++ hashtable::DoFindNodeT(node_pointer pNode, const U& other, BinaryPredicate predicate) const + { + for(; pNode; pNode = pNode->mpNext) + { +@@ -2002,17 +2044,17 @@ namespace eastl + // specializations of the insert function for const value_type& and value_type&&, and so the only time this function + // should get called is when args refers to arguments to construct a value_type. + +- node_type* const pNodeNew = DoAllocateNode(eastl::forward(args)...); ++ node_pointer const pNodeNew = DoAllocateNode(eastl::forward(args)...); + const key_type& k = mExtractKey(pNodeNew->mValue); + const hash_code_t c = get_hash_code(k); + size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); +- node_type* const pNode = DoFindNode(mpBucketArray[n], k, c); ++ node_pointer const pNode = DoFindNode(mpBucketArray[n], k, c); + + if(pNode == NULL) // If value is not present... add it. + { + const eastl::pair bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1); + +- set_code(pNodeNew, c); // This is a no-op for most hashtables. ++ set_code(allocator_type::to_raw(pNodeNew), c); // This is a no-op for most hashtables. + + #if EASTL_EXCEPTIONS_ENABLED + try +@@ -2024,7 +2066,7 @@ namespace eastl + DoRehash(bRehash.second); + } + +- EASTL_ASSERT((uintptr_t)mpBucketArray != (uintptr_t)&gpEmptyBucketArray[0]); ++ EASTL_ASSERT(!allocator_type::is_empty_hashtable(mpBucketArray)); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + ++mnElementCount; +@@ -2066,12 +2108,12 @@ namespace eastl + if(bRehash.first) + DoRehash(bRehash.second); + +- node_type* pNodeNew = DoAllocateNode(eastl::forward(args)...); ++ node_pointer pNodeNew = DoAllocateNode(eastl::forward(args)...); + const key_type& k = mExtractKey(pNodeNew->mValue); + const hash_code_t c = get_hash_code(k); + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + +- set_code(pNodeNew, c); // This is a no-op for most hashtables. ++ set_code(allocator_type::to_raw(pNodeNew), c); // This is a no-op for most hashtables. + + // To consider: Possibly make this insertion not make equal elements contiguous. + // As it stands now, we insert equal values contiguously in the hashtable. +@@ -2079,11 +2121,11 @@ namespace eastl + // erase(value) can more quickly find equal values. The downside is that + // this insertion operation taking some extra time. How important is it to + // us that equal_range span all equal items? +- node_type* const pNodePrev = DoFindNode(mpBucketArray[n], k, c); ++ node_pointer const pNodePrev = DoFindNode(mpBucketArray[n], k, c); + + if(pNodePrev == NULL) + { +- EASTL_ASSERT((void**)mpBucketArray != &gpEmptyBucketArray[0]); ++ EASTL_ASSERT(!allocator_type::is_empty_hashtable(mpBucketArray)); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + } +@@ -2102,16 +2144,18 @@ namespace eastl + template + template +- typename hashtable::node_type* ++ typename hashtable::node_pointer + hashtable::DoAllocateNode(Args&&... args) + { +- node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++ node_pointer const pNode = mAllocator.template allocate_node(); + EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif ++ auto raii = allocator_type::make_raii(pNode); + ::new(eastl::addressof(pNode->mValue)) value_type(eastl::forward(args)...); + pNode->mpNext = NULL; + return pNode; +@@ -2119,7 +2163,8 @@ namespace eastl + } + catch(...) + { +- EASTLFree(mAllocator, pNode, sizeof(node_type)); ++// EASTLFree(mAllocator, pNode, sizeof(node_type)); ++ mAllocator.deallocate_node(pNode); + throw; + } + #endif +@@ -2139,12 +2184,12 @@ namespace eastl + template + eastl::pair::iterator, bool> + hashtable::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. ++ hash_code_t c, node_pointer pNodeNew, 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); ++ node_pointer const pNode = DoFindNode(mpBucketArray[n], k, c); + + if(pNode == NULL) // If value is not present... add it. + { +@@ -2158,6 +2203,7 @@ namespace eastl + + if(pNodeNew) + { ++ auto raii = allocator_type::make_raii(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; +@@ -2171,7 +2217,7 @@ namespace eastl + #endif + } + +- set_code(pNodeNew, c); // This is a no-op for most hashtables. ++ set_code(allocator_type::to_raw(pNodeNew), c); // This is a no-op for most hashtables. + + #if EASTL_EXCEPTIONS_ENABLED + try +@@ -2183,7 +2229,7 @@ namespace eastl + DoRehash(bRehash.second); + } + +- EASTL_ASSERT((uintptr_t)mpBucketArray != (uintptr_t)&gpEmptyBucketArray[0]); ++ EASTL_ASSERT(!allocator_type::is_empty_hashtable(mpBucketArray)); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + ++mnElementCount; +@@ -2222,7 +2268,7 @@ namespace eastl + typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU> + template + typename hashtable::iterator +- hashtable::DoInsertValueExtra(BoolConstantT, const key_type& k, hash_code_t c, node_type* pNodeNew, value_type&& value, ++ hashtable::DoInsertValueExtra(BoolConstantT, const key_type& k, hash_code_t c, node_pointer pNodeNew, value_type&& value, + DISABLE_IF_TRUETYPE(BoolConstantT)) // false_type means bUniqueKeys is false. + { + const eastl::pair bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1); +@@ -2232,12 +2278,14 @@ namespace eastl + + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + +- if(pNodeNew) ++ if(pNodeNew) { ++ auto raii = allocator_type::make_raii(pNodeNew); + ::new(eastl::addressof(pNodeNew->mValue)) value_type(eastl::move(value)); // It's expected that pNodeNew was allocated with allocate_uninitialized_node. ++ } + else + pNodeNew = DoAllocateNode(eastl::move(value)); + +- set_code(pNodeNew, c); // This is a no-op for most hashtables. ++ set_code(allocator_type::to_raw(pNodeNew), c); // This is a no-op for most hashtables. + + // To consider: Possibly make this insertion not make equal elements contiguous. + // As it stands now, we insert equal values contiguously in the hashtable. +@@ -2245,11 +2293,11 @@ namespace eastl + // erase(value) can more quickly find equal values. The downside is that + // this insertion operation taking some extra time. How important is it to + // us that equal_range span all equal items? +- node_type* const pNodePrev = DoFindNode(mpBucketArray[n], k, c); ++ node_pointer const pNodePrev = DoFindNode(mpBucketArray[n], k, c); + + if(pNodePrev == NULL) + { +- EASTL_ASSERT((void**)mpBucketArray != &gpEmptyBucketArray[0]); ++ EASTL_ASSERT(!allocator_type::is_empty_hashtable(mpBucketArray)); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + } +@@ -2280,16 +2328,18 @@ namespace eastl + + template +- typename hashtable::node_type* ++ typename hashtable::node_pointer + hashtable::DoAllocateNode(value_type&& value) + { +- node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++ node_pointer const pNode = mAllocator.template allocate_node(); + EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif ++ auto raii = allocator_type::make_raii(pNode); + ::new(eastl::addressof(pNode->mValue)) value_type(eastl::move(value)); + pNode->mpNext = NULL; + return pNode; +@@ -2297,7 +2347,8 @@ namespace eastl + } + catch(...) + { +- EASTLFree(mAllocator, pNode, sizeof(node_type)); ++// EASTLFree(mAllocator, pNode, sizeof(node_type)); ++ mAllocator.deallocate_node(pNode); + throw; + } + #endif +@@ -2308,13 +2359,13 @@ namespace eastl + typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU> + template + eastl::pair::iterator, bool> +- hashtable::DoInsertValueExtra(BoolConstantT, const key_type& k, hash_code_t c, node_type* pNodeNew, const value_type& value, ++ hashtable::DoInsertValueExtra(BoolConstantT, const key_type& k, hash_code_t c, node_pointer 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); ++ node_pointer const pNode = DoFindNode(mpBucketArray[n], k, c); + + if(pNode == NULL) // If value is not present... add it. + { +@@ -2328,6 +2379,7 @@ namespace eastl + + if(pNodeNew) + { ++ auto raii = allocator_type::make_raii(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; +@@ -2341,7 +2393,7 @@ namespace eastl + #endif + } + +- set_code(pNodeNew, c); // This is a no-op for most hashtables. ++ set_code(allocator_type::to_raw(pNodeNew), c); // This is a no-op for most hashtables. + + #if EASTL_EXCEPTIONS_ENABLED + try +@@ -2353,7 +2405,7 @@ namespace eastl + DoRehash(bRehash.second); + } + +- EASTL_ASSERT((uintptr_t)mpBucketArray != (uintptr_t)&gpEmptyBucketArray[0]); ++ EASTL_ASSERT(!allocator_type::is_empty_hashtable(mpBucketArray)); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + ++mnElementCount; +@@ -2392,7 +2444,7 @@ namespace eastl + typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU> + template + typename hashtable::iterator +- hashtable::DoInsertValueExtra(BoolConstantT, const key_type& k, hash_code_t c, node_type* pNodeNew, const value_type& value, ++ hashtable::DoInsertValueExtra(BoolConstantT, const key_type& k, hash_code_t c, node_pointer pNodeNew, const value_type& value, + DISABLE_IF_TRUETYPE(BoolConstantT)) // false_type means bUniqueKeys is false. + { + const eastl::pair bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1); +@@ -2402,12 +2454,14 @@ namespace eastl + + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + +- if(pNodeNew) ++ if(pNodeNew) { ++ auto raii = allocator_type::make_raii(pNodeNew); + ::new(eastl::addressof(pNodeNew->mValue)) value_type(value); // It's expected that pNodeNew was allocated with allocate_uninitialized_node. ++ } + else + pNodeNew = DoAllocateNode(value); + +- set_code(pNodeNew, c); // This is a no-op for most hashtables. ++ set_code(allocator_type::to_raw(pNodeNew), c); // This is a no-op for most hashtables. + + // To consider: Possibly make this insertion not make equal elements contiguous. + // As it stands now, we insert equal values contiguously in the hashtable. +@@ -2415,11 +2469,11 @@ namespace eastl + // erase(value) can more quickly find equal values. The downside is that + // this insertion operation taking some extra time. How important is it to + // us that equal_range span all equal items? +- node_type* const pNodePrev = DoFindNode(mpBucketArray[n], k, c); ++ node_pointer const pNodePrev = DoFindNode(mpBucketArray[n], k, c); + + if(pNodePrev == NULL) + { +- EASTL_ASSERT((void**)mpBucketArray != &gpEmptyBucketArray[0]); ++ EASTL_ASSERT(!allocator_type::is_empty_hashtable(mpBucketArray)); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + } +@@ -2450,16 +2504,18 @@ namespace eastl + + template +- typename hashtable::node_type* ++ typename hashtable::node_pointer + hashtable::DoAllocateNode(const value_type& value) + { +- node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++ node_pointer const pNode = mAllocator.template allocate_node(); + EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif ++ auto raii = allocator_type::make_raii(pNode); + ::new(eastl::addressof(pNode->mValue)) value_type(value); + pNode->mpNext = NULL; + return pNode; +@@ -2467,7 +2523,8 @@ namespace eastl + } + catch(...) + { +- EASTLFree(mAllocator, pNode, sizeof(node_type)); ++ // EASTLFree(mAllocator, pNode, sizeof(node_type)); ++ mAllocator.deallocate_node(pNode); + throw; + } + #endif +@@ -2476,11 +2533,12 @@ namespace eastl + + template +- typename hashtable::node_type* ++ typename hashtable::node_pointer + hashtable::allocate_uninitialized_node() + { + // We don't wrap this in try/catch because users of this function are expected to do that themselves as needed. +- node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++ node_pointer const pNode = mAllocator.template allocate_node(); + EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + // Leave pNode->mValue uninitialized. + pNode->mpNext = NULL; +@@ -2490,10 +2548,11 @@ namespace eastl + + template +- void hashtable::free_uninitialized_node(node_type* pNode) ++ void hashtable::free_uninitialized_node(node_pointer pNode) + { + // pNode->mValue is expected to be uninitialized. +- EASTLFree(mAllocator, pNode, sizeof(node_type)); ++// EASTLFree(mAllocator, pNode, sizeof(node_type)); ++ mAllocator.deallocate_node(pNode); + } + + +@@ -2503,7 +2562,7 @@ namespace eastl + hashtable::DoInsertKey(true_type, const key_type& key, const hash_code_t c) // true_type means bUniqueKeys is true. + { + size_type n = (size_type)bucket_index(key, c, (uint32_t)mnBucketCount); +- node_type* const pNode = DoFindNode(mpBucketArray[n], key, c); ++ node_pointer const pNode = DoFindNode(mpBucketArray[n], key, c); + + if(pNode == NULL) + { +@@ -2511,8 +2570,8 @@ namespace eastl + + // Allocate the new node before doing the rehash so that we don't + // do a rehash if the allocation throws. +- node_type* const pNodeNew = DoAllocateNodeFromKey(key); +- set_code(pNodeNew, c); // This is a no-op for most hashtables. ++ node_pointer const pNodeNew = DoAllocateNodeFromKey(key); ++ set_code(allocator_type::to_raw(pNodeNew), c); // This is a no-op for most hashtables. + + #if EASTL_EXCEPTIONS_ENABLED + try +@@ -2524,7 +2583,7 @@ namespace eastl + DoRehash(bRehash.second); + } + +- EASTL_ASSERT((void**)mpBucketArray != &gpEmptyBucketArray[0]); ++ EASTL_ASSERT(!allocator_type::is_empty_hashtable(mpBucketArray)); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + ++mnElementCount; +@@ -2557,8 +2616,8 @@ namespace eastl + + const size_type n = (size_type)bucket_index(key, c, (uint32_t)mnBucketCount); + +- node_type* const pNodeNew = DoAllocateNodeFromKey(key); +- set_code(pNodeNew, c); // This is a no-op for most hashtables. ++ node_pointer const pNodeNew = DoAllocateNodeFromKey(key); ++ set_code(allocator_type::to_raw(pNodeNew), c); // This is a no-op for most hashtables. + + // To consider: Possibly make this insertion not make equal elements contiguous. + // As it stands now, we insert equal values contiguously in the hashtable. +@@ -2566,11 +2625,11 @@ namespace eastl + // erase(value) can more quickly find equal values. The downside is that + // this insertion operation taking some extra time. How important is it to + // us that equal_range span all equal items? +- node_type* const pNodePrev = DoFindNode(mpBucketArray[n], key, c); ++ node_pointer const pNodePrev = DoFindNode(mpBucketArray[n], key, c); + + if(pNodePrev == NULL) + { +- EASTL_ASSERT((void**)mpBucketArray != &gpEmptyBucketArray[0]); ++ EASTL_ASSERT(!allocator_type::is_empty_hashtable(mpBucketArray)); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + } +@@ -2592,7 +2651,7 @@ namespace eastl + hashtable::DoInsertKey(true_type, key_type&& key, const hash_code_t c) // true_type means bUniqueKeys is true. + { + size_type n = (size_type)bucket_index(key, c, (uint32_t)mnBucketCount); +- node_type* const pNode = DoFindNode(mpBucketArray[n], key, c); ++ node_pointer const pNode = DoFindNode(mpBucketArray[n], key, c); + + if(pNode == NULL) + { +@@ -2600,8 +2659,8 @@ namespace eastl + + // Allocate the new node before doing the rehash so that we don't + // do a rehash if the allocation throws. +- node_type* const pNodeNew = DoAllocateNodeFromKey(eastl::move(key)); +- set_code(pNodeNew, c); // This is a no-op for most hashtables. ++ node_pointer const pNodeNew = DoAllocateNodeFromKey(eastl::move(key)); ++ set_code(allocator_type::to_raw(pNodeNew), c); // This is a no-op for most hashtables. + + #if EASTL_EXCEPTIONS_ENABLED + try +@@ -2613,7 +2672,7 @@ namespace eastl + DoRehash(bRehash.second); + } + +- EASTL_ASSERT((void**)mpBucketArray != &gpEmptyBucketArray[0]); ++ EASTL_ASSERT(!allocator_type::is_empty_hashtable(mpBucketArray)); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + ++mnElementCount; +@@ -2645,8 +2704,8 @@ namespace eastl + + const size_type n = (size_type)bucket_index(key, c, (uint32_t)mnBucketCount); + +- node_type* const pNodeNew = DoAllocateNodeFromKey(eastl::move(key)); +- set_code(pNodeNew, c); // This is a no-op for most hashtables. ++ node_pointer const pNodeNew = DoAllocateNodeFromKey(eastl::move(key)); ++ set_code(allocator_type::to_raw(pNodeNew), c); // This is a no-op for most hashtables. + + // To consider: Possibly make this insertion not make equal elements contiguous. + // As it stands now, we insert equal values contiguously in the hashtable. +@@ -2654,11 +2713,11 @@ namespace eastl + // erase(value) can more quickly find equal values. The downside is that + // this insertion operation taking some extra time. How important is it to + // us that equal_range span all equal items? +- node_type* const pNodePrev = DoFindNode(mpBucketArray[n], key, c); ++ node_pointer const pNodePrev = DoFindNode(mpBucketArray[n], key, c); + + if(pNodePrev == NULL) + { +- EASTL_ASSERT((void**)mpBucketArray != &gpEmptyBucketArray[0]); ++ EASTL_ASSERT(!allocator_type::is_empty_hashtable(mpBucketArray)); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + } +@@ -2755,7 +2814,7 @@ namespace eastl + typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU> + template + typename hashtable::insert_return_type +- hashtable::insert(hash_code_t c, node_type* pNodeNew, P&& otherValue) ++ hashtable::insert(hash_code_t c, node_pointer pNodeNew, P&& otherValue) + { + // pNodeNew->mValue is expected to be uninitialized. + value_type value(eastl::forward

(otherValue)); // Need to use forward instead of move because P&& is a "universal reference" instead of an rvalue reference. +@@ -2778,7 +2837,7 @@ namespace eastl + template + typename hashtable::insert_return_type +- hashtable::insert(const value_type& value) ++ hashtable::insert(const value_type& value) + { + return DoInsertValue(has_unique_keys_type(), value); + } +@@ -2787,7 +2846,7 @@ namespace eastl + template + typename hashtable::insert_return_type +- hashtable::insert(hash_code_t c, node_type* pNodeNew, const value_type& value) ++ hashtable::insert(hash_code_t c, node_pointer pNodeNew, const value_type& value) + { + // pNodeNew->mValue is expected to be uninitialized. + const key_type& k = mExtractKey(value); +@@ -2904,8 +2963,8 @@ namespace eastl + iterator iNext(i.mpNode, i.mpBucket); // Convert from const_iterator to iterator while constructing. + ++iNext; + +- node_type* pNode = i.mpNode; +- node_type* pNodeCurrent = *i.mpBucket; ++ node_pointer pNode = i.mpNode; ++ node_pointer pNodeCurrent = *i.mpBucket; + + if(pNodeCurrent == pNode) + *i.mpBucket = pNodeCurrent->mpNext; +@@ -2913,7 +2972,7 @@ namespace eastl + { + // We have a singly-linked list, so we have no choice but to + // walk down it till we find the node before the node at 'i'. +- node_type* pNodeNext = pNodeCurrent->mpNext; ++ node_pointer pNodeNext = pNodeCurrent->mpNext; + + while(pNodeNext != pNode) + { +@@ -2957,14 +3016,14 @@ namespace eastl + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + const size_type nElementCountSaved = mnElementCount; + +- node_type** pBucketArray = mpBucketArray + n; ++ node_pointer* pBucketArray = mpBucketArray + n; + +- while(*pBucketArray && !compare(k, c, *pBucketArray)) ++ while(*pBucketArray && !compare(k, c, allocator_type::to_raw(*pBucketArray))) + pBucketArray = &(*pBucketArray)->mpNext; + +- while(*pBucketArray && compare(k, c, *pBucketArray)) ++ while(*pBucketArray && compare(k, c, allocator_type::to_raw(*pBucketArray))) + { +- node_type* const pNode = *pBucketArray; ++ node_pointer const pNode = *pBucketArray; + *pBucketArray = pNode->mpNext; + DoFreeNode(pNode); + --mnElementCount; +@@ -3010,12 +3069,12 @@ namespace eastl + // container built into scratch memory. + mnBucketCount = 1; + +- #ifdef _MSC_VER +- mpBucketArray = (node_type**)&gpEmptyBucketArray[0]; +- #else +- void* p = &gpEmptyBucketArray[0]; +- memcpy(&mpBucketArray, &p, sizeof(mpBucketArray)); // Other compilers implement strict aliasing and casting is thus unsafe. +- #endif ++ // #ifdef _MSC_VER ++ mpBucketArray = allocator_type::template get_empty_hashtable(); ++ // #else ++ // auto p = &gpEmptyBucketArray[0]; ++ // memcpy(&mpBucketArray, &p, sizeof(mpBucketArray)); // Other compilers implement strict aliasing and casting is thus unsafe. ++ // #endif + + mnElementCount = 0; + mRehashPolicy.mnNextResize = 0; +@@ -3046,19 +3105,19 @@ namespace eastl + typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU> + void hashtable::DoRehash(size_type nNewBucketCount) + { +- node_type** const pBucketArray = DoAllocateBuckets(nNewBucketCount); // nNewBucketCount should always be >= 2. ++ bucket_array_type const pBucketArray = DoAllocateBuckets(nNewBucketCount); // nNewBucketCount should always be >= 2. + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif +- node_type* pNode; ++ node_pointer pNode; + + for(size_type i = 0; i < mnBucketCount; ++i) + { + while((pNode = mpBucketArray[i]) != NULL) // Using '!=' disables compiler warnings. + { +- const size_type nNewBucketIndex = (size_type)bucket_index(pNode, (uint32_t)nNewBucketCount); ++ const size_type nNewBucketIndex = (size_type)bucket_index(allocator_type::to_raw(pNode), (uint32_t)nNewBucketCount); + + mpBucketArray[i] = pNode->mpNext; + pNode->mpNext = pBucketArray[nNewBucketIndex]; +@@ -3091,10 +3150,11 @@ namespace eastl + inline bool hashtable::validate() const + { + // Verify our empty bucket array is unmodified. +- if(gpEmptyBucketArray[0] != NULL) ++ auto empty_hashtable = allocator_type::template get_empty_hashtable(); ++ if(empty_hashtable[0] != NULL) + return false; + +- if(gpEmptyBucketArray[1] != (void*)uintptr_t(~0)) ++ if(!allocator_type::is_hashtable_sentinel(empty_hashtable[1])) + return false; + + // Verify that we have at least one bucket. Calculations can +@@ -3104,7 +3164,7 @@ namespace eastl + + // Verify that gpEmptyBucketArray is used correctly. + // gpEmptyBucketArray is only used when initially empty. +- if((void**)mpBucketArray == &gpEmptyBucketArray[0]) ++ if(allocator_type::is_empty_hashtable(mpBucketArray)) + { + if(mnElementCount) // gpEmptyBucketArray is used only for empty hash tables. + return false; +diff --git a/include/EASTL/internal/type_pod.h b/include/EASTL/internal/type_pod.h +index 998e957..327a3f2 100644 +--- a/include/EASTL/internal/type_pod.h ++++ b/include/EASTL/internal/type_pod.h +@@ -1721,7 +1721,7 @@ namespace eastl + template + eastl::false_type destructible_test_function(...); + +- template >().~destructible_test_helper())> ++ template >().~destructible_test_helper())> + eastl::true_type destructible_test_function(int); + + template ::value || // Exclude these types from being considered destructible. +diff --git a/include/EASTL/iterator.h b/include/EASTL/iterator.h +index 6760348..548ef64 100644 +--- a/include/EASTL/iterator.h ++++ b/include/EASTL/iterator.h +@@ -76,6 +76,8 @@ namespace eastl + struct bidirectional_iterator_tag : public forward_iterator_tag { }; + struct random_access_iterator_tag : public bidirectional_iterator_tag { }; + struct contiguous_iterator_tag : public random_access_iterator_tag { }; // Extension to the C++ standard. Contiguous ranges are more than random access, they are physically contiguous. ++ #else ++ struct contiguous_iterator_tag : public std::random_access_iterator_tag { }; // Extension to the C++ standard. Contiguous ranges are more than random access, they are physically contiguous. + #endif + + +diff --git a/include/EASTL/string.h b/include/EASTL/string.h +index 18c2e7c..7d45375 100644 +--- a/include/EASTL/string.h ++++ b/include/EASTL/string.h +@@ -293,6 +293,9 @@ namespace eastl + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to size_t. + typedef ptrdiff_t difference_type; + typedef Allocator allocator_type; ++ protected: ++ typedef typename allocator_type::template array_pointer heap_array_type; ++ public: + + static const size_type npos = (size_type)-1; /// 'npos' means non-valid position or simply non-position. + +@@ -332,7 +335,7 @@ namespace eastl + // The view of memory when the string data is obtained from the allocator. + struct HeapLayout + { +- value_type* mpBegin; // Begin of string. ++ heap_array_type mpBegin; // Begin of string. + size_type mnSize; // Size of the string. Number of characters currently in the string, not including the trailing '0' + size_type mnCapacity; // Capacity of the string. Number of characters string can hold, not including the trailing '0' + }; +@@ -428,8 +431,8 @@ namespace eastl + + inline size_type GetRemainingCapacity() const EA_NOEXCEPT { return size_type(CapacityPtr() - EndPtr()); } + +- inline value_type* HeapBeginPtr() EA_NOEXCEPT { return heap.mpBegin; }; +- inline const value_type* HeapBeginPtr() const EA_NOEXCEPT { return heap.mpBegin; }; ++ inline value_type* HeapBeginPtr() EA_NOEXCEPT { return allocator_type::to_raw(heap.mpBegin); }; ++ inline const value_type* HeapBeginPtr() const EA_NOEXCEPT { return allocator_type::to_raw(heap.mpBegin); }; + + inline value_type* SSOBeginPtr() EA_NOEXCEPT { return sso.mData; } + inline const value_type* SSOBeginPtr() const EA_NOEXCEPT { return sso.mData; } +@@ -457,7 +460,8 @@ namespace eastl + inline value_type* CapacityPtr() EA_NOEXCEPT { return IsHeap() ? HeapCapacityPtr() : SSOCapacityPtr(); } + inline const value_type* CapacityPtr() const EA_NOEXCEPT { return IsHeap() ? HeapCapacityPtr() : SSOCapacityPtr(); } + +- inline void SetHeapBeginPtr(value_type* pBegin) EA_NOEXCEPT { heap.mpBegin = pBegin; } ++ inline void SetHeapBeginPtr(heap_array_type pBegin) EA_NOEXCEPT { heap.mpBegin = pBegin; } ++ inline const heap_array_type& GetHeapBeginPtr() const EA_NOEXCEPT { return heap.mpBegin; } + + inline void SetHeapCapacity(size_type cap) EA_NOEXCEPT + { +@@ -751,8 +755,8 @@ namespace eastl + + protected: + // Helper functions for initialization/insertion operations. +- value_type* DoAllocate(size_type n); +- void DoFree(value_type* p, size_type n); ++ heap_array_type DoAllocate(size_type n); ++ void DoFree(heap_array_type p, size_type n); + size_type GetNewCapacity(size_type currentCapacity); + size_type GetNewCapacity(size_type currentCapacity, size_type minimumGrowSize); + void AllocateSelf(); +@@ -995,6 +999,8 @@ namespace eastl + inline basic_string::~basic_string() + { + DeallocateSelf(); ++ AllocateSelf(); ++ allocator_type::force_changes_in_dtor(this); + } + + +@@ -1408,21 +1414,22 @@ namespace eastl + // A heap based layout wants to reduce its size to within sso capacity + // An sso layout wanting to reduce its capacity will not get in here + pointer pOldBegin = internalLayout().BeginPtr(); ++ heap_array_type pOldHeap = internalLayout().GetHeapBeginPtr(); + const size_type nOldCap = internalLayout().GetHeapCapacity(); + + CharStringUninitializedCopy(pOldBegin, pOldBegin + n, internalLayout().SSOBeginPtr()); + internalLayout().SetSSOSize(n); + *internalLayout().SSOEndPtr() = 0; + +- DoFree(pOldBegin, nOldCap + 1); ++ DoFree(pOldHeap, nOldCap + 1); + + return; + } + +- pointer pNewBegin = DoAllocate(n + 1); // We need the + 1 to accomodate the trailing 0. ++ heap_array_type pNewBegin = DoAllocate(n + 1); // We need the + 1 to accomodate the trailing 0. + size_type nSavedSize = internalLayout().GetSize(); // save the size in case we transition from sso->heap + +- pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), internalLayout().EndPtr(), pNewBegin); ++ pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), internalLayout().EndPtr(), allocator_type::to_raw(pNewBegin)); + *pNewEnd = 0; + + DeallocateSelf(); +@@ -1479,7 +1486,7 @@ namespace eastl + if (internalLayout().IsSSO()) + { + const size_type n = internalLayout().GetSize() + 1; // +1' so that we have room for the terminating 0. +- pDetached = DoAllocate(n); ++ pDetached = allocator_type::to_raw(DoAllocate(n)); + pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), internalLayout().EndPtr(), pDetached); + *pNewEnd = 0; + } +@@ -1718,9 +1725,9 @@ namespace eastl + { + const size_type nLength = GetNewCapacity(nCapacity, nNewSize - nCapacity); + +- pointer pNewBegin = DoAllocate(nLength + 1); ++ heap_array_type pNewBegin = DoAllocate(nLength + 1); + +- pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), internalLayout().EndPtr(), pNewBegin); ++ pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), internalLayout().EndPtr(), allocator_type::to_raw(pNewBegin)); + pNewEnd = CharStringUninitializedCopy(pBegin, pEnd, pNewEnd); + *pNewEnd = 0; + +@@ -2185,9 +2192,9 @@ namespace eastl + const size_type nOldCap = capacity(); + const size_type nLength = GetNewCapacity(nOldCap, (nOldSize + n) - nOldCap); + +- iterator pNewBegin = DoAllocate(nLength + 1); ++ heap_array_type pNewBegin = DoAllocate(nLength + 1); + +- iterator pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), p, pNewBegin); ++ iterator pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), p, allocator_type::to_raw(pNewBegin)); + pNewEnd = CharStringUninitializedFillN(pNewEnd, n, c); + pNewEnd = CharStringUninitializedCopy(p, internalLayout().EndPtr(), pNewEnd); + *pNewEnd = 0; +@@ -2293,9 +2300,9 @@ namespace eastl + else + nLength = GetNewCapacity(nOldCap, (nOldSize + n) - nOldCap); + +- pointer pNewBegin = DoAllocate(nLength + 1); ++ heap_array_type pNewBegin = DoAllocate(nLength + 1); + +- pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), p, pNewBegin); ++ pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), p, allocator_type::to_raw(pNewBegin)); + pNewEnd = CharStringUninitializedCopy(pBegin, pEnd, pNewEnd); + pNewEnd = CharStringUninitializedCopy(p, internalLayout().EndPtr(), pNewEnd); + *pNewEnd = 0; +@@ -2572,9 +2579,9 @@ namespace eastl + const size_type nOldCap = capacity(); + const size_type nNewCapacity = GetNewCapacity(nOldCap, (nOldSize + (nLength2 - nLength1)) - nOldCap); + +- pointer pNewBegin = DoAllocate(nNewCapacity + 1); ++ heap_array_type pNewBegin = DoAllocate(nNewCapacity + 1); + +- pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), pBegin1, pNewBegin); ++ pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), pBegin1, allocator_type::to_raw(pNewBegin)); + pNewEnd = CharStringUninitializedCopy(pBegin2, pEnd2, pNewEnd); + pNewEnd = CharStringUninitializedCopy(pEnd1, internalLayout().EndPtr(), pNewEnd); + *pNewEnd = 0; +@@ -3208,9 +3215,9 @@ namespace eastl + const size_type nOldCap = capacity(); + const size_type nLength = GetNewCapacity(nOldCap, 1); + +- iterator pNewBegin = DoAllocate(nLength + 1); ++ heap_array_type pNewBegin = DoAllocate(nLength + 1); + +- pNewPosition = CharStringUninitializedCopy(internalLayout().BeginPtr(), p, pNewBegin); ++ pNewPosition = CharStringUninitializedCopy(internalLayout().BeginPtr(), p, allocator_type::to_raw(pNewBegin)); + *pNewPosition = c; + + iterator pNewEnd = pNewPosition + 1; +@@ -3266,18 +3273,20 @@ namespace eastl + + + template +- inline typename basic_string::value_type* ++ inline typename basic_string::heap_array_type + basic_string::DoAllocate(size_type n) + { +- return (value_type*)EASTLAlloc(get_allocator(), n * sizeof(value_type)); ++ // return (value_type*)EASTLAlloc(get_allocator(), n * sizeof(value_type)); ++ return get_allocator().template allocate_array(n); + } + + + template +- inline void basic_string::DoFree(value_type* p, size_type n) ++ inline void basic_string::DoFree(heap_array_type p, size_type n) + { + if(p) +- EASTLFree(get_allocator(), p, n * sizeof(value_type)); ++ // EASTLFree(get_allocator(), p, n * sizeof(value_type)); ++ get_allocator().deallocate_array(p, n); + } + + +@@ -3329,7 +3338,7 @@ namespace eastl + + if(n > SSOLayout::SSO_CAPACITY) + { +- pointer pBegin = DoAllocate(n + 1); ++ heap_array_type pBegin = DoAllocate(n + 1); + internalLayout().SetHeapBeginPtr(pBegin); + internalLayout().SetHeapCapacity(n); + internalLayout().SetHeapSize(n); +@@ -3344,7 +3353,7 @@ namespace eastl + { + if(internalLayout().IsHeap()) + { +- DoFree(internalLayout().BeginPtr(), internalLayout().GetHeapCapacity() + 1); ++ DoFree(internalLayout().GetHeapBeginPtr(), internalLayout().GetHeapCapacity() + 1); + } + } + +@@ -3760,22 +3769,22 @@ namespace eastl + } + + +- template +- inline bool operator==(const typename basic_string::value_type* p, const basic_string& b) +- { +- typedef typename basic_string::size_type size_type; +- const size_type n = (size_type)CharStrlen(p); +- return ((n == b.size()) && (memcmp(p, b.data(), (size_t)n * sizeof(*p)) == 0)); +- } ++ // template ++ // inline bool operator==(const typename basic_string::value_type* p, const basic_string& b) ++ // { ++ // typedef typename basic_string::size_type size_type; ++ // const size_type n = (size_type)CharStrlen(p); ++ // return ((n == b.size()) && (memcmp(p, b.data(), (size_t)n * sizeof(*p)) == 0)); ++ // } + + +- template +- inline bool operator==(const basic_string& a, const typename basic_string::value_type* p) +- { +- typedef typename basic_string::size_type size_type; +- const size_type n = (size_type)CharStrlen(p); +- return ((a.size() == n) && (memcmp(a.data(), p, (size_t)n * sizeof(*p)) == 0)); +- } ++ // template ++ // inline bool operator==(const basic_string& a, const typename basic_string::value_type* p) ++ // { ++ // typedef typename basic_string::size_type size_type; ++ // const size_type n = (size_type)CharStrlen(p); ++ // return ((a.size() == n) && (memcmp(a.data(), p, (size_t)n * sizeof(*p)) == 0)); ++ // } + + + template +@@ -3785,18 +3794,18 @@ namespace eastl + } + + +- template +- inline bool operator!=(const typename basic_string::value_type* p, const basic_string& b) +- { +- return !(p == b); +- } ++ // template ++ // inline bool operator!=(const typename basic_string::value_type* p, const basic_string& b) ++ // { ++ // return !(p == b); ++ // } + + +- template +- inline bool operator!=(const basic_string& a, const typename basic_string::value_type* p) +- { +- return !(a == p); +- } ++ // template ++ // inline bool operator!=(const basic_string& a, const typename basic_string::value_type* p) ++ // { ++ // return !(a == p); ++ // } + + + // Operator< (and also >, <=, and >=). +@@ -3806,22 +3815,22 @@ namespace eastl + return basic_string::compare(a.begin(), a.end(), b.begin(), b.end()) < 0; } + + +- template +- inline bool operator<(const typename basic_string::value_type* p, const basic_string& b) +- { +- typedef typename basic_string::size_type size_type; +- const size_type n = (size_type)CharStrlen(p); +- return basic_string::compare(p, p + n, b.begin(), b.end()) < 0; +- } ++ // template ++ // inline bool operator<(const typename basic_string::value_type* p, const basic_string& b) ++ // { ++ // typedef typename basic_string::size_type size_type; ++ // const size_type n = (size_type)CharStrlen(p); ++ // return basic_string::compare(p, p + n, b.begin(), b.end()) < 0; ++ // } + + +- template +- inline bool operator<(const basic_string& a, const typename basic_string::value_type* p) +- { +- typedef typename basic_string::size_type size_type; +- const size_type n = (size_type)CharStrlen(p); +- return basic_string::compare(a.begin(), a.end(), p, p + n) < 0; +- } ++ // template ++ // inline bool operator<(const basic_string& a, const typename basic_string::value_type* p) ++ // { ++ // typedef typename basic_string::size_type size_type; ++ // const size_type n = (size_type)CharStrlen(p); ++ // return basic_string::compare(a.begin(), a.end(), p, p + n) < 0; ++ // } + + + template +@@ -3831,18 +3840,18 @@ namespace eastl + } + + +- template +- inline bool operator>(const typename basic_string::value_type* p, const basic_string& b) +- { +- return b < p; +- } ++ // template ++ // inline bool operator>(const typename basic_string::value_type* p, const basic_string& b) ++ // { ++ // return b < p; ++ // } + + +- template +- inline bool operator>(const basic_string& a, const typename basic_string::value_type* p) +- { +- return p < a; +- } ++ // template ++ // inline bool operator>(const basic_string& a, const typename basic_string::value_type* p) ++ // { ++ // return p < a; ++ // } + + + template +@@ -3852,18 +3861,18 @@ namespace eastl + } + + +- template +- inline bool operator<=(const typename basic_string::value_type* p, const basic_string& b) +- { +- return !(b < p); +- } ++ // template ++ // inline bool operator<=(const typename basic_string::value_type* p, const basic_string& b) ++ // { ++ // return !(b < p); ++ // } + + +- template +- inline bool operator<=(const basic_string& a, const typename basic_string::value_type* p) +- { +- return !(p < a); +- } ++ // template ++ // inline bool operator<=(const basic_string& a, const typename basic_string::value_type* p) ++ // { ++ // return !(p < a); ++ // } + + + template +@@ -3873,18 +3882,18 @@ namespace eastl + } + + +- template +- inline bool operator>=(const typename basic_string::value_type* p, const basic_string& b) +- { +- return !(p < b); +- } ++ // template ++ // inline bool operator>=(const typename basic_string::value_type* p, const basic_string& b) ++ // { ++ // return !(p < b); ++ // } + + +- template +- inline bool operator>=(const basic_string& a, const typename basic_string::value_type* p) +- { +- return !(a < p); +- } ++ // template ++ // inline bool operator>=(const basic_string& a, const typename basic_string::value_type* p) ++ // { ++ // return !(a < p); ++ // } + + + template +@@ -3919,10 +3928,10 @@ namespace eastl + /// + template struct hash; + +- template <> +- struct hash ++ template ++ struct hash> + { +- size_t operator()(const string& x) const ++ size_t operator()(const basic_string& x) const + { + const unsigned char* p = (const unsigned char*)x.c_str(); // To consider: limit p to at most 256 chars. + unsigned int c, result = 2166136261U; // We implement an FNV-like string hash. +@@ -3947,10 +3956,10 @@ namespace eastl + }; + #endif + +- template <> +- struct hash ++ template ++ struct hash> + { +- size_t operator()(const string16& x) const ++ size_t operator()(const basic_string& x) const + { + const char16_t* p = x.c_str(); + unsigned int c, result = 2166136261U; +@@ -3960,10 +3969,10 @@ namespace eastl + } + }; + +- template <> +- struct hash ++ template ++ struct hash> + { +- size_t operator()(const string32& x) const ++ size_t operator()(const basic_string& x) const + { + const char32_t* p = x.c_str(); + unsigned int c, result = 2166136261U; +@@ -3974,10 +3983,10 @@ namespace eastl + }; + + #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE +- template <> +- struct hash ++ template ++ struct hash> + { +- size_t operator()(const wstring& x) const ++ size_t operator()(const basic_string& x) const + { + const wchar_t* p = x.c_str(); + unsigned int c, result = 2166136261U; +diff --git a/include/EASTL/vector.h b/include/EASTL/vector.h +index 1736a78..c4bed7b 100644 +--- a/include/EASTL/vector.h ++++ b/include/EASTL/vector.h +@@ -127,6 +127,7 @@ namespace eastl + typedef Allocator allocator_type; + typedef eastl_size_t size_type; + typedef ptrdiff_t difference_type; ++ typedef typename Allocator::template array_pointer array_type; + + #if defined(_MSC_VER) && (_MSC_VER >= 1400) && (_MSC_VER <= 1600) && !EASTL_STD_CPP_ONLY // _MSC_VER of 1400 means VS2005, 1600 means VS2010. VS2012 generates errors with usage of enum:size_type. + enum : size_type { // Use Microsoft enum language extension, allowing for smaller debug symbols than using a static const. Users have been affected by this. +@@ -139,7 +140,7 @@ namespace eastl + #endif + + protected: +- T* mpBegin; ++ array_type mpBegin; + T* mpEnd; + eastl::compressed_pair mCapacityAllocator; + +@@ -160,8 +161,8 @@ namespace eastl + void set_allocator(const allocator_type& allocator); + + protected: +- T* DoAllocate(size_type n); +- void DoFree(T* p, size_type n); ++ array_type DoAllocate(size_type n); ++ void DoFree(array_type p, size_type n); + size_type GetNewCapacity(size_type currentCapacity); + + }; // VectorBase +@@ -192,6 +193,7 @@ namespace eastl + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef typename base_type::allocator_type allocator_type; ++ typedef typename base_type::array_type array_type; + + using base_type::mpBegin; + using base_type::mpEnd; +@@ -323,10 +325,10 @@ namespace eastl + using should_move_tag = should_move_or_copy_tag; + + template // Allocates a pointer of array count n and copy-constructs it with [first,last). +- pointer DoRealloc(size_type n, ForwardIterator first, ForwardIterator last, should_copy_tag); ++ array_type DoRealloc(size_type n, ForwardIterator first, ForwardIterator last, should_copy_tag); + + template // Allocates a pointer of array count n and copy-constructs it with [first,last). +- pointer DoRealloc(size_type n, ForwardIterator first, ForwardIterator last, should_move_tag); ++ array_type DoRealloc(size_type n, ForwardIterator first, ForwardIterator last, should_move_tag); + + template + void DoInit(Integer n, Integer value, true_type); +@@ -396,7 +398,7 @@ namespace eastl + + template + inline VectorBase::VectorBase() +- : mpBegin(NULL), ++ : mpBegin(nullptr), + mpEnd(NULL), + mCapacityAllocator(NULL, allocator_type(EASTL_VECTOR_DEFAULT_NAME)) + { +@@ -405,7 +407,7 @@ namespace eastl + + template + inline VectorBase::VectorBase(const allocator_type& allocator) +- : mpBegin(NULL), ++ : mpBegin(nullptr), + mpEnd(NULL), + mCapacityAllocator(NULL, allocator) + { +@@ -417,7 +419,7 @@ namespace eastl + : mCapacityAllocator(allocator) + { + mpBegin = DoAllocate(n); +- mpEnd = mpBegin; ++ mpEnd = allocator_type::to_raw(mpBegin); + internalCapacityPtr() = mpBegin + n; + } + +@@ -426,7 +428,13 @@ namespace eastl + inline VectorBase::~VectorBase() + { + if(mpBegin) +- EASTLFree(internalAllocator(), mpBegin, (internalCapacityPtr() - mpBegin) * sizeof(T)); ++// EASTLFree(internalAllocator(), mpBegin, (internalCapacityPtr() - mpBegin) * sizeof(T)); ++ internalAllocator().deallocate_array(mpBegin, internalCapacityPtr() - mpBegin); ++ ++ mpBegin = nullptr; ++ mpEnd = nullptr; ++ internalCapacityPtr() = nullptr; ++ allocator_type::force_changes_in_dtor(this); + } + + +@@ -454,7 +462,7 @@ namespace eastl + + + template +- inline T* VectorBase::DoAllocate(size_type n) ++ inline typename VectorBase::array_type VectorBase::DoAllocate(size_type n) + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(n >= 0x80000000)) +@@ -465,7 +473,8 @@ namespace eastl + // This is fine, as our default ctor initializes with NULL pointers. + if(EASTL_LIKELY(n)) + { +- auto* p = (T*)allocate_memory(internalAllocator(), n * sizeof(T), EASTL_ALIGN_OF(T), 0); ++// auto* p = (T*)allocate_memory(internalAllocator(), n * sizeof(T), EASTL_ALIGN_OF(T), 0); ++ auto p = internalAllocator().template allocate_array(n); + EASTL_ASSERT_MSG(p != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + return p; + } +@@ -477,10 +486,11 @@ namespace eastl + + + template +- inline void VectorBase::DoFree(T* p, size_type n) ++ inline void VectorBase::DoFree(array_type p, size_type n) + { + if(p) +- EASTLFree(internalAllocator(), p, n * sizeof(T)); ++ // EASTLFree(internalAllocator(), p, n * sizeof(T)); ++ internalAllocator().deallocate_array(p, n); + } + + +@@ -519,7 +529,8 @@ namespace eastl + inline vector::vector(size_type n, const allocator_type& allocator) + : base_type(n, allocator) + { +- eastl::uninitialized_default_fill_n(mpBegin, n); ++ auto raii = allocator_type::make_raii(mpBegin); ++ eastl::uninitialized_default_fill_n(allocator_type::to_raw(mpBegin), n); + mpEnd = mpBegin + n; + } + +@@ -528,7 +539,8 @@ namespace eastl + inline vector::vector(size_type n, const value_type& value, const allocator_type& allocator) + : base_type(n, allocator) + { +- eastl::uninitialized_fill_n_ptr(mpBegin, n, value); ++ auto raii = allocator_type::make_raii(mpBegin); ++ eastl::uninitialized_fill_n_ptr(allocator_type::to_raw(mpBegin), n, value); + mpEnd = mpBegin + n; + } + +@@ -537,7 +549,8 @@ namespace eastl + inline vector::vector(const this_type& x) + : base_type(x.size(), x.internalAllocator()) + { +- mpEnd = eastl::uninitialized_copy_ptr(x.mpBegin, x.mpEnd, mpBegin); ++ auto raii = allocator_type::make_raii(mpBegin); ++ mpEnd = eastl::uninitialized_copy_ptr(allocator_type::to_raw(x.mpBegin), x.mpEnd, allocator_type::to_raw(mpBegin)); + } + + +@@ -545,7 +558,8 @@ namespace eastl + inline vector::vector(const this_type& x, const allocator_type& allocator) + : base_type(x.size(), allocator) + { +- mpEnd = eastl::uninitialized_copy_ptr(x.mpBegin, x.mpEnd, mpBegin); ++ auto raii = allocator_type::make_raii(mpBegin); ++ mpEnd = eastl::uninitialized_copy_ptr(allocator_type::to_raw(x.mpBegin), x.mpEnd, allocator_type::to_raw(mpBegin)); + } + + +@@ -592,7 +606,7 @@ namespace eastl + inline vector::~vector() + { + // Call destructor for the values. Parent class will free the memory. +- eastl::destruct(mpBegin, mpEnd); ++ eastl::destruct(allocator_type::to_raw(mpBegin), mpEnd); + } + + +@@ -685,7 +699,7 @@ namespace eastl + inline typename vector::iterator + vector::begin() EA_NOEXCEPT + { +- return mpBegin; ++ return allocator_type::to_raw(mpBegin); + } + + +@@ -693,7 +707,7 @@ namespace eastl + inline typename vector::const_iterator + vector::begin() const EA_NOEXCEPT + { +- return mpBegin; ++ return allocator_type::to_raw(mpBegin); + } + + +@@ -701,7 +715,7 @@ namespace eastl + inline typename vector::const_iterator + vector::cbegin() const EA_NOEXCEPT + { +- return mpBegin; ++ return allocator_type::to_raw(mpBegin); + } + + +@@ -757,7 +771,7 @@ namespace eastl + inline typename vector::reverse_iterator + vector::rend() EA_NOEXCEPT + { +- return reverse_iterator(mpBegin); ++ return reverse_iterator(allocator_type::to_raw(mpBegin)); + } + + +@@ -765,7 +779,7 @@ namespace eastl + inline typename vector::const_reverse_iterator + vector::rend() const EA_NOEXCEPT + { +- return const_reverse_iterator(mpBegin); ++ return const_reverse_iterator(allocator_type::to_raw(mpBegin)); + } + + +@@ -773,7 +787,7 @@ namespace eastl + inline typename vector::const_reverse_iterator + vector::crend() const EA_NOEXCEPT + { +- return const_reverse_iterator(mpBegin); ++ return const_reverse_iterator(allocator_type::to_raw(mpBegin)); + } + + +@@ -852,8 +866,8 @@ namespace eastl + } + else // Else new capacity > size. + { +- pointer const pNewData = DoRealloc(n, mpBegin, mpEnd, should_move_tag()); +- eastl::destruct(mpBegin, mpEnd); ++ auto pNewData = DoRealloc(n, allocator_type::to_raw(mpBegin), mpEnd, should_move_tag()); ++ eastl::destruct(allocator_type::to_raw(mpBegin), mpEnd); + DoFree(mpBegin, (size_type)(internalCapacityPtr() - mpBegin)); + + const ptrdiff_t nPrevSize = mpEnd - mpBegin; +@@ -878,7 +892,7 @@ namespace eastl + inline typename vector::pointer + vector::data() EA_NOEXCEPT + { +- return mpBegin; ++ return allocator_type::to_raw(mpBegin); + } + + +@@ -886,7 +900,7 @@ namespace eastl + inline typename vector::const_pointer + vector::data() const EA_NOEXCEPT + { +- return mpBegin; ++ return allocator_type::to_raw(mpBegin); + } + + +@@ -971,7 +985,7 @@ namespace eastl + // We allow the user to reference an empty container. + #endif + +- return *mpBegin; ++ return *allocator_type::to_raw(mpBegin); + } + + +@@ -986,7 +1000,7 @@ namespace eastl + // We allow the user to reference an empty container. + #endif + +- return *mpBegin; ++ return *allocator_type::to_raw(mpBegin); + } + + +@@ -1023,8 +1037,10 @@ namespace eastl + template + inline void vector::push_back(const value_type& value) + { +- if(mpEnd < internalCapacityPtr()) ++ if(mpEnd < internalCapacityPtr()) { ++ auto raii = allocator_type::make_raii(mpBegin); + ::new((void*)mpEnd++) value_type(value); ++ } + else + DoInsertValueEnd(value); + } +@@ -1033,8 +1049,10 @@ namespace eastl + template + inline void vector::push_back(value_type&& value) + { +- if (mpEnd < internalCapacityPtr()) ++ if (mpEnd < internalCapacityPtr()) { ++ auto raii = allocator_type::make_raii(mpBegin); + ::new((void*)mpEnd++) value_type(eastl::move(value)); ++ } + else + DoInsertValueEnd(eastl::move(value)); + } +@@ -1044,8 +1062,10 @@ namespace eastl + inline typename vector::reference + vector::push_back() + { +- if(mpEnd < internalCapacityPtr()) ++ if(mpEnd < internalCapacityPtr()) { ++ auto raii = allocator_type::make_raii(mpBegin); + ::new((void*)mpEnd++) value_type(); ++ } + else // Note that in this case we create a temporary, which is less desirable. + DoInsertValueEnd(value_type()); + +@@ -1090,6 +1110,7 @@ namespace eastl + DoInsertValue(position, eastl::forward(args)...); + else + { ++ auto raii = allocator_type::make_raii(mpBegin); + ::new((void*)mpEnd) value_type(eastl::forward(args)...); + ++mpEnd; // Increment this after the construction above in case the construction throws an exception. + } +@@ -1104,6 +1125,7 @@ namespace eastl + { + if(mpEnd < internalCapacityPtr()) + { ++ auto raii = allocator_type::make_raii(mpBegin); + ::new((void*)mpEnd) value_type(eastl::forward(args)...); // If value_type has a move constructor, it will use it and this operation may be faster than otherwise. + ++mpEnd; // Increment this after the construction above in case the construction throws an exception. + } +@@ -1129,6 +1151,7 @@ namespace eastl + DoInsertValue(position, value); + else + { ++ auto raii = allocator_type::make_raii(mpBegin); + ::new((void*)mpEnd) value_type(value); + ++mpEnd; // Increment this after the construction above in case the construction throws an exception. + } +@@ -1325,8 +1348,8 @@ namespace eastl + template + inline void vector::clear() EA_NOEXCEPT + { +- eastl::destruct(mpBegin, mpEnd); +- mpEnd = mpBegin; ++ eastl::destruct(allocator_type::to_raw(mpBegin), mpEnd); ++ mpEnd = allocator_type::to_raw(mpBegin); + } + + +@@ -1337,7 +1360,8 @@ namespace eastl + // resets the container to an empty state without freeing the memory of + // the contained objects. This is useful for very quickly tearing down a + // container built into scratch memory. +- mpBegin = mpEnd = internalCapacityPtr() = NULL; ++ mpBegin = nullptr; ++ mpEnd = internalCapacityPtr() = NULL; + } + + +@@ -1385,22 +1409,24 @@ namespace eastl + + template + template +- inline typename vector::pointer ++ inline typename vector::array_type + vector::DoRealloc(size_type n, ForwardIterator first, ForwardIterator last, should_copy_tag) + { +- T* const p = DoAllocate(n); // p is of type T* but is not constructed. +- eastl::uninitialized_copy_ptr(first, last, p); // copy-constructs p from [first,last). ++ auto p = DoAllocate(n); // p is of type T* but is not constructed. ++ auto raii = allocator_type::make_raii(p); ++ eastl::uninitialized_copy_ptr(first, last, allocator_type::to_raw(p)); // copy-constructs p from [first,last). + return p; + } + + + template + template +- inline typename vector::pointer ++ inline typename vector::array_type + vector::DoRealloc(size_type n, ForwardIterator first, ForwardIterator last, should_move_tag) + { +- T* const p = DoAllocate(n); // p is of type T* but is not constructed. +- eastl::uninitialized_move_ptr_if_noexcept(first, last, p); // move-constructs p from [first,last). ++ auto p = DoAllocate(n); // p is of type T* but is not constructed. ++ auto raii = allocator_type::make_raii(p); ++ eastl::uninitialized_move_ptr_if_noexcept(first, last, allocator_type::to_raw(p)); // move-constructs p from [first,last). + return p; + } + +@@ -1412,9 +1438,10 @@ namespace eastl + mpBegin = DoAllocate((size_type)n); + internalCapacityPtr() = mpBegin + n; + mpEnd = internalCapacityPtr(); ++ auto raii = allocator_type::make_raii(mpBegin); + + typedef typename eastl::remove_const::type non_const_value_type; // If T is a const type (e.g. const int) then we need to initialize it as if it were non-const. +- eastl::uninitialized_fill_n_ptr((non_const_value_type*)mpBegin, n, value); ++ eastl::uninitialized_fill_n_ptr((non_const_value_type*)allocator_type::to_raw(mpBegin), n, value); + } + + +@@ -1445,9 +1472,10 @@ namespace eastl + mpBegin = DoAllocate(n); + internalCapacityPtr() = mpBegin + n; + mpEnd = internalCapacityPtr(); ++ auto raii = allocator_type::make_raii(mpBegin); + + typedef typename eastl::remove_const::type non_const_value_type; // If T is a const type (e.g. const int) then we need to initialize it as if it were non-const. +- eastl::uninitialized_copy_ptr(first, last, (non_const_value_type*)mpBegin); ++ eastl::uninitialized_copy_ptr(first, last, (non_const_value_type*)allocator_type::to_raw(mpBegin)); + } + + +@@ -1478,13 +1506,14 @@ namespace eastl + } + else if(n > size_type(mpEnd - mpBegin)) // If n > size ... + { +- eastl::fill(mpBegin, mpEnd, value); ++ eastl::fill(allocator_type::to_raw(mpBegin), mpEnd, value); ++ auto raii = allocator_type::make_raii(mpBegin); + eastl::uninitialized_fill_n_ptr(mpEnd, n - size_type(mpEnd - mpBegin), value); + mpEnd += n - size_type(mpEnd - mpBegin); + } + else // else 0 <= n <= size + { +- eastl::fill_n(mpBegin, n, value); ++ eastl::fill_n(allocator_type::to_raw(mpBegin), n, value); + erase(mpBegin + n, mpEnd); + } + } +@@ -1494,7 +1523,7 @@ namespace eastl + template + void vector::DoAssignFromIterator(InputIterator first, InputIterator last, EASTL_ITC_NS::input_iterator_tag) + { +- iterator position(mpBegin); ++ iterator position(allocator_type::to_raw(mpBegin)); + + while((position != mpEnd) && (first != last)) + { +@@ -1517,8 +1546,8 @@ namespace eastl + + if(n > size_type(internalCapacityPtr() - mpBegin)) // If n > capacity ... + { +- pointer const pNewData = DoRealloc(n, first, last, should_move_or_copy_tag()); +- eastl::destruct(mpBegin, mpEnd); ++ auto pNewData = DoRealloc(n, first, last, should_move_or_copy_tag()); ++ eastl::destruct(allocator_type::to_raw(mpBegin), mpEnd); + DoFree(mpBegin, (size_type)(internalCapacityPtr() - mpBegin)); + + mpBegin = pNewData; +@@ -1527,14 +1556,15 @@ namespace eastl + } + else if(n <= size_type(mpEnd - mpBegin)) // If n <= size ... + { +- pointer const pNewEnd = eastl::copy(first, last, mpBegin); // Since we are copying to mpBegin, we don't have to worry about needing copy_backward or a memmove-like copy (as opposed to memcpy-like copy). ++ pointer const pNewEnd = eastl::copy(first, last, allocator_type::to_raw(mpBegin)); // Since we are copying to mpBegin, we don't have to worry about needing copy_backward or a memmove-like copy (as opposed to memcpy-like copy). + eastl::destruct(pNewEnd, mpEnd); + mpEnd = pNewEnd; + } + else // else size < n <= capacity + { + RandomAccessIterator position = first + (mpEnd - mpBegin); +- eastl::copy(first, position, mpBegin); // Since we are copying to mpBegin, we don't have to worry about needing copy_backward or a memmove-like copy (as opposed to memcpy-like copy). ++ eastl::copy(first, position, allocator_type::to_raw(mpBegin)); // Since we are copying to mpBegin, we don't have to worry about needing copy_backward or a memmove-like copy (as opposed to memcpy-like copy). ++ auto raii = allocator_type::make_raii(mpBegin); + mpEnd = eastl::uninitialized_copy_ptr(position, last, mpEnd); + } + } +@@ -1588,12 +1618,14 @@ namespace eastl + + if(n < nExtra) // If the inserted values are entirely within initialized memory (i.e. are before mpEnd)... + { ++ auto raii = allocator_type::make_raii(mpBegin); + eastl::uninitialized_move_ptr(mpEnd - n, mpEnd, mpEnd); + eastl::move_backward(destPosition, mpEnd - n, mpEnd); // We need move_backward because of potential overlap issues. + eastl::copy(first, last, destPosition); + } + else + { ++ auto raii = allocator_type::make_raii(mpBegin); + BidirectionalIterator iTemp = first; + eastl::advance(iTemp, nExtra); + eastl::uninitialized_copy_ptr(iTemp, last, mpEnd); +@@ -1608,29 +1640,30 @@ namespace eastl + const size_type nPrevSize = size_type(mpEnd - mpBegin); + const size_type nGrowSize = GetNewCapacity(nPrevSize); + const size_type nNewSize = nGrowSize > (nPrevSize + n) ? nGrowSize : (nPrevSize + n); +- pointer const pNewData = DoAllocate(nNewSize); ++ auto pNewData = DoAllocate(nNewSize); ++ auto raii = allocator_type::make_raii(pNewData); + + #if EASTL_EXCEPTIONS_ENABLED +- pointer pNewEnd = pNewData; ++ pointer pNewEnd = allocator_type::to_raw(pNewData); + try + { +- pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, destPosition, pNewData); ++ pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), destPosition, allocator_type::to_raw(pNewData)); + pNewEnd = eastl::uninitialized_copy_ptr(first, last, pNewEnd); + pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(destPosition, mpEnd, pNewEnd); + } + catch(...) + { +- eastl::destruct(pNewData, pNewEnd); ++ eastl::destruct(allocator_type::to_raw(pNewData), pNewEnd); + DoFree(pNewData, nNewSize); + throw; + } + #else +- pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, destPosition, pNewData); ++ pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), destPosition, allocator_type::to_raw(pNewData)); + pNewEnd = eastl::uninitialized_copy_ptr(first, last, pNewEnd); + pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(destPosition, mpEnd, pNewEnd); + #endif + +- eastl::destruct(mpBegin, mpEnd); ++ eastl::destruct(allocator_type::to_raw(mpBegin), mpEnd); + DoFree(mpBegin, (size_type)(internalCapacityPtr() - mpBegin)); + + mpBegin = pNewData; +@@ -1662,12 +1695,14 @@ namespace eastl + + if(n < nExtra) + { ++ auto raii = allocator_type::make_raii(mpBegin); + eastl::uninitialized_move_ptr(mpEnd - n, mpEnd, mpEnd); + eastl::move_backward(destPosition, mpEnd - n, mpEnd); // We need move_backward because of potential overlap issues. + eastl::fill(destPosition, destPosition + n, temp); + } + else + { ++ auto raii = allocator_type::make_raii(mpBegin); + eastl::uninitialized_fill_n_ptr(mpEnd, n - nExtra, temp); + eastl::uninitialized_move_ptr(destPosition, mpEnd, mpEnd + n - nExtra); + eastl::fill(destPosition, mpEnd, temp); +@@ -1681,29 +1716,30 @@ namespace eastl + const size_type nPrevSize = size_type(mpEnd - mpBegin); + const size_type nGrowSize = GetNewCapacity(nPrevSize); + const size_type nNewSize = nGrowSize > (nPrevSize + n) ? nGrowSize : (nPrevSize + n); +- pointer const pNewData = DoAllocate(nNewSize); ++ auto pNewData = DoAllocate(nNewSize); ++ auto raii = allocator_type::make_raii(pNewData); + + #if EASTL_EXCEPTIONS_ENABLED +- pointer pNewEnd = pNewData; ++ pointer pNewEnd = allocator_type::to_raw(pNewData); + try + { +- pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, destPosition, pNewData); ++ pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), destPosition, allocator_type::to_raw(pNewData)); + eastl::uninitialized_fill_n_ptr(pNewEnd, n, value); + pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(destPosition, mpEnd, pNewEnd + n); + } + catch(...) + { +- eastl::destruct(pNewData, pNewEnd); ++ eastl::destruct(allocator_type::to_raw(pNewData), pNewEnd); + DoFree(pNewData, nNewSize); + throw; + } + #else +- pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, destPosition, pNewData); ++ pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), destPosition, allocator_type::to_raw(pNewData)); + eastl::uninitialized_fill_n_ptr(pNewEnd, n, value); + pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(destPosition, mpEnd, pNewEnd + n); + #endif + +- eastl::destruct(mpBegin, mpEnd); ++ eastl::destruct(allocator_type::to_raw(mpBegin), mpEnd); + DoFree(mpBegin, (size_type)(internalCapacityPtr() - mpBegin)); + + mpBegin = pNewData; +@@ -1725,11 +1761,12 @@ namespace eastl + template + void vector::DoGrow(size_type n) + { +- pointer const pNewData = DoAllocate(n); ++ auto pNewData = DoAllocate(n); ++ auto raii = allocator_type::make_raii(pNewData); + +- pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, mpEnd, pNewData); ++ pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), mpEnd, allocator_type::to_raw(pNewData)); + +- eastl::destruct(mpBegin, mpEnd); ++ eastl::destruct(allocator_type::to_raw(mpBegin), mpEnd); + DoFree(mpBegin, (size_type)(internalCapacityPtr() - mpBegin)); + + mpBegin = pNewData; +@@ -1756,28 +1793,29 @@ namespace eastl + const size_type nPrevSize = size_type(mpEnd - mpBegin); + const size_type nGrowSize = GetNewCapacity(nPrevSize); + const size_type nNewSize = eastl::max(nGrowSize, nPrevSize + n); +- pointer const pNewData = DoAllocate(nNewSize); ++ auto pNewData = DoAllocate(nNewSize); ++ auto raii = allocator_type::make_raii(pNewData); + + #if EASTL_EXCEPTIONS_ENABLED +- pointer pNewEnd = pNewData; // Assign pNewEnd a value here in case the copy throws. ++ pointer pNewEnd = allocator_type::to_raw(pNewData); // Assign pNewEnd a value here in case the copy throws. + try + { +- pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, mpEnd, pNewData); ++ pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), mpEnd, allocator_type::to_raw(pNewData)); + } + catch(...) + { +- eastl::destruct(pNewData, pNewEnd); ++ eastl::destruct(allocator_type::to_raw(pNewData), pNewEnd); + DoFree(pNewData, nNewSize); + throw; + } + #else +- pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, mpEnd, pNewData); ++ pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), mpEnd, allocator_type::to_raw(pNewData)); + #endif + + eastl::uninitialized_fill_n_ptr(pNewEnd, n, value); + pNewEnd += n; + +- eastl::destruct(mpBegin, mpEnd); ++ eastl::destruct(allocator_type::to_raw(mpBegin), mpEnd); + DoFree(mpBegin, (size_type)(internalCapacityPtr() - mpBegin)); + + mpBegin = pNewData; +@@ -1786,6 +1824,7 @@ namespace eastl + } + else + { ++ auto raii = allocator_type::make_raii(mpBegin); + eastl::uninitialized_fill_n_ptr(mpEnd, n, value); + mpEnd += n; + } +@@ -1799,25 +1838,26 @@ namespace eastl + const size_type nPrevSize = size_type(mpEnd - mpBegin); + const size_type nGrowSize = GetNewCapacity(nPrevSize); + const size_type nNewSize = eastl::max(nGrowSize, nPrevSize + n); +- pointer const pNewData = DoAllocate(nNewSize); ++ auto pNewData = DoAllocate(nNewSize); ++ auto raii = allocator_type::make_raii(pNewData); + + #if EASTL_EXCEPTIONS_ENABLED +- pointer pNewEnd = pNewData; // Assign pNewEnd a value here in case the copy throws. +- try { pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, mpEnd, pNewData); } ++ pointer pNewEnd = allocator_type::to_raw(pNewData); // Assign pNewEnd a value here in case the copy throws. ++ try { pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), mpEnd, allocator_type::to_raw(pNewData)); } + catch (...) + { +- eastl::destruct(pNewData, pNewEnd); ++ eastl::destruct(allocator_type::to_raw(pNewData), pNewEnd); + DoFree(pNewData, nNewSize); + throw; + } + #else +- pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, mpEnd, pNewData); ++ pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), mpEnd, allocator_type::to_raw(pNewData)); + #endif + + eastl::uninitialized_default_fill_n(pNewEnd, n); + pNewEnd += n; + +- eastl::destruct(mpBegin, mpEnd); ++ eastl::destruct(allocator_type::to_raw(mpBegin), mpEnd); + DoFree(mpBegin, (size_type)(internalCapacityPtr() - mpBegin)); + + mpBegin = pNewData; +@@ -1826,6 +1866,7 @@ namespace eastl + } + else + { ++ auto raii = allocator_type::make_raii(mpBegin); + eastl::uninitialized_default_fill_n(mpEnd, n); + mpEnd += n; + } +@@ -1859,6 +1900,7 @@ namespace eastl + #else + value_type value(eastl::forward(args)...); // Need to do this before the move_backward below because maybe args refers to something within the moving range. + #endif ++ auto raii = allocator_type::make_raii(mpBegin); + ::new(static_cast(mpEnd)) value_type(eastl::move(*(mpEnd - 1))); // mpEnd is uninitialized memory, so we must construct into it instead of move into it like we do with the other elements below. + eastl::move_backward(destPosition, mpEnd - 1, mpEnd); // We need to go backward because of potential overlap issues. + eastl::destruct(destPosition); +@@ -1870,34 +1912,35 @@ namespace eastl + const size_type nPosSize = size_type(destPosition - mpBegin); // Index of the insertion position. + const size_type nPrevSize = size_type(mpEnd - mpBegin); + const size_type nNewSize = GetNewCapacity(nPrevSize); +- pointer const pNewData = DoAllocate(nNewSize); ++ auto pNewData = DoAllocate(nNewSize); ++ auto raii = allocator_type::make_raii(pNewData); + + #if EASTL_EXCEPTIONS_ENABLED +- pointer pNewEnd = pNewData; ++ pointer pNewEnd = allocator_type::to_raw(pNewData); + try + { // To do: We are not handling exceptions properly below. In particular we don't want to + // call eastl::destruct on the entire range if only the first part of the range was constructed. + ::new((void*)(pNewData + nPosSize)) value_type(eastl::forward(args)...); // Because the old data is potentially being moved rather than copied, we need to move. + pNewEnd = NULL; // Set to NULL so that in catch we can tell the exception occurred during the next call. +- pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, destPosition, pNewData); // the value first, because it might possibly be a reference to the old data being moved. ++ pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), destPosition, allocator_type::to_raw(pNewData)); // the value first, because it might possibly be a reference to the old data being moved. + pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(destPosition, mpEnd, ++pNewEnd); + } + catch(...) + { + if(pNewEnd) +- eastl::destruct(pNewData, pNewEnd); // Destroy what has been constructed so far. ++ eastl::destruct(allocator_type::to_raw(pNewData), pNewEnd); // Destroy what has been constructed so far. + else +- eastl::destruct(pNewData + nPosSize); // The exception occurred during the first uninitialized move, so destroy only the value at nPosSize. ++ eastl::destruct(allocator_type::to_raw(pNewData) + nPosSize); // The exception occurred during the first unintialized move, so destroy only the value at nPosSize. + DoFree(pNewData, nNewSize); + throw; + } + #else + ::new((void*)(pNewData + nPosSize)) value_type(eastl::forward(args)...); // Because the old data is potentially being moved rather than copied, we need to move +- pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, destPosition, pNewData); // the value first, because it might possibly be a reference to the old data being moved. +- pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(destPosition, mpEnd, ++pNewEnd); // Question: with exceptions disabled, do we assume all operations are noexcept and thus there's no need for uninitialized_move_ptr_if_noexcept? ++ pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), destPosition, allocator_type::to_raw(pNewData)); // the value first, because it might possibly be a reference to the old data being moved. ++ pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(destPosition, mpEnd, ++pNewEnd); // Question: with exceptions disabled, do we asssume all operations are noexcept and thus there's no need for uninitialized_move_ptr_if_noexcept? + #endif + +- eastl::destruct(mpBegin, mpEnd); ++ eastl::destruct(allocator_type::to_raw(mpBegin), mpEnd); + DoFree(mpBegin, (size_type)(internalCapacityPtr() - mpBegin)); + + mpBegin = pNewData; +@@ -1913,29 +1956,30 @@ namespace eastl + { + const size_type nPrevSize = size_type(mpEnd - mpBegin); + const size_type nNewSize = GetNewCapacity(nPrevSize); +- pointer const pNewData = DoAllocate(nNewSize); ++ auto pNewData = DoAllocate(nNewSize); ++ auto raii = allocator_type::make_raii(pNewData); + + #if EASTL_EXCEPTIONS_ENABLED +- pointer pNewEnd = pNewData; // Assign pNewEnd a value here in case the copy throws. ++ pointer pNewEnd = allocator_type::to_raw(pNewData); // Assign pNewEnd a value here in case the copy throws. + try + { +- pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, mpEnd, pNewData); ++ pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), mpEnd, allocator_type::to_raw(pNewData)); + ::new((void*)pNewEnd) value_type(eastl::forward(args)...); + pNewEnd++; + } + catch(...) + { +- eastl::destruct(pNewData, pNewEnd); ++ eastl::destruct(allocator_type::to_raw(pNewData), pNewEnd); + DoFree(pNewData, nNewSize); + throw; + } + #else +- pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, mpEnd, pNewData); ++ pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), mpEnd, allocator_type::to_raw(pNewData)); + ::new((void*)pNewEnd) value_type(eastl::forward(args)...); + pNewEnd++; + #endif + +- eastl::destruct(mpBegin, mpEnd); ++ eastl::destruct(allocator_type::to_raw(mpBegin), mpEnd); + DoFree(mpBegin, (size_type)(internalCapacityPtr() - mpBegin)); + + mpBegin = pNewData; diff --git a/library/3rdparty/clone-EABase-EASTL.bat b/library/3rdparty/clone-EABase-EASTL.bat index ff97a7c..c034280 100644 --- a/library/3rdparty/clone-EABase-EASTL.bat +++ b/library/3rdparty/clone-EABase-EASTL.bat @@ -10,10 +10,10 @@ git apply ..\EABase-2.09.06.diff rmdir /S /Q .git cd .. -git clone --depth 1 -b 3.17.03 https://github.com/electronicarts/EASTL.git +git clone --depth 1 -b 3.18.00 https://github.com/electronicarts/EASTL.git @if ERRORLEVEL 1 exit /b %ERRORLEVEL% cd EASTL -git apply ..\EASTL-3.17.03.diff +git apply ..\EASTL-3.18.00.diff @if ERRORLEVEL 1 exit /b %ERRORLEVEL% rmdir /S /Q .git cd .. diff --git a/library/3rdparty/clone-EABase-EASTL.sh b/library/3rdparty/clone-EABase-EASTL.sh index 4ee64e5..b8da912 100644 --- a/library/3rdparty/clone-EABase-EASTL.sh +++ b/library/3rdparty/clone-EABase-EASTL.sh @@ -10,8 +10,8 @@ git apply ../EABase-2.09.06.diff rm -Rf .git cd .. -git clone --depth 1 -b 3.17.03 https://github.com/electronicarts/EASTL.git +git clone --depth 1 -b 3.18.00 https://github.com/electronicarts/EASTL.git cd EASTL -git apply ../EASTL-3.17.03.diff +git apply ../EASTL-3.18.00.diff rm -Rf .git cd .. From 4295fc14c20308894e344883b35654e4986c3ef4 Mon Sep 17 00:00:00 2001 From: Marcos Bracco Date: Mon, 6 Feb 2023 17:04:31 -0300 Subject: [PATCH 22/31] update EASTL to version 3.18.00 --- library/3rdparty/EASTL/README.md | 7 +- library/3rdparty/EASTL/doc/EASTL-n2271.pdf | Bin 0 -> 345371 bytes library/3rdparty/EASTL/doc/EASTL.natvis | 70 + .../3rdparty/EASTL/include/EASTL/algorithm.h | 872 +- .../EASTL/include/EASTL/allocator_malloc.h | 2 +- library/3rdparty/EASTL/include/EASTL/any.h | 4 +- library/3rdparty/EASTL/include/EASTL/array.h | 35 - library/3rdparty/EASTL/include/EASTL/atomic.h | 72 +- library/3rdparty/EASTL/include/EASTL/bit.h | 65 + library/3rdparty/EASTL/include/EASTL/bitset.h | 2 +- .../EASTL/include/EASTL/bonus/adaptors.h | 9 +- .../EASTL/include/EASTL/bonus/tuple_vector.h | 8 +- library/3rdparty/EASTL/include/EASTL/chrono.h | 3 +- .../EASTL/include/EASTL/fixed_hash_map.h | 36 +- .../EASTL/include/EASTL/fixed_hash_set.h | 54 +- .../3rdparty/EASTL/include/EASTL/fixed_list.h | 8 +- .../EASTL/include/EASTL/fixed_slist.h | 8 +- .../EASTL/include/EASTL/fixed_vector.h | 2 +- .../3rdparty/EASTL/include/EASTL/functional.h | 27 +- .../atomic/arch/arm/arch_arm_memory_barrier.h | 4 +- .../EASTL/internal/atomic/arch/x86/arch_x86.h | 17 +- .../atomic/arch/x86/arch_x86_add_fetch.h | 2 +- .../atomic/arch/x86/arch_x86_and_fetch.h | 2 +- .../atomic/arch/x86/arch_x86_cmpxchg_strong.h | 2 +- .../atomic/arch/x86/arch_x86_cmpxchg_weak.h | 2 +- .../atomic/arch/x86/arch_x86_exchange.h | 2 +- .../atomic/arch/x86/arch_x86_fetch_add.h | 2 +- .../atomic/arch/x86/arch_x86_fetch_and.h | 2 +- .../atomic/arch/x86/arch_x86_fetch_or.h | 2 +- .../atomic/arch/x86/arch_x86_fetch_sub.h | 2 +- .../atomic/arch/x86/arch_x86_fetch_xor.h | 2 +- .../internal/atomic/arch/x86/arch_x86_load.h | 84 +- .../atomic/arch/x86/arch_x86_memory_barrier.h | 2 +- .../atomic/arch/x86/arch_x86_or_fetch.h | 2 +- .../internal/atomic/arch/x86/arch_x86_store.h | 2 +- .../atomic/arch/x86/arch_x86_sub_fetch.h | 2 +- .../atomic/arch/x86/arch_x86_thread_fence.h | 2 +- .../atomic/arch/x86/arch_x86_xor_fetch.h | 2 +- .../include/EASTL/internal/atomic/atomic.h | 11 +- .../EASTL/internal/atomic/atomic_base_width.h | 4 +- .../EASTL/internal/atomic/atomic_casts.h | 2 +- .../EASTL/internal/atomic/atomic_flag.h | 16 +- .../EASTL/internal/atomic/atomic_integral.h | 16 +- .../internal/atomic/atomic_memory_order.h | 12 +- .../EASTL/internal/atomic/atomic_pointer.h | 16 +- .../internal/atomic/atomic_size_aligned.h | 46 +- .../EASTL/internal/atomic/atomic_standalone.h | 16 +- .../EASTL/internal/atomic/compiler/compiler.h | 2 +- .../atomic/compiler/msvc/compiler_msvc.h | 16 +- .../compiler/msvc/compiler_msvc_barrier.h | 4 +- .../msvc/compiler_msvc_cmpxchg_strong.h | 1 - .../EASTL/include/EASTL/internal/config.h | 34 +- .../EASTL/include/EASTL/internal/copy_help.h | 57 +- .../EASTL/include/EASTL/internal/fill_help.h | 4 +- .../EASTL/include/EASTL/internal/fixed_pool.h | 11 +- .../EASTL/include/EASTL/internal/function.h | 2 + .../include/EASTL/internal/function_detail.h | 4 +- .../include/EASTL/internal/functional_base.h | 92 +- .../EASTL/include/EASTL/internal/hashtable.h | 30 +- .../include/EASTL/internal/integer_sequence.h | 30 + .../EASTL/include/EASTL/internal/move_help.h | 2 +- .../include/EASTL/internal/red_black_tree.h | 24 +- .../EASTL/include/EASTL/internal/smart_ptr.h | 5 +- .../include/EASTL/internal/thread_support.h | 18 +- .../include/EASTL/internal/type_compound.h | 59 +- .../include/EASTL/internal/type_fundamental.h | 55 +- .../EASTL/include/EASTL/internal/type_pod.h | 46 +- .../include/EASTL/internal/type_properties.h | 61 +- .../EASTL/internal/type_transformations.h | 306 +- .../EASTL/include/EASTL/intrusive_list.h | 8 + .../3rdparty/EASTL/include/EASTL/iterator.h | 184 +- library/3rdparty/EASTL/include/EASTL/list.h | 2 +- library/3rdparty/EASTL/include/EASTL/memory.h | 4 +- library/3rdparty/EASTL/include/EASTL/meta.h | 57 +- .../EASTL/include/EASTL/numeric_limits.h | 10 +- .../3rdparty/EASTL/include/EASTL/optional.h | 2 +- .../3rdparty/EASTL/include/EASTL/shared_ptr.h | 4 +- library/3rdparty/EASTL/include/EASTL/slist.h | 2 +- library/3rdparty/EASTL/include/EASTL/sort.h | 12 +- library/3rdparty/EASTL/include/EASTL/span.h | 44 +- library/3rdparty/EASTL/include/EASTL/string.h | 18 +- library/3rdparty/EASTL/include/EASTL/tuple.h | 56 +- .../EASTL/include/EASTL/type_traits.h | 38 +- .../3rdparty/EASTL/include/EASTL/unique_ptr.h | 13 +- .../3rdparty/EASTL/include/EASTL/utility.h | 8 +- .../3rdparty/EASTL/include/EASTL/variant.h | 774 +- library/3rdparty/EASTL/include/EASTL/vector.h | 4 +- .../3rdparty/EASTL/source/numeric_limits.cpp | 6 +- .../3rdparty/EASTL/source/red_black_tree.cpp | 6 +- .../3rdparty/EASTL/source/thread_support.cpp | 6 +- .../3rdparty/EASTL/test/source/EASTLTest.h | 1 + .../EASTL/test/source/TestAlgorithm.cpp | 123 +- .../EASTL/test/source/TestAllocator.cpp | 3 +- .../EASTL/test/source/TestAtomicBasic.cpp | 8068 +++++++++-------- .../EASTL/test/source/TestBitcast.cpp | 52 + .../EASTL/test/source/TestFunctional.cpp | 177 +- .../3rdparty/EASTL/test/source/TestHash.cpp | 10 + .../EASTL/test/source/TestIntrusiveHash.cpp | 6 + .../EASTL/test/source/TestIterator.cpp | 121 +- .../3rdparty/EASTL/test/source/TestMap.cpp | 13 + .../EASTL/test/source/TestOptional.cpp | 16 +- .../3rdparty/EASTL/test/source/TestSort.cpp | 17 + .../3rdparty/EASTL/test/source/TestSpan.cpp | 20 +- .../EASTL/test/source/TestTypeTraits.cpp | 177 +- .../EASTL/test/source/TestVariant.cpp | 905 +- library/3rdparty/EASTL/test/source/main.cpp | 1 + 106 files changed, 7964 insertions(+), 5427 deletions(-) create mode 100644 library/3rdparty/EASTL/doc/EASTL-n2271.pdf create mode 100644 library/3rdparty/EASTL/include/EASTL/bit.h create mode 100644 library/3rdparty/EASTL/test/source/TestBitcast.cpp diff --git a/library/3rdparty/EASTL/README.md b/library/3rdparty/EASTL/README.md index 7cc400a..07b8ea3 100644 --- a/library/3rdparty/EASTL/README.md +++ b/library/3rdparty/EASTL/README.md @@ -44,8 +44,11 @@ Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on compiling and testi EASTL was created by Paul Pedriana and he maintained the project for roughly 10 years. -Roberto Parolin is the current EASTL owner and primary maintainer within EA and is responsible for the open source repository. -Max Winkler is the secondary maintainer for EASTL within EA and on the open source repository. +EASTL was subsequently maintained by Roberto Parolin for more than 8 years. +He was the driver and proponent for getting EASTL opensourced. +Rob was a mentor to all members of the team and taught us everything we ever wanted to know about C++ spookyness. + +Max Winkler is the current EASTL owner and primary maintainer within EA and is responsible for the open source repository. Significant EASTL contributions were made by (in alphabetical order): diff --git a/library/3rdparty/EASTL/doc/EASTL-n2271.pdf b/library/3rdparty/EASTL/doc/EASTL-n2271.pdf new file mode 100644 index 0000000000000000000000000000000000000000..8a1b0b9eb29d228394e997bfe45aaf10c572cf3d GIT binary patch literal 345371 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%0ARTUwm;{^k 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%0AcjqMHwYv$I;1wrVBM*k}{eZ-wK0z+~0eEzkrS< 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

CCf?=U7bD15amgS<+^_sTb>R zBbU9Ujk8S{_t%flULvd_7U&OGhbD#b`1<>bmVpWP{t) zT*gxd%Z|?r)?6&VFcRc?5Jqf{;_s5#%o^%_H>UEXI*Wxy8%B8I5 zvBLzE5zF2E&3UdXCCZZ@8VGI~HB$|X3AD$ta`-;1texS1(2RW3n-QbH4(ZCrndZIH zJMKqXDL|lsuAbOkM|CZYENg#1i$H)EmC#>vy8EMg2lhoR{mWTKp5>JX?OKOObN3#t zVAFXJZ|C56M|JZf!KQt-NF{h!d_{*Cvtv5Kc=NPAU%m#45<68tXq)fl2 zE4z*=u3Ixmk{0TZfv%$`dYIVP5Jq@YzyfU|5JuVN)rV0LI#=1Y&?LQ0@D}Z}snHEA zo}{GuLI%qBg~=((U+eU!lIL228EQm_sB;nm^gQ>h++7mF$k+yI)E>O8^e5a<;BiFL z+SWr?&uYZNi+LEp=9!mV1;ay~@v%<2VfV!f#{fdcloZa-`P~99uAwo;D9R6vp+myw z%;&j00hPH}rEcqHK)i>hKnp8;EU1<4O6A8;)?rvl@<6;Eg97W~%0An?{vIA`!i}UZ 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

(otherValue)); // Need to use forward instead of move because P&& is a "universal reference" instead of an rvalue reference. +@@ -2670,7 +2728,7 @@ namespace eastl + template + typename hashtable::insert_return_type +- hashtable::insert(const value_type& value) ++ hashtable::insert(const value_type& value) + { + return DoInsertValue(has_unique_keys_type(), value); + } +@@ -2679,7 +2737,7 @@ namespace eastl + template + typename hashtable::insert_return_type +- hashtable::insert(hash_code_t c, node_type* pNodeNew, const value_type& value) ++ hashtable::insert(hash_code_t c, node_pointer pNodeNew, const value_type& value) + { + // pNodeNew->mValue is expected to be uninitialized. + const key_type& k = mExtractKey(value); +@@ -2796,8 +2854,8 @@ namespace eastl + iterator iNext(i.mpNode, i.mpBucket); // Convert from const_iterator to iterator while constructing. + ++iNext; + +- node_type* pNode = i.mpNode; +- node_type* pNodeCurrent = *i.mpBucket; ++ node_pointer pNode = i.mpNode; ++ node_pointer pNodeCurrent = *i.mpBucket; + + if(pNodeCurrent == pNode) + *i.mpBucket = pNodeCurrent->mpNext; +@@ -2805,7 +2863,7 @@ namespace eastl + { + // We have a singly-linked list, so we have no choice but to + // walk down it till we find the node before the node at 'i'. +- node_type* pNodeNext = pNodeCurrent->mpNext; ++ node_pointer pNodeNext = pNodeCurrent->mpNext; + + while(pNodeNext != pNode) + { +@@ -2849,15 +2907,15 @@ namespace eastl + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + const size_type nElementCountSaved = mnElementCount; + +- node_type** pBucketArray = mpBucketArray + n; ++ node_pointer* pBucketArray = mpBucketArray + n; + +- while(*pBucketArray && !compare(k, c, *pBucketArray)) ++ while(*pBucketArray && !compare(k, c, allocator_type::to_raw(*pBucketArray))) + pBucketArray = &(*pBucketArray)->mpNext; + +- node_type* pDeleteList = nullptr; +- while(*pBucketArray && compare(k, c, *pBucketArray)) ++ node_pointer pDeleteList = nullptr; ++ while(*pBucketArray && compare(k, c, allocator_type::to_raw(*pBucketArray))) + { +- node_type* const pNode = *pBucketArray; ++ node_pointer const pNode = *pBucketArray; + *pBucketArray = pNode->mpNext; + // 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. +@@ -2868,7 +2926,7 @@ namespace eastl + } + + while (pDeleteList) { +- node_type* const pToDelete = pDeleteList; ++ node_pointer const pToDelete = pDeleteList; + pDeleteList = pDeleteList->mpNext; + DoFreeNode(pToDelete); + } +@@ -2913,12 +2971,12 @@ namespace eastl + // container built into scratch memory. + mnBucketCount = 1; + +- #ifdef _MSC_VER +- mpBucketArray = (node_type**)&gpEmptyBucketArray[0]; +- #else +- void* p = &gpEmptyBucketArray[0]; +- memcpy(&mpBucketArray, &p, sizeof(mpBucketArray)); // Other compilers implement strict aliasing and casting is thus unsafe. +- #endif ++ // #ifdef _MSC_VER ++ mpBucketArray = allocator_type::template get_empty_hashtable(); ++ // #else ++ // auto p = &gpEmptyBucketArray[0]; ++ // memcpy(&mpBucketArray, &p, sizeof(mpBucketArray)); // Other compilers implement strict aliasing and casting is thus unsafe. ++ // #endif + + mnElementCount = 0; + mRehashPolicy.mnNextResize = 0; +@@ -2949,19 +3007,19 @@ namespace eastl + typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU> + void hashtable::DoRehash(size_type nNewBucketCount) + { +- node_type** const pBucketArray = DoAllocateBuckets(nNewBucketCount); // nNewBucketCount should always be >= 2. ++ bucket_array_type const pBucketArray = DoAllocateBuckets(nNewBucketCount); // nNewBucketCount should always be >= 2. + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif +- node_type* pNode; ++ node_pointer pNode; + + for(size_type i = 0; i < mnBucketCount; ++i) + { + while((pNode = mpBucketArray[i]) != NULL) // Using '!=' disables compiler warnings. + { +- const size_type nNewBucketIndex = (size_type)bucket_index(pNode, (uint32_t)nNewBucketCount); ++ const size_type nNewBucketIndex = (size_type)bucket_index(allocator_type::to_raw(pNode), (uint32_t)nNewBucketCount); + + mpBucketArray[i] = pNode->mpNext; + pNode->mpNext = pBucketArray[nNewBucketIndex]; +@@ -2994,10 +3052,11 @@ namespace eastl + inline bool hashtable::validate() const + { + // Verify our empty bucket array is unmodified. +- if(gpEmptyBucketArray[0] != NULL) ++ auto empty_hashtable = allocator_type::template get_empty_hashtable(); ++ if(empty_hashtable[0] != NULL) + return false; + +- if(gpEmptyBucketArray[1] != (void*)uintptr_t(~0)) ++ if(!allocator_type::is_hashtable_sentinel(empty_hashtable[1])) + return false; + + // Verify that we have at least one bucket. Calculations can +@@ -3007,7 +3066,7 @@ namespace eastl + + // Verify that gpEmptyBucketArray is used correctly. + // gpEmptyBucketArray is only used when initially empty. +- if((void**)mpBucketArray == &gpEmptyBucketArray[0]) ++ if(allocator_type::is_empty_hashtable(mpBucketArray)) + { + if(mnElementCount) // gpEmptyBucketArray is used only for empty hash tables. + return false; +diff --git a/include/EASTL/iterator.h b/include/EASTL/iterator.h +index 6c268aa..d76938a 100644 +--- a/include/EASTL/iterator.h ++++ b/include/EASTL/iterator.h +@@ -78,6 +78,8 @@ namespace eastl + struct bidirectional_iterator_tag : public forward_iterator_tag { }; + struct random_access_iterator_tag : public bidirectional_iterator_tag { }; + struct contiguous_iterator_tag : public random_access_iterator_tag { }; // Extension to the C++ standard. Contiguous ranges are more than random access, they are physically contiguous. ++ #else ++ struct contiguous_iterator_tag : public std::random_access_iterator_tag { }; // Extension to the C++ standard. Contiguous ranges are more than random access, they are physically contiguous. + #endif + + +diff --git a/include/EASTL/string.h b/include/EASTL/string.h +index 3a70b79..538bad4 100644 +--- a/include/EASTL/string.h ++++ b/include/EASTL/string.h +@@ -293,6 +293,9 @@ namespace eastl + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to size_t. + typedef ptrdiff_t difference_type; + typedef Allocator allocator_type; ++ protected: ++ typedef typename allocator_type::template array_pointer heap_array_type; ++ public: + + static const EA_CONSTEXPR size_type npos = (size_type)-1; /// 'npos' means non-valid position or simply non-position. + +@@ -337,7 +340,7 @@ namespace eastl + // The view of memory when the string data is obtained from the allocator. + struct HeapLayout + { +- value_type* mpBegin; // Begin of string. ++ heap_array_type mpBegin; // Begin of string. + size_type mnSize; // Size of the string. Number of characters currently in the string, not including the trailing '0' + size_type mnCapacity; // Capacity of the string. Number of characters string can hold, not including the trailing '0' + }; +@@ -433,8 +436,8 @@ namespace eastl + + inline size_type GetRemainingCapacity() const EA_NOEXCEPT { return size_type(CapacityPtr() - EndPtr()); } + +- inline value_type* HeapBeginPtr() EA_NOEXCEPT { return heap.mpBegin; }; +- inline const value_type* HeapBeginPtr() const EA_NOEXCEPT { return heap.mpBegin; }; ++ inline value_type* HeapBeginPtr() EA_NOEXCEPT { return allocator_type::to_raw(heap.mpBegin); }; ++ inline const value_type* HeapBeginPtr() const EA_NOEXCEPT { return allocator_type::to_raw(heap.mpBegin); }; + + inline value_type* SSOBeginPtr() EA_NOEXCEPT { return sso.mData; } + inline const value_type* SSOBeginPtr() const EA_NOEXCEPT { return sso.mData; } +@@ -462,7 +465,8 @@ namespace eastl + inline value_type* CapacityPtr() EA_NOEXCEPT { return IsHeap() ? HeapCapacityPtr() : SSOCapacityPtr(); } + inline const value_type* CapacityPtr() const EA_NOEXCEPT { return IsHeap() ? HeapCapacityPtr() : SSOCapacityPtr(); } + +- inline void SetHeapBeginPtr(value_type* pBegin) EA_NOEXCEPT { heap.mpBegin = pBegin; } ++ inline void SetHeapBeginPtr(heap_array_type pBegin) EA_NOEXCEPT { heap.mpBegin = pBegin; } ++ inline const heap_array_type& GetHeapBeginPtr() const EA_NOEXCEPT { return heap.mpBegin; } + + inline void SetHeapCapacity(size_type cap) EA_NOEXCEPT + { +@@ -756,8 +760,8 @@ namespace eastl + + protected: + // Helper functions for initialization/insertion operations. +- value_type* DoAllocate(size_type n); +- void DoFree(value_type* p, size_type n); ++ heap_array_type DoAllocate(size_type n); ++ void DoFree(heap_array_type p, size_type n); + size_type GetNewCapacity(size_type currentCapacity); + size_type GetNewCapacity(size_type currentCapacity, size_type minimumGrowSize); + void AllocateSelf(); +@@ -1000,6 +1004,8 @@ namespace eastl + inline basic_string::~basic_string() + { + DeallocateSelf(); ++ AllocateSelf(); ++ allocator_type::force_changes_in_dtor(this); + } + + +@@ -1413,21 +1419,22 @@ namespace eastl + // A heap based layout wants to reduce its size to within sso capacity + // An sso layout wanting to reduce its capacity will not get in here + pointer pOldBegin = internalLayout().BeginPtr(); ++ heap_array_type pOldHeap = internalLayout().GetHeapBeginPtr(); + const size_type nOldCap = internalLayout().GetHeapCapacity(); + + CharStringUninitializedCopy(pOldBegin, pOldBegin + n, internalLayout().SSOBeginPtr()); + internalLayout().SetSSOSize(n); + *internalLayout().SSOEndPtr() = 0; + +- DoFree(pOldBegin, nOldCap + 1); ++ DoFree(pOldHeap, nOldCap + 1); + + return; + } + +- pointer pNewBegin = DoAllocate(n + 1); // We need the + 1 to accomodate the trailing 0. ++ heap_array_type pNewBegin = DoAllocate(n + 1); // We need the + 1 to accomodate the trailing 0. + size_type nSavedSize = internalLayout().GetSize(); // save the size in case we transition from sso->heap + +- pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), internalLayout().EndPtr(), pNewBegin); ++ pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), internalLayout().EndPtr(), allocator_type::to_raw(pNewBegin)); + *pNewEnd = 0; + + DeallocateSelf(); +@@ -1484,7 +1491,7 @@ namespace eastl + if (internalLayout().IsSSO()) + { + const size_type n = internalLayout().GetSize() + 1; // +1' so that we have room for the terminating 0. +- pDetached = DoAllocate(n); ++ pDetached = allocator_type::to_raw(DoAllocate(n)); + pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), internalLayout().EndPtr(), pDetached); + *pNewEnd = 0; + } +@@ -1723,9 +1730,9 @@ namespace eastl + { + const size_type nLength = GetNewCapacity(nCapacity, nNewSize - nCapacity); + +- pointer pNewBegin = DoAllocate(nLength + 1); ++ heap_array_type pNewBegin = DoAllocate(nLength + 1); + +- pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), internalLayout().EndPtr(), pNewBegin); ++ pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), internalLayout().EndPtr(), allocator_type::to_raw(pNewBegin)); + pNewEnd = CharStringUninitializedCopy(pBegin, pEnd, pNewEnd); + *pNewEnd = 0; + +@@ -2194,9 +2201,9 @@ namespace eastl + const size_type nOldCap = capacity(); + const size_type nLength = GetNewCapacity(nOldCap, (nOldSize + n) - nOldCap); + +- iterator pNewBegin = DoAllocate(nLength + 1); ++ heap_array_type pNewBegin = DoAllocate(nLength + 1); + +- iterator pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), p, pNewBegin); ++ iterator pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), p, allocator_type::to_raw(pNewBegin)); + pNewEnd = CharStringUninitializedFillN(pNewEnd, n, c); + pNewEnd = CharStringUninitializedCopy(p, internalLayout().EndPtr(), pNewEnd); + *pNewEnd = 0; +@@ -2302,9 +2309,9 @@ namespace eastl + else + nLength = GetNewCapacity(nOldCap, (nOldSize + n) - nOldCap); + +- pointer pNewBegin = DoAllocate(nLength + 1); ++ heap_array_type pNewBegin = DoAllocate(nLength + 1); + +- pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), p, pNewBegin); ++ pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), p, allocator_type::to_raw(pNewBegin)); + pNewEnd = CharStringUninitializedCopy(pBegin, pEnd, pNewEnd); + pNewEnd = CharStringUninitializedCopy(p, internalLayout().EndPtr(), pNewEnd); + *pNewEnd = 0; +@@ -2581,9 +2588,9 @@ namespace eastl + const size_type nOldCap = capacity(); + const size_type nNewCapacity = GetNewCapacity(nOldCap, (nOldSize + (nLength2 - nLength1)) - nOldCap); + +- pointer pNewBegin = DoAllocate(nNewCapacity + 1); ++ heap_array_type pNewBegin = DoAllocate(nNewCapacity + 1); + +- pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), pBegin1, pNewBegin); ++ pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), pBegin1, allocator_type::to_raw(pNewBegin)); + pNewEnd = CharStringUninitializedCopy(pBegin2, pEnd2, pNewEnd); + pNewEnd = CharStringUninitializedCopy(pEnd1, internalLayout().EndPtr(), pNewEnd); + *pNewEnd = 0; +@@ -3217,9 +3224,9 @@ namespace eastl + const size_type nOldCap = capacity(); + const size_type nLength = GetNewCapacity(nOldCap, 1); + +- iterator pNewBegin = DoAllocate(nLength + 1); ++ heap_array_type pNewBegin = DoAllocate(nLength + 1); + +- pNewPosition = CharStringUninitializedCopy(internalLayout().BeginPtr(), p, pNewBegin); ++ pNewPosition = CharStringUninitializedCopy(internalLayout().BeginPtr(), p, allocator_type::to_raw(pNewBegin)); + *pNewPosition = c; + + iterator pNewEnd = pNewPosition + 1; +@@ -3275,18 +3282,20 @@ namespace eastl + + + template +- inline typename basic_string::value_type* ++ inline typename basic_string::heap_array_type + basic_string::DoAllocate(size_type n) + { +- return (value_type*)EASTLAlloc(get_allocator(), n * sizeof(value_type)); ++ // return (value_type*)EASTLAlloc(get_allocator(), n * sizeof(value_type)); ++ return get_allocator().template allocate_array(n); + } + + + template +- inline void basic_string::DoFree(value_type* p, size_type n) ++ inline void basic_string::DoFree(heap_array_type p, size_type n) + { + if(p) +- EASTLFree(get_allocator(), p, n * sizeof(value_type)); ++ // EASTLFree(get_allocator(), p, n * sizeof(value_type)); ++ get_allocator().deallocate_array(p, n); + } + + +@@ -3338,7 +3347,7 @@ namespace eastl + + if(n > SSOLayout::SSO_CAPACITY) + { +- pointer pBegin = DoAllocate(n + 1); ++ heap_array_type pBegin = DoAllocate(n + 1); + internalLayout().SetHeapBeginPtr(pBegin); + internalLayout().SetHeapCapacity(n); + internalLayout().SetHeapSize(n); +@@ -3353,7 +3362,7 @@ namespace eastl + { + if(internalLayout().IsHeap()) + { +- DoFree(internalLayout().BeginPtr(), internalLayout().GetHeapCapacity() + 1); ++ DoFree(internalLayout().GetHeapBeginPtr(), internalLayout().GetHeapCapacity() + 1); + } + } + +@@ -3769,22 +3778,22 @@ namespace eastl + } + + #if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) +- template +- inline bool operator==(const typename basic_string::value_type* p, const basic_string& b) +- { +- typedef typename basic_string::size_type size_type; +- const size_type n = (size_type)CharStrlen(p); +- return ((n == b.size()) && (memcmp(p, b.data(), (size_t)n * sizeof(*p)) == 0)); +- } ++ // template ++ // inline bool operator==(const typename basic_string::value_type* p, const basic_string& b) ++ // { ++ // typedef typename basic_string::size_type size_type; ++ // const size_type n = (size_type)CharStrlen(p); ++ // return ((n == b.size()) && (memcmp(p, b.data(), (size_t)n * sizeof(*p)) == 0)); ++ // } + #endif + +- template +- inline bool operator==(const basic_string& a, const typename basic_string::value_type* p) +- { +- typedef typename basic_string::size_type size_type; +- const size_type n = (size_type)CharStrlen(p); +- return ((a.size() == n) && (memcmp(a.data(), p, (size_t)n * sizeof(*p)) == 0)); +- } ++ // template ++ // inline bool operator==(const basic_string& a, const typename basic_string::value_type* p) ++ // { ++ // typedef typename basic_string::size_type size_type; ++ // 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 +@@ -3793,45 +3802,44 @@ namespace eastl + return basic_string::compare(a.begin(), a.end(), b.begin(), b.end()) <=> 0; + } + +- template +- inline auto operator<=>(const basic_string& a, const typename basic_string::value_type* p) +- { +- typedef typename basic_string::size_type size_type; +- const size_type n = (size_type)CharStrlen(p); +- return basic_string::compare(a.begin(), a.end(), p, p + n) <=> 0; +- } ++ // template ++ // inline auto operator<=>(const basic_string& a, const typename basic_string::value_type* p) ++ // { ++ // typedef typename basic_string::size_type size_type; ++ // const size_type n = (size_type)CharStrlen(p); ++ // return basic_string::compare(a.begin(), a.end(), p, p + n) <=> 0; ++ // } + +- template +- inline auto operator<=>(const basic_string& a, const typename basic_string::view_type v) +- { +- typedef typename basic_string::view_type view_type; +- return static_cast(a) <=> v; +- } ++ // template ++ // inline auto operator<=>(const basic_string& a, const typename basic_string::view_type v) ++ // { ++ // typedef typename basic_string::view_type view_type; ++ // return static_cast(a) <=> v; ++ // } + + #else + +- template +- inline bool operator==(const typename basic_string::view_type v, const basic_string& 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::view_type view_type; +- return v == static_cast(b); +- } ++ // template ++ // inline bool operator==(const typename basic_string::view_type v, const basic_string& 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). + +- template +- inline bool operator==(const basic_string& a, const typename basic_string::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::view_type view_type; ++ // return v == static_cast(b); ++ // } + +- typedef typename basic_string::view_type view_type; +- return static_cast(a) == v; +- } ++ // template ++ // inline bool operator==(const basic_string& a, const typename basic_string::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::view_type view_type; ++ // return static_cast(a) == v; ++ // } + + template + inline bool operator!=(const basic_string& a, const basic_string& b) +@@ -3839,40 +3847,40 @@ namespace eastl + return !(a == b); + } + +- template +- inline bool operator!=(const typename basic_string::value_type* p, const basic_string& b) +- { +- return !(p == b); +- } ++ // template ++ // inline bool operator!=(const typename basic_string::value_type* p, const basic_string& b) ++ // { ++ // return !(p == b); ++ // } + + +- template +- inline bool operator!=(const basic_string& a, const typename basic_string::value_type* p) +- { +- return !(a == p); +- } ++ // template ++ // inline bool operator!=(const basic_string& a, const typename basic_string::value_type* p) ++ // { ++ // return !(a == p); ++ // } + + +- template +- inline bool operator!=(const typename basic_string::view_type v, const basic_string& 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). ++ // template ++ // inline bool operator!=(const typename basic_string::view_type v, const basic_string& 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); +- } ++ // return !(v == b); ++ // } + + +- template +- inline bool operator!=(const basic_string& a, const typename basic_string::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). ++ // template ++ // inline bool operator!=(const basic_string& a, const typename basic_string::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); +- } ++ // return !(a == v); ++ // } + + + // Operator< (and also >, <=, and >=). +@@ -3882,46 +3890,46 @@ namespace eastl + return basic_string::compare(a.begin(), a.end(), b.begin(), b.end()) < 0; } + + +- template +- inline bool operator<(const typename basic_string::value_type* p, const basic_string& b) +- { +- typedef typename basic_string::size_type size_type; +- const size_type n = (size_type)CharStrlen(p); +- return basic_string::compare(p, p + n, b.begin(), b.end()) < 0; +- } ++ // template ++ // inline bool operator<(const typename basic_string::value_type* p, const basic_string& b) ++ // { ++ // typedef typename basic_string::size_type size_type; ++ // const size_type n = (size_type)CharStrlen(p); ++ // return basic_string::compare(p, p + n, b.begin(), b.end()) < 0; ++ // } + + +- template +- inline bool operator<(const basic_string& a, const typename basic_string::value_type* p) +- { +- typedef typename basic_string::size_type size_type; +- const size_type n = (size_type)CharStrlen(p); +- return basic_string::compare(a.begin(), a.end(), p, p + n) < 0; +- } ++ // template ++ // inline bool operator<(const basic_string& a, const typename basic_string::value_type* p) ++ // { ++ // typedef typename basic_string::size_type size_type; ++ // const size_type n = (size_type)CharStrlen(p); ++ // return basic_string::compare(a.begin(), a.end(), p, p + n) < 0; ++ // } + + +- template +- inline bool operator<(const typename basic_string::view_type v, const basic_string& 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). ++ // template ++ // inline bool operator<(const typename basic_string::view_type v, const basic_string& 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::view_type view_type; +- return v < static_cast(b); +- } ++ // typedef typename basic_string::view_type view_type; ++ // return v < static_cast(b); ++ // } + + +- template +- inline bool operator<(const basic_string& a, const typename basic_string::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). ++ // template ++ // inline bool operator<(const basic_string& a, const typename basic_string::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::view_type view_type; +- return static_cast(a) < v; +- } ++ // typedef typename basic_string::view_type view_type; ++ // return static_cast(a) < v; ++ // } + + + template +@@ -3931,40 +3939,40 @@ namespace eastl + } + + +- template +- inline bool operator>(const typename basic_string::value_type* p, const basic_string& b) +- { +- return b < p; +- } ++ // template ++ // inline bool operator>(const typename basic_string::value_type* p, const basic_string& b) ++ // { ++ // return b < p; ++ // } + + +- template +- inline bool operator>(const basic_string& a, const typename basic_string::value_type* p) +- { +- return p < a; +- } ++ // template ++ // inline bool operator>(const basic_string& a, const typename basic_string::value_type* p) ++ // { ++ // return p < a; ++ // } + + +- template +- inline bool operator>(const typename basic_string::view_type v, const basic_string& 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). ++ // template ++ // inline bool operator>(const typename basic_string::view_type v, const basic_string& 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; +- } ++ // return b < v; ++ // } + + +- template +- inline bool operator>(const basic_string& a, const typename basic_string::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). ++ // template ++ // inline bool operator>(const basic_string& a, const typename basic_string::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; +- } ++ // return v < a; ++ // } + + + template +@@ -3974,40 +3982,40 @@ namespace eastl + } + + +- template +- inline bool operator<=(const typename basic_string::value_type* p, const basic_string& b) +- { +- return !(b < p); +- } ++ // template ++ // inline bool operator<=(const typename basic_string::value_type* p, const basic_string& b) ++ // { ++ // return !(b < p); ++ // } + + +- template +- inline bool operator<=(const basic_string& a, const typename basic_string::value_type* p) +- { +- return !(p < a); +- } ++ // template ++ // inline bool operator<=(const basic_string& a, const typename basic_string::value_type* p) ++ // { ++ // return !(p < a); ++ // } + + +- template +- inline bool operator<=(const typename basic_string::view_type v, const basic_string& 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). ++ // template ++ // inline bool operator<=(const typename basic_string::view_type v, const basic_string& 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); +- } ++ // return !(b < v); ++ // } + + +- template +- inline bool operator<=(const basic_string& a, const typename basic_string::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). ++ // template ++ // inline bool operator<=(const basic_string& a, const typename basic_string::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); +- } ++ // return !(v < a); ++ // } + + + template +@@ -4017,40 +4025,40 @@ namespace eastl + } + + +- template +- inline bool operator>=(const typename basic_string::value_type* p, const basic_string& b) +- { +- return !(p < b); +- } ++ // template ++ // inline bool operator>=(const typename basic_string::value_type* p, const basic_string& b) ++ // { ++ // return !(p < b); ++ // } + + +- template +- inline bool operator>=(const basic_string& a, const typename basic_string::value_type* p) +- { +- return !(a < p); +- } ++ // template ++ // inline bool operator>=(const basic_string& a, const typename basic_string::value_type* p) ++ // { ++ // return !(a < p); ++ // } + + +- template +- inline bool operator>=(const typename basic_string::view_type v, const basic_string& 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 +- inline bool operator>=(const basic_string& a, const typename basic_string::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); +- } ++ // template ++ // inline bool operator>=(const typename basic_string::view_type v, const basic_string& 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 ++ // inline bool operator>=(const basic_string& a, const typename basic_string::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 +@@ -4085,10 +4093,10 @@ namespace eastl + /// + template struct hash; + +- template <> +- struct hash ++ template ++ struct hash> + { +- size_t operator()(const string& x) const ++ size_t operator()(const basic_string& x) const + { + const unsigned char* p = (const unsigned char*)x.c_str(); // To consider: limit p to at most 256 chars. + unsigned int c, result = 2166136261U; // We implement an FNV-like string hash. +@@ -4113,10 +4121,10 @@ namespace eastl + }; + #endif + +- template <> +- struct hash ++ template ++ struct hash> + { +- size_t operator()(const string16& x) const ++ size_t operator()(const basic_string& x) const + { + const char16_t* p = x.c_str(); + unsigned int c, result = 2166136261U; +@@ -4126,10 +4134,10 @@ namespace eastl + } + }; + +- template <> +- struct hash ++ template ++ struct hash> + { +- size_t operator()(const string32& x) const ++ size_t operator()(const basic_string& x) const + { + const char32_t* p = x.c_str(); + unsigned int c, result = 2166136261U; +@@ -4140,10 +4148,10 @@ namespace eastl + }; + + #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE +- template <> +- struct hash ++ template ++ struct hash> + { +- size_t operator()(const wstring& x) const ++ size_t operator()(const basic_string& x) const + { + const wchar_t* p = x.c_str(); + unsigned int c, result = 2166136261U; +diff --git a/include/EASTL/vector.h b/include/EASTL/vector.h +index b6ca8dc..b6ae031 100644 +--- a/include/EASTL/vector.h ++++ b/include/EASTL/vector.h +@@ -127,6 +127,7 @@ namespace eastl + typedef Allocator allocator_type; + typedef eastl_size_t size_type; + typedef ptrdiff_t difference_type; ++ typedef typename Allocator::template array_pointer array_type; + + #if defined(_MSC_VER) && (_MSC_VER >= 1400) && (_MSC_VER <= 1600) && !EASTL_STD_CPP_ONLY // _MSC_VER of 1400 means VS2005, 1600 means VS2010. VS2012 generates errors with usage of enum:size_type. + enum : size_type { // Use Microsoft enum language extension, allowing for smaller debug symbols than using a static const. Users have been affected by this. +@@ -139,7 +140,7 @@ namespace eastl + #endif + + protected: +- T* mpBegin; ++ array_type mpBegin; + T* mpEnd; + eastl::compressed_pair mCapacityAllocator; + +@@ -160,8 +161,8 @@ namespace eastl + void set_allocator(const allocator_type& allocator); + + protected: +- T* DoAllocate(size_type n); +- void DoFree(T* p, size_type n); ++ array_type DoAllocate(size_type n); ++ void DoFree(array_type p, size_type n); + size_type GetNewCapacity(size_type currentCapacity); + + }; // VectorBase +@@ -192,6 +193,7 @@ namespace eastl + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef typename base_type::allocator_type allocator_type; ++ typedef typename base_type::array_type array_type; + + using base_type::mpBegin; + using base_type::mpEnd; +@@ -323,10 +325,10 @@ namespace eastl + using should_move_tag = should_move_or_copy_tag; + + template // Allocates a pointer of array count n and copy-constructs it with [first,last). +- pointer DoRealloc(size_type n, ForwardIterator first, ForwardIterator last, should_copy_tag); ++ array_type DoRealloc(size_type n, ForwardIterator first, ForwardIterator last, should_copy_tag); + + template // Allocates a pointer of array count n and copy-constructs it with [first,last). +- pointer DoRealloc(size_type n, ForwardIterator first, ForwardIterator last, should_move_tag); ++ array_type DoRealloc(size_type n, ForwardIterator first, ForwardIterator last, should_move_tag); + + template + void DoInit(Integer n, Integer value, true_type); +@@ -396,7 +398,7 @@ namespace eastl + + template + inline VectorBase::VectorBase() +- : mpBegin(NULL), ++ : mpBegin(nullptr), + mpEnd(NULL), + mCapacityAllocator(NULL, allocator_type(EASTL_VECTOR_DEFAULT_NAME)) + { +@@ -405,7 +407,7 @@ namespace eastl + + template + inline VectorBase::VectorBase(const allocator_type& allocator) +- : mpBegin(NULL), ++ : mpBegin(nullptr), + mpEnd(NULL), + mCapacityAllocator(NULL, allocator) + { +@@ -417,7 +419,7 @@ namespace eastl + : mCapacityAllocator(allocator) + { + mpBegin = DoAllocate(n); +- mpEnd = mpBegin; ++ mpEnd = allocator_type::to_raw(mpBegin); + internalCapacityPtr() = mpBegin + n; + } + +@@ -426,7 +428,13 @@ namespace eastl + inline VectorBase::~VectorBase() + { + if(mpBegin) +- EASTLFree(internalAllocator(), mpBegin, (internalCapacityPtr() - mpBegin) * sizeof(T)); ++// EASTLFree(internalAllocator(), mpBegin, (internalCapacityPtr() - mpBegin) * sizeof(T)); ++ internalAllocator().deallocate_array(mpBegin, internalCapacityPtr() - mpBegin); ++ ++ mpBegin = nullptr; ++ mpEnd = nullptr; ++ internalCapacityPtr() = nullptr; ++ allocator_type::force_changes_in_dtor(this); + } + + +@@ -454,7 +462,7 @@ namespace eastl + + + template +- inline T* VectorBase::DoAllocate(size_type n) ++ inline typename VectorBase::array_type VectorBase::DoAllocate(size_type n) + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(n >= 0x80000000)) +@@ -465,7 +473,8 @@ namespace eastl + // This is fine, as our default ctor initializes with NULL pointers. + if(EASTL_LIKELY(n)) + { +- auto* p = (T*)allocate_memory(internalAllocator(), n * sizeof(T), EASTL_ALIGN_OF(T), 0); ++// auto* p = (T*)allocate_memory(internalAllocator(), n * sizeof(T), EASTL_ALIGN_OF(T), 0); ++ auto p = internalAllocator().template allocate_array(n); + EASTL_ASSERT_MSG(p != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + return p; + } +@@ -477,10 +486,11 @@ namespace eastl + + + template +- inline void VectorBase::DoFree(T* p, size_type n) ++ inline void VectorBase::DoFree(array_type p, size_type n) + { + if(p) +- EASTLFree(internalAllocator(), p, n * sizeof(T)); ++ // EASTLFree(internalAllocator(), p, n * sizeof(T)); ++ internalAllocator().deallocate_array(p, n); + } + + +@@ -519,7 +529,8 @@ namespace eastl + inline vector::vector(size_type n, const allocator_type& allocator) + : base_type(n, allocator) + { +- eastl::uninitialized_default_fill_n(mpBegin, n); ++ auto raii = allocator_type::make_raii(mpBegin); ++ eastl::uninitialized_default_fill_n(allocator_type::to_raw(mpBegin), n); + mpEnd = mpBegin + n; + } + +@@ -528,7 +539,8 @@ namespace eastl + inline vector::vector(size_type n, const value_type& value, const allocator_type& allocator) + : base_type(n, allocator) + { +- eastl::uninitialized_fill_n_ptr(mpBegin, n, value); ++ auto raii = allocator_type::make_raii(mpBegin); ++ eastl::uninitialized_fill_n_ptr(allocator_type::to_raw(mpBegin), n, value); + mpEnd = mpBegin + n; + } + +@@ -537,7 +549,8 @@ namespace eastl + inline vector::vector(const this_type& x) + : base_type(x.size(), x.internalAllocator()) + { +- mpEnd = eastl::uninitialized_copy_ptr(x.mpBegin, x.mpEnd, mpBegin); ++ auto raii = allocator_type::make_raii(mpBegin); ++ mpEnd = eastl::uninitialized_copy_ptr(allocator_type::to_raw(x.mpBegin), x.mpEnd, allocator_type::to_raw(mpBegin)); + } + + +@@ -545,7 +558,8 @@ namespace eastl + inline vector::vector(const this_type& x, const allocator_type& allocator) + : base_type(x.size(), allocator) + { +- mpEnd = eastl::uninitialized_copy_ptr(x.mpBegin, x.mpEnd, mpBegin); ++ auto raii = allocator_type::make_raii(mpBegin); ++ mpEnd = eastl::uninitialized_copy_ptr(allocator_type::to_raw(x.mpBegin), x.mpEnd, allocator_type::to_raw(mpBegin)); + } + + +@@ -592,7 +606,7 @@ namespace eastl + inline vector::~vector() + { + // Call destructor for the values. Parent class will free the memory. +- eastl::destruct(mpBegin, mpEnd); ++ eastl::destruct(allocator_type::to_raw(mpBegin), mpEnd); + } + + +@@ -685,7 +699,7 @@ namespace eastl + inline typename vector::iterator + vector::begin() EA_NOEXCEPT + { +- return mpBegin; ++ return allocator_type::to_raw(mpBegin); + } + + +@@ -693,7 +707,7 @@ namespace eastl + inline typename vector::const_iterator + vector::begin() const EA_NOEXCEPT + { +- return mpBegin; ++ return allocator_type::to_raw(mpBegin); + } + + +@@ -701,7 +715,7 @@ namespace eastl + inline typename vector::const_iterator + vector::cbegin() const EA_NOEXCEPT + { +- return mpBegin; ++ return allocator_type::to_raw(mpBegin); + } + + +@@ -757,7 +771,7 @@ namespace eastl + inline typename vector::reverse_iterator + vector::rend() EA_NOEXCEPT + { +- return reverse_iterator(mpBegin); ++ return reverse_iterator(allocator_type::to_raw(mpBegin)); + } + + +@@ -765,7 +779,7 @@ namespace eastl + inline typename vector::const_reverse_iterator + vector::rend() const EA_NOEXCEPT + { +- return const_reverse_iterator(mpBegin); ++ return const_reverse_iterator(allocator_type::to_raw(mpBegin)); + } + + +@@ -773,7 +787,7 @@ namespace eastl + inline typename vector::const_reverse_iterator + vector::crend() const EA_NOEXCEPT + { +- return const_reverse_iterator(mpBegin); ++ return const_reverse_iterator(allocator_type::to_raw(mpBegin)); + } + + +@@ -852,8 +866,8 @@ namespace eastl + } + else // Else new capacity > size. + { +- pointer const pNewData = DoRealloc(n, mpBegin, mpEnd, should_move_tag()); +- eastl::destruct(mpBegin, mpEnd); ++ auto pNewData = DoRealloc(n, allocator_type::to_raw(mpBegin), mpEnd, should_move_tag()); ++ eastl::destruct(allocator_type::to_raw(mpBegin), mpEnd); + DoFree(mpBegin, (size_type)(internalCapacityPtr() - mpBegin)); + + const ptrdiff_t nPrevSize = mpEnd - mpBegin; +@@ -878,7 +892,7 @@ namespace eastl + inline typename vector::pointer + vector::data() EA_NOEXCEPT + { +- return mpBegin; ++ return allocator_type::to_raw(mpBegin); + } + + +@@ -886,7 +900,7 @@ namespace eastl + inline typename vector::const_pointer + vector::data() const EA_NOEXCEPT + { +- return mpBegin; ++ return allocator_type::to_raw(mpBegin); + } + + +@@ -971,7 +985,7 @@ namespace eastl + // We allow the user to reference an empty container. + #endif + +- return *mpBegin; ++ return *allocator_type::to_raw(mpBegin); + } + + +@@ -986,7 +1000,7 @@ namespace eastl + // We allow the user to reference an empty container. + #endif + +- return *mpBegin; ++ return *allocator_type::to_raw(mpBegin); + } + + +@@ -1023,8 +1037,10 @@ namespace eastl + template + inline void vector::push_back(const value_type& value) + { +- if(mpEnd < internalCapacityPtr()) ++ if(mpEnd < internalCapacityPtr()) { ++ auto raii = allocator_type::make_raii(mpBegin); + ::new((void*)mpEnd++) value_type(value); ++ } + else + DoInsertValueEnd(value); + } +@@ -1033,8 +1049,10 @@ namespace eastl + template + inline void vector::push_back(value_type&& value) + { +- if (mpEnd < internalCapacityPtr()) ++ if (mpEnd < internalCapacityPtr()) { ++ auto raii = allocator_type::make_raii(mpBegin); + ::new((void*)mpEnd++) value_type(eastl::move(value)); ++ } + else + DoInsertValueEnd(eastl::move(value)); + } +@@ -1044,8 +1062,10 @@ namespace eastl + inline typename vector::reference + vector::push_back() + { +- if(mpEnd < internalCapacityPtr()) ++ if(mpEnd < internalCapacityPtr()) { ++ auto raii = allocator_type::make_raii(mpBegin); + ::new((void*)mpEnd++) value_type(); ++ } + else // Note that in this case we create a temporary, which is less desirable. + DoInsertValueEnd(value_type()); + +@@ -1091,6 +1111,7 @@ namespace eastl + DoInsertValue(position, eastl::forward(args)...); + else + { ++ auto raii = allocator_type::make_raii(mpBegin); + ::new((void*)mpEnd) value_type(eastl::forward(args)...); + ++mpEnd; // Increment this after the construction above in case the construction throws an exception. + } +@@ -1105,6 +1126,7 @@ namespace eastl + { + if(mpEnd < internalCapacityPtr()) + { ++ auto raii = allocator_type::make_raii(mpBegin); + ::new((void*)mpEnd) value_type(eastl::forward(args)...); // If value_type has a move constructor, it will use it and this operation may be faster than otherwise. + ++mpEnd; // Increment this after the construction above in case the construction throws an exception. + } +@@ -1130,6 +1152,7 @@ namespace eastl + DoInsertValue(position, value); + else + { ++ auto raii = allocator_type::make_raii(mpBegin); + ::new((void*)mpEnd) value_type(value); + ++mpEnd; // Increment this after the construction above in case the construction throws an exception. + } +@@ -1326,8 +1349,8 @@ namespace eastl + template + inline void vector::clear() EA_NOEXCEPT + { +- eastl::destruct(mpBegin, mpEnd); +- mpEnd = mpBegin; ++ eastl::destruct(allocator_type::to_raw(mpBegin), mpEnd); ++ mpEnd = allocator_type::to_raw(mpBegin); + } + + +@@ -1338,7 +1361,8 @@ namespace eastl + // resets the container to an empty state without freeing the memory of + // the contained objects. This is useful for very quickly tearing down a + // container built into scratch memory. +- mpBegin = mpEnd = internalCapacityPtr() = NULL; ++ mpBegin = nullptr; ++ mpEnd = internalCapacityPtr() = NULL; + } + + +@@ -1386,22 +1410,24 @@ namespace eastl + + template + template +- inline typename vector::pointer ++ inline typename vector::array_type + vector::DoRealloc(size_type n, ForwardIterator first, ForwardIterator last, should_copy_tag) + { +- T* const p = DoAllocate(n); // p is of type T* but is not constructed. +- eastl::uninitialized_copy_ptr(first, last, p); // copy-constructs p from [first,last). ++ auto p = DoAllocate(n); // p is of type T* but is not constructed. ++ auto raii = allocator_type::make_raii(p); ++ eastl::uninitialized_copy_ptr(first, last, allocator_type::to_raw(p)); // copy-constructs p from [first,last). + return p; + } + + + template + template +- inline typename vector::pointer ++ inline typename vector::array_type + vector::DoRealloc(size_type n, ForwardIterator first, ForwardIterator last, should_move_tag) + { +- T* const p = DoAllocate(n); // p is of type T* but is not constructed. +- eastl::uninitialized_move_ptr_if_noexcept(first, last, p); // move-constructs p from [first,last). ++ auto p = DoAllocate(n); // p is of type T* but is not constructed. ++ auto raii = allocator_type::make_raii(p); ++ eastl::uninitialized_move_ptr_if_noexcept(first, last, allocator_type::to_raw(p)); // move-constructs p from [first,last). + return p; + } + +@@ -1413,9 +1439,10 @@ namespace eastl + mpBegin = DoAllocate((size_type)n); + internalCapacityPtr() = mpBegin + n; + mpEnd = internalCapacityPtr(); ++ auto raii = allocator_type::make_raii(mpBegin); + + typedef typename eastl::remove_const::type non_const_value_type; // If T is a const type (e.g. const int) then we need to initialize it as if it were non-const. +- eastl::uninitialized_fill_n_ptr((non_const_value_type*)mpBegin, n, value); ++ eastl::uninitialized_fill_n_ptr((non_const_value_type*)allocator_type::to_raw(mpBegin), n, value); + } + + +@@ -1446,9 +1473,10 @@ namespace eastl + mpBegin = DoAllocate(n); + internalCapacityPtr() = mpBegin + n; + mpEnd = internalCapacityPtr(); ++ auto raii = allocator_type::make_raii(mpBegin); + + typedef typename eastl::remove_const::type non_const_value_type; // If T is a const type (e.g. const int) then we need to initialize it as if it were non-const. +- eastl::uninitialized_copy_ptr(first, last, (non_const_value_type*)mpBegin); ++ eastl::uninitialized_copy_ptr(first, last, (non_const_value_type*)allocator_type::to_raw(mpBegin)); + } + + +@@ -1479,13 +1507,14 @@ namespace eastl + } + else if(n > size_type(mpEnd - mpBegin)) // If n > size ... + { +- eastl::fill(mpBegin, mpEnd, value); ++ eastl::fill(allocator_type::to_raw(mpBegin), mpEnd, value); ++ auto raii = allocator_type::make_raii(mpBegin); + eastl::uninitialized_fill_n_ptr(mpEnd, n - size_type(mpEnd - mpBegin), value); + mpEnd += n - size_type(mpEnd - mpBegin); + } + else // else 0 <= n <= size + { +- eastl::fill_n(mpBegin, n, value); ++ eastl::fill_n(allocator_type::to_raw(mpBegin), n, value); + erase(mpBegin + n, mpEnd); + } + } +@@ -1495,7 +1524,7 @@ namespace eastl + template + void vector::DoAssignFromIterator(InputIterator first, InputIterator last, EASTL_ITC_NS::input_iterator_tag) + { +- iterator position(mpBegin); ++ iterator position(allocator_type::to_raw(mpBegin)); + + while((position != mpEnd) && (first != last)) + { +@@ -1518,8 +1547,8 @@ namespace eastl + + if(n > size_type(internalCapacityPtr() - mpBegin)) // If n > capacity ... + { +- pointer const pNewData = DoRealloc(n, first, last, should_move_or_copy_tag()); +- eastl::destruct(mpBegin, mpEnd); ++ auto pNewData = DoRealloc(n, first, last, should_move_or_copy_tag()); ++ eastl::destruct(allocator_type::to_raw(mpBegin), mpEnd); + DoFree(mpBegin, (size_type)(internalCapacityPtr() - mpBegin)); + + mpBegin = pNewData; +@@ -1528,14 +1557,15 @@ namespace eastl + } + else if(n <= size_type(mpEnd - mpBegin)) // If n <= size ... + { +- pointer const pNewEnd = eastl::copy(first, last, mpBegin); // Since we are copying to mpBegin, we don't have to worry about needing copy_backward or a memmove-like copy (as opposed to memcpy-like copy). ++ pointer const pNewEnd = eastl::copy(first, last, allocator_type::to_raw(mpBegin)); // Since we are copying to mpBegin, we don't have to worry about needing copy_backward or a memmove-like copy (as opposed to memcpy-like copy). + eastl::destruct(pNewEnd, mpEnd); + mpEnd = pNewEnd; + } + else // else size < n <= capacity + { + RandomAccessIterator position = first + (mpEnd - mpBegin); +- eastl::copy(first, position, mpBegin); // Since we are copying to mpBegin, we don't have to worry about needing copy_backward or a memmove-like copy (as opposed to memcpy-like copy). ++ eastl::copy(first, position, allocator_type::to_raw(mpBegin)); // Since we are copying to mpBegin, we don't have to worry about needing copy_backward or a memmove-like copy (as opposed to memcpy-like copy). ++ auto raii = allocator_type::make_raii(mpBegin); + mpEnd = eastl::uninitialized_copy_ptr(position, last, mpEnd); + } + } +@@ -1589,12 +1619,14 @@ namespace eastl + + if(n < nExtra) // If the inserted values are entirely within initialized memory (i.e. are before mpEnd)... + { ++ auto raii = allocator_type::make_raii(mpBegin); + eastl::uninitialized_move_ptr(mpEnd - n, mpEnd, mpEnd); + eastl::move_backward(destPosition, mpEnd - n, mpEnd); // We need move_backward because of potential overlap issues. + eastl::copy(first, last, destPosition); + } + else + { ++ auto raii = allocator_type::make_raii(mpBegin); + BidirectionalIterator iTemp = first; + eastl::advance(iTemp, nExtra); + eastl::uninitialized_copy_ptr(iTemp, last, mpEnd); +@@ -1609,29 +1641,30 @@ namespace eastl + const size_type nPrevSize = size_type(mpEnd - mpBegin); + const size_type nGrowSize = GetNewCapacity(nPrevSize); + const size_type nNewSize = nGrowSize > (nPrevSize + n) ? nGrowSize : (nPrevSize + n); +- pointer const pNewData = DoAllocate(nNewSize); ++ auto pNewData = DoAllocate(nNewSize); ++ auto raii = allocator_type::make_raii(pNewData); + + #if EASTL_EXCEPTIONS_ENABLED +- pointer pNewEnd = pNewData; ++ pointer pNewEnd = allocator_type::to_raw(pNewData); + try + { +- pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, destPosition, pNewData); ++ pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), destPosition, allocator_type::to_raw(pNewData)); + pNewEnd = eastl::uninitialized_copy_ptr(first, last, pNewEnd); + pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(destPosition, mpEnd, pNewEnd); + } + catch(...) + { +- eastl::destruct(pNewData, pNewEnd); ++ eastl::destruct(allocator_type::to_raw(pNewData), pNewEnd); + DoFree(pNewData, nNewSize); + throw; + } + #else +- pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, destPosition, pNewData); ++ pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), destPosition, allocator_type::to_raw(pNewData)); + pNewEnd = eastl::uninitialized_copy_ptr(first, last, pNewEnd); + pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(destPosition, mpEnd, pNewEnd); + #endif + +- eastl::destruct(mpBegin, mpEnd); ++ eastl::destruct(allocator_type::to_raw(mpBegin), mpEnd); + DoFree(mpBegin, (size_type)(internalCapacityPtr() - mpBegin)); + + mpBegin = pNewData; +@@ -1663,12 +1696,14 @@ namespace eastl + + if(n < nExtra) + { ++ auto raii = allocator_type::make_raii(mpBegin); + eastl::uninitialized_move_ptr(mpEnd - n, mpEnd, mpEnd); + eastl::move_backward(destPosition, mpEnd - n, mpEnd); // We need move_backward because of potential overlap issues. + eastl::fill(destPosition, destPosition + n, temp); + } + else + { ++ auto raii = allocator_type::make_raii(mpBegin); + eastl::uninitialized_fill_n_ptr(mpEnd, n - nExtra, temp); + eastl::uninitialized_move_ptr(destPosition, mpEnd, mpEnd + n - nExtra); + eastl::fill(destPosition, mpEnd, temp); +@@ -1682,29 +1717,30 @@ namespace eastl + const size_type nPrevSize = size_type(mpEnd - mpBegin); + const size_type nGrowSize = GetNewCapacity(nPrevSize); + const size_type nNewSize = nGrowSize > (nPrevSize + n) ? nGrowSize : (nPrevSize + n); +- pointer const pNewData = DoAllocate(nNewSize); ++ auto pNewData = DoAllocate(nNewSize); ++ auto raii = allocator_type::make_raii(pNewData); + + #if EASTL_EXCEPTIONS_ENABLED +- pointer pNewEnd = pNewData; ++ pointer pNewEnd = allocator_type::to_raw(pNewData); + try + { +- pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, destPosition, pNewData); ++ pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), destPosition, allocator_type::to_raw(pNewData)); + eastl::uninitialized_fill_n_ptr(pNewEnd, n, value); + pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(destPosition, mpEnd, pNewEnd + n); + } + catch(...) + { +- eastl::destruct(pNewData, pNewEnd); ++ eastl::destruct(allocator_type::to_raw(pNewData), pNewEnd); + DoFree(pNewData, nNewSize); + throw; + } + #else +- pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, destPosition, pNewData); ++ pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), destPosition, allocator_type::to_raw(pNewData)); + eastl::uninitialized_fill_n_ptr(pNewEnd, n, value); + pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(destPosition, mpEnd, pNewEnd + n); + #endif + +- eastl::destruct(mpBegin, mpEnd); ++ eastl::destruct(allocator_type::to_raw(mpBegin), mpEnd); + DoFree(mpBegin, (size_type)(internalCapacityPtr() - mpBegin)); + + mpBegin = pNewData; +@@ -1726,11 +1762,12 @@ namespace eastl + template + void vector::DoGrow(size_type n) + { +- pointer const pNewData = DoAllocate(n); ++ auto pNewData = DoAllocate(n); ++ auto raii = allocator_type::make_raii(pNewData); + +- pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, mpEnd, pNewData); ++ pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), mpEnd, allocator_type::to_raw(pNewData)); + +- eastl::destruct(mpBegin, mpEnd); ++ eastl::destruct(allocator_type::to_raw(mpBegin), mpEnd); + DoFree(mpBegin, (size_type)(internalCapacityPtr() - mpBegin)); + + mpBegin = pNewData; +@@ -1757,28 +1794,29 @@ namespace eastl + const size_type nPrevSize = size_type(mpEnd - mpBegin); + const size_type nGrowSize = GetNewCapacity(nPrevSize); + const size_type nNewSize = eastl::max(nGrowSize, nPrevSize + n); +- pointer const pNewData = DoAllocate(nNewSize); ++ auto pNewData = DoAllocate(nNewSize); ++ auto raii = allocator_type::make_raii(pNewData); + + #if EASTL_EXCEPTIONS_ENABLED +- pointer pNewEnd = pNewData; // Assign pNewEnd a value here in case the copy throws. ++ pointer pNewEnd = allocator_type::to_raw(pNewData); // Assign pNewEnd a value here in case the copy throws. + try + { +- pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, mpEnd, pNewData); ++ pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), mpEnd, allocator_type::to_raw(pNewData)); + } + catch(...) + { +- eastl::destruct(pNewData, pNewEnd); ++ eastl::destruct(allocator_type::to_raw(pNewData), pNewEnd); + DoFree(pNewData, nNewSize); + throw; + } + #else +- pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, mpEnd, pNewData); ++ pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), mpEnd, allocator_type::to_raw(pNewData)); + #endif + + eastl::uninitialized_fill_n_ptr(pNewEnd, n, value); + pNewEnd += n; + +- eastl::destruct(mpBegin, mpEnd); ++ eastl::destruct(allocator_type::to_raw(mpBegin), mpEnd); + DoFree(mpBegin, (size_type)(internalCapacityPtr() - mpBegin)); + + mpBegin = pNewData; +@@ -1787,6 +1825,7 @@ namespace eastl + } + else + { ++ auto raii = allocator_type::make_raii(mpBegin); + eastl::uninitialized_fill_n_ptr(mpEnd, n, value); + mpEnd += n; + } +@@ -1800,25 +1839,26 @@ namespace eastl + const size_type nPrevSize = size_type(mpEnd - mpBegin); + const size_type nGrowSize = GetNewCapacity(nPrevSize); + const size_type nNewSize = eastl::max(nGrowSize, nPrevSize + n); +- pointer const pNewData = DoAllocate(nNewSize); ++ auto pNewData = DoAllocate(nNewSize); ++ auto raii = allocator_type::make_raii(pNewData); + + #if EASTL_EXCEPTIONS_ENABLED +- pointer pNewEnd = pNewData; // Assign pNewEnd a value here in case the copy throws. +- try { pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, mpEnd, pNewData); } ++ pointer pNewEnd = allocator_type::to_raw(pNewData); // Assign pNewEnd a value here in case the copy throws. ++ try { pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), mpEnd, allocator_type::to_raw(pNewData)); } + catch (...) + { +- eastl::destruct(pNewData, pNewEnd); ++ eastl::destruct(allocator_type::to_raw(pNewData), pNewEnd); + DoFree(pNewData, nNewSize); + throw; + } + #else +- pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, mpEnd, pNewData); ++ pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), mpEnd, allocator_type::to_raw(pNewData)); + #endif + + eastl::uninitialized_default_fill_n(pNewEnd, n); + pNewEnd += n; + +- eastl::destruct(mpBegin, mpEnd); ++ eastl::destruct(allocator_type::to_raw(mpBegin), mpEnd); + DoFree(mpBegin, (size_type)(internalCapacityPtr() - mpBegin)); + + mpBegin = pNewData; +@@ -1827,6 +1867,7 @@ namespace eastl + } + else + { ++ auto raii = allocator_type::make_raii(mpBegin); + eastl::uninitialized_default_fill_n(mpEnd, n); + mpEnd += n; + } +@@ -1860,6 +1901,7 @@ namespace eastl + #else + value_type value(eastl::forward(args)...); // Need to do this before the move_backward below because maybe args refers to something within the moving range. + #endif ++ auto raii = allocator_type::make_raii(mpBegin); + ::new(static_cast(mpEnd)) value_type(eastl::move(*(mpEnd - 1))); // mpEnd is uninitialized memory, so we must construct into it instead of move into it like we do with the other elements below. + eastl::move_backward(destPosition, mpEnd - 1, mpEnd); // We need to go backward because of potential overlap issues. + eastl::destruct(destPosition); +@@ -1871,34 +1913,35 @@ namespace eastl + const size_type nPosSize = size_type(destPosition - mpBegin); // Index of the insertion position. + const size_type nPrevSize = size_type(mpEnd - mpBegin); + const size_type nNewSize = GetNewCapacity(nPrevSize); +- pointer const pNewData = DoAllocate(nNewSize); ++ auto pNewData = DoAllocate(nNewSize); ++ auto raii = allocator_type::make_raii(pNewData); + + #if EASTL_EXCEPTIONS_ENABLED +- pointer pNewEnd = pNewData; ++ pointer pNewEnd = allocator_type::to_raw(pNewData); + try + { // To do: We are not handling exceptions properly below. In particular we don't want to + // call eastl::destruct on the entire range if only the first part of the range was constructed. + ::new((void*)(pNewData + nPosSize)) value_type(eastl::forward(args)...); // Because the old data is potentially being moved rather than copied, we need to move. + pNewEnd = NULL; // Set to NULL so that in catch we can tell the exception occurred during the next call. +- pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, destPosition, pNewData); // the value first, because it might possibly be a reference to the old data being moved. ++ pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), destPosition, allocator_type::to_raw(pNewData)); // the value first, because it might possibly be a reference to the old data being moved. + pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(destPosition, mpEnd, ++pNewEnd); + } + catch(...) + { + if(pNewEnd) +- eastl::destruct(pNewData, pNewEnd); // Destroy what has been constructed so far. ++ eastl::destruct(allocator_type::to_raw(pNewData), pNewEnd); // Destroy what has been constructed so far. + else +- eastl::destruct(pNewData + nPosSize); // The exception occurred during the first uninitialized move, so destroy only the value at nPosSize. ++ eastl::destruct(allocator_type::to_raw(pNewData) + nPosSize); // The exception occurred during the first unintialized move, so destroy only the value at nPosSize. + DoFree(pNewData, nNewSize); + throw; + } + #else + ::new((void*)(pNewData + nPosSize)) value_type(eastl::forward(args)...); // Because the old data is potentially being moved rather than copied, we need to move +- pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, destPosition, pNewData); // the value first, because it might possibly be a reference to the old data being moved. +- pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(destPosition, mpEnd, ++pNewEnd); // Question: with exceptions disabled, do we assume all operations are noexcept and thus there's no need for uninitialized_move_ptr_if_noexcept? ++ pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), destPosition, allocator_type::to_raw(pNewData)); // the value first, because it might possibly be a reference to the old data being moved. ++ pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(destPosition, mpEnd, ++pNewEnd); // Question: with exceptions disabled, do we asssume all operations are noexcept and thus there's no need for uninitialized_move_ptr_if_noexcept? + #endif + +- eastl::destruct(mpBegin, mpEnd); ++ eastl::destruct(allocator_type::to_raw(mpBegin), mpEnd); + DoFree(mpBegin, (size_type)(internalCapacityPtr() - mpBegin)); + + mpBegin = pNewData; +@@ -1914,29 +1957,30 @@ namespace eastl + { + const size_type nPrevSize = size_type(mpEnd - mpBegin); + const size_type nNewSize = GetNewCapacity(nPrevSize); +- pointer const pNewData = DoAllocate(nNewSize); ++ auto pNewData = DoAllocate(nNewSize); ++ auto raii = allocator_type::make_raii(pNewData); + + #if EASTL_EXCEPTIONS_ENABLED +- pointer pNewEnd = pNewData; // Assign pNewEnd a value here in case the copy throws. ++ pointer pNewEnd = allocator_type::to_raw(pNewData); // Assign pNewEnd a value here in case the copy throws. + try + { +- pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, mpEnd, pNewData); ++ pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), mpEnd, allocator_type::to_raw(pNewData)); + ::new((void*)pNewEnd) value_type(eastl::forward(args)...); + pNewEnd++; + } + catch(...) + { +- eastl::destruct(pNewData, pNewEnd); ++ eastl::destruct(allocator_type::to_raw(pNewData), pNewEnd); + DoFree(pNewData, nNewSize); + throw; + } + #else +- pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, mpEnd, pNewData); ++ pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), mpEnd, allocator_type::to_raw(pNewData)); + ::new((void*)pNewEnd) value_type(eastl::forward(args)...); + pNewEnd++; + #endif + +- eastl::destruct(mpBegin, mpEnd); ++ eastl::destruct(allocator_type::to_raw(mpBegin), mpEnd); + DoFree(mpBegin, (size_type)(internalCapacityPtr() - mpBegin)); + + mpBegin = pNewData; diff --git a/library/3rdparty/clone-EABase-EASTL.bat b/library/3rdparty/clone-EABase-EASTL.bat index c034280..eb95719 100644 --- a/library/3rdparty/clone-EABase-EASTL.bat +++ b/library/3rdparty/clone-EABase-EASTL.bat @@ -10,10 +10,10 @@ git apply ..\EABase-2.09.06.diff rmdir /S /Q .git cd .. -git clone --depth 1 -b 3.18.00 https://github.com/electronicarts/EASTL.git +git clone --depth 1 -b 3.19.05 https://github.com/electronicarts/EASTL.git @if ERRORLEVEL 1 exit /b %ERRORLEVEL% cd EASTL -git apply ..\EASTL-3.18.00.diff +git apply ..\EASTL-3.19.05.diff @if ERRORLEVEL 1 exit /b %ERRORLEVEL% rmdir /S /Q .git cd .. diff --git a/library/3rdparty/clone-EABase-EASTL.sh b/library/3rdparty/clone-EABase-EASTL.sh index b8da912..395194d 100644 --- a/library/3rdparty/clone-EABase-EASTL.sh +++ b/library/3rdparty/clone-EABase-EASTL.sh @@ -10,8 +10,8 @@ git apply ../EABase-2.09.06.diff rm -Rf .git cd .. -git clone --depth 1 -b 3.18.00 https://github.com/electronicarts/EASTL.git +git clone --depth 1 -b 3.19.05 https://github.com/electronicarts/EASTL.git cd EASTL -git apply ../EASTL-3.18.00.diff +git apply ../EASTL-3.19.05.diff rm -Rf .git cd .. From 6759f5b55babda06ca429d2d8574d41d99f6c22c Mon Sep 17 00:00:00 2001 From: Marcos Bracco Date: Wed, 22 Feb 2023 17:08:18 -0300 Subject: [PATCH 24/31] Diff for EASTL-3.19.05 update --- library/3rdparty/EASTL-3.19.05.diff | 41 +++++++++++++++++++++++-- library/3rdparty/clone-EABase-EASTL.bat | 2 +- library/3rdparty/clone-EABase-EASTL.sh | 2 +- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/library/3rdparty/EASTL-3.19.05.diff b/library/3rdparty/EASTL-3.19.05.diff index 38a8d10..af75371 100644 --- a/library/3rdparty/EASTL-3.19.05.diff +++ b/library/3rdparty/EASTL-3.19.05.diff @@ -102,6 +102,19 @@ index d645466..3c66a4e 100644 /// dummy_allocator /// /// Defines an allocator which does nothing. It returns NULL from allocate calls. +diff --git a/include/EASTL/hash_map.h b/include/EASTL/hash_map.h +index e7cad7b..8b03514 100644 +--- a/include/EASTL/hash_map.h ++++ b/include/EASTL/hash_map.h +@@ -334,7 +334,7 @@ namespace eastl + } + else + { +- node_type* const pNodeNew = ++ auto const pNodeNew = + base_type::DoAllocateNode(piecewise_construct, eastl::forward_as_tuple(eastl::forward(k)), + forward_as_tuple(eastl::forward(args)...)); + // the key might have been moved from above, so we can't use `k` anymore. diff --git a/include/EASTL/internal/atomic/atomic_integral.h b/include/EASTL/internal/atomic/atomic_integral.h index a9c96c7..674e051 100644 --- a/include/EASTL/internal/atomic/atomic_integral.h @@ -120,7 +133,7 @@ index a9c96c7..674e051 100644 } // namespace internal diff --git a/include/EASTL/internal/hashtable.h b/include/EASTL/internal/hashtable.h -index 077f5b4..d4cdfd1 100644 +index 077f5b4..3868634 100644 --- a/include/EASTL/internal/hashtable.h +++ b/include/EASTL/internal/hashtable.h @@ -103,34 +103,34 @@ namespace eastl @@ -477,7 +490,7 @@ index 077f5b4..d4cdfd1 100644 typedef typename type_select, iterator>::type insert_return_type; typedef hashtable this_type; -@@ -873,7 +904,7 @@ namespace eastl +@@ -873,14 +904,14 @@ namespace eastl }; protected: @@ -486,6 +499,14 @@ index 077f5b4..d4cdfd1 100644 size_type mnBucketCount; size_type mnElementCount; 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; ++ node_pointer node; + hash_code_t code; + size_type bucket_index; + }; @@ -916,7 +947,7 @@ namespace eastl iterator begin() EA_NOEXCEPT @@ -1050,7 +1071,7 @@ index 077f5b4..d4cdfd1 100644 { for(; pNode; pNode = pNode->mpNext) { -@@ -2011,7 +2053,7 @@ namespace eastl +@@ -2011,11 +2053,11 @@ namespace eastl typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU> template // only enabled when keys are unique eastl::pair::iterator, bool> @@ -1059,6 +1080,20 @@ index 077f5b4..d4cdfd1 100644 { const eastl::pair bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1); +- set_code(pNodeNew, c); // This is a no-op for most hashtables. ++ set_code(allocator_type::to_raw(pNodeNew), c); // This is a no-op for most hashtables. + + #if EASTL_EXCEPTIONS_ENABLED + try +@@ -2027,7 +2069,7 @@ namespace eastl + DoRehash(bRehash.second); + } + +- EASTL_ASSERT((uintptr_t)mpBucketArray != (uintptr_t)&gpEmptyBucketArray[0]); ++ EASTL_ASSERT(!allocator_type::is_empty_hashtable(mpBucketArray)); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + ++mnElementCount; @@ -2060,11 +2102,11 @@ namespace eastl // specializations of the insert function for const value_type& and value_type&&, and so the only time this function // should get called is when args refers to arguments to construct a value_type. diff --git a/library/3rdparty/clone-EABase-EASTL.bat b/library/3rdparty/clone-EABase-EASTL.bat index eb95719..380fff7 100644 --- a/library/3rdparty/clone-EABase-EASTL.bat +++ b/library/3rdparty/clone-EABase-EASTL.bat @@ -10,7 +10,7 @@ git apply ..\EABase-2.09.06.diff rmdir /S /Q .git cd .. -git clone --depth 1 -b 3.19.05 https://github.com/electronicarts/EASTL.git +git clone --depth 1 -b eastl-3.19.05 https://github.com/electronicarts/EASTL.git @if ERRORLEVEL 1 exit /b %ERRORLEVEL% cd EASTL git apply ..\EASTL-3.19.05.diff diff --git a/library/3rdparty/clone-EABase-EASTL.sh b/library/3rdparty/clone-EABase-EASTL.sh index 395194d..7d48308 100644 --- a/library/3rdparty/clone-EABase-EASTL.sh +++ b/library/3rdparty/clone-EABase-EASTL.sh @@ -10,7 +10,7 @@ git apply ../EABase-2.09.06.diff rm -Rf .git cd .. -git clone --depth 1 -b 3.19.05 https://github.com/electronicarts/EASTL.git +git clone --depth 1 -b eastl-3.19.05 https://github.com/electronicarts/EASTL.git cd EASTL git apply ../EASTL-3.19.05.diff rm -Rf .git From fb126273c9b694f7f07980d798b949e541d9a35c Mon Sep 17 00:00:00 2001 From: Marcos Bracco Date: Wed, 22 Feb 2023 17:33:39 -0300 Subject: [PATCH 25/31] update EASTL to 3.19.05 --- .../EASTL/.github/workflows/c-cpp.yml | 132 ++++ library/3rdparty/EASTL/README.md | 4 +- library/3rdparty/EASTL/doc/Design.md | 2 +- library/3rdparty/EASTL/doc/EASTL.natvis | 118 +++- library/3rdparty/EASTL/doc/FAQ.md | 2 +- .../3rdparty/EASTL/include/EASTL/algorithm.h | 146 ++++- .../3rdparty/EASTL/include/EASTL/allocator.h | 10 +- library/3rdparty/EASTL/include/EASTL/array.h | 96 ++- library/3rdparty/EASTL/include/EASTL/bit.h | 107 +++ library/3rdparty/EASTL/include/EASTL/bitset.h | 6 +- .../EASTL/include/EASTL/bonus/lru_cache.h | 2 +- .../EASTL/include/EASTL/bonus/overloaded.h | 81 +++ .../EASTL/include/EASTL/bonus/tuple_vector.h | 12 +- library/3rdparty/EASTL/include/EASTL/chrono.h | 110 ++-- .../3rdparty/EASTL/include/EASTL/compare.h | 45 ++ library/3rdparty/EASTL/include/EASTL/deque.h | 45 +- .../EASTL/include/EASTL/fixed_substring.h | 10 + .../3rdparty/EASTL/include/EASTL/hash_map.h | 186 ++++-- .../3rdparty/EASTL/include/EASTL/hash_set.h | 28 +- library/3rdparty/EASTL/include/EASTL/heap.h | 4 +- .../EASTL/internal/atomic/arch/x86/arch_x86.h | 4 +- .../atomic/arch/x86/arch_x86_exchange.h | 2 +- .../EASTL/internal/atomic/atomic_base_width.h | 2 +- .../EASTL/internal/atomic/atomic_integral.h | 2 +- .../atomic/atomic_macros/atomic_macros.h | 11 + .../atomic/atomic_macros/atomic_macros_base.h | 7 +- .../atomic/compiler/msvc/compiler_msvc.h | 1 - .../compiler/msvc/compiler_msvc_cpu_pause.h | 19 +- .../EASTL/include/EASTL/internal/config.h | 48 +- .../EASTL/include/EASTL/internal/copy_help.h | 37 +- .../EASTL/include/EASTL/internal/fixed_pool.h | 4 +- .../EASTL/include/EASTL/internal/function.h | 4 +- .../include/EASTL/internal/functional_base.h | 7 +- .../include/EASTL/internal/generic_iterator.h | 17 +- .../EASTL/include/EASTL/internal/hashtable.h | 300 +++------ .../include/EASTL/internal/integer_sequence.h | 32 +- .../include/EASTL/internal/red_black_tree.h | 42 -- .../include/EASTL/internal/thread_support.h | 86 --- .../include/EASTL/internal/type_detected.h | 180 ++++++ .../include/EASTL/internal/type_fundamental.h | 6 +- .../EASTL/include/EASTL/internal/type_pod.h | 25 +- .../include/EASTL/internal/type_properties.h | 14 + .../EASTL/internal/type_transformations.h | 38 +- .../include/EASTL/internal/type_void_t.h | 43 ++ .../3rdparty/EASTL/include/EASTL/iterator.h | 157 +++-- library/3rdparty/EASTL/include/EASTL/list.h | 33 +- library/3rdparty/EASTL/include/EASTL/map.h | 142 +++- library/3rdparty/EASTL/include/EASTL/memory.h | 41 ++ .../3rdparty/EASTL/include/EASTL/numeric.h | 97 +++ .../EASTL/include/EASTL/numeric_limits.h | 101 +++ .../3rdparty/EASTL/include/EASTL/optional.h | 24 +- library/3rdparty/EASTL/include/EASTL/queue.h | 9 +- library/3rdparty/EASTL/include/EASTL/set.h | 24 +- .../3rdparty/EASTL/include/EASTL/shared_ptr.h | 61 +- library/3rdparty/EASTL/include/EASTL/slist.h | 40 +- library/3rdparty/EASTL/include/EASTL/sort.h | 19 +- library/3rdparty/EASTL/include/EASTL/stack.h | 8 +- library/3rdparty/EASTL/include/EASTL/string.h | 217 ++++++- .../EASTL/include/EASTL/string_view.h | 248 ++++++- library/3rdparty/EASTL/include/EASTL/tuple.h | 67 +- .../EASTL/include/EASTL/type_traits.h | 9 + .../3rdparty/EASTL/include/EASTL/unique_ptr.h | 19 +- .../3rdparty/EASTL/include/EASTL/utility.h | 102 ++- .../3rdparty/EASTL/include/EASTL/variant.h | 50 +- library/3rdparty/EASTL/include/EASTL/vector.h | 45 +- library/3rdparty/EASTL/source/assert.cpp | 8 +- .../3rdparty/EASTL/source/numeric_limits.cpp | 26 + .../3rdparty/EASTL/test/source/EASTLTest.h | 2 + .../EASTL/test/source/TestAlgorithm.cpp | 235 ++++++- .../EASTL/test/source/TestAllocator.cpp | 2 + .../3rdparty/EASTL/test/source/TestArray.cpp | 47 ++ .../3rdparty/EASTL/test/source/TestChrono.cpp | 11 +- .../3rdparty/EASTL/test/source/TestDeque.cpp | 44 +- .../3rdparty/EASTL/test/source/TestExtra.cpp | 610 +++++++++++++++++- .../EASTL/test/source/TestFixedString.cpp | 52 ++ .../EASTL/test/source/TestFunctional.cpp | 34 + .../3rdparty/EASTL/test/source/TestHash.cpp | 12 +- .../EASTL/test/source/TestIterator.cpp | 111 +++- .../3rdparty/EASTL/test/source/TestList.cpp | 103 ++- .../3rdparty/EASTL/test/source/TestMap.cpp | 65 +- library/3rdparty/EASTL/test/source/TestMap.h | 30 +- .../3rdparty/EASTL/test/source/TestMemory.cpp | 44 ++ .../EASTL/test/source/TestNumericLimits.cpp | 5 + .../EASTL/test/source/TestOptional.cpp | 42 ++ .../3rdparty/EASTL/test/source/TestSList.cpp | 114 +++- .../3rdparty/EASTL/test/source/TestSet.cpp | 48 +- .../EASTL/test/source/TestSmartPtr.cpp | 39 +- .../3rdparty/EASTL/test/source/TestSort.cpp | 42 +- .../3rdparty/EASTL/test/source/TestString.inl | 40 +- .../EASTL/test/source/TestStringView.cpp | 19 +- .../EASTL/test/source/TestStringView.inl | 80 +++ .../3rdparty/EASTL/test/source/TestTuple.cpp | 51 ++ .../EASTL/test/source/TestTypeTraits.cpp | 160 ++++- .../EASTL/test/source/TestUtility.cpp | 293 ++++++++- .../EASTL/test/source/TestVariant.cpp | 139 ++-- .../3rdparty/EASTL/test/source/TestVector.cpp | 94 ++- 96 files changed, 5240 insertions(+), 952 deletions(-) create mode 100644 library/3rdparty/EASTL/.github/workflows/c-cpp.yml create mode 100644 library/3rdparty/EASTL/include/EASTL/bonus/overloaded.h create mode 100644 library/3rdparty/EASTL/include/EASTL/compare.h create mode 100644 library/3rdparty/EASTL/include/EASTL/internal/type_detected.h create mode 100644 library/3rdparty/EASTL/include/EASTL/internal/type_void_t.h diff --git a/library/3rdparty/EASTL/.github/workflows/c-cpp.yml b/library/3rdparty/EASTL/.github/workflows/c-cpp.yml new file mode 100644 index 0000000..1537c9c --- /dev/null +++ b/library/3rdparty/EASTL/.github/workflows/c-cpp.yml @@ -0,0 +1,132 @@ +name: EASTL Build & Test Pipeline + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + checkout: + name: Checkout EASTL and submodules + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + path: EASTL/ + - run: cd EASTL/ && git submodule update --init + - name: Upload checked out code + uses: actions/upload-artifact@v2.3.1 + with: + name: Code + path: EASTL/ + + build: + needs: checkout + + strategy: + fail-fast: false + matrix: + os: [ windows-latest, ubuntu-latest ] + compiler: [ clang, gcc, msvc ] + configuration: [ Debug, Release ] + exclude: + - os: windows-latest + compiler: gcc + - os: windows-latest + compiler: clang + - os: ubuntu-latest + compiler: msvc + include: + - os: windows-latest + compiler: msvc + cxxflags: '/std:c++20 /Zc:char8_t' + - os: ubuntu-latest + compiler: clang + cc: 'clang-11' + cxx: 'clang++-11' + cxxflags: '-std=c++20' + - os: ubuntu-latest + compiler: gcc + cc: 'gcc-10' + cxx: 'g++-10' + cxxflags: '-std=c++2a' + + name: Build EASTL + runs-on: ${{ matrix.os }} + + steps: + - name: Download a Build Artifact + uses: actions/download-artifact@v2.1.0 + with: + name: Code + path: Code/ + + - run: mkdir build + - run: cd build && cmake ../Code -DEASTL_BUILD_BENCHMARK:BOOL=ON -DEASTL_BUILD_TESTS:BOOL=ON + env: + CXXFLAGS: ${{ matrix.cxxflags }} + CXX: ${{ matrix.cxx }} + CC: ${{ matrix.cc }} + - run: cd build && cmake --build . --config ${{ matrix.configuration }} + - name: Upload binaries + uses: actions/upload-artifact@v2.3.1 + with: + name: Binaries-${{ matrix.os }}-${{ matrix.compiler }}-${{ matrix.configuration }} + path: build/ + + test: + needs: build + name: Run EASTL tests + strategy: + fail-fast: false + matrix: + os: [ windows-latest, ubuntu-latest ] + compiler: [ clang, msvc, gcc ] + configuration: [ Debug, Release ] + exclude: + - os: windows-latest + compiler: gcc + - os: windows-latest + compiler: clang + - os: ubuntu-latest + compiler: msvc + runs-on: ${{ matrix.os }} + + steps: + - name: Download a Build Artifact + uses: actions/download-artifact@v2.1.0 + with: + name: Binaries-${{ matrix.os }}-${{ matrix.compiler }}-${{ matrix.configuration }} + path: Binaries/ + - if: matrix.os == 'ubuntu-latest' + run: chmod 755 ./Binaries/test/EASTLTest + - run: cd Binaries/test && ctest -C ${{ matrix.configuration }} -V + + benchmark: + needs: build + name: Run EASTL benchmarks + strategy: + fail-fast: false + matrix: + os: [ windows-latest, ubuntu-latest ] + compiler: [ clang, msvc, gcc ] + configuration: [ Release ] + exclude: + - os: windows-latest + compiler: gcc + - os: windows-latest + compiler: clang + - os: ubuntu-latest + compiler: msvc + runs-on: ${{ matrix.os }} + + steps: + - name: Download a Build Artifact + uses: actions/download-artifact@v2.1.0 + with: + name: Binaries-${{ matrix.os }}-${{ matrix.compiler }}-${{ matrix.configuration }} + path: Binaries/ + - if: matrix.os == 'ubuntu-latest' + run: chmod 755 ./Binaries/benchmark/EASTLBenchmarks + - run: cd Binaries/benchmark && ctest -C ${{ matrix.configuration }} -V diff --git a/library/3rdparty/EASTL/README.md b/library/3rdparty/EASTL/README.md index 07b8ea3..8548d9e 100644 --- a/library/3rdparty/EASTL/README.md +++ b/library/3rdparty/EASTL/README.md @@ -42,13 +42,13 @@ Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on compiling and testi ## Credits And Maintainers -EASTL was created by Paul Pedriana and he maintained the project for roughly 10 years. +EASTL was created by Paul Pedriana and he maintained the project for roughly 10 years. EASTL was subsequently maintained by Roberto Parolin for more than 8 years. He was the driver and proponent for getting EASTL opensourced. Rob was a mentor to all members of the team and taught us everything we ever wanted to know about C++ spookyness. -Max Winkler is the current EASTL owner and primary maintainer within EA and is responsible for the open source repository. +After Rob, maintenance of EASTL passed to Max Winkler for roughly a year, until landing with its current maintainer Liam Mitchell. Significant EASTL contributions were made by (in alphabetical order): diff --git a/library/3rdparty/EASTL/doc/Design.md b/library/3rdparty/EASTL/doc/Design.md index bda7378..5877bb7 100644 --- a/library/3rdparty/EASTL/doc/Design.md +++ b/library/3rdparty/EASTL/doc/Design.md @@ -306,7 +306,7 @@ EASTL algorithms very much follow the philosophy of standard C++ algorithms, as EASTL algorithms are optimized at least as well as the best STL algorithms found in commercial libraries and are significantly optimized over the algorithms that come with the first-party STLs that come with compilers. Most significantly, EASTL algorithms take advantage of type traits of contained classes and take advantage of iterator types to optimize code generation. For example, if you resize an array of integers (or other "pod" type), EASTL will detect that this can be done with a memcpy instead of a slow object-by-object move as would Micrsoft STL. -The optimizations found in EASTL algorithms and the supporting code in EASTL type traits consistts of some fairly tricky advanced C++ and while it is fairly easy to read, it requires a C++ expert (language lawyer, really) to implement confidently. The result of this is that it takes more effort to develop and maintain EASTL than it would to maintain a simpler library. However, the performance advantages have been deemed worth the tradeoff. +The optimizations found in EASTL algorithms and the supporting code in EASTL type traits consists of some fairly tricky advanced C++ and while it is fairly easy to read, it requires a C++ expert (language lawyer, really) to implement confidently. The result of this is that it takes more effort to develop and maintain EASTL than it would to maintain a simpler library. However, the performance advantages have been deemed worth the tradeoff. ## Smart Pointer Design diff --git a/library/3rdparty/EASTL/doc/EASTL.natvis b/library/3rdparty/EASTL/doc/EASTL.natvis index 2fb311b..949d29d 100644 --- a/library/3rdparty/EASTL/doc/EASTL.natvis +++ b/library/3rdparty/EASTL/doc/EASTL.natvis @@ -70,7 +70,7 @@ (mPair.mFirst.heap.mnCapacity & ~kHeapMask) mPair.mFirst.heap.mpBegin,sb - mPair.mFirst.sso.mRemainingSizeField.mnRemainingSize + (SSOLayout::SSO_CAPACITY - mPair.mFirst.sso.mRemainingSizeField.mnRemainingSize) SSOLayout::SSO_CAPACITY mPair.mFirst.sso.mData,sb @@ -87,7 +87,7 @@ (mPair.mFirst.heap.mnCapacity & ~kHeapMask) mPair.mFirst.heap.mpBegin,su - mPair.mFirst.sso.mRemainingSizeField.mnRemainingSize + (SSOLayout::SSO_CAPACITY - mPair.mFirst.sso.mRemainingSizeField.mnRemainingSize) SSOLayout::SSO_CAPACITY mPair.mFirst.sso.mData,su @@ -407,14 +407,29 @@ - [{mnElementCount}] {{}} - [{mnElementCount}] {{ ... }} - - - mnBucketCount - mpBucketArray - - + [{mnElementCount}] {{}} + [{mnElementCount}] {{ ... }} + + + mnBucketCount + mpBucketArray + + + + + + entry->mValue + + entry = entry->mpNext + + + bucketIndex++ + + entry = mpBucketArray[bucketIndex] + + + + @@ -629,7 +644,88 @@ - + + + ({*this,view(noparens)}) + + + + + {(*((eastl::Internal::TupleLeaf<0,$T1,0>*)&mImpl)).mValue} + ({*this,view(noparens)}) + + (*((eastl::Internal::TupleLeaf<0,$T1,0>*)&mImpl)).mValue + + + + + {(*((eastl::Internal::TupleLeaf<0,$T1,0>*)&mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf<1,$T2,0>*)&mImpl)).mValue} + ({*this,view(noparens)}) + + (*((eastl::Internal::TupleLeaf<0,$T1,0>*)&mImpl)).mValue + (*((eastl::Internal::TupleLeaf<1,$T2,0>*)&mImpl)).mValue + + + + + {(*((eastl::Internal::TupleLeaf<0,$T1,0>*)&mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf<1,$T2,0>*)&mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf<2,$T3,0>*)&mImpl)).mValue} + ({*this,view(noparens)}) + + (*((eastl::Internal::TupleLeaf<0,$T1,0>*)&mImpl)).mValue + (*((eastl::Internal::TupleLeaf<1,$T2,0>*)&mImpl)).mValue + (*((eastl::Internal::TupleLeaf<2,$T3,0>*)&mImpl)).mValue + + + + + {(*((eastl::Internal::TupleLeaf<0,$T1,0>*)&mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf<1,$T2,0>*)&mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf<2,$T3,0>*)&mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf<3,$T4,0>*)&mImpl)).mValue} + ({*this,view(noparens)}) + + (*((eastl::Internal::TupleLeaf<0,$T1,0>*)&mImpl)).mValue + (*((eastl::Internal::TupleLeaf<1,$T2,0>*)&mImpl)).mValue + (*((eastl::Internal::TupleLeaf<2,$T3,0>*)&mImpl)).mValue + (*((eastl::Internal::TupleLeaf<3,$T4,0>*)&mImpl)).mValue + + + + + {(*((eastl::Internal::TupleLeaf<0,$T1,0>*)&mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf<1,$T2,0>*)&mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf<2,$T3,0>*)&mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf<3,$T4,0>*)&mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf<4,$T5,0>*)&mImpl)).mValue} + ({*this,view(noparens)}) + + (*((eastl::Internal::TupleLeaf<0,$T1,0>*)&mImpl)).mValue + (*((eastl::Internal::TupleLeaf<1,$T2,0>*)&mImpl)).mValue + (*((eastl::Internal::TupleLeaf<2,$T3,0>*)&mImpl)).mValue + (*((eastl::Internal::TupleLeaf<3,$T4,0>*)&mImpl)).mValue + (*((eastl::Internal::TupleLeaf<4,$T5,0>*)&mImpl)).mValue + + + + + {(*((eastl::Internal::TupleLeaf<0,$T1,0>*)&mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf<1,$T2,0>*)&mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf<2,$T3,0>*)&mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf<3,$T4,0>*)&mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf<4,$T5,0>*)&mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf<5,$T6,0>*)&mImpl)).mValue} + ({*this,view(noparens)}) + + (*((eastl::Internal::TupleLeaf<0,$T1,0>*)&mImpl)).mValue + (*((eastl::Internal::TupleLeaf<1,$T2,0>*)&mImpl)).mValue + (*((eastl::Internal::TupleLeaf<2,$T3,0>*)&mImpl)).mValue + (*((eastl::Internal::TupleLeaf<3,$T4,0>*)&mImpl)).mValue + (*((eastl::Internal::TupleLeaf<4,$T5,0>*)&mImpl)).mValue + (*((eastl::Internal::TupleLeaf<5,$T6,0>*)&mImpl)).mValue + + + + + {(*((eastl::Internal::TupleLeaf<0,$T1,0>*)&mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf<1,$T2,0>*)&mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf<2,$T3,0>*)&mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf<3,$T4,0>*)&mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf<4,$T5,0>*)&mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf<5,$T6,0>*)&mImpl)).mValue}, {(*((eastl::Internal::TupleLeaf<6,$T7,0>*)&mImpl)).mValue} + ({*this,view(noparens)}) + + (*((eastl::Internal::TupleLeaf<0,$T1,0>*)&mImpl)).mValue + (*((eastl::Internal::TupleLeaf<1,$T2,0>*)&mImpl)).mValue + (*((eastl::Internal::TupleLeaf<2,$T3,0>*)&mImpl)).mValue + (*((eastl::Internal::TupleLeaf<3,$T4,0>*)&mImpl)).mValue + (*((eastl::Internal::TupleLeaf<4,$T5,0>*)&mImpl)).mValue + (*((eastl::Internal::TupleLeaf<5,$T6,0>*)&mImpl)).mValue + (*((eastl::Internal::TupleLeaf<6,$T7,0>*)&mImpl)).mValue + + diff --git a/library/3rdparty/EASTL/doc/FAQ.md b/library/3rdparty/EASTL/doc/FAQ.md index e80172b..1444c48 100644 --- a/library/3rdparty/EASTL/doc/FAQ.md +++ b/library/3rdparty/EASTL/doc/FAQ.md @@ -211,7 +211,7 @@ EASTL additions/amendments to std STL * vector and string have set_capacity(). * string has sprintf(), append_sprintf(), trim(), compare_i(), make_lower(), make_upper(). * deque allows you to specify the subarray size. -* list has a push_back(void) and push_back(void) function. +* list has a push_front(void) and push_back(void) function. * hash_map, hash_set, etc. have find_as(). EASTL coverage of TR1 (tr1 refers to proposed additions for the next C++ standard library, ~2008) diff --git a/library/3rdparty/EASTL/include/EASTL/algorithm.h b/library/3rdparty/EASTL/include/EASTL/algorithm.h index da35c2e..6d758c8 100644 --- a/library/3rdparty/EASTL/include/EASTL/algorithm.h +++ b/library/3rdparty/EASTL/include/EASTL/algorithm.h @@ -128,6 +128,7 @@ // iter_swap // lexicographical_compare // lexicographical_compare +// lexicographical_compare_three_way // lower_bound // lower_bound // make_heap Found in heap.h @@ -163,6 +164,8 @@ // random_shuffle // 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 #include #include +#include EA_DISABLE_ALL_VC_WARNINGS(); @@ -806,18 +810,18 @@ namespace eastl template inline T&& median_impl(T&& a, T&& b, T&& c) { - if(a < b) + if(eastl::less()(a, b)) { - if(b < c) + if(eastl::less()(b, c)) return eastl::forward(b); - else if(a < c) + else if(eastl::less()(a, c)) return eastl::forward(c); else return eastl::forward(a); } - else if(a < c) + else if(eastl::less()(a, c)) return eastl::forward(a); - else if(b < c) + else if(eastl::less()(b, c)) return eastl::forward(c); return eastl::forward(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::iterator_category IIC; - typedef typename eastl::iterator_traits::iterator_category OIC; - typedef typename eastl::iterator_traits::value_type value_type_input; - typedef typename eastl::iterator_traits::value_type value_type_output; - const bool canBeMemmoved = eastl::is_trivially_copyable::value && - eastl::is_same::value && - (eastl::is_pointer::value || eastl::is_same::value) && - (eastl::is_pointer::value || eastl::is_same::value); + const bool canBeMemmoved = internal::can_be_memmoved_helper::value; return eastl::move_and_copy_backward_helper::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 + 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 + 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 + 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)) diff --git a/library/3rdparty/EASTL/include/EASTL/allocator.h b/library/3rdparty/EASTL/include/EASTL/allocator.h index 84d0445..3c66a4e 100644 --- a/library/3rdparty/EASTL/include/EASTL/allocator.h +++ b/library/3rdparty/EASTL/include/EASTL/allocator.h @@ -143,8 +143,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 /// @@ -168,8 +169,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. @@ -370,12 +372,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/library/3rdparty/EASTL/include/EASTL/array.h b/library/3rdparty/EASTL/include/EASTL/array.h index 05d5d32..34ad07d 100644 --- a/library/3rdparty/EASTL/include/EASTL/array.h +++ b/library/3rdparty/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 + inline synth_three_way_result operator<=>(const array& a, const array& b) + { + return eastl::lexicographical_compare_three_way(&a.mValue[0], &a.mValue[N], &b.mValue[0], &b.mValue[N], synth_three_way{}); + } +#else template EA_CPP14_CONSTEXPR inline bool operator<(const array& a, const array& 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 inline void swap(array& a, array& b) @@ -478,9 +485,96 @@ namespace eastl return internal::to_array(eastl::move(a), eastl::make_index_sequence{}); } +#if EASTL_TUPLE_ENABLED + + template + class tuple_size> : public integral_constant + { + }; + + template + class tuple_size> : public integral_constant + { + }; + + template + class tuple_element> + { + public: + using type = T; + }; + + template + class tuple_element> + { + public: + using type = const T; + }; + + template + struct GetArray + { + template + static EA_CONSTEXPR T& getInternal(array& a) + { + return a[I]; + } + + template + static EA_CONSTEXPR const T& getInternal(const array& a) + { + return a[I]; + } + + template + static EA_CONSTEXPR T&& getInternal(array&& a) + { + return eastl::forward(a[I]); + } + }; + + template + EA_CONSTEXPR tuple_element_t>& get(array& p) + { + return GetArray::getInternal(p); + } + + template + EA_CONSTEXPR const tuple_element_t>& get(const array& p) + { + return GetArray::getInternal(p); + } + + template + EA_CONSTEXPR tuple_element_t>&& get(array&& p) + { + return GetArray::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 + + template + class std::tuple_size<::eastl::array> : public ::eastl::integral_constant + { + }; + + template + struct std::tuple_element> + { + 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/library/3rdparty/EASTL/include/EASTL/bit.h b/library/3rdparty/EASTL/include/EASTL/bit.h index 64efe48..0eeeed0 100644 --- a/library/3rdparty/EASTL/include/EASTL/bit.h +++ b/library/3rdparty/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 >> + EA_CONSTEXPR int countl_zero(const T num) EA_NOEXCEPT + { + EA_CONSTEXPR auto DIGITS = eastl::numeric_limits::digits; + EA_CONSTEXPR auto DIGITS_U = eastl::numeric_limits::digits; + EA_CONSTEXPR auto DIGITS_ULL = eastl::numeric_limits::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(num)) - DIFF; + } + else + { + EA_CONSTEXPR auto DIFF = DIGITS_ULL - DIGITS; + return EASTL_COUNT_LEADING_ZEROES(static_cast(num)) - DIFF; + } + } + + template >> + EA_CONSTEXPR bool has_single_bit(const T num) EA_NOEXCEPT + { + return num != 0 && (num & (num - 1)) == 0; + } + + template >> + EA_CONSTEXPR T bit_ceil(const T num) EA_NOEXCEPT + { + if (num <= 1U) + { + return T(1); + } + + const auto shift = eastl::numeric_limits::digits - eastl::countl_zero(static_cast(num - 1)); + return static_cast(T(1) << shift); + } + + template >> + EA_CONSTEXPR T bit_floor(const T num) EA_NOEXCEPT + { + if (num == 0) + { + return T(0); + } + + const auto shift = eastl::numeric_limits::digits - eastl::countl_zero(num) - 1; + return static_cast(T(1) << shift); + } + + template >> + EA_CONSTEXPR T bit_width(const T num) EA_NOEXCEPT + { + return static_cast(eastl::numeric_limits::digits - eastl::countl_zero(num)); + } + #endif + } // namespace eastl #endif // EASTL_BIT_H diff --git a/library/3rdparty/EASTL/include/EASTL/bitset.h b/library/3rdparty/EASTL/include/EASTL/bitset.h index 8778372..c31831a 100644 --- a/library/3rdparty/EASTL/include/EASTL/bitset.h +++ b/library/3rdparty/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 inline bool bitset::operator!=(const this_type& x) const { return !base_type::operator==(x); } - +#endif template inline bool bitset::test(size_type i) const diff --git a/library/3rdparty/EASTL/include/EASTL/bonus/lru_cache.h b/library/3rdparty/EASTL/include/EASTL/bonus/lru_cache.h index 46d053d..a8d7c33 100644 --- a/library/3rdparty/EASTL/include/EASTL/bonus/lru_cache.h +++ b/library/3rdparty/EASTL/include/EASTL/bonus/lru_cache.h @@ -122,7 +122,7 @@ namespace eastl } lru_cache(std::initializer_list> il) - : lru_cache(il.size()) + : lru_cache(static_cast(il.size())) { for(auto& p : il) insert_or_assign(p.first, p.second); diff --git a/library/3rdparty/EASTL/include/EASTL/bonus/overloaded.h b/library/3rdparty/EASTL/include/EASTL/bonus/overloaded.h new file mode 100644 index 0000000..55ca158 --- /dev/null +++ b/library/3rdparty/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 +#include + + +#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 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 + struct overloaded; + + template + struct overloaded : T + { + template + EA_CPP14_CONSTEXPR overloaded(U&& u) : T(eastl::forward(u)) + { + } + + using T::operator(); + }; + + template + struct overloaded : T, overloaded + { + template + EA_CPP14_CONSTEXPR overloaded(U&& u, V&&... v) : T(eastl::forward(u)), overloaded(eastl::forward(v)...) + { + } + + using T::operator(); + using overloaded::operator(); + }; + + #ifdef __cpp_deduction_guides + template + overloaded(T...) -> overloaded; + #endif + + /////////////////////////////////////////////////////////////////////////// + /// make_overloaded + /// + /// Helper function to create an overloaded instance when lacking deduction guides. + /// make_overloaded(f1, f2, f3) == overloaded{f1, f2, f3} + /////////////////////////////////////////////////////////////////////////// + template + EA_CPP14_CONSTEXPR overloaded::type...> make_overloaded(T&&... t) + { + return overloaded::type...>{eastl::forward(t)...}; + } + +} // namespace eastl + +#endif // EASTL_OVERLOADED_H \ No newline at end of file diff --git a/library/3rdparty/EASTL/include/EASTL/bonus/tuple_vector.h b/library/3rdparty/EASTL/include/EASTL/bonus/tuple_vector.h index 7123c57..6ade75a 100644 --- a/library/3rdparty/EASTL/include/EASTL/bonus/tuple_vector.h +++ b/library/3rdparty/EASTL/include/EASTL/bonus/tuple_vector.h @@ -340,13 +340,13 @@ struct TupleVecIterCompatible, TupleTypes> : // storing - and harmoniously updating on each modification - a full tuple of pointers to the tupleVec's data template struct TupleVecIter, Ts...> - : public iterator, eastl_size_t, tuple, tuple> + : public iterator, eastl_size_t, tuple, tuple> { private: typedef TupleVecIter, Ts...> this_type; typedef eastl_size_t size_type; - typedef iterator, eastl_size_t, tuple, tuple> iter_type; + typedef iterator, eastl_size_t, tuple, tuple> iter_type; template friend struct TupleVecIter; @@ -1411,7 +1411,6 @@ class move_iterator, T { public: typedef TupleVecInternal::TupleVecIter, 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 traits_type; typedef typename traits_type::iterator_category iterator_category; @@ -1477,6 +1476,13 @@ class move_iterator, T { 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; + friend is_iterator_wrapper; }; template diff --git a/library/3rdparty/EASTL/include/EASTL/chrono.h b/library/3rdparty/EASTL/include/EASTL/chrono.h index 5d8ca42..4b94fe4 100644 --- a/library/3rdparty/EASTL/include/EASTL/chrono.h +++ b/library/3rdparty/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 @@ -50,12 +50,9 @@ #if defined(EA_PLATFORM_MICROSOFT) && !defined(EA_PLATFORM_MINGW) // Nothing to do -#elif defined(EA_PLATFORM_SONY) - #include - #include #elif defined(EA_PLATFORM_APPLE) #include -#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 @@ -104,7 +101,7 @@ namespace chrono namespace Internal { /////////////////////////////////////////////////////////////////////////////// - // IsRatio + // IsRatio /////////////////////////////////////////////////////////////////////////////// template struct IsRatio : eastl::false_type {}; template struct IsRatio> : eastl::true_type {}; @@ -114,7 +111,7 @@ namespace chrono /////////////////////////////////////////////////////////////////////////////// - // IsDuration + // IsDuration /////////////////////////////////////////////////////////////////////////////// template struct IsDuration : eastl::false_type{}; template struct IsDuration> : eastl::true_type{}; @@ -124,7 +121,7 @@ namespace chrono /////////////////////////////////////////////////////////////////////////////// - // RatioGCD + // RatioGCD /////////////////////////////////////////////////////////////////////////////// template struct RatioGCD @@ -197,10 +194,10 @@ namespace chrono /////////////////////////////////////////////////////////////////////////////// - // duration_cast + // duration_cast /////////////////////////////////////////////////////////////////////////////// template - inline typename eastl::enable_if::value, ToDuration>::type + inline typename eastl::enable_if::value, ToDuration>::type duration_cast(const duration& d) { typedef typename duration::this_type FromDuration; @@ -209,12 +206,12 @@ namespace chrono /////////////////////////////////////////////////////////////////////////////// - // duration + // duration /////////////////////////////////////////////////////////////////////////////// template class duration { - Rep mRep; + Rep mRep; public: typedef Rep rep; @@ -222,7 +219,7 @@ namespace chrono typedef duration 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 inline EA_CONSTEXPR explicit duration( @@ -258,12 +255,12 @@ namespace chrono : mRep(duration_cast(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::zero()); } EA_CONSTEXPR inline static duration min() { return duration(duration_values::min()); } @@ -314,7 +311,7 @@ namespace chrono duration::type, Period1> EASTL_FORCE_INLINE operator*(const duration& lhs, const Rep2& rhs) { - typedef typename duration, Period1>::type common_duration_t; + typedef duration::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 + template 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, nano>::type SystemClock_Period; - typedef eastl::ratio_multiply, nano>::type SteadyClock_Period; + typedef eastl::ratio_multiply, nano>::type SystemClock_Period; + typedef eastl::ratio_multiply, 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 struct common_type, chrono::duration> @@ -680,7 +689,7 @@ namespace chrono /////////////////////////////////////////////////////////////////////////////// - // time_point common_type specialization + // time_point common_type specialization /////////////////////////////////////////////////////////////////////////////// template struct common_type, chrono::time_point> @@ -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/library/3rdparty/EASTL/include/EASTL/compare.h b/library/3rdparty/EASTL/include/EASTL/compare.h new file mode 100644 index 0000000..9bc3bd6 --- /dev/null +++ b/library/3rdparty/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 + +namespace eastl +{ + +#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) + struct synth_three_way + { + template + constexpr auto operator()(const T& t, const U& u) const requires requires + { + {t < u}->std::convertible_to; + {u < t}->std::convertible_to; + } + { + if constexpr (std::three_way_comparable_with) + { + return t <=> u; + } + else + { + return (t < u) ? std::weak_ordering::less : + (u < t) ? std::weak_ordering::greater : + std::weak_ordering::equivalent; + } + } + }; + + template + using synth_three_way_result = decltype(synth_three_way{}(declval(), declval())); +#endif + +} // namespace eastl + + +#endif // Header include guard \ No newline at end of file diff --git a/library/3rdparty/EASTL/include/EASTL/deque.h b/library/3rdparty/EASTL/include/EASTL/deque.h index c2d55b1..9a812c9 100644 --- a/library/3rdparty/EASTL/include/EASTL/deque.h +++ b/library/3rdparty/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 + inline synth_three_way_result operator<=>(const deque& a, const deque& b) + { + return eastl::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end(), synth_three_way{}); + } + +#else template inline bool operator!=(const deque& a, const deque& b) { @@ -2648,6 +2656,7 @@ namespace eastl { return !(a < b); } +#endif template inline void swap(deque& a, deque& b) @@ -2661,17 +2670,39 @@ namespace eastl // https://en.cppreference.com/w/cpp/container/deque/erase2 /////////////////////////////////////////////////////////////////////// template - void erase(deque& c, const U& value) + typename deque::size_type erase(deque& 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::size_type>(numRemoved); } template - void erase_if(deque& 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::size_type erase_if(deque& 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::size_type>(numRemoved); } diff --git a/library/3rdparty/EASTL/include/EASTL/fixed_substring.h b/library/3rdparty/EASTL/include/EASTL/fixed_substring.h index 033052f..e186cfc 100644 --- a/library/3rdparty/EASTL/include/EASTL/fixed_substring.h +++ b/library/3rdparty/EASTL/include/EASTL/fixed_substring.h @@ -108,6 +108,10 @@ namespace eastl { } + fixed_substring(const fixed_substring& x) + : fixed_substring(static_cast(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/library/3rdparty/EASTL/include/EASTL/hash_map.h b/library/3rdparty/EASTL/include/EASTL/hash_map.h index c363597..8b03514 100644 --- a/library/3rdparty/EASTL/include/EASTL/hash_map.h +++ b/library/3rdparty/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 hashMap; /// i = hashMap.find_as("hello", hash(), equal_to_2()); /// - template , typename Predicate = eastl::equal_to, + template , typename Predicate = eastl::equal_to, typename Allocator = EASTLAllocatorType, bool bCacheHashCode = false> class hash_map : public hashtable, Allocator, eastl::use_first >, Predicate, Hash, mod_range_hashing, default_ranged_hash, prime_rehash_policy, bCacheHashCode, true, true> { public: - typedef hashtable, Allocator, - eastl::use_first >, - Predicate, Hash, mod_range_hashing, default_ranged_hash, + typedef hashtable, Allocator, + eastl::use_first >, + Predicate, Hash, mod_range_hashing, default_ranged_hash, prime_rehash_policy, bCacheHashCode, true, true> base_type; typedef hash_map 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 >(), 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 >(), 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 hm = { {3,"c"}, {4,"d"}, {5,"e"} }; ) - /// - hash_map(std::initializer_list ilist, size_type nBucketCount = 0, const Hash& hashFunction = Hash(), + /// + hash_map(std::initializer_list 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 >(), 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 - 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 >(), 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 + inline insert_return_type try_emplace(const key_type& k, Args&&... args) + { + return try_emplace_forwarding(k, eastl::forward(args)...); + } + + template + inline insert_return_type try_emplace(key_type&& k, Args&&... args) { + return try_emplace_forwarding(eastl::move(k), eastl::forward(args)...); + } + + template + 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)...); + return base_type::DoGetResultIterator(true_type(), result); + } + + template + 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)...); + return base_type::DoGetResultIterator(true_type(), result); + } + private: + template + 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(key_data.node, base_type::mpBucketArray + key_data.bucket_index), false); + } + else + { + auto const pNodeNew = + base_type::DoAllocateNode(piecewise_construct, eastl::forward_as_tuple(eastl::forward(k)), + forward_as_tuple(eastl::forward(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(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 - void erase_if(eastl::hash_map& c, UserPredicate predicate) + typename eastl::hash_map::size_type erase_if(eastl::hash_map& 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 Predicate = eastl::equal_to, @@ -322,9 +380,9 @@ namespace eastl Hash, mod_range_hashing, default_ranged_hash, prime_rehash_policy, bCacheHashCode, true, false> { public: - typedef hashtable, Allocator, - eastl::use_first >, - Predicate, Hash, mod_range_hashing, default_ranged_hash, + typedef hashtable, Allocator, + eastl::use_first >, + Predicate, Hash, mod_range_hashing, default_ranged_hash, prime_rehash_policy, bCacheHashCode, true, false> base_type; typedef hash_multimap 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 >(), 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 >(), 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 hm = { {3,"c"}, {3,"C"}, {4,"d"} }; ) - /// - hash_multimap(std::initializer_list ilist, size_type nBucketCount = 0, const Hash& hashFunction = Hash(), + /// + hash_multimap(std::initializer_list 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 >(), 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 - 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 >(), 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 - void erase_if(eastl::hash_multimap& c, UserPredicate predicate) + typename eastl::hash_multimap::size_type erase_if(eastl::hash_multimap& 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 - inline bool operator==(const hash_map& a, + inline bool operator==(const hash_map& a, const hash_map& b) { typedef typename hash_map::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 - inline bool operator!=(const hash_map& a, + inline bool operator!=(const hash_map& a, const hash_map& b) { return !(a == b); } - +#endif template - inline bool operator==(const hash_multimap& a, + inline bool operator==(const hash_multimap& a, const hash_multimap& b) { typedef typename hash_multimap::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 aRange; eastl::pair 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 - inline bool operator!=(const hash_multimap& a, + inline bool operator!=(const hash_multimap& a, const hash_multimap& b) { return !(a == b); } +#endif } // namespace eastl #endif // Header include guard - - - - - - diff --git a/library/3rdparty/EASTL/include/EASTL/hash_set.h b/library/3rdparty/EASTL/include/EASTL/hash_set.h index c075975..3215d36 100644 --- a/library/3rdparty/EASTL/include/EASTL/hash_set.h +++ b/library/3rdparty/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(), allocator) { // Empty @@ -207,8 +218,9 @@ namespace eastl /// /// https://en.cppreference.com/w/cpp/container/unordered_set/erase_if template - void erase_if(eastl::hash_set& c, UserPredicate predicate) + typename eastl::hash_set::size_type erase_if(eastl::hash_set& 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 - void erase_if(eastl::hash_multiset& c, UserPredicate predicate) + typename eastl::hash_multiset::size_type erase_if(eastl::hash_multiset& 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 inline bool operator!=(const hash_set& a, const hash_set& b) { return !(a == b); } - +#endif template inline bool operator==(const hash_multiset& a, @@ -443,12 +459,14 @@ namespace eastl return true; } +#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) template inline bool operator!=(const hash_multiset& a, const hash_multiset& b) { return !(a == b); } +#endif } // namespace eastl diff --git a/library/3rdparty/EASTL/include/EASTL/heap.h b/library/3rdparty/EASTL/include/EASTL/heap.h index f0e770b..a8e4260 100644 --- a/library/3rdparty/EASTL/include/EASTL/heap.h +++ b/library/3rdparty/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()(*(first + parentPosition), value); parentPosition = (position - 1) >> 1) { *(first + position) = eastl::forward(*(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()(*(first + childPosition), *(first + (childPosition - 1)))) // Choose the larger of the two children. --childPosition; *(first + position) = eastl::forward(*(first + childPosition)); // Swap positions with this child. position = childPosition; diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86.h index 142a514..77c383a 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86.h +++ b/library/3rdparty/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/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_exchange.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_exchange.h index 624d2f5..b1de7d8 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_exchange.h +++ b/library/3rdparty/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/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_base_width.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_base_width.h index ca47618..ac76097 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_base_width.h +++ b/library/3rdparty/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/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_integral.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_integral.h index 96858de..674e051 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_integral.h +++ b/library/3rdparty/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/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros.h index 941ac51..437b221 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros.h @@ -10,6 +10,7 @@ #pragma once #endif +#include #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/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros_base.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros_base.h index f03720d..486e137 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros_base.h +++ b/library/3rdparty/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 atomic macro not implemented!") + static_assert(!eastl::is_same_v, "eastl::atomic atomic macro not implemented!") /* Compiler && Arch Not Implemented */ diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc.h index 6df8c05..90901ee 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc.h @@ -12,7 +12,6 @@ EA_DISABLE_ALL_VC_WARNINGS(); -#include #include EA_RESTORE_ALL_VC_WARNINGS(); diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cpu_pause.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cpu_pause.h index 720701a..5f436b8 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cpu_pause.h +++ b/library/3rdparty/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/library/3rdparty/EASTL/include/EASTL/internal/config.h b/library/3rdparty/EASTL/include/EASTL/internal/config.h index 8dc1420..733595e 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/config.h +++ b/library/3rdparty/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.19.05" + #define EASTL_VERSION_N 31905 #endif @@ -669,6 +669,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 // @@ -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::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 diff --git a/library/3rdparty/EASTL/include/EASTL/internal/copy_help.h b/library/3rdparty/EASTL/include/EASTL/internal/copy_help.h index 67b5d87..0b2c1b8 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/copy_help.h +++ b/library/3rdparty/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 + using is_contiguous_iterator_helper = eastl::is_same; + #else + template + using is_contiguous_iterator_helper = eastl::false_type; + #endif + + template + struct can_be_memmoved_helper { + using IIC = typename eastl::iterator_traits::iterator_category; + using OIC = typename eastl::iterator_traits::iterator_category; + using value_type_input = typename eastl::iterator_traits::value_type; + using value_type_output = typename eastl::iterator_traits::value_type; + + static constexpr bool value = eastl::is_trivially_copyable::value && + eastl::is_same::value && + (eastl::is_pointer::value || is_contiguous_iterator_helper::value) && + (eastl::is_pointer::value || is_contiguous_iterator_helper::value); + + }; + } template inline OutputIterator move_and_copy_chooser(InputIterator first, InputIterator last, OutputIterator result) { typedef typename eastl::iterator_traits::iterator_category IIC; - typedef typename eastl::iterator_traits::iterator_category OIC; - typedef typename eastl::iterator_traits::value_type value_type_input; - typedef typename eastl::iterator_traits::value_type value_type_output; - const bool canBeMemmoved = eastl::is_trivially_copyable::value && - eastl::is_same::value && - (eastl::is_pointer::value || eastl::is_same::value) && - (eastl::is_pointer::value || eastl::is_same::value); + const bool canBeMemmoved = internal::can_be_memmoved_helper::value; return eastl::move_and_copy_helper::move_or_copy(first, last, result); // Need to chose based on the input iterator tag and not the output iterator tag, because containers accept input ranges of iterator types different than self. } @@ -143,7 +164,7 @@ namespace eastl template inline OutputIterator move_and_copy_unwrapper(InputIterator first, InputIterator last, OutputIterator result) { - return OutputIterator(eastl::move_and_copy_chooser(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(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/library/3rdparty/EASTL/include/EASTL/internal/fixed_pool.h b/library/3rdparty/EASTL/include/EASTL/internal/fixed_pool.h index 4d71035..b56675d 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/fixed_pool.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/fixed_pool.h @@ -1480,12 +1480,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/library/3rdparty/EASTL/include/EASTL/internal/function.h b/library/3rdparty/EASTL/include/EASTL/internal/function.h index 785969d..ace71d8 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/function.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/function.h @@ -133,7 +133,7 @@ namespace eastl { return !f; } - +#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) template bool operator==(std::nullptr_t, const function& f) EA_NOEXCEPT { @@ -151,7 +151,7 @@ namespace eastl { return !!f; } - +#endif template void swap(function& lhs, function& rhs) { diff --git a/library/3rdparty/EASTL/include/EASTL/internal/functional_base.h b/library/3rdparty/EASTL/include/EASTL/internal/functional_base.h index ef27800..de446db 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/functional_base.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/functional_base.h @@ -118,7 +118,8 @@ namespace eastl template struct is_invocable_r_impl::type>, Args...> - : public is_convertible::type, R> {}; + : public disjunction::type, R>, + is_same::type, void>> {}; template struct is_invocable_r : public is_invocable_r_impl {}; @@ -232,7 +233,7 @@ namespace eastl T& get() const EA_NOEXCEPT; template - typename eastl::result_of::type operator() (ArgTypes&&...) const; + typename eastl::invoke_result::type operator() (ArgTypes&&...) const; private: T* val; @@ -269,7 +270,7 @@ namespace eastl template template - typename eastl::result_of::type reference_wrapper::operator() (ArgTypes&&... args) const + typename eastl::invoke_result::type reference_wrapper::operator() (ArgTypes&&... args) const { return eastl::invoke(*val, eastl::forward(args)...); } diff --git a/library/3rdparty/EASTL/include/EASTL/internal/generic_iterator.h b/library/3rdparty/EASTL/include/EASTL/internal/generic_iterator.h index b32998a..0f1e28b 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/generic_iterator.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/generic_iterator.h @@ -56,7 +56,6 @@ namespace eastl typedef typename eastl::iterator_traits::reference reference; typedef typename eastl::iterator_traits::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 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; + friend is_iterator_wrapper; + }; // 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 intVector; @@ -196,7 +204,10 @@ namespace eastl /// template inline typename eastl::is_iterator_wrapper_helper::value>::iterator_type unwrap_generic_iterator(Iterator it) - { return eastl::is_iterator_wrapper_helper::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::value>::get_unwrapped(it); + } } // namespace eastl diff --git a/library/3rdparty/EASTL/include/EASTL/internal/hashtable.h b/library/3rdparty/EASTL/include/EASTL/internal/hashtable.h index 9f56ed2..3868634 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/hashtable.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/hashtable.h @@ -910,6 +910,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_pointer 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); @@ -1034,11 +1040,6 @@ namespace eastl template iterator emplace_hint(const_iterator position, Args&&... args); - template insert_return_type try_emplace(const key_type& k, Args&&... args); - template insert_return_type try_emplace(key_type&& k, Args&&... args); - template iterator try_emplace(const_iterator position, const key_type& k, Args&&... args); - template 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); @@ -1231,6 +1232,9 @@ namespace eastl bucket_array_type DoAllocateBuckets(size_type n); void DoFreeBuckets(bucket_array_type pBucketArray, size_type n); + template , ENABLE_IF_TRUETYPE(Enabled) = nullptr> // only enabled when keys are unique + eastl::pair DoInsertUniqueNode(const key_type& k, hash_code_t c, size_type n, node_pointer pNodeNew); + template eastl::pair DoInsertValue(BoolConstantT, Args&&... args); @@ -1309,6 +1313,7 @@ namespace eastl void DoRehash(size_type nBucketCount); node_pointer DoFindNode(node_pointer pNode, const key_type& k, hash_code_t c) const; + NodeFindKeyData DoFindKeyData(const key_type& k) const; template ENABLE_IF_HAS_HASHCODE(T, node_type) DoFindNode(T* pNode, hash_code_t c) const @@ -1324,6 +1329,14 @@ namespace eastl template node_pointer DoFindNodeT(node_pointer pNode, const U& u, BinaryPredicate predicate) const; + private: + template , ENABLE_IF_TRUETYPE(Enabled) = nullptr> + eastl::pair DoInsertValueExtraForwarding(const key_type& k, + hash_code_t c, + node_pointer pNodeNew, + V&& value); + + }; // class hashtable @@ -1995,6 +2008,16 @@ namespace eastl } + template + inline typename hashtable::NodeFindKeyData + hashtable::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 @@ -2026,6 +2049,41 @@ namespace eastl } + template + template // only enabled when keys are unique + eastl::pair::iterator, bool> + hashtable::DoInsertUniqueNode(const key_type& k, hash_code_t c, size_type n, node_pointer pNodeNew) + { + const eastl::pair bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1); + + set_code(allocator_type::to_raw(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(!allocator_type::is_empty_hashtable(mpBucketArray)); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + ++mnElementCount; + + return eastl::pair(iterator(pNodeNew, mpBucketArray + n), true); + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + EA_CONSTEXPR_IF(bDeleteOnException) { DoFreeNode(pNodeNew); } + throw; + } + #endif + } template @@ -2052,34 +2110,7 @@ namespace eastl if(pNode == NULL) // If value is not present... add it. { - const eastl::pair bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1); - - set_code(allocator_type::to_raw(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(!allocator_type::is_empty_hashtable(mpBucketArray)); - pNodeNew->mpNext = mpBucketArray[n]; - mpBucketArray[n] = pNodeNew; - ++mnElementCount; - - return eastl::pair(iterator(pNodeNew, mpBucketArray + n), true); - #if EASTL_EXCEPTIONS_ENABLED - } - catch(...) - { - DoFreeNode(pNodeNew); - throw; - } - #endif + return DoInsertUniqueNode(k, c, n, pNodeNew); } else { @@ -2178,13 +2209,32 @@ 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 template - eastl::pair::iterator, bool> + inline eastl::pair::iterator, bool> hashtable::DoInsertValueExtra(BoolConstantT, const key_type& k, hash_code_t c, node_pointer pNodeNew, value_type&& value, ENABLE_IF_TRUETYPE(BoolConstantT)) // true_type means bUniqueKeys is true. + { + return DoInsertValueExtraForwarding(k, c, pNodeNew, eastl::move(value)); + } + + template + template + inline eastl::pair::iterator, bool> + hashtable::DoInsertValueExtra(BoolConstantT, const key_type& k, + hash_code_t c, node_pointer pNodeNew, const value_type& value, ENABLE_IF_TRUETYPE(BoolConstantT)) // true_type means bUniqueKeys is true. + { + return DoInsertValueExtraForwarding(k, c, pNodeNew, value); + } + + template + template // true_type means bUniqueKeys is true. + eastl::pair::iterator, bool> + hashtable::DoInsertValueExtraForwarding(const key_type& k, + hash_code_t c, node_pointer 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. @@ -2193,57 +2243,19 @@ namespace eastl if(pNode == NULL) // If value is not present... add it. { - const eastl::pair 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) { auto raii = allocator_type::make_raii(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(value)); // It's expected that pNodeNew was allocated with allocate_uninitialized_node. + return DoInsertUniqueNode(k, c, n, pNodeNew); } else { pNodeNew = DoAllocateNode(eastl::move(value)); - #if EASTL_EXCEPTIONS_ENABLED - nodeAllocated = true; - #endif + return DoInsertUniqueNode(k, c, n, pNodeNew); } - - set_code(allocator_type::to_raw(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(!allocator_type::is_empty_hashtable(mpBucketArray)); - pNodeNew->mpNext = mpBucketArray[n]; - mpBucketArray[n] = pNodeNew; - ++mnElementCount; - - return eastl::pair(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. @@ -2354,79 +2366,6 @@ namespace eastl #endif } - - template - template - eastl::pair::iterator, bool> - hashtable::DoInsertValueExtra(BoolConstantT, const key_type& k, hash_code_t c, node_pointer 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_pointer const pNode = DoFindNode(mpBucketArray[n], k, c); - - if(pNode == NULL) // If value is not present... add it. - { - const eastl::pair 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) - { - auto raii = allocator_type::make_raii(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(allocator_type::to_raw(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(!allocator_type::is_empty_hashtable(mpBucketArray)); - pNodeNew->mpNext = mpBucketArray[n]; - mpBucketArray[n] = pNodeNew; - ++mnElementCount; - - return eastl::pair(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(pNode, mpBucketArray + n), false); - } - - template template @@ -2753,54 +2692,6 @@ namespace eastl return DoGetResultIterator(has_unique_keys_type(), result); } - template - template - // inline eastl::pair::iterator, bool> - inline typename hashtable::insert_return_type - hashtable::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)...)); - } - - template - template - // inline eastl::pair::iterator, bool> - inline typename hashtable::insert_return_type - hashtable::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)...)); - } - - template - template - inline typename hashtable::iterator - hashtable::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)...))); - - return DoGetResultIterator(has_unique_keys_type(), result); - } - - template - template - inline typename hashtable::iterator - hashtable::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)...))); - - return DoGetResultIterator(has_unique_keys_type(), result); - } - template typename hashtable::insert_return_type @@ -3021,14 +2912,25 @@ namespace eastl while(*pBucketArray && !compare(k, c, allocator_type::to_raw(*pBucketArray))) pBucketArray = &(*pBucketArray)->mpNext; + node_pointer pDeleteList = nullptr; while(*pBucketArray && compare(k, c, allocator_type::to_raw(*pBucketArray))) { node_pointer 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_pointer const pToDelete = pDeleteList; + pDeleteList = pDeleteList->mpNext; + DoFreeNode(pToDelete); + } + return nElementCountSaved - mnElementCount; } diff --git a/library/3rdparty/EASTL/include/EASTL/internal/integer_sequence.h b/library/3rdparty/EASTL/include/EASTL/internal/integer_sequence.h index 2a5539d..ba5dd4e 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/integer_sequence.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/integer_sequence.h @@ -24,6 +24,21 @@ class integer_sequence static EA_CONSTEXPR size_t size() EA_NOEXCEPT { return sizeof...(Ints); } }; +template +using index_sequence = integer_sequence; + +#if (defined(EA_COMPILER_GNUC) && EA_COMPILER_VERSION >= 8001) + +template +using make_integer_sequence = integer_sequence; + +#elif (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_BUILTIN(__make_integer_seq)) || (defined(EA_COMPILER_MSVC) && (EA_COMPILER_VERSION >= 1910)) + +template +using make_integer_sequence = __make_integer_seq; + +#else + template struct make_index_sequence_impl; @@ -39,12 +54,6 @@ struct make_index_sequence_impl<0, integer_sequence> typedef integer_sequence type; }; -template -using index_sequence = integer_sequence; - -template -using make_index_sequence = typename make_index_sequence_impl>::type; - template struct integer_sequence_convert_impl; @@ -54,15 +63,20 @@ struct integer_sequence_convert_impl> typedef integer_sequence type; }; -template +template struct make_integer_sequence_impl { - typedef typename integer_sequence_convert_impl>::type type; + typedef typename integer_sequence_convert_impl>::type>::type type; }; -template +template using make_integer_sequence = typename make_integer_sequence_impl::type; +#endif + +template +using make_index_sequence = make_integer_sequence; + // Helper alias template that converts any type parameter pack into an index sequence of the same length template using index_sequence_for = make_index_sequence; diff --git a/library/3rdparty/EASTL/include/EASTL/internal/red_black_tree.h b/library/3rdparty/EASTL/include/EASTL/internal/red_black_tree.h index 111fbb4..5b29b7c 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/red_black_tree.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/red_black_tree.h @@ -478,11 +478,6 @@ namespace eastl template iterator emplace_hint(const_iterator position, Args&&... args); - template eastl::pair try_emplace(const key_type& k, Args&&... args); - template eastl::pair try_emplace(key_type&& k, Args&&... args); - template iterator try_emplace(const_iterator position, const key_type& k, Args&&... args); - template iterator try_emplace(const_iterator position, key_type&& k, Args&&... args); - // Standard conversion overload to avoid the overhead of mismatched 'pair' types. template ::value>::type> insert_return_type insert(P&& otherValue); @@ -1108,43 +1103,6 @@ namespace eastl return DoInsertValueHint(has_unique_keys_type(), position, eastl::forward(args)...); } - template - template - inline eastl::pair::iterator, bool> - rbtree::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)...)); - } - - template - template - inline eastl::pair::iterator, bool> - rbtree::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)...)); - } - - template - template - inline typename rbtree::iterator - rbtree::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)...)); - } - - template - template - inline typename rbtree::iterator - rbtree::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)...)); - } - - template template inline typename rbtree::insert_return_type // map/set::insert return a pair, multimap/multiset::iterator return an iterator. diff --git a/library/3rdparty/EASTL/include/EASTL/internal/thread_support.h b/library/3rdparty/EASTL/include/EASTL/internal/thread_support.h index 60272a9..49856c0 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/thread_support.h +++ b/library/3rdparty/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/library/3rdparty/EASTL/include/EASTL/internal/type_detected.h b/library/3rdparty/EASTL/include/EASTL/internal/type_detected.h new file mode 100644 index 0000000..e368a6f --- /dev/null +++ b/library/3rdparty/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 +#if defined(EA_PRAGMA_ONCE_SUPPORTED) +#pragma once +#endif + +#include + +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 Op, class... Args> + struct detector + { + using type = Default; + using value_t = false_type; + }; + + template class Op, class... Args> + struct detector>, Op, Args...> + { + using type = Op; + 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 + // using detect_can_use_addition_operator = decltype(declval() + declval()); + // + // template + // void sum(const T& t, const U& u) + // { + // static_assert(is_detected::value, "Supplied types cannot be summedtogether."); + // // or... + // static_assert(is_detected_v, "Supplied types cannot be summedtogether."); + // return t + u; + // } + // + /////////////////////////////////////////////////////////////////////// + template

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 LW^r*%1Fio9i6?)M literal 0 HcmV?d00001 diff --git a/library/3rdparty/EASTL/doc/EASTL.natvis b/library/3rdparty/EASTL/doc/EASTL.natvis index 30986d5..2fb311b 100644 --- a/library/3rdparty/EASTL/doc/EASTL.natvis +++ b/library/3rdparty/EASTL/doc/EASTL.natvis @@ -558,6 +558,76 @@ {mFlag.mAtomic} + + + [valueless_by_exception] + {{ index=0, value={($T1*)mStorage.mBuffer.mCharData}} + {{ index=1, value={($T2*)mStorage.mBuffer.mCharData}} + {{ index=2, value={($T3*)mStorage.mBuffer.mCharData}} + {{ index=3, value={($T4*)mStorage.mBuffer.mCharData}} + {{ index=4, value={($T5*)mStorage.mBuffer.mCharData}} + {{ index=5, value={($T6*)mStorage.mBuffer.mCharData}} + {{ index=6, value={($T7*)mStorage.mBuffer.mCharData}} + {{ index=7, value={($T8*)mStorage.mBuffer.mCharData}} + {{ index=8, value={($T9*)mStorage.mBuffer.mCharData}} + {{ index=9, value={($T10*)mStorage.mBuffer.mCharData}} + {{ index=10, value={($T11*)mStorage.mBuffer.mCharData}} + {{ index=11, value={($T12*)mStorage.mBuffer.mCharData}} + {{ index=12, value={($T13*)mStorage.mBuffer.mCharData}} + {{ index=13, value={($T14*)mStorage.mBuffer.mCharData}} + {{ index=14, value={($T15*)mStorage.mBuffer.mCharData}} + {{ index=15, value={($T16*)mStorage.mBuffer.mCharData}} + {{ index=16, value={($T17*)mStorage.mBuffer.mCharData}} + {{ index=17, value={($T18*)mStorage.mBuffer.mCharData}} + {{ index=18, value={($T19*)mStorage.mBuffer.mCharData}} + {{ index=19, value={($T20*)mStorage.mBuffer.mCharData}} + {{ index=20, value={($T21*)mStorage.mBuffer.mCharData}} + {{ index=21, value={($T22*)mStorage.mBuffer.mCharData}} + {{ index=22, value={($T23*)mStorage.mBuffer.mCharData}} + {{ index=23, value={($T24*)mStorage.mBuffer.mCharData}} + {{ index=24, value={($T25*)mStorage.mBuffer.mCharData}} + {{ index=25, value={($T26*)mStorage.mBuffer.mCharData}} + {{ index=26, value={($T27*)mStorage.mBuffer.mCharData}} + {{ index=27, value={($T28*)mStorage.mBuffer.mCharData}} + {{ index=28, value={($T29*)mStorage.mBuffer.mCharData}} + {{ index=29, value={($T30*)mStorage.mBuffer.mCharData}} + {{ index=30, value={($T31*)mStorage.mBuffer.mCharData}} + + index() + ($T1*)mStorage.mBuffer.mCharData + ($T2*)mStorage.mBuffer.mCharData + ($T3*)mStorage.mBuffer.mCharData + ($T4*)mStorage.mBuffer.mCharData + ($T5*)mStorage.mBuffer.mCharData + ($T6*)mStorage.mBuffer.mCharData + ($T7*)mStorage.mBuffer.mCharData + ($T8*)mStorage.mBuffer.mCharData + ($T9*)mStorage.mBuffer.mCharData + ($T10*)mStorage.mBuffer.mCharData + ($T11*)mStorage.mBuffer.mCharData + ($T12*)mStorage.mBuffer.mCharData + ($T13*)mStorage.mBuffer.mCharData + ($T14*)mStorage.mBuffer.mCharData + ($T15*)mStorage.mBuffer.mCharData + ($T16*)mStorage.mBuffer.mCharData + ($T17*)mStorage.mBuffer.mCharData + ($T18*)mStorage.mBuffer.mCharData + ($T19*)mStorage.mBuffer.mCharData + ($T20*)mStorage.mBuffer.mCharData + ($T21*)mStorage.mBuffer.mCharData + ($T22*)mStorage.mBuffer.mCharData + ($T23*)mStorage.mBuffer.mCharData + ($T24*)mStorage.mBuffer.mCharData + ($T25*)mStorage.mBuffer.mCharData + ($T26*)mStorage.mBuffer.mCharData + ($T27*)mStorage.mBuffer.mCharData + ($T28*)mStorage.mBuffer.mCharData + ($T29*)mStorage.mBuffer.mCharData + ($T30*)mStorage.mBuffer.mCharData + ($T31*)mStorage.mBuffer.mCharData + + + diff --git a/library/3rdparty/EASTL/include/EASTL/algorithm.h b/library/3rdparty/EASTL/include/EASTL/algorithm.h index ff2bf8b..da35c2e 100644 --- a/library/3rdparty/EASTL/include/EASTL/algorithm.h +++ b/library/3rdparty/EASTL/include/EASTL/algorithm.h @@ -3,8 +3,8 @@ ///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// -// This file implements some of the primary algorithms from the C++ STL -// algorithm library. These versions are just like that STL versions and so +// This file implements some of the primary algorithms from the C++ STL +// algorithm library. These versions are just like that STL versions and so // are redundant. They are provided solely for the purpose of projects that // either cannot use standard C++ STL or want algorithms that have guaranteed // identical behaviour across platforms. @@ -13,11 +13,11 @@ /////////////////////////////////////////////////////////////////////////////// // Definitions -// +// // You will notice that we are very particular about the templated typenames -// we use here. You will notice that we follow the C++ standard closely in -// these respects. Each of these typenames have a specific meaning; -// this is why we don't just label templated arguments with just letters +// we use here. You will notice that we follow the C++ standard closely in +// these respects. Each of these typenames have a specific meaning; +// this is why we don't just label templated arguments with just letters // such as T, U, V, A, B. Here we provide a quick reference for the typenames // we use. See the C++ standard, section 25-8 for more details. // -------------------------------------------------------------- @@ -39,9 +39,9 @@ // RandomAccessIterator An input iterator which can be addressed like an array. It is a superset of all other input iterators. // OutputIterator An output iterator (iterator you write to) which allows writing each element only once in only in a forward direction. // -// Note that with iterators that a function which takes an InputIterator will +// Note that with iterators that a function which takes an InputIterator will // also work with a ForwardIterator, BidirectionalIterator, or RandomAccessIterator. -// The given iterator type is merely the -minimum- supported functionality the +// The given iterator type is merely the -minimum- supported functionality the // iterator must support. /////////////////////////////////////////////////////////////////////////////// @@ -51,15 +51,15 @@ // // There are a number of opportunities for opptimizations that we take here // in this library. The most obvious kinds are those that subsitute memcpy -// in the place of a conventional loop for data types with which this is +// in the place of a conventional loop for data types with which this is // possible. The algorithms here are optimized to a higher level than currently // available C++ STL algorithms from vendors such as Microsoft. This is especially -// so for game programming on console devices, as we do things such as reduce -// branching relative to other STL algorithm implementations. However, the +// so for game programming on console devices, as we do things such as reduce +// branching relative to other STL algorithm implementations. However, the // proper implementation of these algorithm optimizations is a fairly tricky -// thing. +// thing. // -// The various things we look to take advantage of in order to implement +// The various things we look to take advantage of in order to implement // optimizations include: // - Taking advantage of random access iterators. // - Taking advantage of POD (plain old data) data types. @@ -76,9 +76,9 @@ // Supported Algorithms // // Algorithms that we implement are listed here. Note that these items are not -// all within this header file, as we split up the header files in order to +// all within this header file, as we split up the header files in order to // improve compilation performance. Items marked with '+' are items that are -// extensions which don't exist in the C++ standard. +// extensions which don't exist in the C++ standard. // // ------------------------------------------------------------------------------- // Algorithm Notes @@ -94,6 +94,7 @@ // +binary_search_i // +change_heap Found in heap.h // +change_heap Found in heap.h +// clamp // copy // copy_if C++11 // copy_n C++11 @@ -159,7 +160,7 @@ // push_heap Found in heap.h // pop_heap Found in heap.h // pop_heap Found in heap.h -// random_shuffle +// random_shuffle // remove // remove_if // remove_copy @@ -172,6 +173,7 @@ // replace_copy_if // reverse_copy // reverse +// random_shuffle // rotate // rotate_copy // search @@ -179,10 +181,16 @@ // search_n // set_difference // set_difference +// set_difference_2 +// set_difference_2 +// set_decomposition +// set_decomposition // set_intersection // set_intersection // set_symmetric_difference // set_symmetric_difference +// set_union +// set_union // sort Found in sort.h // sort Found in sort.h // sort_heap Found in heap.h @@ -205,8 +213,8 @@ // Algorithms from the C++ standard that we don't implement are listed here. // Most of these items are absent because they aren't used very often. // They also happen to be the more complicated than other algorithms. -// However, we can implement any of these functions for users that might -// need them. +// However, we can implement any of these functions for users that might +// need them. // includes // includes // inplace_merge @@ -216,10 +224,7 @@ // paritition // prev_permutation // prev_permutation -// random_shuffle // search_n -// set_union -// set_union // stable_partition // unique_copy // unique_copy @@ -284,16 +289,16 @@ namespace eastl { /// min_element /// - /// min_element finds the smallest element in the range [first, last). - /// It returns the first iterator i in [first, last) such that no other - /// iterator in [first, last) points to a value smaller than *i. + /// min_element finds the smallest element in the range [first, last). + /// It returns the first iterator i in [first, last) such that no other + /// iterator in [first, last) points to a value smaller than *i. /// The return value is last if and only if [first, last) is an empty range. /// - /// Returns: The first iterator i in the range [first, last) such that - /// for any iterator j in the range [first, last) the following corresponding + /// Returns: The first iterator i in the range [first, last) such that + /// for any iterator j in the range [first, last) the following corresponding /// condition holds: !(*j < *i). /// - /// Complexity: Exactly 'max((last - first) - 1, 0)' applications of the + /// Complexity: Exactly 'max((last - first) - 1, 0)' applications of the /// corresponding comparisons. /// template @@ -316,16 +321,16 @@ namespace eastl /// min_element /// - /// min_element finds the smallest element in the range [first, last). - /// It returns the first iterator i in [first, last) such that no other - /// iterator in [first, last) points to a value smaller than *i. + /// min_element finds the smallest element in the range [first, last). + /// It returns the first iterator i in [first, last) such that no other + /// iterator in [first, last) points to a value smaller than *i. /// The return value is last if and only if [first, last) is an empty range. /// - /// Returns: The first iterator i in the range [first, last) such that - /// for any iterator j in the range [first, last) the following corresponding + /// Returns: The first iterator i in the range [first, last) such that + /// for any iterator j in the range [first, last) the following corresponding /// conditions hold: compare(*j, *i) == false. /// - /// Complexity: Exactly 'max((last - first) - 1, 0)' applications of the + /// Complexity: Exactly 'max((last - first) - 1, 0)' applications of the /// corresponding comparisons. /// template @@ -348,16 +353,16 @@ namespace eastl /// max_element /// - /// max_element finds the largest element in the range [first, last). - /// It returns the first iterator i in [first, last) such that no other - /// iterator in [first, last) points to a value greater than *i. + /// max_element finds the largest element in the range [first, last). + /// It returns the first iterator i in [first, last) such that no other + /// iterator in [first, last) points to a value greater than *i. /// The return value is last if and only if [first, last) is an empty range. /// - /// Returns: The first iterator i in the range [first, last) such that - /// for any iterator j in the range [first, last) the following corresponding + /// Returns: The first iterator i in the range [first, last) such that + /// for any iterator j in the range [first, last) the following corresponding /// condition holds: !(*i < *j). /// - /// Complexity: Exactly 'max((last - first) - 1, 0)' applications of the + /// Complexity: Exactly 'max((last - first) - 1, 0)' applications of the /// corresponding comparisons. /// template @@ -380,16 +385,16 @@ namespace eastl /// max_element /// - /// max_element finds the largest element in the range [first, last). - /// It returns the first iterator i in [first, last) such that no other - /// iterator in [first, last) points to a value greater than *i. + /// max_element finds the largest element in the range [first, last). + /// It returns the first iterator i in [first, last) such that no other + /// iterator in [first, last) points to a value greater than *i. /// The return value is last if and only if [first, last) is an empty range. /// - /// Returns: The first iterator i in the range [first, last) such that - /// for any iterator j in the range [first, last) the following corresponding + /// Returns: The first iterator i in the range [first, last) such that + /// for any iterator j in the range [first, last) the following corresponding /// condition holds: compare(*i, *j) == false. /// - /// Complexity: Exactly 'max((last - first) - 1, 0)' applications of the + /// Complexity: Exactly 'max((last - first) - 1, 0)' applications of the /// corresponding comparisons. /// template @@ -414,7 +419,7 @@ namespace eastl /// min /// - /// Min returns the lesser of its two arguments; it returns the first + /// Min returns the lesser of its two arguments; it returns the first /// argument if neither is less than the other. The two arguments are /// compared with operator <. /// @@ -423,15 +428,15 @@ namespace eastl /// which for example may in practice result in something different than: /// b <= a ? b : a /// in the case where b is different from a (though they compare as equal). - /// We choose the specific ordering here because that's the ordering + /// We choose the specific ordering here because that's the ordering /// done by other STL implementations. /// - /// Some compilers (e.g. VS20003 - VS2013) generate poor code for the case of + /// Some compilers (e.g. VS20003 - VS2013) generate poor code for the case of /// scalars returned by reference, so we provide a specialization for those cases. - /// The specialization returns T by value instead of reference, which is + /// The specialization returns T by value instead of reference, which is /// not that the Standard specifies. The Standard allows you to use /// an expression like &max(x, y), which would be impossible in this case. - /// However, we have found no actual code that uses min or max like this and + /// However, we have found no actual code that uses min or max like this and /// this specialization causes no problems in practice. Microsoft has acknowledged /// the problem and may fix it for a future VS version. /// @@ -441,7 +446,7 @@ namespace eastl { return b < a ? b : a; } - + template inline EA_CONSTEXPR typename eastl::enable_if::value, const T&>::type min(const T& a, const T& b) @@ -458,7 +463,7 @@ namespace eastl /// min_alt /// - /// This is an alternative version of min that avoids any possible + /// This is an alternative version of min that avoids any possible /// collisions with Microsoft #defines of min and max. /// /// See min(a, b) for detailed specifications. @@ -486,10 +491,10 @@ namespace eastl /// min /// - /// Min returns the lesser of its two arguments; it returns the first + /// Min returns the lesser of its two arguments; it returns the first /// argument if neither is less than the other. The two arguments are - /// compared with the Compare function (or function object), which - /// takes two arguments and returns true if the first is less than + /// compared with the Compare function (or function object), which + /// takes two arguments and returns true if the first is less than /// the second. /// /// See min(a, b) for detailed specifications. @@ -520,7 +525,7 @@ namespace eastl /// min_alt /// - /// This is an alternative version of min that avoids any possible + /// This is an alternative version of min that avoids any possible /// collisions with Microsoft #defines of min and max. /// /// See min(a, b) for detailed specifications. @@ -537,7 +542,7 @@ namespace eastl /// max /// - /// Max returns the greater of its two arguments; it returns the first + /// Max returns the greater of its two arguments; it returns the first /// argument if neither is greater than the other. The two arguments are /// compared with operator < (and not operator >). /// @@ -546,7 +551,7 @@ namespace eastl /// which for example may in practice result in something different than: /// a <= b ? b : a /// in the case where b is different from a (though they compare as equal). - /// We choose the specific ordering here because that's the ordering + /// We choose the specific ordering here because that's the ordering /// done by other STL implementations. /// template @@ -572,7 +577,7 @@ namespace eastl /// max_alt /// - /// This is an alternative version of max that avoids any possible + /// This is an alternative version of max that avoids any possible /// collisions with Microsoft #defines of min and max. /// template @@ -597,10 +602,10 @@ namespace eastl #if EASTL_MINMAX_ENABLED /// max /// - /// Min returns the lesser of its two arguments; it returns the first + /// Min returns the lesser of its two arguments; it returns the first /// argument if neither is less than the other. The two arguments are - /// compared with the Compare function (or function object), which - /// takes two arguments and returns true if the first is less than + /// compared with the Compare function (or function object), which + /// takes two arguments and returns true if the first is less than /// the second. /// template @@ -610,11 +615,11 @@ namespace eastl return compare(a, b) ? b : a; } #endif - + /// max_alt /// - /// This is an alternative version of max that avoids any possible + /// This is an alternative version of max that avoids any possible /// collisions with Microsoft #defines of min and max. /// template @@ -661,22 +666,22 @@ namespace eastl /// minmax_element /// - /// Returns: make_pair(first, first) if [first, last) is empty, otherwise make_pair(m, M), - /// where m is the first iterator in [first,last) such that no iterator in the range - /// refers to a smaller element, and where M is the last iterator in [first,last) such + /// Returns: make_pair(first, first) if [first, last) is empty, otherwise make_pair(m, M), + /// where m is the first iterator in [first,last) such that no iterator in the range + /// refers to a smaller element, and where M is the last iterator in [first,last) such /// that no iterator in the range refers to a larger element. /// - /// Complexity: At most max([(3/2)*(N - 1)], 0) applications of the corresponding predicate, + /// Complexity: At most max([(3/2)*(N - 1)], 0) applications of the corresponding predicate, /// where N is distance(first, last). /// template - eastl::pair + eastl::pair minmax_element(ForwardIterator first, ForwardIterator last, Compare compare) { eastl::pair result(first, first); - + if(!(first == last) && !(++first == last)) - { + { if(compare(*first, *result.first)) { result.second = result.first; @@ -691,22 +696,22 @@ namespace eastl if(++first == last) { - if(compare(*i, *result.first)) + if(compare(*i, *result.first)) result.first = i; - else if(!compare(*i, *result.second)) + else if(!compare(*i, *result.second)) result.second = i; break; - } + } else { if(compare(*first, *i)) { - if(compare(*first, *result.first)) + if(compare(*first, *result.first)) result.first = first; - if(!compare(*i, *result.second)) + if(!compare(*i, *result.second)) result.second = i; - } + } else { if(compare(*i, *result.first)) @@ -724,7 +729,7 @@ namespace eastl template - eastl::pair + eastl::pair minmax_element(ForwardIterator first, ForwardIterator last) { typedef typename eastl::iterator_traits::value_type value_type; @@ -745,14 +750,14 @@ namespace eastl // The following optimization is a problem because it changes the return value in a way that would break // users unless they used auto (e.g. auto result = minmax(17, 33); ) // - // template + // template // inline EA_CONSTEXPR typename eastl::enable_if::value, eastl::pair >::type // minmax(T a, T b) // { // return (b < a) ? eastl::make_pair(b, a) : eastl::make_pair(a, b); // } // - // template + // template // inline typename eastl::enable_if::value, eastl::pair >::type // minmax(const T& a, const T& b) // { @@ -761,9 +766,9 @@ namespace eastl // It turns out that the following conforming definition of minmax generates a warning when used with VC++ up // to at least VS2012. The VS2012 version of minmax is a broken and non-conforming definition, and we don't - // want to do that. We could do it for scalars alone, though we'd have to decide if we are going to do that + // want to do that. We could do it for scalars alone, though we'd have to decide if we are going to do that // for all compilers, because it changes the return value from a pair of references to a pair of values. - template + template inline eastl::pair minmax(const T& a, const T& b) { @@ -771,7 +776,7 @@ namespace eastl } - template + template eastl::pair minmax(const T& a, const T& b, Compare compare) { @@ -822,7 +827,7 @@ namespace eastl /// median finds which element of three (a, b, d) is in-between the other two. /// If two or more elements are equal, the first (e.g. a before b) is chosen. /// - /// Complexity: Either two or three comparisons will be required, depending + /// Complexity: Either two or three comparisons will be required, depending /// on the values. /// template @@ -836,7 +841,7 @@ namespace eastl /// median finds which element of three (a, b, d) is in-between the other two. /// If two or more elements are equal, the first (e.g. a before b) is chosen. /// - /// Complexity: Either two or three comparisons will be required, depending + /// Complexity: Either two or three comparisons will be required, depending /// on the values. /// template @@ -871,7 +876,7 @@ namespace eastl /// median finds which element of three (a, b, d) is in-between the other two. /// If two or more elements are equal, the first (e.g. a before b) is chosen. /// - /// Complexity: Either two or three comparisons will be required, depending + /// Complexity: Either two or three comparisons will be required, depending /// on the values. /// template @@ -885,7 +890,7 @@ namespace eastl /// median finds which element of three (a, b, d) is in-between the other two. /// If two or more elements are equal, the first (e.g. a before b) is chosen. /// - /// Complexity: Either two or three comparisons will be required, depending + /// Complexity: Either two or three comparisons will be required, depending /// on the values. /// template @@ -938,7 +943,7 @@ namespace eastl { for(; first != last; ++first) { - if(p(*first)) + if(p(*first)) return false; } return true; @@ -947,14 +952,14 @@ namespace eastl /// adjacent_find /// - /// Returns: The first iterator i such that both i and i + 1 are in the range - /// [first, last) for which the following corresponding conditions hold: *i == *(i + 1). + /// Returns: The first iterator i such that both i and i + 1 are in the range + /// [first, last) for which the following corresponding conditions hold: *i == *(i + 1). /// Returns last if no such iterator is found. /// /// Complexity: Exactly 'find(first, last, value) - first' applications of the corresponding predicate. /// template - inline ForwardIterator + inline ForwardIterator adjacent_find(ForwardIterator first, ForwardIterator last) { if(first != last) @@ -975,14 +980,14 @@ namespace eastl /// adjacent_find /// - /// Returns: The first iterator i such that both i and i + 1 are in the range - /// [first, last) for which the following corresponding conditions hold: predicate(*i, *(i + 1)) != false. + /// Returns: The first iterator i such that both i and i + 1 are in the range + /// [first, last) for which the following corresponding conditions hold: predicate(*i, *(i + 1)) != false. /// Returns last if no such iterator is found. /// /// Complexity: Exactly 'find(first, last, value) - first' applications of the corresponding predicate. /// template - inline ForwardIterator + inline ForwardIterator adjacent_find(ForwardIterator first, ForwardIterator last, BinaryPredicate predicate) { if(first != last) @@ -1005,7 +1010,7 @@ namespace eastl /// New for C++11 /// Randomizes a sequence of values via a user-supplied UniformRandomNumberGenerator. /// The difference between this and the original random_shuffle function is that this uses the more - /// advanced and flexible UniformRandomNumberGenerator interface as opposed to the more + /// advanced and flexible UniformRandomNumberGenerator interface as opposed to the more /// limited RandomNumberGenerator interface of random_shuffle. /// /// Effects: Shuffles the elements in the range [first, last) with uniform distribution. @@ -1065,7 +1070,7 @@ namespace eastl // as it turns out that the latter results in unequal distribution probabilities. // http://www.cigital.com/papers/download/developer_gambling.php - for(RandomAccessIterator i = first + 1; i < last; ++i) + for(RandomAccessIterator i = first + 1; i < last; ++i) iter_swap(i, first + (difference_type)rng((eastl_size_t)((i - first) + 1))); } @@ -1087,7 +1092,7 @@ namespace eastl /// inline void random_shuffle(RandomAccessIterator first, RandomAccessIterator last) /// { /// for(RandomAccessIterator i = first + 1; i < last; ++i) - /// iter_swap(i, first + SomeRangedRandomNumberGenerator((i - first) + 1)); + /// iter_swap(i, first + SomeRangedRandomNumberGenerator((i - first) + 1)); /// } @@ -1111,13 +1116,13 @@ namespace eastl template inline OutputIterator move_n_impl(RandomAccessIterator first, Size n, OutputIterator result, EASTL_ITC_NS::random_access_iterator_tag) - { + { return eastl::move(first, first + n, result); // Take advantage of the optimizations present in the move algorithm. } template - inline OutputIterator + inline OutputIterator move_n(InputIterator first, Size n, OutputIterator result) { typedef typename eastl::iterator_traits::iterator_category IC; @@ -1129,9 +1134,9 @@ namespace eastl /// copy_n /// /// Same as copy(InputIterator, InputIterator, OutputIterator) except based on count instead of iterator range. - /// Effects: Copies exactly count values from the range beginning at first to the range beginning at result, if count > 0. Does nothing otherwise. - /// Returns: Iterator in the destination range, pointing past the last element copied if count>0 or first otherwise. - /// Complexity: Exactly count assignments, if count > 0. + /// Effects: Copies exactly count values from the range beginning at first to the range beginning at result, if count > 0. Does nothing otherwise. + /// Returns: Iterator in the destination range, pointing past the last element copied if count>0 or first otherwise. + /// Complexity: Exactly count assignments, if count > 0. /// template inline OutputIterator @@ -1145,13 +1150,13 @@ namespace eastl template inline OutputIterator copy_n_impl(RandomAccessIterator first, Size n, OutputIterator result, EASTL_ITC_NS::random_access_iterator_tag) - { + { return eastl::copy(first, first + n, result); // Take advantage of the optimizations present in the copy algorithm. } template - inline OutputIterator + inline OutputIterator copy_n(InputIterator first, Size n, OutputIterator result) { typedef typename eastl::iterator_traits::iterator_category IC; @@ -1162,7 +1167,7 @@ namespace eastl /// copy_if /// /// Effects: Assigns to the result iterator only if the predicate is true. - /// + /// template inline OutputIterator copy_if(InputIterator first, InputIterator last, OutputIterator result, Predicate predicate) @@ -1224,7 +1229,7 @@ namespace eastl // Specialization for copying non-trivial data via a random-access iterator. It's theoretically faster because the compiler can see the count when its a compile-time const. // This specialization converts the random access BidirectionalIterator1 last-first to an integral type. There's simple way for us to take advantage of a random access output iterator, // as the range is specified by the input instead of the output, and distance(first, last) for a non-random-access iterator is potentially slow. - template <> + template <> struct move_and_copy_backward_helper { template @@ -1258,9 +1263,9 @@ namespace eastl typedef typename eastl::iterator_traits::value_type value_type_input; typedef typename eastl::iterator_traits::value_type value_type_output; - const bool canBeMemmoved = eastl::is_trivially_copyable::value && - eastl::is_same::value && - (eastl::is_pointer::value || eastl::is_same::value) && + const bool canBeMemmoved = eastl::is_trivially_copyable::value && + eastl::is_same::value && + (eastl::is_pointer::value || eastl::is_same::value) && (eastl::is_pointer::value || eastl::is_same::value); return eastl::move_and_copy_backward_helper::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. @@ -1277,16 +1282,16 @@ namespace eastl /// move_backward /// - /// The elements are moved in reverse order (the last element is moved first), but their relative order is preserved. - /// After this operation the elements in the moved-from range will still contain valid values of the - /// appropriate type, but not necessarily the same values as before the move. + /// The elements are moved in reverse order (the last element is moved first), but their relative order is preserved. + /// After this operation the elements in the moved-from range will still contain valid values of the + /// appropriate type, but not necessarily the same values as before the move. /// Returns the beginning of the result range. /// Note: When moving between containers, the dest range must be valid; this function doesn't resize containers. - /// Note: If result is within [first, last), move must be used instead of move_backward. + /// Note: If result is within [first, last), move must be used instead of move_backward. /// /// Example usage: - /// eastl::move_backward(myArray.begin(), myArray.end(), myDestArray.end()); - /// + /// eastl::move_backward(myArray.begin(), myArray.end(), myDestArray.end()); + /// /// Reference implementation: /// template /// BidirectionalIterator2 move_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 resultEnd) @@ -1295,7 +1300,7 @@ namespace eastl /// *--resultEnd = eastl::move(*--last); /// return resultEnd; /// } - /// + /// template inline BidirectionalIterator2 move_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 resultEnd) { @@ -1306,9 +1311,9 @@ namespace eastl /// copy_backward /// /// copies memory in the range of [first, last) to the range *ending* with result. - /// - /// Effects: Copies elements in the range [first, last) into the range - /// [result - (last - first), result) starting from last 1 and proceeding to first. + /// + /// Effects: Copies elements in the range [first, last) into the range + /// [result - (last - first), result) starting from last 1 and proceeding to first. /// For each positive integer n <= (last - first), performs *(result n) = *(last - n). /// /// Requires: result shall not be in the range [first, last). @@ -1316,7 +1321,7 @@ namespace eastl /// Returns: result - (last - first). That is, returns the beginning of the result range. /// /// Complexity: Exactly 'last - first' assignments. - /// + /// template inline BidirectionalIterator2 copy_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 resultEnd) { @@ -1330,7 +1335,7 @@ namespace eastl /// /// Counts the number of items in the range of [first, last) which equal the input value. /// - /// Effects: Returns the number of iterators i in the range [first, last) for which the + /// Effects: Returns the number of iterators i in the range [first, last) for which the /// following corresponding conditions hold: *i == value. /// /// Complexity: At most 'last - first' applications of the corresponding predicate. @@ -1372,10 +1377,10 @@ namespace eastl /// count_if /// - /// Counts the number of items in the range of [first, last) which match + /// Counts the number of items in the range of [first, last) which match /// the input value as defined by the input predicate function. /// - /// Effects: Returns the number of iterators i in the range [first, last) for which the + /// Effects: Returns the number of iterators i in the range [first, last) for which the /// following corresponding conditions hold: predicate(*i) != false. /// /// Complexity: At most 'last - first' applications of the corresponding predicate. @@ -1400,14 +1405,14 @@ namespace eastl /// find /// - /// finds the value within the unsorted range of [first, last). + /// finds the value within the unsorted range of [first, last). /// - /// Returns: The first iterator i in the range [first, last) for which - /// the following corresponding conditions hold: *i == value. + /// Returns: The first iterator i in the range [first, last) for which + /// the following corresponding conditions hold: *i == value. /// Returns last if no such iterator is found. /// /// Complexity: At most 'last - first' applications of the corresponding predicate. - /// This is a linear search and not a binary one. + /// This is a linear search and not a binary one. /// /// Note: The predicate version of find is find_if and not another variation of find. /// This is because both versions would have three parameters and there could be ambiguity. @@ -1437,10 +1442,10 @@ namespace eastl /// find_if /// - /// finds the value within the unsorted range of [first, last). + /// finds the value within the unsorted range of [first, last). /// - /// Returns: The first iterator i in the range [first, last) for which - /// the following corresponding conditions hold: pred(*i) != false. + /// Returns: The first iterator i in the range [first, last) for which + /// the following corresponding conditions hold: pred(*i) != false. /// Returns last if no such iterator is found. /// If the sequence of elements to search for (i.e. first2 - last2) is empty, /// the find always fails and last1 will be returned. @@ -1467,7 +1472,7 @@ namespace eastl /// returns false for the elements instead of true. /// template - inline InputIterator + inline InputIterator find_if_not(InputIterator first, InputIterator last, Predicate predicate) { for(; first != last; ++first) @@ -1483,27 +1488,27 @@ namespace eastl /// find_first_of /// - /// find_first_of is similar to find in that it performs linear search through - /// a range of ForwardIterators. The difference is that while find searches - /// for one particular value, find_first_of searches for any of several values. - /// Specifically, find_first_of searches for the first occurrance in the - /// range [first1, last1) of any of the elements in [first2, last2). + /// find_first_of is similar to find in that it performs linear search through + /// a range of ForwardIterators. The difference is that while find searches + /// for one particular value, find_first_of searches for any of several values. + /// Specifically, find_first_of searches for the first occurrance in the + /// range [first1, last1) of any of the elements in [first2, last2). /// This function is thus similar to the strpbrk standard C string function. /// If the sequence of elements to search for (i.e. first2-last2) is empty, /// the find always fails and last1 will be returned. /// /// Effects: Finds an element that matches one of a set of values. /// - /// Returns: The first iterator i in the range [first1, last1) such that for some + /// Returns: The first iterator i in the range [first1, last1) such that for some /// integer j in the range [first2, last2) the following conditions hold: *i == *j. /// Returns last1 if no such iterator is found. /// - /// Complexity: At most '(last1 - first1) * (last2 - first2)' applications of the + /// Complexity: At most '(last1 - first1) * (last2 - first2)' applications of the /// corresponding predicate. /// template ForwardIterator1 - find_first_of(ForwardIterator1 first1, ForwardIterator1 last1, + find_first_of(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2) { for(; first1 != last1; ++first1) @@ -1520,25 +1525,25 @@ namespace eastl /// find_first_of /// - /// find_first_of is similar to find in that it performs linear search through - /// a range of ForwardIterators. The difference is that while find searches - /// for one particular value, find_first_of searches for any of several values. - /// Specifically, find_first_of searches for the first occurrance in the - /// range [first1, last1) of any of the elements in [first2, last2). + /// find_first_of is similar to find in that it performs linear search through + /// a range of ForwardIterators. The difference is that while find searches + /// for one particular value, find_first_of searches for any of several values. + /// Specifically, find_first_of searches for the first occurrance in the + /// range [first1, last1) of any of the elements in [first2, last2). /// This function is thus similar to the strpbrk standard C string function. /// /// Effects: Finds an element that matches one of a set of values. /// - /// Returns: The first iterator i in the range [first1, last1) such that for some + /// Returns: The first iterator i in the range [first1, last1) such that for some /// integer j in the range [first2, last2) the following conditions hold: pred(*i, *j) != false. /// Returns last1 if no such iterator is found. /// - /// Complexity: At most '(last1 - first1) * (last2 - first2)' applications of the + /// Complexity: At most '(last1 - first1) * (last2 - first2)' applications of the /// corresponding predicate. /// template ForwardIterator1 - find_first_of(ForwardIterator1 first1, ForwardIterator1 last1, + find_first_of(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate predicate) { @@ -1559,16 +1564,16 @@ namespace eastl /// Searches through first range for the first element that does not belong the second input range. /// This is very much like the C++ string find_first_not_of function. /// - /// Returns: The first iterator i in the range [first1, last1) such that for some + /// Returns: The first iterator i in the range [first1, last1) such that for some /// integer j in the range [first2, last2) the following conditions hold: !(*i == *j). /// Returns last1 if no such iterator is found. /// - /// Complexity: At most '(last1 - first1) * (last2 - first2)' applications of the + /// Complexity: At most '(last1 - first1) * (last2 - first2)' applications of the /// corresponding predicate. /// template ForwardIterator1 - find_first_not_of(ForwardIterator1 first1, ForwardIterator1 last1, + find_first_not_of(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2) { for(; first1 != last1; ++first1) @@ -1587,17 +1592,17 @@ namespace eastl /// Searches through first range for the first element that does not belong the second input range. /// This is very much like the C++ string find_first_not_of function. /// - /// Returns: The first iterator i in the range [first1, last1) such that for some + /// Returns: The first iterator i in the range [first1, last1) such that for some /// integer j in the range [first2, last2) the following conditions hold: pred(*i, *j) == false. /// Returns last1 if no such iterator is found. /// - /// Complexity: At most '(last1 - first1) * (last2 - first2)' applications of the + /// Complexity: At most '(last1 - first1) * (last2 - first2)' applications of the /// corresponding predicate. /// template inline ForwardIterator1 - find_first_not_of(ForwardIterator1 first1, ForwardIterator1 last1, - ForwardIterator2 first2, ForwardIterator2 last2, + find_first_not_of(ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate predicate) { typedef typename eastl::iterator_traits::value_type value_type; @@ -1614,7 +1619,7 @@ namespace eastl template inline BidirectionalIterator1 - find_last_of(BidirectionalIterator1 first1, BidirectionalIterator1 last1, + find_last_of(BidirectionalIterator1 first1, BidirectionalIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2) { if((first1 != last1) && (first2 != last2)) @@ -1634,8 +1639,8 @@ namespace eastl template BidirectionalIterator1 - find_last_of(BidirectionalIterator1 first1, BidirectionalIterator1 last1, - ForwardIterator2 first2, ForwardIterator2 last2, + find_last_of(BidirectionalIterator1 first1, BidirectionalIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate predicate) { typedef typename eastl::iterator_traits::value_type value_type; @@ -1657,7 +1662,7 @@ namespace eastl template inline BidirectionalIterator1 - find_last_not_of(BidirectionalIterator1 first1, BidirectionalIterator1 last1, + find_last_not_of(BidirectionalIterator1 first1, BidirectionalIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2) { if((first1 != last1) && (first2 != last2)) @@ -1677,8 +1682,8 @@ namespace eastl template inline BidirectionalIterator1 - find_last_not_of(BidirectionalIterator1 first1, BidirectionalIterator1 last1, - ForwardIterator2 first2, ForwardIterator2 last2, + find_last_not_of(BidirectionalIterator1 first1, BidirectionalIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate predicate) { typedef typename eastl::iterator_traits::value_type value_type; @@ -1704,8 +1709,8 @@ namespace eastl /// /// Calls the Function function for each value in the range [first, last). /// Function takes a single parameter: the current value. - /// - /// Effects: Applies function to the result of dereferencing every iterator in + /// + /// Effects: Applies function to the result of dereferencing every iterator in /// the range [first, last), starting from first and proceeding to last 1. /// /// Returns: function. @@ -1713,7 +1718,7 @@ namespace eastl /// Complexity: Applies function exactly 'last - first' times. /// /// Note: If function returns a result, the result is ignored. - /// + /// template inline Function for_each(InputIterator first, InputIterator last, Function function) @@ -1727,20 +1732,20 @@ namespace eastl /// /// Calls the Function function for each value in the range [first, first + n). /// Function takes a single parameter: the current value. - /// - /// Effects: Applies function to the result of dereferencing every iterator in + /// + /// Effects: Applies function to the result of dereferencing every iterator in /// the range [first, first + n), starting from first and proceeding to last 1. /// /// Returns: first + n. /// /// Complexity: Applies function exactly 'first + n' times. /// - /// Note: + /// Note: //// * If function returns a result, the result is ignored. //// * If n < 0, behaviour is undefined. /// template - EA_CPP14_CONSTEXPR inline InputIterator + EA_CPP14_CONSTEXPR inline InputIterator for_each_n(InputIterator first, Size n, Function function) { for (Size i = 0; i < n; ++first, i++) @@ -1754,15 +1759,15 @@ namespace eastl /// Iterates the range of [first, last) and assigns to each element the /// result of the function generator. Generator is a function which takes /// no arguments. - /// + /// /// Complexity: Exactly 'last - first' invocations of generator and assignments. /// template inline void generate(ForwardIterator first, ForwardIterator last, Generator generator) { - for(; first != last; ++first) // We cannot call generate_n(first, last-first, generator) - *first = generator(); // because the 'last-first' might not be supported by the + for(; first != last; ++first) // We cannot call generate_n(first, last-first, generator) + *first = generator(); // because the 'last-first' might not be supported by the } // given iterator. @@ -1771,7 +1776,7 @@ namespace eastl /// Iterates an interator n times and assigns the result of generator /// to each succeeding element. Generator is a function which takes /// no arguments. - /// + /// /// Complexity: Exactly n invocations of generator and assignments. /// template @@ -1788,7 +1793,7 @@ namespace eastl /// /// Iterates the input range of [first, last) and the output iterator result /// and assigns the result of unaryOperation(input) to result. - /// + /// /// Effects: Assigns through every iterator i in the range [result, result + (last1 - first1)) /// a new corresponding value equal to unaryOperation(*(first1 + (i - result)). /// @@ -1814,7 +1819,7 @@ namespace eastl /// /// Iterates the input range of [first, last) and the output iterator result /// and assigns the result of binaryOperation(input1, input2) to result. - /// + /// /// Effects: Assigns through every iterator i in the range [result, result + (last1 - first1)) /// a new corresponding value equal to binaryOperation(*(first1 + (i - result), *(first2 + (i - result))). /// @@ -1838,14 +1843,14 @@ namespace eastl /// equal /// - /// Returns: true if for every iterator i in the range [first1, last1) the - /// following corresponding conditions hold: predicate(*i, *(first2 + (i - first1))) != false. + /// Returns: true if for every iterator i in the range [first1, last1) the + /// following corresponding conditions hold: predicate(*i, *(first2 + (i - first1))) != false. /// Otherwise, returns false. /// /// Complexity: At most last1 first1 applications of the corresponding predicate. /// /// To consider: Make specializations of this for scalar types and random access - /// iterators that uses memcmp or some trick memory comparison function. + /// iterators that uses memcmp or some trick memory comparison function. /// We should verify that such a thing results in an improvement. /// template @@ -1902,8 +1907,8 @@ namespace eastl /// equal /// - /// Returns: true if for every iterator i in the range [first1, last1) the - /// following corresponding conditions hold: pred(*i, *(first2 + (i first1))) != false. + /// Returns: true if for every iterator i in the range [first1, last1) the + /// following corresponding conditions hold: pred(*i, *(first2 + (i first1))) != false. /// Otherwise, returns false. /// /// Complexity: At most last1 first1 applications of the corresponding predicate. @@ -1925,20 +1930,20 @@ namespace eastl /// identical /// /// Returns true if the two input ranges are equivalent. - /// There is a subtle difference between this algorithm and - /// the 'equal' algorithm. The equal algorithm assumes the + /// There is a subtle difference between this algorithm and + /// the 'equal' algorithm. The equal algorithm assumes the /// two ranges are of equal length. This algorithm efficiently - /// compares two ranges for both length equality and for + /// compares two ranges for both length equality and for /// element equality. There is no other standard algorithm /// that can do this. /// - /// Returns: true if the sequence of elements defined by the range + /// Returns: true if the sequence of elements defined by the range /// [first1, last1) is of the same length as the sequence of /// elements defined by the range of [first2, last2) and if - /// the elements in these ranges are equal as per the + /// the elements in these ranges are equal as per the /// equal algorithm. /// - /// Complexity: At most 'min((last1 - first1), (last2 - first2))' applications + /// Complexity: At most 'min((last1 - first1), (last2 - first2))' applications /// of the corresponding comparison. /// template @@ -1972,19 +1977,19 @@ namespace eastl /// lexicographical_compare /// - /// Returns: true if the sequence of elements defined by the range - /// [first1, last1) is lexicographically less than the sequence of + /// Returns: true if the sequence of elements defined by the range + /// [first1, last1) is lexicographically less than the sequence of /// elements defined by the range [first2, last2). Returns false otherwise. /// - /// Complexity: At most 'min((last1 - first1), (last2 - first2))' applications + /// Complexity: At most 'min((last1 - first1), (last2 - first2))' 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 + /// 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 @@ -2072,30 +2077,30 @@ namespace eastl /// lexicographical_compare /// - /// Returns: true if the sequence of elements defined by the range - /// [first1, last1) is lexicographically less than the sequence of + /// Returns: true if the sequence of elements defined by the range + /// [first1, last1) is lexicographically less than the sequence of /// elements defined by the range [first2, last2). Returns false otherwise. /// - /// Complexity: At most 'min((last1 -first1), (last2 - first2))' applications + /// Complexity: At most 'min((last1 -first1), (last2 - first2))' 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 + /// 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. /// /// Note: False is always returned if range 1 is exhausted before range 2. /// The result of this is that you can't do a successful reverse compare - /// (e.g. use greater<> as the comparison instead of less<>) unless the + /// (e.g. use greater<> as the comparison instead of less<>) unless the /// two sequences are of identical length. What you want to do is reverse /// the order of the arguments in order to get the desired effect. /// template inline bool - lexicographical_compare(InputIterator1 first1, InputIterator1 last1, + lexicographical_compare(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, Compare compare) { for(; (first1 != last1) && (first2 != last2); ++first1, ++first2) @@ -2111,14 +2116,14 @@ namespace eastl /// mismatch /// - /// Finds the first position where the two ranges [first1, last1) and - /// [first2, first2 + (last1 - first1)) differ. The two versions of + /// Finds the first position where the two ranges [first1, last1) and + /// [first2, first2 + (last1 - first1)) differ. The two versions of /// mismatch use different tests for whether elements differ. /// /// Returns: A pair of iterators i and j such that j == first2 + (i - first1) - /// and i is the first iterator in the range [first1, last1) for which the + /// and i is the first iterator in the range [first1, last1) for which the /// following corresponding condition holds: !(*i == *(first2 + (i - first1))). - /// Returns the pair last1 and first2 + (last1 - first1) if such an iterator + /// Returns the pair last1 and first2 + (last1 - first1) if such an iterator /// i is not found. /// /// Complexity: At most last1 first1 applications of the corresponding predicate. @@ -2140,14 +2145,14 @@ namespace eastl /// mismatch /// - /// Finds the first position where the two ranges [first1, last1) and - /// [first2, first2 + (last1 - first1)) differ. The two versions of + /// Finds the first position where the two ranges [first1, last1) and + /// [first2, first2 + (last1 - first1)) differ. The two versions of /// mismatch use different tests for whether elements differ. /// /// Returns: A pair of iterators i and j such that j == first2 + (i - first1) - /// and i is the first iterator in the range [first1, last1) for which the + /// and i is the first iterator in the range [first1, last1) for which the /// following corresponding condition holds: pred(*i, *(first2 + (i - first1))) == false. - /// Returns the pair last1 and first2 + (last1 - first1) if such an iterator + /// Returns the pair last1 and first2 + (last1 - first1) if such an iterator /// i is not found. /// /// Complexity: At most last1 first1 applications of the corresponding predicate. @@ -2170,20 +2175,20 @@ namespace eastl /// lower_bound /// - /// Finds the position of the first element in a sorted range that has a value + /// Finds the position of the first element in a sorted range that has a value /// greater than or equivalent to a specified value. /// - /// Effects: Finds the first position into which value can be inserted without + /// Effects: Finds the first position into which value can be inserted without /// violating the ordering. - /// - /// Returns: The furthermost iterator i in the range [first, last) such that - /// for any iterator j in the range [first, i) the following corresponding + /// + /// Returns: The furthermost iterator i in the range [first, last) such that + /// for any iterator j in the range [first, i) the following corresponding /// condition holds: *j < value. /// /// Complexity: At most 'log(last - first) + 1' comparisons. /// - /// Optimizations: We have no need to specialize this implementation for random - /// access iterators (e.g. contiguous array), as the code below will already + /// Optimizations: We have no need to specialize this implementation for random + /// access iterators (e.g. contiguous array), as the code below will already /// take advantage of them. /// template @@ -2216,22 +2221,22 @@ namespace eastl /// lower_bound /// - /// Finds the position of the first element in a sorted range that has a value + /// Finds the position of the first element in a sorted range that has a value /// greater than or equivalent to a specified value. The input Compare function /// takes two arguments and returns true if the first argument is less than /// the second argument. /// - /// Effects: Finds the first position into which value can be inserted without + /// Effects: Finds the first position into which value can be inserted without /// violating the ordering. - /// - /// Returns: The furthermost iterator i in the range [first, last) such that - /// for any iterator j in the range [first, i) the following corresponding + /// + /// Returns: The furthermost iterator i in the range [first, last) such that + /// for any iterator j in the range [first, i) the following corresponding /// condition holds: compare(*j, value) != false. /// /// Complexity: At most 'log(last - first) + 1' comparisons. /// - /// Optimizations: We have no need to specialize this implementation for random - /// access iterators (e.g. contiguous array), as the code below will already + /// Optimizations: We have no need to specialize this implementation for random + /// access iterators (e.g. contiguous array), as the code below will already /// take advantage of them. /// template @@ -2265,14 +2270,14 @@ namespace eastl /// upper_bound /// - /// Finds the position of the first element in a sorted range that has a + /// Finds the position of the first element in a sorted range that has a /// value that is greater than a specified value. /// - /// Effects: Finds the furthermost position into which value can be inserted + /// Effects: Finds the furthermost position into which value can be inserted /// without violating the ordering. /// - /// Returns: The furthermost iterator i in the range [first, last) such that - /// for any iterator j in the range [first, i) the following corresponding + /// Returns: The furthermost iterator i in the range [first, last) such that + /// for any iterator j in the range [first, i) the following corresponding /// condition holds: !(value < *j). /// /// Complexity: At most 'log(last - first) + 1' comparisons. @@ -2309,16 +2314,16 @@ namespace eastl /// upper_bound /// - /// Finds the position of the first element in a sorted range that has a + /// Finds the position of the first element in a sorted range that has a /// value that is greater than a specified value. The input Compare function /// takes two arguments and returns true if the first argument is less than /// the second argument. /// - /// Effects: Finds the furthermost position into which value can be inserted + /// Effects: Finds the furthermost position into which value can be inserted /// without violating the ordering. /// - /// Returns: The furthermost iterator i in the range [first, last) such that - /// for any iterator j in the range [first, i) the following corresponding + /// Returns: The furthermost iterator i in the range [first, last) such that + /// for any iterator j in the range [first, i) the following corresponding /// condition holds: compare(value, *j) == false. /// /// Complexity: At most 'log(last - first) + 1' comparisons. @@ -2355,10 +2360,10 @@ namespace eastl /// equal_range /// - /// Effects: Finds the largest subrange [i, j) such that the value can be inserted - /// at any iterator k in it without violating the ordering. k satisfies the + /// Effects: Finds the largest subrange [i, j) such that the value can be inserted + /// at any iterator k in it without violating the ordering. k satisfies the /// corresponding conditions: !(*k < value) && !(value < *k). - /// + /// /// Complexity: At most '2 * log(last - first) + 1' comparisons. /// template @@ -2393,7 +2398,7 @@ namespace eastl { ForwardIterator j(i); - return ResultType(eastl::lower_bound(first, i, value), + return ResultType(eastl::lower_bound(first, i, value), eastl::upper_bound(++j, last, value)); } } @@ -2403,10 +2408,10 @@ namespace eastl /// equal_range /// - /// Effects: Finds the largest subrange [i, j) such that the value can be inserted - /// at any iterator k in it without violating the ordering. k satisfies the + /// Effects: Finds the largest subrange [i, j) such that the value can be inserted + /// at any iterator k in it without violating the ordering. k satisfies the /// corresponding conditions: compare(*k, value) == false && compare(value, *k) == false. - /// + /// /// Complexity: At most '2 * log(last - first) + 1' comparisons. /// template @@ -2441,7 +2446,7 @@ namespace eastl { ForwardIterator j(i); - return ResultType(eastl::lower_bound(first, i, value, compare), + return ResultType(eastl::lower_bound(first, i, value, compare), eastl::upper_bound(++j, last, value, compare)); } } @@ -2451,9 +2456,9 @@ namespace eastl /// replace /// - /// Effects: Substitutes elements referred by the iterator i in the range [first, last) + /// Effects: Substitutes elements referred by the iterator i in the range [first, last) /// with new_value, when the following corresponding conditions hold: *i == old_value. - /// + /// /// Complexity: Exactly 'last - first' applications of the corresponding predicate. /// /// Note: The predicate version of replace is replace_if and not another variation of replace. @@ -2473,9 +2478,9 @@ namespace eastl /// replace_if /// - /// Effects: Substitutes elements referred by the iterator i in the range [first, last) + /// Effects: Substitutes elements referred by the iterator i in the range [first, last) /// with new_value, when the following corresponding conditions hold: predicate(*i) != false. - /// + /// /// Complexity: Exactly 'last - first' applications of the corresponding predicate. /// /// Note: The predicate version of replace_if is replace and not another variation of replace_if. @@ -2495,8 +2500,8 @@ namespace eastl /// remove_copy /// - /// Effects: Copies all the elements referred to by the iterator i in the range - /// [first, last) for which the following corresponding condition does not hold: + /// Effects: Copies all the elements referred to by the iterator i in the range + /// [first, last) for which the following corresponding condition does not hold: /// *i == value. /// /// Requires: The ranges [first, last) and [result, result + (last - first)) shall not overlap. @@ -2513,7 +2518,7 @@ namespace eastl { if(!(*first == value)) // Note that we always express value comparisons in terms of < or ==. { - *result = move(*first); + *result = eastl::move(*first); ++result; } } @@ -2523,8 +2528,8 @@ namespace eastl /// remove_copy_if /// - /// Effects: Copies all the elements referred to by the iterator i in the range - /// [first, last) for which the following corresponding condition does not hold: + /// Effects: Copies all the elements referred to by the iterator i in the range + /// [first, last) for which the following corresponding condition does not hold: /// predicate(*i) != false. /// /// Requires: The ranges [first, last) and [result, result + (last - first)) shall not overlap. @@ -2551,7 +2556,7 @@ namespace eastl /// remove /// - /// Effects: Eliminates all the elements referred to by iterator i in the + /// Effects: Eliminates all the elements referred to by iterator i in the /// range [first, last) for which the following corresponding condition /// holds: *i == value. /// @@ -2562,9 +2567,9 @@ namespace eastl /// Note: The predicate version of remove is remove_if and not another variation of remove. /// This is because both versions would have the same parameter count and there could be ambiguity. /// - /// Note: Since this function moves the element to the back of the heap and + /// Note: Since this function moves the element to the back of the heap and /// 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 + /// the container erase function if the user wants to erase the element /// from the container. /// /// Example usage: @@ -2588,8 +2593,8 @@ namespace eastl /// remove_if /// - /// Effects: Eliminates all the elements referred to by iterator i in the - /// range [first, last) for which the following corresponding condition + /// Effects: Eliminates all the elements referred to by iterator i in the + /// range [first, last) for which the following corresponding condition /// holds: predicate(*i) != false. /// /// Returns: The end of the resulting range. @@ -2599,9 +2604,9 @@ namespace eastl /// Note: The predicate version of remove_if is remove and not another variation of remove_if. /// This is because both versions would have the same parameter count and there could be ambiguity. /// - /// Note: Since this function moves the element to the back of the heap and + /// Note: Since this function moves the element to the back of the heap and /// 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 + /// the container erase function if the user wants to erase the element /// from the container. /// /// Example usage: @@ -2626,7 +2631,7 @@ namespace eastl /// replace_copy /// /// Effects: Assigns to every iterator i in the range [result, result + (last - first)) - /// either new_value or *(first + (i - result)) depending on whether the following + /// either new_value or *(first + (i - result)) depending on whether the following /// corresponding conditions hold: *(first + (i - result)) == old_value. /// /// Requires: The ranges [first, last) and [result, result + (last - first)) shall not overlap. @@ -2651,7 +2656,7 @@ namespace eastl /// replace_copy_if /// /// Effects: Assigns to every iterator i in the range [result, result + (last - first)) - /// either new_value or *(first + (i - result)) depending on whether the following + /// either new_value or *(first + (i - result)) depending on whether the following /// corresponding conditions hold: predicate(*(first + (i - result))) != false. /// /// Requires: The ranges [first, last) and [result, result+(lastfirst)) shall not overlap. @@ -2677,7 +2682,7 @@ namespace eastl // reverse // - // We provide helper functions which allow reverse to be implemented more + // We provide helper functions which allow reverse to be implemented more // efficiently for some types of iterators and types. // template @@ -2701,7 +2706,7 @@ namespace eastl /// /// Reverses the values within the range [first, last). /// - /// Effects: For each nonnegative integer i <= (last - first) / 2, + /// Effects: For each nonnegative integer i <= (last - first) / 2, /// applies swap to all pairs of iterators first + i, (last i) - 1. /// /// Complexity: Exactly '(last - first) / 2' swaps. @@ -2719,7 +2724,7 @@ namespace eastl /// /// Copies the range [first, last) in reverse order to the result. /// - /// Effects: Copies the range [first, last) to the range + /// Effects: Copies the range [first, last) to the range /// [result, result + (last - first)) such that for any nonnegative /// integer i < (last - first) the following assignment takes place: /// *(result + (last - first) - i) = *(first + i) @@ -2744,9 +2749,9 @@ namespace eastl /// search /// - /// Search finds a subsequence within the range [first1, last1) that is identical to [first2, last2) - /// when compared element-by-element. It returns an iterator pointing to the beginning of that - /// subsequence, or else last1 if no such subsequence exists. As such, it is very much like + /// Search finds a subsequence within the range [first1, last1) that is identical to [first2, last2) + /// when compared element-by-element. It returns an iterator pointing to the beginning of that + /// subsequence, or else last1 if no such subsequence exists. As such, it is very much like /// the C strstr function, with the primary difference being that strstr uses 0-terminated strings /// whereas search uses an end iterator to specify the end of a string. /// @@ -2758,7 +2763,7 @@ namespace eastl /// template ForwardIterator1 - search(ForwardIterator1 first1, ForwardIterator1 last1, + search(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2) { if(first2 != last2) // If there is anything to search for... @@ -2839,9 +2844,9 @@ namespace eastl /// search /// - /// Search finds a subsequence within the range [first1, last1) that is identical to [first2, last2) - /// when compared element-by-element. It returns an iterator pointing to the beginning of that - /// subsequence, or else last1 if no such subsequence exists. As such, it is very much like + /// Search finds a subsequence within the range [first1, last1) that is identical to [first2, last2) + /// when compared element-by-element. It returns an iterator pointing to the beginning of that + /// subsequence, or else last1 if no such subsequence exists. As such, it is very much like /// the C strstr function, with the only difference being that strstr uses 0-terminated strings /// whereas search uses an end iterator to specify the end of a string. /// @@ -2853,7 +2858,7 @@ namespace eastl /// template ForwardIterator1 - search(ForwardIterator1 first1, ForwardIterator1 last1, + search(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate predicate) { @@ -2894,7 +2899,7 @@ namespace eastl return first; Size d1 = (Size)eastl::distance(first, last); // Should d1 be of type Size, ptrdiff_t, or iterator_traits::difference_type? - // The problem with using iterator_traits::difference_type is that + // The problem with using iterator_traits::difference_type is that if(count > d1) // ForwardIterator may not be a true iterator but instead something like a pointer. return last; @@ -2922,7 +2927,7 @@ namespace eastl if(count <= 0) return first; else if(count == 1) - return find(first, last, value); + return eastl::find(first, last, value); else if(last > first) { RandomAccessIterator lookAhead; @@ -2972,9 +2977,9 @@ namespace eastl /// search_n /// - /// Returns: The first iterator i in the range [first, last count) such that - /// for any nonnegative integer n less than count the following corresponding - /// conditions hold: *(i + n) == value, pred(*(i + n),value) != false. + /// Returns: The first iterator i in the range [first, last count) such that + /// for any nonnegative integer n less than count the following corresponding + /// conditions hold: *(i + n) == value, pred(*(i + n),value) != false. /// Returns last if no such iterator is found. /// /// Complexity: At most '(last1 - first1) * count' applications of the corresponding predicate. @@ -2990,13 +2995,13 @@ namespace eastl /// binary_search /// - /// Returns: true if there is an iterator i in the range [first last) that + /// Returns: true if there is an iterator i in the range [first last) that /// satisfies the corresponding conditions: !(*i < value) && !(value < *i). /// /// Complexity: At most 'log(last - first) + 2' comparisons. /// /// Note: The reason binary_search returns bool instead of an iterator is - /// that search_n, lower_bound, or equal_range already return an iterator. + /// that search_n, lower_bound, or equal_range already return an iterator. /// However, there are arguments that binary_search should return an iterator. /// Note that we provide binary_search_i (STL extension) to return an iterator. /// @@ -3021,8 +3026,8 @@ namespace eastl /// binary_search /// - /// Returns: true if there is an iterator i in the range [first last) that - /// satisfies the corresponding conditions: compare(*i, value) == false && + /// Returns: true if there is an iterator i in the range [first last) that + /// satisfies the corresponding conditions: compare(*i, value) == false && /// compare(value, *i) == false. /// /// Complexity: At most 'log(last - first) + 2' comparisons. @@ -3041,7 +3046,7 @@ namespace eastl /// binary_search_i /// - /// Returns: iterator if there is an iterator i in the range [first last) that + /// Returns: iterator if there is an iterator i in the range [first last) that /// satisfies the corresponding conditions: !(*i < value) && !(value < *i). /// Returns last if the value is not found. /// @@ -3061,7 +3066,7 @@ namespace eastl /// binary_search_i /// - /// Returns: iterator if there is an iterator i in the range [first last) that + /// Returns: iterator if there is an iterator i in the range [first last) that /// satisfies the corresponding conditions: !(*i < value) && !(value < *i). /// Returns last if the value is not found. /// @@ -3082,12 +3087,12 @@ namespace eastl /// unique /// /// Given a sorted range, this function removes duplicated items. - /// Note that if you have a container then you will probably want - /// to call erase on the container with the return value if your + /// Note that if you have a container then you will probably want + /// to call erase on the container with the return value if your /// goal is to remove the duplicated items from the container. /// - /// Effects: Eliminates all but the first element from every consecutive - /// group of equal elements referred to by the iterator i in the range + /// Effects: Eliminates all but the first element from every consecutive + /// group of equal elements referred to by the iterator i in the range /// [first, last) for which the following corresponding condition holds: /// *i == *(i - 1). /// @@ -3109,7 +3114,7 @@ namespace eastl if(first != last) // We expect that there are duplicated items, else the user wouldn't be calling this function. { ForwardIterator dest(first); - + for(++first; first != last; ++first) { if(!(*dest == *first)) // Note that we always express value comparisons in terms of < or ==. @@ -3124,12 +3129,12 @@ namespace eastl /// unique /// /// Given a sorted range, this function removes duplicated items. - /// Note that if you have a container then you will probably want - /// to call erase on the container with the return value if your + /// Note that if you have a container then you will probably want + /// to call erase on the container with the return value if your /// goal is to remove the duplicated items from the container. /// - /// Effects: Eliminates all but the first element from every consecutive - /// group of equal elements referred to by the iterator i in the range + /// Effects: Eliminates all but the first element from every consecutive + /// group of equal elements referred to by the iterator i in the range /// [first, last) for which the following corresponding condition holds: /// predicate(*i, *(i - 1)) != false. /// @@ -3146,7 +3151,7 @@ namespace eastl if(first != last) // We expect that there are duplicated items, else the user wouldn't be calling this function. { ForwardIterator dest(first); - + for(++first; first != last; ++first) { if(!predicate(*dest, *first)) @@ -3162,8 +3167,8 @@ namespace eastl // find_end // // We provide two versions here, one for a bidirectional iterators and one for - // regular forward iterators. Given that we are searching backward, it's a bit - // more efficient if we can use backwards iteration to implement our search, + // regular forward iterators. Given that we are searching backward, it's a bit + // more efficient if we can use backwards iteration to implement our search, // though this requires an iterator that can be reversed. // template @@ -3199,13 +3204,13 @@ namespace eastl typedef eastl::reverse_iterator reverse_iterator1; typedef eastl::reverse_iterator reverse_iterator2; - reverse_iterator1 rresult(eastl::search(reverse_iterator1(last1), reverse_iterator1(first1), + reverse_iterator1 rresult(eastl::search(reverse_iterator1(last1), reverse_iterator1(first1), reverse_iterator2(last2), reverse_iterator2(first2))); if(rresult.base() != first1) // If we found something... { BidirectionalIterator1 result(rresult.base()); - eastl::advance(result, -eastl::distance(first2, last2)); // We have an opportunity to optimize this, as the + eastl::advance(result, -eastl::distance(first2, last2)); // We have an opportunity to optimize this, as the return result; // search function already calculates this distance. } return last1; @@ -3214,7 +3219,7 @@ namespace eastl /// find_end /// /// Finds the last occurrence of the second sequence in the first sequence. - /// As such, this function is much like the C string function strrstr and it + /// As such, this function is much like the C string function strrstr and it /// is also the same as a reversed version of 'search'. It is called find_end /// instead of the possibly more consistent search_end simply because the C++ /// standard algorithms have such naming. @@ -3236,7 +3241,7 @@ namespace eastl - // To consider: Fold the predicate and non-predicate versions of + // To consider: Fold the predicate and non-predicate versions of // this algorithm into a single function. template ForwardIterator1 @@ -3267,14 +3272,14 @@ namespace eastl BidirectionalIterator1 find_end_impl(BidirectionalIterator1 first1, BidirectionalIterator1 last1, BidirectionalIterator2 first2, BidirectionalIterator2 last2, - BinaryPredicate predicate, + BinaryPredicate predicate, EASTL_ITC_NS::bidirectional_iterator_tag, EASTL_ITC_NS::bidirectional_iterator_tag) { typedef eastl::reverse_iterator reverse_iterator1; typedef eastl::reverse_iterator reverse_iterator2; reverse_iterator1 rresult(eastl::search - (reverse_iterator1(last1), reverse_iterator1(first1), + (reverse_iterator1(last1), reverse_iterator1(first1), reverse_iterator2(last2), reverse_iterator2(first2), predicate)); if(rresult.base() != first1) // If we found something... @@ -3292,8 +3297,8 @@ namespace eastl /// Effects: Finds a subsequence of equal values in a sequence. /// /// Returns: The last iterator i in the range [first1, last1 - (last2 - first2)) - /// such that for any nonnegative integer n < (last2 - first2), the following - /// corresponding conditions hold: pred(*(i+n),*(first2+n)) != false. Returns + /// such that for any nonnegative integer n < (last2 - first2), the following + /// corresponding conditions hold: pred(*(i+n),*(first2+n)) != false. Returns /// last1 if no such iterator is found. /// /// Complexity: At most (last2 - first2) * (last1 - first1 - (last2 - first2) + 1) @@ -3313,31 +3318,30 @@ namespace eastl } - /// set_difference /// - /// set_difference iterates over both input ranges and copies elements present + /// set_difference iterates over both input ranges and copies elements present /// in the first range but not the second to the output range. /// - /// Effects: Copies the elements of the range [first1, last1) which are not - /// present in the range [first2, last2) to the range beginning at result. + /// Effects: Copies the elements of the range [first1, last1) which are not + /// present in the range [first2, last2) to the range beginning at result. /// The elements in the constructed range are sorted. - /// + /// /// Requires: The input ranges must be sorted. /// Requires: The output range shall not overlap with either of the original ranges. - /// + /// /// Returns: The end of the output range. - /// + /// /// Complexity: At most (2 * ((last1 - first1) + (last2 - first2)) - 1) comparisons. /// template OutputIterator set_difference(InputIterator1 first1, InputIterator1 last1, - InputIterator2 first2, InputIterator2 last2, - OutputIterator result) + InputIterator2 first2, InputIterator2 last2, + OutputIterator result) { while((first1 != last1) && (first2 != last2)) { - if(*first1 < *first2) + if(*first1 < *first2) { *result = *first1; ++first1; @@ -3345,7 +3349,7 @@ namespace eastl } else if(*first2 < *first1) ++first2; - else + else { ++first1; ++first2; @@ -3358,12 +3362,12 @@ namespace eastl template OutputIterator set_difference(InputIterator1 first1, InputIterator1 last1, - InputIterator2 first2, InputIterator2 last2, - OutputIterator result, Compare compare) + InputIterator2 first2, InputIterator2 last2, + OutputIterator result, Compare compare) { while((first1 != last1) && (first2 != last2)) { - if(compare(*first1, *first2)) + if(compare(*first1, *first2)) { EASTL_VALIDATE_COMPARE(!compare(*first2, *first1)); // Validate that the compare function is sane. *result = *first1; @@ -3375,7 +3379,7 @@ namespace eastl EASTL_VALIDATE_COMPARE(!compare(*first1, *first2)); // Validate that the compare function is sane. ++first2; } - else + else { ++first1; ++first2; @@ -3386,15 +3390,75 @@ namespace eastl } + /// set_difference_2 + /// + /// set_difference_2 iterates over both input ranges and copies elements present + /// in the first range but not the second to the first output range and copies + /// elements present in the second range but not in the first to the second output + /// range. + /// + /// Effects: Copies the elements of the range [first1, last1) which are not + /// present in the range [first2, last2) to the first output range beginning at + /// result1 AND copies the element of range [first2, last2) which are not present + /// in the range [first1, last) to the second output range beginning at result2. + /// The elements in the constructed range are sorted. + /// + /// Requires: The input ranges must be sorted. + /// Requires: The output ranges shall not overlap with either of the original ranges. + /// + /// Returns: Nothing. + /// + /// Complexity: At most (2 * ((last1 - first1) + (last2 - first2)) - 1) comparisons. + /// + template + void set_difference_2(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, + OutputIterator result1, OutputIterator result2, Compare compare) + { + while ((first1 != last1) && (first2 != last2)) + { + if (compare(*first1, *first2)) + { + EASTL_VALIDATE_COMPARE(!compare(*first2, *first1)); // Validate that the compare function is sane. + *result1++ = *first1++; + } + else if (compare(*first2, *first1)) + { + EASTL_VALIDATE_COMPARE(!compare(*first1, *first2)); // Validate that the compare function is sane. + *result2++ = *first2++; + } + else + { + ++first1; + ++first2; + } + } + + eastl::copy(first2, last2, result2); + eastl::copy(first1, last1, result1); + } + + /// set_difference_2 + /// + /// set_difference_2 with the default comparison object is eastl::less<>. + /// + template + void set_difference_2(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, + OutputIterator result1, OutputIterator result2) + { + eastl::set_difference_2(first1, last1, first2, last2, result1, result2, eastl::less<>{}); + } + /// set_symmetric_difference /// - /// set_difference iterates over both input ranges and copies elements present + /// set_difference iterates over both input ranges and copies elements present /// in the either range but not the other to the output range. /// - /// Effects: Copies the elements of the range [first1, last1) which are not - /// present in the range [first2, last2), and the elements of the range [first2, last2) - /// which are not present in the range [first1, last1) to the range beginning at result. + /// Effects: Copies the elements of the range [first1, last1) which are not + /// present in the range [first2, last2), and the elements of the range [first2, last2) + /// which are not present in the range [first1, last1) to the range beginning at result. /// The elements in the constructed range are sorted. /// /// Requires: The input ranges must be sorted. @@ -3403,7 +3467,7 @@ namespace eastl /// Returns: The end of the constructed range. /// /// Complexity: At most (2 * ((last1 - first1) + (last2 - first2)) - 1) comparisons. - /// + /// template OutputIterator set_symmetric_difference(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, @@ -3429,7 +3493,7 @@ namespace eastl ++first2; } } - + return eastl::copy(first2, last2, eastl::copy(first1, last1, result)); } @@ -3461,31 +3525,29 @@ namespace eastl ++first2; } } - + return eastl::copy(first2, last2, eastl::copy(first1, last1, result)); } - - /// set_intersection /// /// set_intersection over both ranges and copies elements present in - /// both ranges to the output range. + /// both ranges to the output range. /// - /// Effects: Constructs a sorted intersection of the elements from the + /// Effects: Constructs a sorted intersection of the elements from the /// two ranges; that is, the set of elements that are present in both of the ranges. /// /// Requires: The input ranges must be sorted. /// Requires: The resulting range shall not overlap with either of the original ranges. - /// + /// /// Returns: The end of the constructed range. - /// + /// /// Complexity: At most 2 * ((last1 - first1) + (last2 - first2)) - 1) comparisons. - /// - /// Note: The copying operation is stable; if an element is present in both ranges, + /// + /// Note: The copying operation is stable; if an element is present in both ranges, /// the one from the first range is copied. - /// + /// template OutputIterator set_intersection(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, @@ -3543,10 +3605,10 @@ namespace eastl /// set_union /// - /// set_union iterators over both ranges and copies elements present in + /// set_union iterates over both ranges and copies elements present in /// both ranges to the output range. /// - /// Effects: Constructs a sorted union of the elements from the two ranges; + /// Effects: Constructs a sorted union of the elements from the two ranges; /// that is, the set of elements that are present in one or both of the ranges. /// /// Requires: The input ranges must be sorted. @@ -3556,7 +3618,7 @@ namespace eastl /// /// Complexity: At most (2 * ((last1 - first1) + (last2 - first2)) - 1) comparisons. /// - /// Note: The copying operation is stable; if an element is present in both ranges, + /// Note: The copying operation is stable; if an element is present in both ranges, /// the one from the first range is copied. /// template @@ -3621,6 +3683,67 @@ namespace eastl } + /// set_decomposition + /// + /// set_decomposition iterates over both ranges and copies elements to one of the three + /// categories of output ranges. + /// + /// Effects: Constructs three sorted containers of the elements from the two ranges. + /// * OutputIterator1 is elements only in Container1. + /// * OutputIterator2 is elements only in Container2. + /// * OutputIterator3 is elements that are in both Container1 and Container2. + /// + /// Requires: The input ranges must be sorted. + /// Requires: The resulting ranges shall not overlap with either of the original ranges. + /// + /// Returns: The end of the constructed range of elements in both Container1 and Container2. + /// + /// Complexity: At most (2 * ((last1 - first1) + (last2 - first2)) - 1) comparisons. + /// + template + OutputIterator3 set_decomposition(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, + OutputIterator1 result1, OutputIterator2 result2, OutputIterator3 result3, Compare compare) + { + while ((first1 != last1) && (first2 != last2)) + { + if (compare(*first1, *first2)) + { + EASTL_VALIDATE_COMPARE(!compare(*first2, *first1)); // Validate that the compare function is sane. + *result1++ = *first1++; + } + else if (compare(*first2, *first1)) + { + EASTL_VALIDATE_COMPARE(!compare(*first1, *first2)); // Validate that the compare function is sane. + *result2++ = *first2++; + } + else + { + *result3++ = *first1++; + ++first2; + } + } + + eastl::copy(first1, last1, result1); + eastl::copy(first2, last2, result2); + + return result3; + } + + /// set_decomposition + /// + /// set_decomposition with the default comparison object is eastl::less<>. + /// + template + OutputIterator3 set_decomposition(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, + OutputIterator1 result1, OutputIterator2 result2, OutputIterator3 result3) + { + return eastl::set_decomposition(first1, last1, first2, last2, result1, result2, result3, eastl::less<>{}); + } + + /// is_permutation /// template @@ -3643,7 +3766,7 @@ namespace eastl for(ForwardIterator1 i = first1; i != last1; ++i) { - if(i == eastl::find(first1, i, *i)) + if(i == eastl::find(first1, i, *i)) { const difference_type c = eastl::count(first2, last2, *i); @@ -3678,7 +3801,7 @@ namespace eastl for(ForwardIterator1 i = first1; i != last1; ++i) { - if(i == eastl::find(first1, i, *i, predicate)) + if(i == eastl::find(first1, i, *i, predicate)) { const difference_type c = eastl::count(first2, last2, *i, predicate); @@ -3694,7 +3817,7 @@ namespace eastl /// next_permutation /// - /// mutates the range [first, last) to the next permutation. Returns true if the + /// mutates the range [first, last) to the next permutation. Returns true if the /// new range is not the final permutation (sorted like the starting permutation). /// Permutations start with a sorted range, and false is returned when next_permutation /// results in the initial sorted range, or if the range has <= 1 element. @@ -3703,10 +3826,10 @@ namespace eastl /// /// http://marknelson.us/2002/03/01/next-permutation/ /// Basically we start with an ordered range and reverse it's order one specifically - /// chosen swap and reverse at a time. It happens that this require going through every + /// chosen swap and reverse at a time. It happens that this require going through every /// permutation of the range. We use the same variable names as the document above. /// - /// To consider: Significantly improved permutation/combination functionality: + /// To consider: Significantly improved permutation/combination functionality: /// http://home.roadrunner.com/~hinnant/combinations.html /// /// Example usage: @@ -3730,14 +3853,14 @@ namespace eastl for(;;) { BidirectionalIterator ii(i), j; - + if(compare(*--i, *ii)) // Find two consecutive values where the first is less than the second. { j = last; while(!compare(*i, *--j)) // Find the final value that's greater than the first (it may be equal to the second). {} eastl::iter_swap(i, j); // Swap the first and the final. - eastl::reverse(ii, last); // Reverse the ranget from second to last. + eastl::reverse(ii, last); // Reverse the ranget from second to last. return true; } @@ -3758,29 +3881,29 @@ namespace eastl { typedef typename eastl::iterator_traits::value_type value_type; - return next_permutation(first, last, eastl::less()); + return eastl::next_permutation(first, last, eastl::less()); } /// rotate /// - /// Effects: For each non-negative integer i < (last - first), places the element from the + /// Effects: For each non-negative integer i < (last - first), places the element from the /// position first + i into position first + (i + (last - middle)) % (last - first). /// /// Returns: first + (last - middle). That is, returns where first went to. - /// + /// /// Remarks: This is a left rotate. - /// - /// Requires: [first,middle) and [middle,last) shall be valid ranges. ForwardIterator shall - /// satisfy the requirements of ValueSwappable (17.6.3.2). The type of *first shall satisfy + /// + /// Requires: [first,middle) and [middle,last) shall be valid ranges. ForwardIterator shall + /// satisfy the requirements of ValueSwappable (17.6.3.2). The type of *first shall satisfy /// the requirements of MoveConstructible (Table 20) and the requirements of MoveAssignable. /// /// Complexity: At most last - first swaps. /// - /// Note: While rotate works on ForwardIterators (e.g. slist) and BidirectionalIterators (e.g. list), - /// you can get much better performance (O(1) instead of O(n)) with slist and list rotation by - /// doing splice operations on those lists instead of calling this rotate function. + /// Note: While rotate works on ForwardIterators (e.g. slist) and BidirectionalIterators (e.g. list), + /// you can get much better performance (O(1) instead of O(n)) with slist and list rotation by + /// doing splice operations on those lists instead of calling this rotate function. /// /// http://www.cs.bell-labs.com/cm/cs/pearls/s02b.pdf / http://books.google.com/books?id=kse_7qbWbjsC&pg=PA14&lpg=PA14&dq=Programming+Pearls+flipping+hands /// http://books.google.com/books?id=tjOlkl7ecVQC&pg=PA189&lpg=PA189&dq=stepanov+Elements+of+Programming+rotate @@ -3789,7 +3912,7 @@ namespace eastl /// Strategy: /// - We handle the special case of (middle == first) and (middle == last) no-ops /// up front in the main rotate entry point. - /// - There's a basic ForwardIterator implementation (rotate_general_impl) which is + /// - There's a basic ForwardIterator implementation (rotate_general_impl) which is /// a fallback implementation that's not as fast as others but works for all cases. /// - There's a slightly better BidirectionalIterator implementation. /// - We have specialized versions for rotating elements that are is_trivially_move_assignable. @@ -3798,7 +3921,7 @@ namespace eastl /// (with any iterator type) to avoid a lot of logic involved with algorithms like "flipping hands" /// and achieve near optimal O(n) behavior. it turns out that rotate-by-one is a common use /// case in practice. - /// + /// namespace Internal { template @@ -3866,7 +3989,7 @@ namespace eastl { return Internal::rotate_general_impl(first, middle, last); } }; - template <> + template <> struct rotate_helper { template @@ -3878,18 +4001,18 @@ namespace eastl } }; - template <> + template <> struct rotate_helper { template static BidirectionalIterator rotate_impl(BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last) { return Internal::rotate_general_impl(first, middle, last); } // rotate_general_impl outperforms the flipping hands algorithm. - /* + /* // Simplest "flipping hands" implementation. Disabled because it's slower on average than rotate_general_impl. template static BidirectionalIterator rotate_impl(BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last) - { + { eastl::reverse(first, middle); eastl::reverse(middle, last); eastl::reverse(first, last); @@ -3905,7 +4028,7 @@ namespace eastl eastl::reverse_impl(middle, last, EASTL_ITC_NS::bidirectional_iterator_tag()); // Reverse the right side. // Reverse the entire range. - while((first != middle) && (middle != last)) + while((first != middle) && (middle != last)) { eastl::iter_swap(first, --last); ++first; @@ -3925,13 +4048,13 @@ namespace eastl */ }; - template <> + template <> struct rotate_helper { template static BidirectionalIterator rotate_impl(BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last) { - if(eastl::next(first) == middle) // If moving trivial types by a single element, memcpy is fast for that case. + if(eastl::next(first) == middle) // If moving trivial types by a single element, memcpy is fast for that case. return Internal::move_rotate_left_by_one(first, last); if(eastl::next(middle) == last) return Internal::move_rotate_right_by_one(first, last); @@ -3951,11 +4074,11 @@ namespace eastl return x; } - template <> + template <> struct rotate_helper { // This is the juggling algorithm, using move operations. - // In practice this implementation is about 25% faster than rotate_general_impl. We may want to + // In practice this implementation is about 25% faster than rotate_general_impl. We may want to // consider sticking with just rotate_general_impl and avoid the code generation of this function. template static RandomAccessIterator rotate_impl(RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last) @@ -3992,19 +4115,19 @@ namespace eastl } }; - template <> + template <> struct rotate_helper { // Experiments were done which tested the performance of using an intermediate buffer - // to do memcpy's to as opposed to executing a swapping algorithm. It turns out this is + // to do memcpy's to as opposed to executing a swapping algorithm. It turns out this is // actually slower than even rotate_general_impl, partly because the average case involves - // memcpy'ing a quarter of the element range twice. Experiments were done with various kinds + // memcpy'ing a quarter of the element range twice. Experiments were done with various kinds // of PODs with various element counts. template static RandomAccessIterator rotate_impl(RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last) { - if(eastl::next(first) == middle) // If moving trivial types by a single element, memcpy is fast for that case. + if(eastl::next(first) == middle) // If moving trivial types by a single element, memcpy is fast for that case. return Internal::move_rotate_left_by_one(first, last); if(eastl::next(middle) == last) return Internal::move_rotate_right_by_one(first, last); @@ -4043,7 +4166,7 @@ namespace eastl /// rotate_copy /// - /// Similar to rotate except writes the output to the OutputIterator and + /// Similar to rotate except writes the output to the OutputIterator and /// returns an OutputIterator to the element past the last element copied /// (i.e. result + (last - first)) /// @@ -4061,12 +4184,6 @@ namespace eastl /// /// http://en.cppreference.com/w/cpp/algorithm/clamp /// - template - EA_CONSTEXPR const T& clamp(const T& v, const T& lo, const T& hi) - { - return clamp(v, lo, hi, eastl::less<>()); - } - template EA_CONSTEXPR const T& clamp(const T& v, const T& lo, const T& hi, Compare comp) { @@ -4075,6 +4192,13 @@ namespace eastl comp(v, lo) ? lo : comp(hi, v) ? hi : v; } + template + EA_CONSTEXPR const T& clamp(const T& v, const T& lo, const T& hi) + { + return eastl::clamp(v, lo, hi, eastl::less<>()); + } + + } // namespace eastl diff --git a/library/3rdparty/EASTL/include/EASTL/allocator_malloc.h b/library/3rdparty/EASTL/include/EASTL/allocator_malloc.h index 31f8dec..78f4f69 100644 --- a/library/3rdparty/EASTL/include/EASTL/allocator_malloc.h +++ b/library/3rdparty/EASTL/include/EASTL/allocator_malloc.h @@ -40,7 +40,7 @@ #endif #elif defined(EA_PLATFORM_BSD) #include - #elif defined(EA_COMPILER_CLANG) + #elif defined(__clang__) #if __has_include() #include #elif __has_include() diff --git a/library/3rdparty/EASTL/include/EASTL/any.h b/library/3rdparty/EASTL/include/EASTL/any.h index ef8a312..c2ef638 100644 --- a/library/3rdparty/EASTL/include/EASTL/any.h +++ b/library/3rdparty/EASTL/include/EASTL/any.h @@ -9,7 +9,7 @@ // // eastl::any is a type-safe container for single values of any type. Our // implementation makes use of the "small local buffer" optimization to avoid -// unnecessary dynamic memory allocation if the specified type is a eligible to +// unnecessary dynamic memory allocation if the specified type is eligible to // be stored in its local buffer. The user type must satisfy the size // requirements and must be no-throw move-constructible to qualify for the local // buffer optimization. @@ -591,7 +591,7 @@ namespace eastl // NOTE(rparolin): The runtime type check was commented out because in DLL builds the templated function pointer // value will be different -- completely breaking the validation mechanism. Due to the fact that eastl::any uses - // type erasure we can't refesh (on copy/move) the cached function pointer to the internal handler function because + // type erasure we can't refresh (on copy/move) the cached function pointer to the internal handler function because // we don't statically know the type. template inline const ValueType* any_cast(const any* pAny) EA_NOEXCEPT diff --git a/library/3rdparty/EASTL/include/EASTL/array.h b/library/3rdparty/EASTL/include/EASTL/array.h index 590aa94..05d5d32 100644 --- a/library/3rdparty/EASTL/include/EASTL/array.h +++ b/library/3rdparty/EASTL/include/EASTL/array.h @@ -279,12 +279,6 @@ namespace eastl EA_CPP14_CONSTEXPR inline typename array::reference array::operator[](size_type i) { - #if EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY(i >= N)) - EASTL_FAIL_MSG("array::operator[] -- out of range"); - #endif - - EA_ANALYSIS_ASSUME(i < N); return mValue[i]; } @@ -293,13 +287,6 @@ namespace eastl EA_CPP14_CONSTEXPR inline typename array::const_reference array::operator[](size_type i) const { - #if EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY(i >= N)) - EASTL_FAIL_MSG("array::operator[] -- out of range"); - - #endif - - EA_ANALYSIS_ASSUME(i < N); return mValue[i]; } @@ -308,11 +295,6 @@ namespace eastl EA_CPP14_CONSTEXPR inline typename array::reference array::front() { - #if EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY(empty())) // We don't allow the user to reference an empty container. - EASTL_FAIL_MSG("array::front -- empty array"); - #endif - return mValue[0]; } @@ -321,11 +303,6 @@ namespace eastl EA_CPP14_CONSTEXPR inline typename array::const_reference array::front() const { - #if EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY(empty())) // We don't allow the user to reference an empty container. - EASTL_FAIL_MSG("array::front -- empty array"); - #endif - return mValue[0]; } @@ -334,11 +311,6 @@ namespace eastl EA_CPP14_CONSTEXPR inline typename array::reference array::back() { - #if EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY(empty())) // We don't allow the user to reference an empty container. - EASTL_FAIL_MSG("array::back -- empty array"); - #endif - return mValue[N - 1]; } @@ -347,11 +319,6 @@ namespace eastl EA_CPP14_CONSTEXPR inline typename array::const_reference array::back() const { - #if EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY(empty())) // We don't allow the user to reference an empty container. - EASTL_FAIL_MSG("array::back -- empty array"); - #endif - return mValue[N - 1]; } @@ -381,7 +348,6 @@ namespace eastl EASTL_FAIL_MSG("array::at -- out of range"); #endif - EA_ANALYSIS_ASSUME(i < N); return static_cast(mValue[i]); } @@ -397,7 +363,6 @@ namespace eastl EASTL_FAIL_MSG("array::at -- out of range"); #endif - EA_ANALYSIS_ASSUME(i < N); return static_cast(mValue[i]); } diff --git a/library/3rdparty/EASTL/include/EASTL/atomic.h b/library/3rdparty/EASTL/include/EASTL/atomic.h index f27a72d..27117e9 100644 --- a/library/3rdparty/EASTL/include/EASTL/atomic.h +++ b/library/3rdparty/EASTL/include/EASTL/atomic.h @@ -243,36 +243,27 @@ // Deviations from the standard. This does not include new features added: // // 1. -// Description: Atomic class constructors are not and will not be constexpr. -// Reasoning : We assert in the constructor that the this pointer is properly aligned. -// There are no other constexpr functions that can be called in a constexpr -// context. The only use for constexpr here is const-init time or ensuring -// that the object's value is placed in the executable at compile-time instead -// of having to call the ctor at static-init time. If you are using constexpr -// to solve static-init order fiasco, there are other solutions for that. -// -// 2. // Description: Atomics are always lock free // Reasoning : We don't want people to fall into performance traps where implicit locking // is done. If your user defined type is large enough to not support atomic // instructions then your user code should do the locking. // -// 3. +// 2. // Description: Atomic objects can not be volatile // Reasoning : Volatile objects do not make sense in the context of eastl::atomic. // Use the given memory orders to get the ordering you need. // Atomic objects have to become visible on the bus. See below for details. // -// 4. +// 3. // Description: Consume memory order is not supported // Reasoning : See below for the reasoning. // -// 5. +// 4. // Description: ATOMIC_INIT() macros and the ATOMIC_LOCK_FREE macros are not implemented // Reasoning : Use the is_lock_free() method instead of the macros. // ATOMIC_INIT() macros aren't needed since the default constructor value initializes. // -// 6. +// 5. // Description: compare_exchange failure memory order cannot be stronger than success memory order // Reasoning : Besides the argument that it ideologically does not make sense that a failure // of the atomic operation shouldn't have a stricter ordering guarantee than the @@ -284,7 +275,7 @@ // that versions of compilers that say they support C++17 do not properly adhere to this // new requirement in their intrinsics. Thus we will not support this. // -// 7. +// 6. // Description: All memory orders are distinct types instead of enum values // Reasoning : This will not affect how the API is used in user code. // It allows us to statically assert on invalid memory orders since they are compile-time types @@ -1384,13 +1375,62 @@ // The read_depends operation can be used on loads from only an eastl::atomic type. The return pointer of the load must and can only be used to then further load values. And that is it. // If you are unsure, upgrade this load to an acquire operation. // -// MyStruct* ptr = gAtomicPtr.load(read_depends); +// MyStruct* ptr = gAtomicPtr.load(memory_order_read_depends); // int a = ptr->a; // int b = ptr->b; // return a + b; // // The loads from ptr after the gAtomicPtr load ensure that the correct values of a and b are observed. This pairs with a Release operation on the writer side by releasing gAtomicPtr. // +// +// As said above the returned pointer from a .load(memory_order_read_depends) can only be used to then further load values. +// Dereferencing(*) and Arrow Dereferencing(->) are valid operations on return values from .load(memory_order_read_depends). +// +// MyStruct* ptr = gAtomicPtr.load(memory_order_read_depends); +// int a = ptr->a; - VALID +// int a = *ptr; - VALID +// +// Since dereferencing is just indexing via some offset from some base address, this also means addition and subtraction of constants is ok. +// +// int* ptr = gAtomicPtr.load(memory_order_read_depends); +// int a = *(ptr + 1) - VALID +// int a = *(ptr - 1) - VALID +// +// Casts also work correctly since casting is just offsetting a pointer depending on the inheritance hierarchy or if using intrusive containers. +// +// ReadDependsIntrusive** intrusivePtr = gAtomicPtr.load(memory_order_read_depends); +// ReadDependsIntrusive* ptr = ((ReadDependsIntrusive*)(((char*)intrusivePtr) - offsetof(ReadDependsIntrusive, next))); +// +// Base* basePtr = gAtomicPtr.load(memory_order_read_depends); +// Dervied* derivedPtr = static_cast(basePtr); +// +// Both of the above castings from the result of the load are valid for this memory order. +// +// You can reinterpret_cast the returned pointer value to a uintptr_t to set bits, clear bits, or xor bits but the pointer must be casted back before doing anything else. +// +// int* ptr = gAtomicPtr.load(memory_order_read_depends); +// ptr = reinterpret_cast(reinterpret_cast(ptr) & ~3); +// +// Do not use any equality or relational operator (==, !=, >, <, >=, <=) results in the computation of offsets before dereferencing. +// As we learned above in the Control Dependencies section, CPUs will not order Load-Load Control Dependencies. Relational and equality operators are often compiled using branches. +// It doesn't have to be compiled to branched, condition instructions could be used. Or some architectures provide comparison instructions such as set less than which do not need +// branches when using the result of the relational operator in arithmetic statements. Then again short circuiting may need to introduct branches since C++ guarantees the +// rest of the expression must not be evaluated. +// The following odd code is forbidden. +// +// int* ptr = gAtomicPtr.load(memory_order_read_depends); +// int* ptr2 = ptr + (ptr >= 0); +// int a = *ptr2; +// +// Only equality comparisons against nullptr are allowed. This is becase the compiler cannot assume that the address of the loaded value is some known address and substitute our loaded value. +// int* ptr = gAtomicPtr.load(memory_order_read_depends); +// if (ptr == nullptr); - VALID +// if (ptr != nullptr); - VALID +// +// Thus the above sentence that states: +// The return pointer of the load must and can only be used to then further load values. And that is it. +// must be respected by the programmer. This memory order is an optimization added for efficient read heavy pointer swapping data structures. IF you are unsure, use memory_order_acquire. +// // ******** Relaxed && eastl::atomic guarantees ******** // // We saw various ways that compiler barriers do not help us and that we need something more granular to make sure accesses are not mangled by the compiler to be considered atomic. @@ -1586,7 +1626,7 @@ // ---------------------------------------------------------------------------------------- // // In this example it is entirely possible that we observe r0 = 1 && r1 = 0 even though we have source code causality and sequentially consistent operations. -// Observability is tied to the atomic object on which the operation was performed and the thread fence doesn't synchronize-with the fetch_add because there is no +// Observability is tied to the atomic object on which the operation was performed and the thread fence doesn't synchronize-with the fetch_add because // there is no load above the fence that reads the value from the fetch_add. // // ******** Sequential Consistency Semantics ******** diff --git a/library/3rdparty/EASTL/include/EASTL/bit.h b/library/3rdparty/EASTL/include/EASTL/bit.h new file mode 100644 index 0000000..64efe48 --- /dev/null +++ b/library/3rdparty/EASTL/include/EASTL/bit.h @@ -0,0 +1,65 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_BIT_H +#define EASTL_BIT_H + +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + +#include +#include +#include // memcpy + +namespace eastl +{ + // eastl::bit_cast + // Obtains a value of type To by reinterpreting the object representation of 'from'. + // Every bit in the value representation of the returned To object is equal to the + // corresponding bit in the object representation of 'from'. + // + // In order for bit_cast to be constexpr, the compiler needs to explicitly support + // it by providing the __builtin_bit_cast builtin. If that builtin is not available, + // then we memcpy into aligned storage at runtime and return that instead. + // + // Both types To and From must be equal in size, and must be trivially copyable. + + #if defined(EASTL_CONSTEXPR_BIT_CAST_SUPPORTED) && EASTL_CONSTEXPR_BIT_CAST_SUPPORTED + + template::value + && eastl::is_trivially_copyable::value + > + > + EA_CONSTEXPR To bit_cast(const From& from) EA_NOEXCEPT + { + return __builtin_bit_cast(To, from); + } + + #else + + template::value + && eastl::is_trivially_copyable::value + > + > + inline To bit_cast(const From& from) EA_NOEXCEPT + { + typename eastl::aligned_storage::type to; + ::memcpy(eastl::addressof(to), eastl::addressof(from), sizeof(To)); + return reinterpret_cast(to); + } + + #endif // EASTL_CONSTEXPR_BIT_CAST_SUPPORTED + +} // namespace eastl + +#endif // EASTL_BIT_H diff --git a/library/3rdparty/EASTL/include/EASTL/bitset.h b/library/3rdparty/EASTL/include/EASTL/bitset.h index d926105..8778372 100644 --- a/library/3rdparty/EASTL/include/EASTL/bitset.h +++ b/library/3rdparty/EASTL/include/EASTL/bitset.h @@ -1505,7 +1505,7 @@ EA_RESTORE_GCC_WARNING() inline typename BitsetBase<2, WordType>::size_type BitsetBase<2, WordType>::count() const { - #if defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 304) // GCC 3.4 or later + #if (defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 304)) || defined(__clang__) // GCC 3.4 or later #if(EA_PLATFORM_WORD_SIZE == 4) return (size_type)__builtin_popcountl(mWord[0]) + (size_type)__builtin_popcountl(mWord[1]); #else diff --git a/library/3rdparty/EASTL/include/EASTL/bonus/adaptors.h b/library/3rdparty/EASTL/include/EASTL/bonus/adaptors.h index 7e4cd2a..423cacd 100644 --- a/library/3rdparty/EASTL/include/EASTL/bonus/adaptors.h +++ b/library/3rdparty/EASTL/include/EASTL/bonus/adaptors.h @@ -13,6 +13,7 @@ #include #include #include +#include #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. @@ -60,15 +61,15 @@ namespace eastl }; template - auto begin(const reverse_wrapper& w) -> decltype(rbegin(w.mContainer)) + auto begin(const reverse_wrapper& w) -> decltype(eastl::rbegin(w.mContainer)) { - return rbegin(w.mContainer); + return eastl::rbegin(w.mContainer); } template - auto end(const reverse_wrapper& w) -> decltype(rend(w.mContainer)) + auto end(const reverse_wrapper& w) -> decltype(eastl::rend(w.mContainer)) { - return rend(w.mContainer); + return eastl::rend(w.mContainer); } template diff --git a/library/3rdparty/EASTL/include/EASTL/bonus/tuple_vector.h b/library/3rdparty/EASTL/include/EASTL/bonus/tuple_vector.h index 3ce0939..7123c57 100644 --- a/library/3rdparty/EASTL/include/EASTL/bonus/tuple_vector.h +++ b/library/3rdparty/EASTL/include/EASTL/bonus/tuple_vector.h @@ -728,7 +728,7 @@ class TupleVecImpl, Ts...> : public TupleV { if (newNumElements > oldNumCapacity) { - const size_type newCapacity = max(GetNewCapacity(oldNumCapacity), newNumElements); + const size_type newCapacity = eastl::max(GetNewCapacity(oldNumCapacity), newNumElements); void* ppNewLeaf[sizeof...(Ts)]; pair allocation = TupleRecurser::template DoAllocate( @@ -774,7 +774,7 @@ class TupleVecImpl, Ts...> : public TupleV { if (newNumElements > oldNumCapacity) { - const size_type newCapacity = max(GetNewCapacity(oldNumCapacity), newNumElements); + const size_type newCapacity = eastl::max(GetNewCapacity(oldNumCapacity), newNumElements); void* ppNewLeaf[sizeof...(Ts)]; pair allocation = TupleRecurser::template DoAllocate( @@ -826,7 +826,7 @@ class TupleVecImpl, Ts...> : public TupleV { if (newNumElements > oldNumCapacity) { - const size_type newCapacity = max(GetNewCapacity(oldNumCapacity), newNumElements); + const size_type newCapacity = eastl::max(GetNewCapacity(oldNumCapacity), newNumElements); void* ppNewLeaf[sizeof...(Ts)]; pair allocation = TupleRecurser::template DoAllocate( @@ -880,7 +880,7 @@ class TupleVecImpl, Ts...> : public TupleV { if (newNumElements > oldNumCapacity) { - const size_type newCapacity = max(GetNewCapacity(oldNumCapacity), newNumElements); + const size_type newCapacity = eastl::max(GetNewCapacity(oldNumCapacity), newNumElements); void* ppNewLeaf[sizeof...(Ts)]; pair allocation = TupleRecurser::template DoAllocate( diff --git a/library/3rdparty/EASTL/include/EASTL/chrono.h b/library/3rdparty/EASTL/include/EASTL/chrono.h index 453ab0f..5d8ca42 100644 --- a/library/3rdparty/EASTL/include/EASTL/chrono.h +++ b/library/3rdparty/EASTL/include/EASTL/chrono.h @@ -597,8 +597,7 @@ namespace chrono timespec ts; int result = clock_gettime(CLOCK_MONOTONIC, &ts); - if(result == EINVAL - ) + if (result == -1 && errno == EINVAL) result = clock_gettime(CLOCK_REALTIME, &ts); const uint64_t nNanoseconds = (uint64_t)ts.tv_nsec + ((uint64_t)ts.tv_sec * UINT64_C(1000000000)); diff --git a/library/3rdparty/EASTL/include/EASTL/fixed_hash_map.h b/library/3rdparty/EASTL/include/EASTL/fixed_hash_map.h index af6663d..b94ea54 100644 --- a/library/3rdparty/EASTL/include/EASTL/fixed_hash_map.h +++ b/library/3rdparty/EASTL/include/EASTL/fixed_hash_map.h @@ -251,7 +251,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -267,11 +267,13 @@ namespace eastl { EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); - if(!bEnableOverflow) + if (!bEnableOverflow) + { base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + } #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -288,11 +290,13 @@ namespace eastl { EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); - if(!bEnableOverflow) + if (!bEnableOverflow) + { base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + } #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -314,7 +318,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -377,7 +381,7 @@ namespace eastl mAllocator.copy_overflow_allocator(x.mAllocator); #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); + mAllocator.set_name(x.mAllocator.get_name()); #endif EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); @@ -402,7 +406,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -532,8 +536,10 @@ namespace eastl { EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); - if(!bEnableOverflow) + if (!bEnableOverflow) + { base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + } #if EASTL_NAME_ENABLED mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); @@ -556,7 +562,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -577,7 +583,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -599,7 +605,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -616,7 +622,7 @@ namespace eastl mAllocator.copy_overflow_allocator(x.mAllocator); #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); + mAllocator.set_name(x.mAllocator.get_name()); #endif EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); @@ -662,7 +668,7 @@ namespace eastl mAllocator.copy_overflow_allocator(x.mAllocator); #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); + mAllocator.set_name(x.mAllocator.get_name()); #endif EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); @@ -687,7 +693,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); diff --git a/library/3rdparty/EASTL/include/EASTL/fixed_hash_set.h b/library/3rdparty/EASTL/include/EASTL/fixed_hash_set.h index 0db9f49..fa2783a 100644 --- a/library/3rdparty/EASTL/include/EASTL/fixed_hash_set.h +++ b/library/3rdparty/EASTL/include/EASTL/fixed_hash_set.h @@ -75,7 +75,7 @@ namespace eastl bucketCount + 1, sizeof(typename hash_set::node_type), nodeCount, - EASTL_ALIGN_OF(Value), + EASTL_ALIGN_OF(typename hash_set::node_type), 0, bEnableOverflow, OverflowAllocator>, @@ -83,8 +83,9 @@ namespace eastl { public: typedef fixed_hashtable_allocator::node_type), nodeCount, EASTL_ALIGN_OF(Value), 0, - bEnableOverflow, OverflowAllocator> fixed_allocator_type; + OverflowAllocator, bCacheHashCode>::node_type), nodeCount, + EASTL_ALIGN_OF(typename hash_set::node_type), + 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type; typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type; typedef fixed_hash_set this_type; typedef hash_set base_type; @@ -162,7 +163,7 @@ namespace eastl bucketCount + 1, sizeof(typename hash_multiset::node_type), nodeCount, - EASTL_ALIGN_OF(Value), + EASTL_ALIGN_OF(typename hash_multiset::node_type), 0, bEnableOverflow, OverflowAllocator>, @@ -170,7 +171,8 @@ namespace eastl { public: typedef fixed_hashtable_allocator::node_type), nodeCount, EASTL_ALIGN_OF(Value), 0, + OverflowAllocator, bCacheHashCode>::node_type), nodeCount, EASTL_ALIGN_OF(typename hash_multiset::node_type), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type; typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type; typedef hash_multiset base_type; @@ -238,11 +240,13 @@ namespace eastl { EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); - if(!bEnableOverflow) + if (!bEnableOverflow) + { base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + } #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -262,7 +266,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -279,11 +283,13 @@ namespace eastl { EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); - if(!bEnableOverflow) + if (!bEnableOverflow) + { base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + } #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -302,10 +308,12 @@ namespace eastl EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); if(!bEnableOverflow) + { base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + } #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -322,7 +330,7 @@ namespace eastl mAllocator.copy_overflow_allocator(x.mAllocator); #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); + mAllocator.set_name(x.mAllocator.get_name()); #endif EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); @@ -344,7 +352,7 @@ namespace eastl mAllocator.copy_overflow_allocator(x.mAllocator); #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); + mAllocator.set_name(x.mAllocator.get_name()); #endif EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); @@ -366,7 +374,7 @@ namespace eastl mAllocator.copy_overflow_allocator(x.mAllocator); #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); + mAllocator.set_name(x.mAllocator.get_name()); #endif EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); @@ -391,7 +399,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -515,7 +523,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -535,7 +543,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -556,7 +564,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -578,7 +586,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); @@ -595,7 +603,7 @@ namespace eastl mAllocator.copy_overflow_allocator(x.mAllocator); #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); + mAllocator.set_name(x.mAllocator.get_name()); #endif EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); @@ -617,7 +625,7 @@ namespace eastl mAllocator.copy_overflow_allocator(x.mAllocator); #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); + mAllocator.set_name(x.mAllocator.get_name()); #endif EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); @@ -639,7 +647,7 @@ namespace eastl mAllocator.copy_overflow_allocator(x.mAllocator); #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); + mAllocator.set_name(x.mAllocator.get_name()); #endif EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); @@ -664,7 +672,7 @@ namespace eastl base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. #if EASTL_NAME_ENABLED - mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); + mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); #endif mAllocator.reset(mNodeBuffer); diff --git a/library/3rdparty/EASTL/include/EASTL/fixed_list.h b/library/3rdparty/EASTL/include/EASTL/fixed_list.h index 9e48089..e57c08b 100644 --- a/library/3rdparty/EASTL/include/EASTL/fixed_list.h +++ b/library/3rdparty/EASTL/include/EASTL/fixed_list.h @@ -63,12 +63,12 @@ namespace eastl /// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap. /// template - class fixed_list : public list::node_type), - nodeCount, EASTL_ALIGN_OF(T), 0, bEnableOverflow, OverflowAllocator> > + class fixed_list : public list::node_type), + nodeCount, EASTL_ALIGN_OF(typename list::node_type), 0, bEnableOverflow, OverflowAllocator> > { public: - typedef fixed_node_allocator::node_type), nodeCount, - EASTL_ALIGN_OF(T), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type; + typedef fixed_node_allocator::node_type), nodeCount, + EASTL_ALIGN_OF(typename list::node_type), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type; typedef OverflowAllocator overflow_allocator_type; typedef list base_type; typedef fixed_list this_type; diff --git a/library/3rdparty/EASTL/include/EASTL/fixed_slist.h b/library/3rdparty/EASTL/include/EASTL/fixed_slist.h index 85a7a7b..abad7ad 100644 --- a/library/3rdparty/EASTL/include/EASTL/fixed_slist.h +++ b/library/3rdparty/EASTL/include/EASTL/fixed_slist.h @@ -63,12 +63,12 @@ namespace eastl /// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap. /// template - class fixed_slist : public slist::node_type), - nodeCount, EASTL_ALIGN_OF(T), 0, bEnableOverflow, OverflowAllocator> > + class fixed_slist : public slist::node_type), + nodeCount, EASTL_ALIGN_OF(typename slist::node_type), 0, bEnableOverflow, OverflowAllocator> > { public: - typedef fixed_node_allocator::node_type), nodeCount, - EASTL_ALIGN_OF(T), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type; + typedef fixed_node_allocator::node_type), nodeCount, + EASTL_ALIGN_OF(typename slist::node_type), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type; typedef OverflowAllocator overflow_allocator_type; typedef slist base_type; typedef fixed_slist this_type; diff --git a/library/3rdparty/EASTL/include/EASTL/fixed_vector.h b/library/3rdparty/EASTL/include/EASTL/fixed_vector.h index 633eaa8..1dc482b 100644 --- a/library/3rdparty/EASTL/include/EASTL/fixed_vector.h +++ b/library/3rdparty/EASTL/include/EASTL/fixed_vector.h @@ -356,7 +356,7 @@ namespace eastl get_allocator() = x.get_allocator(); // The primary effect of this is to copy the overflow allocator. #endif - base_type::template DoAssign, true>(make_move_iterator(x.begin()), make_move_iterator(x.end()), false_type()); // Shorter route. + base_type::template DoAssign, true>(eastl::make_move_iterator(x.begin()), eastl::make_move_iterator(x.end()), false_type()); // Shorter route. } return *this; } diff --git a/library/3rdparty/EASTL/include/EASTL/functional.h b/library/3rdparty/EASTL/include/EASTL/functional.h index 556bf02..6fa3489 100644 --- a/library/3rdparty/EASTL/include/EASTL/functional.h +++ b/library/3rdparty/EASTL/include/EASTL/functional.h @@ -389,52 +389,41 @@ namespace eastl // Dual type functions /////////////////////////////////////////////////////////////////////// + template struct equal_to_2 : public binary_function { EA_CPP14_CONSTEXPR bool operator()(const T& a, const U& b) const { return a == b; } - EA_CPP14_CONSTEXPR bool operator()(const U& b, const T& a) const // If you are getting a 'operator() already defined' error related to on this line while compiling a - { return b == a; } // hashtable class (e.g. hash_map), it's likely that you are using hashtable::find_as when you should - }; // be using hashtable::find instead. The problem is that (const T, U) collide. To do: make this work. - template - struct equal_to_2 : public equal_to - { + template , eastl::remove_const_t>>> + EA_CPP14_CONSTEXPR bool operator()(const U& b, const T& a) const + { return b == a; } }; - template struct not_equal_to_2 : public binary_function { EA_CPP14_CONSTEXPR bool operator()(const T& a, const U& b) const { return a != b; } + + template , eastl::remove_const_t>>> EA_CPP14_CONSTEXPR bool operator()(const U& b, const T& a) const { return b != a; } }; - template - struct not_equal_to_2 : public not_equal_to - { - }; - template struct less_2 : public binary_function { EA_CPP14_CONSTEXPR bool operator()(const T& a, const U& b) const { return a < b; } + + template , eastl::remove_const_t>>> EA_CPP14_CONSTEXPR bool operator()(const U& b, const T& a) const { return b < a; } }; - template - struct less_2 : public less - { - }; - - - /// unary_negate /// diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/arm/arch_arm_memory_barrier.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/arm/arch_arm_memory_barrier.h index c52962e..44dc991 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/arm/arch_arm_memory_barrier.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/arm/arch_arm_memory_barrier.h @@ -11,7 +11,7 @@ #endif -#if defined(EA_COMPILER_MSVC) +#if defined(EA_COMPILER_MSVC) && !defined(EA_COMPILER_CLANG_CL) #if defined(EA_PROCESSOR_ARM32) @@ -46,7 +46,7 @@ EASTL_ATOMIC_COMPILER_BARRIER() -#elif defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG) +#elif defined(EA_COMPILER_GNUC) || defined(__clang__) #define EASTL_ARM_DMB_ISH ish diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86.h index 5087c13..142a514 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86.h @@ -32,23 +32,14 @@ ///////////////////////////////////////////////////////////////////////////////// - -#if defined(EA_COMPILER_MSVC) - +#if (defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64) + #define EASTL_ARCH_ATOMIC_HAS_128BIT +#elif defined(EA_COMPILER_MSVC) #if EA_PLATFORM_PTR_SIZE == 8 #define EASTL_ARCH_ATOMIC_HAS_128BIT #endif - #endif - -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) - - #define EASTL_ARCH_ATOMIC_HAS_128BIT - -#endif - - ///////////////////////////////////////////////////////////////////////////////// @@ -104,7 +95,7 @@ * SSE 128-bit loads are not guaranteed to be atomic even though some CPUs * make them atomic such as AMD Ryzen or Intel SandyBridge. */ -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_NOP_PRE_COMPUTE_DESIRED(ret, observed, val) \ diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_add_fetch.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_add_fetch.h index 4534806..7b77528 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_add_fetch.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_add_fetch.h @@ -54,7 +54,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_ADD_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \ diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_and_fetch.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_and_fetch.h index c38ba41..0583163 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_and_fetch.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_and_fetch.h @@ -54,7 +54,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_AND_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \ diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_strong.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_strong.h index e028398..1968e9a 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_strong.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_strong.h @@ -15,7 +15,7 @@ // // void EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_*_*_N(type, bool ret, type * ptr, type * expected, type desired) // -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_CMPXCHG_STRONG_128_IMPL(type, ret, ptr, expected, desired) \ diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_weak.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_weak.h index f8b956a..61a126c 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_weak.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_weak.h @@ -15,7 +15,7 @@ // // void EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_*_*_N(type, bool ret, type * ptr, type * expected, type desired) // -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_128(type, ret, ptr, expected, desired) \ diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_exchange.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_exchange.h index 0f05800..624d2f5 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_exchange.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_exchange.h @@ -51,7 +51,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_EXCHANGE_128(type, ret, ptr, val, MemoryOrder) \ diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_add.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_add.h index d78b333..e816af9 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_add.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_add.h @@ -51,7 +51,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_FETCH_ADD_PRE_COMPUTE_DESIRED(ret, observed, val) \ diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_and.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_and.h index fd7dbb9..ff27b1a 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_and.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_and.h @@ -51,7 +51,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_FETCH_AND_PRE_COMPUTE_DESIRED(ret, observed, val) \ diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_or.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_or.h index 50da6db..8627d3a 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_or.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_or.h @@ -51,7 +51,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_FETCH_OR_PRE_COMPUTE_DESIRED(ret, observed, val) \ diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_sub.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_sub.h index 77bee83..14b43f9 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_sub.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_sub.h @@ -51,7 +51,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_FETCH_SUB_PRE_COMPUTE_DESIRED(ret, observed, val) \ diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_xor.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_xor.h index 2e76b0c..666df8b 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_xor.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_xor.h @@ -51,7 +51,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_FETCH_XOR_PRE_COMPUTE_DESIRED(ret, observed, val) \ diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_load.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_load.h index b044190..644a2a1 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_load.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_load.h @@ -15,7 +15,46 @@ // // void EASTL_ARCH_ATOMIC_LOAD_*_N(type, type ret, type * ptr) // -#if defined(EA_COMPILER_MSVC) + +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) + + + /** + * NOTE: + * + * Since the cmpxchg 128-bit inline assembly does a sete in the asm to set the return boolean, + * it doesn't get dead-store removed even though we don't care about the success of the + * cmpxchg since the compiler cannot reason about what is inside asm blocks. + * Thus this variant just does the minimum required to do an atomic load. + */ +#define EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, MemoryOrder) \ + { \ + EASTL_ATOMIC_FIXED_WIDTH_TYPE_128 expected = 0; \ + ret = EASTL_ATOMIC_TYPE_PUN_CAST(type, expected); \ + \ + /* Compare RDX:RAX with m128. If equal, set ZF and load RCX:RBX into m128. Else, clear ZF and load m128 into RDX:RAX. */ \ + __asm__ __volatile__ ("lock; cmpxchg16b %2" /* cmpxchg16b sets/clears ZF */ \ + /* Output Operands */ \ + : "=a"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[0]), "=d"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[1]), \ + "+m"(*(EASTL_ATOMIC_VOLATILE_INTEGRAL_CAST(__uint128_t, (ptr)))) \ + /* Input Operands */ \ + : "b"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[0]), "c"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[1]), \ + "a"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[0]), "d"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[1]) \ + /* Clobbers */ \ + : "memory", "cc"); \ + } + + +#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_128(type, ret, ptr) \ + EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, RELAXED) + +#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_128(type, ret, ptr) \ + EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, ACQUIRE) + +#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_128(type, ret, ptr) \ + EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, SEQ_CST) + +#elif defined(EA_COMPILER_MSVC) #if defined(EA_COMPILER_MSVC) && (EA_COMPILER_VERSION >= 1920) // >= VS2019 @@ -119,49 +158,6 @@ #define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_128(type, ret, ptr) \ EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, SEQ_CST) - -#endif - - -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) - - - /** - * NOTE: - * - * Since the cmpxchg 128-bit inline assembly does a sete in the asm to set the return boolean, - * it doesn't get dead-store removed even though we don't care about the success of the - * cmpxchg since the compiler cannot reason about what is inside asm blocks. - * Thus this variant just does the minimum required to do an atomic load. - */ - #define EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, MemoryOrder) \ - { \ - EASTL_ATOMIC_FIXED_WIDTH_TYPE_128 expected = 0; \ - ret = EASTL_ATOMIC_TYPE_PUN_CAST(type, expected); \ - \ - /* Compare RDX:RAX with m128. If equal, set ZF and load RCX:RBX into m128. Else, clear ZF and load m128 into RDX:RAX. */ \ - __asm__ __volatile__ ("lock; cmpxchg16b %2" /* cmpxchg16b sets/clears ZF */ \ - /* Output Operands */ \ - : "=a"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[0]), "=d"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[1]), \ - "+m"(*(EASTL_ATOMIC_VOLATILE_INTEGRAL_CAST(__uint128_t, (ptr)))) \ - /* Input Operands */ \ - : "b"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[0]), "c"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[1]), \ - "a"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[0]), "d"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[1]) \ - /* Clobbers */ \ - : "memory", "cc"); \ - } - - - #define EASTL_ARCH_ATOMIC_LOAD_RELAXED_128(type, ret, ptr) \ - EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, RELAXED) - - #define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_128(type, ret, ptr) \ - EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, ACQUIRE) - - #define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_128(type, ret, ptr) \ - EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, SEQ_CST) - - #endif diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_memory_barrier.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_memory_barrier.h index 1d1c8fc..7bad141 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_memory_barrier.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_memory_barrier.h @@ -46,7 +46,7 @@ #endif -#elif defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG) +#elif defined(__clang__) || defined(EA_COMPILER_GNUC) /** * NOTE: diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_or_fetch.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_or_fetch.h index 751cc2a..42f7d61 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_or_fetch.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_or_fetch.h @@ -54,7 +54,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_OR_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \ diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_store.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_store.h index 397ff5f..31655c3 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_store.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_store.h @@ -145,7 +145,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_STORE_128(type, ptr, val, MemoryOrder) \ diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_sub_fetch.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_sub_fetch.h index 124b586..a1d0932 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_sub_fetch.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_sub_fetch.h @@ -54,7 +54,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_SUB_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \ diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_thread_fence.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_thread_fence.h index fe3bd58..183c7f3 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_thread_fence.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_thread_fence.h @@ -31,7 +31,7 @@ #endif -#if defined(EA_COMPILER_MSVC) || defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC) +#if defined(EA_COMPILER_MSVC) || defined(__clang__) || defined(EA_COMPILER_GNUC) #define EASTL_ARCH_ATOMIC_THREAD_FENCE_SEQ_CST() \ EASTL_ATOMIC_CPU_MB() diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_xor_fetch.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_xor_fetch.h index 28cb958..a5b62c3 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_xor_fetch.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_xor_fetch.h @@ -54,7 +54,7 @@ #endif -#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) +#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)) #define EASTL_ARCH_ATOMIC_X86_XOR_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \ diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic.h index 12486f8..eb27d2d 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic.h @@ -62,7 +62,7 @@ namespace internal template struct is_atomic_lockfree_size { - static EASTL_CPP17_INLINE_VARIABLE constexpr bool value = false || + static EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR_OR_CONST bool value = false || #if defined(EASTL_ATOMIC_HAS_8BIT) sizeof(T) == 1 || #endif @@ -85,7 +85,7 @@ namespace internal template struct is_user_type_suitable_for_primary_template { - static EASTL_CPP17_INLINE_VARIABLE constexpr bool value = eastl::internal::is_atomic_lockfree_size::value; + static EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR_OR_CONST bool value = eastl::internal::is_atomic_lockfree_size::value; }; @@ -116,7 +116,7 @@ namespace internal \ public: \ \ - static EASTL_CPP17_INLINE_VARIABLE constexpr bool is_always_lock_free = eastl::internal::is_atomic_lockfree_size::value; \ + static EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR_OR_CONST bool is_always_lock_free = eastl::internal::is_atomic_lockfree_size::value; \ \ public: /* deleted ctors && assignment operators */ \ \ @@ -127,12 +127,12 @@ namespace internal \ public: /* ctors */ \ \ - atomic(type desired) EA_NOEXCEPT \ + EA_CONSTEXPR atomic(type desired) EA_NOEXCEPT \ : Base{ desired } \ { \ } \ \ - atomic() EA_NOEXCEPT_IF(eastl::is_nothrow_default_constructible_v) = default; \ + EA_CONSTEXPR atomic() EA_NOEXCEPT_IF(eastl::is_nothrow_default_constructible_v) = default; \ \ public: \ \ @@ -148,7 +148,6 @@ namespace internal } - #define EASTL_ATOMIC_USING_ATOMIC_BASE(type) \ public: \ \ diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_base_width.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_base_width.h index 3b32e56..ca47618 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_base_width.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_base_width.h @@ -198,12 +198,12 @@ namespace internal \ public: /* ctors */ \ \ - atomic_base_width(T desired) EA_NOEXCEPT \ + EA_CONSTEXPR atomic_base_width(T desired) EA_NOEXCEPT \ : Base{ desired } \ { \ } \ \ - atomic_base_width() EA_NOEXCEPT_IF(eastl::is_nothrow_default_constructible_v) = default; \ + EA_CONSTEXPR atomic_base_width() EA_NOEXCEPT_IF(eastl::is_nothrow_default_constructible_v) = default; \ \ atomic_base_width(const atomic_base_width&) EA_NOEXCEPT = delete; \ \ diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_casts.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_casts.h index 84c1fac..54b9ed2 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_casts.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_casts.h @@ -126,7 +126,7 @@ EASTL_FORCE_INLINE Pun AtomicTypePunCast(const T& fromType) EA_NOEXCEPT * aligned_storage ensures we can TypePun objects that aren't trivially default constructible * but still trivially copyable. */ - typename eastl::aligned_storage::type ret; + typename eastl::aligned_storage::type ret; memcpy(eastl::addressof(ret), eastl::addressof(fromType), sizeof(Pun)); return reinterpret_cast(ret); } diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_flag.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_flag.h index 52b2b1c..eed448a 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_flag.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_flag.h @@ -22,12 +22,12 @@ class atomic_flag { public: /* ctors */ - atomic_flag(bool desired) + EA_CONSTEXPR atomic_flag(bool desired) EA_NOEXCEPT : mFlag{ desired } { } - atomic_flag() EA_NOEXCEPT + EA_CONSTEXPR atomic_flag() EA_NOEXCEPT : mFlag{ false } { } @@ -42,13 +42,13 @@ class atomic_flag public: /* clear */ template - void clear(Order order) volatile EA_NOEXCEPT + void clear(Order /*order*/) volatile EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(Order); } template - void clear(Order order) EA_NOEXCEPT + void clear(Order /*order*/) EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(Order); } @@ -76,14 +76,14 @@ class atomic_flag public: /* test_and_set */ template - bool test_and_set(Order order) volatile EA_NOEXCEPT + bool test_and_set(Order /*order*/) volatile EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(Order); return false; } template - bool test_and_set(Order order) EA_NOEXCEPT + bool test_and_set(Order /*order*/) EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(Order); return false; @@ -122,14 +122,14 @@ class atomic_flag public: /* test */ template - bool test(Order order) const volatile EA_NOEXCEPT + bool test(Order /*order*/) const volatile EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(Order); return false; } template - bool test(Order order) const EA_NOEXCEPT + bool test(Order /*order*/) const EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(Order); return false; diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_integral.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_integral.h index 9f01c25..96858de 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_integral.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_integral.h @@ -24,18 +24,18 @@ namespace internal #define EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_FUNCS_IMPL(funcName) \ template \ - T funcName(T arg, Order order) EA_NOEXCEPT \ + T funcName(T /*arg*/, Order /*order*/) EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(T); \ } \ \ template \ - T funcName(T arg, Order order) volatile EA_NOEXCEPT \ + T funcName(T /*arg*/, Order /*order*/) volatile EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \ } \ \ - T funcName(T arg) volatile EA_NOEXCEPT \ + T funcName(T /*arg*/) volatile EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \ } @@ -54,7 +54,7 @@ namespace internal #define EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_ASSIGNMENT_OPERATOR_IMPL(operatorOp) \ - T operator operatorOp(T arg) volatile EA_NOEXCEPT \ + T operator operatorOp(T /*arg*/) volatile EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \ } @@ -69,12 +69,12 @@ namespace internal public: /* ctors */ - atomic_integral_base(T desired) EA_NOEXCEPT + EA_CONSTEXPR atomic_integral_base(T desired) EA_NOEXCEPT : Base{ desired } { } - atomic_integral_base() EA_NOEXCEPT = default; + EA_CONSTEXPR atomic_integral_base() EA_NOEXCEPT = default; atomic_integral_base(const atomic_integral_base&) EA_NOEXCEPT = delete; @@ -227,12 +227,12 @@ namespace internal \ public: /* ctors */ \ \ - atomic_integral_width(T desired) EA_NOEXCEPT \ + EA_CONSTEXPR atomic_integral_width(T desired) EA_NOEXCEPT \ : Base{ desired } \ { \ } \ \ - atomic_integral_width() EA_NOEXCEPT = default; \ + EA_CONSTEXPR atomic_integral_width() EA_NOEXCEPT = default; \ \ atomic_integral_width(const atomic_integral_width&) EA_NOEXCEPT = delete; \ \ diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_memory_order.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_memory_order.h index b1c1403..1564d87 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_memory_order.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_memory_order.h @@ -30,12 +30,12 @@ struct memory_order_seq_cst_s {}; } // namespace internal -EASTL_CPP17_INLINE_VARIABLE constexpr auto memory_order_relaxed = internal::memory_order_relaxed_s{}; -EASTL_CPP17_INLINE_VARIABLE constexpr auto memory_order_read_depends = internal::memory_order_read_depends_s{}; -EASTL_CPP17_INLINE_VARIABLE constexpr auto memory_order_acquire = internal::memory_order_acquire_s{}; -EASTL_CPP17_INLINE_VARIABLE constexpr auto memory_order_release = internal::memory_order_release_s{}; -EASTL_CPP17_INLINE_VARIABLE constexpr auto memory_order_acq_rel = internal::memory_order_acq_rel_s{}; -EASTL_CPP17_INLINE_VARIABLE constexpr auto memory_order_seq_cst = internal::memory_order_seq_cst_s{}; +EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR auto memory_order_relaxed = internal::memory_order_relaxed_s{}; +EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR auto memory_order_read_depends = internal::memory_order_read_depends_s{}; +EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR auto memory_order_acquire = internal::memory_order_acquire_s{}; +EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR auto memory_order_release = internal::memory_order_release_s{}; +EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR auto memory_order_acq_rel = internal::memory_order_acq_rel_s{}; +EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR auto memory_order_seq_cst = internal::memory_order_seq_cst_s{}; } // namespace eastl diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_pointer.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_pointer.h index 38a4647..c0b19e6 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_pointer.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_pointer.h @@ -27,18 +27,18 @@ namespace internal #define EASTL_ATOMIC_POINTER_STATIC_ASSERT_FUNCS_IMPL(funcName) \ template \ - T* funcName(ptrdiff_t arg, Order order) EA_NOEXCEPT \ + T* funcName(ptrdiff_t /*arg*/, Order /*order*/) EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(T); \ } \ \ template \ - T* funcName(ptrdiff_t arg, Order order) volatile EA_NOEXCEPT \ + T* funcName(ptrdiff_t /*arg*/, Order /*order*/) volatile EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \ } \ \ - T* funcName(ptrdiff_t arg) volatile EA_NOEXCEPT \ + T* funcName(ptrdiff_t /*arg*/) volatile EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \ } @@ -55,7 +55,7 @@ namespace internal } #define EASTL_ATOMIC_POINTER_STATIC_ASSERT_ASSIGNMENT_OPERATOR_IMPL(operatorOp) \ - T* operator operatorOp(ptrdiff_t arg) volatile EA_NOEXCEPT \ + T* operator operatorOp(ptrdiff_t /*arg*/) volatile EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \ } @@ -70,12 +70,12 @@ namespace internal public: /* ctors */ - atomic_pointer_base(T* desired) EA_NOEXCEPT + EA_CONSTEXPR atomic_pointer_base(T* desired) EA_NOEXCEPT : Base{ desired } { } - atomic_pointer_base() EA_NOEXCEPT = default; + EA_CONSTEXPR atomic_pointer_base() EA_NOEXCEPT = default; atomic_pointer_base(const atomic_pointer_base&) EA_NOEXCEPT = delete; @@ -203,12 +203,12 @@ namespace internal \ public: /* ctors */ \ \ - atomic_pointer_width(T* desired) EA_NOEXCEPT \ + EA_CONSTEXPR atomic_pointer_width(T* desired) EA_NOEXCEPT \ : Base{ desired } \ { \ } \ \ - atomic_pointer_width() EA_NOEXCEPT = default; \ + EA_CONSTEXPR atomic_pointer_width() EA_NOEXCEPT = default; \ \ atomic_pointer_width(const atomic_pointer_width&) EA_NOEXCEPT = delete; \ \ diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_size_aligned.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_size_aligned.h index 2043ae2..f503375 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_size_aligned.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_size_aligned.h @@ -24,40 +24,40 @@ namespace internal #define EASTL_ATOMIC_SIZE_ALIGNED_STATIC_ASSERT_CMPXCHG_IMPL(funcName) \ template \ - bool funcName(T& expected, T desired, \ - OrderSuccess orderSuccess, \ - OrderFailure orderFailure) EA_NOEXCEPT \ + bool funcName(T& /*expected*/, T /*desired*/, \ + OrderSuccess /*orderSuccess*/, \ + OrderFailure /*orderFailure*/) EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(T); \ return false; \ } \ \ template \ - bool funcName(T& expected, T desired, \ - OrderSuccess orderSuccess, \ - OrderFailure orderFailure) volatile EA_NOEXCEPT \ + bool funcName(T& /*expected*/, T /*desired*/, \ + OrderSuccess /*orderSuccess*/, \ + OrderFailure /*orderFailure*/) volatile EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \ return false; \ } \ \ template \ - bool funcName(T& expected, T desired, \ - Order order) EA_NOEXCEPT \ + bool funcName(T& /*expected*/, T /*desired*/, \ + Order /*order*/) EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(T); \ return false; \ } \ \ template \ - bool funcName(T& expected, T desired, \ - Order order) volatile EA_NOEXCEPT \ + bool funcName(T& /*expected*/, T /*desired*/, \ + Order /*order*/) volatile EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \ return false; \ } \ \ - bool funcName(T& expected, T desired) volatile EA_NOEXCEPT \ + bool funcName(T& /*expected*/, T /*desired*/) volatile EA_NOEXCEPT \ { \ EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \ return false; \ @@ -75,16 +75,14 @@ namespace internal { public: /* ctors */ - atomic_size_aligned(T desired) EA_NOEXCEPT + EA_CONSTEXPR atomic_size_aligned(T desired) EA_NOEXCEPT : mAtomic{ desired } { - EASTL_ATOMIC_ASSERT_ALIGNED(sizeof(T)); } - atomic_size_aligned() EA_NOEXCEPT_IF(eastl::is_nothrow_default_constructible_v) + EA_CONSTEXPR atomic_size_aligned() EA_NOEXCEPT_IF(eastl::is_nothrow_default_constructible_v) : mAtomic{} /* Value-Initialize which will Zero-Initialize Trivial Constructible types */ { - EASTL_ATOMIC_ASSERT_ALIGNED(sizeof(T)); } atomic_size_aligned(const atomic_size_aligned&) EA_NOEXCEPT = delete; @@ -92,18 +90,18 @@ namespace internal public: /* store */ template - void store(T desired, Order order) EA_NOEXCEPT + void store(T /*desired*/, Order /*order*/) EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(T); } template - void store(T desired, Order order) volatile EA_NOEXCEPT + void store(T /*desired*/, Order /*order*/) volatile EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); } - void store(T desired) volatile EA_NOEXCEPT + void store(T /*desired*/) volatile EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); } @@ -111,13 +109,13 @@ namespace internal public: /* load */ template - T load(Order order) const EA_NOEXCEPT + T load(Order /*order*/) const EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(T); } template - T load(Order order) const volatile EA_NOEXCEPT + T load(Order /*order*/) const volatile EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); } @@ -130,18 +128,18 @@ namespace internal public: /* exchange */ template - T exchange(T desired, Order order) EA_NOEXCEPT + T exchange(T /*desired*/, Order /*order*/) EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(T); } template - T exchange(T desired, Order order) volatile EA_NOEXCEPT + T exchange(T /*desired*/, Order /*order*/) volatile EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); } - T exchange(T desired) volatile EA_NOEXCEPT + T exchange(T /*desired*/) volatile EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); } @@ -156,7 +154,7 @@ namespace internal public: /* assignment operator */ - T operator=(T desired) volatile EA_NOEXCEPT + T operator=(T /*desired*/) volatile EA_NOEXCEPT { EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); } diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_standalone.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_standalone.h index ec0fb33..011d5fb 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_standalone.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/atomic_standalone.h @@ -303,41 +303,33 @@ EASTL_FORCE_INLINE typename eastl::atomic::value_type atomic_load_explicit(co template EASTL_FORCE_INLINE typename eastl::atomic::value_type atomic_load_cond(const eastl::atomic* atomicObj, Predicate pred) EA_NOEXCEPT { - typename eastl::atomic::value_type ret; - for (;;) { - ret = atomicObj->load(); + typename eastl::atomic::value_type ret = atomicObj->load(); if (pred(ret)) { - break; + return ret; } EASTL_ATOMIC_CPU_PAUSE(); } - - return ret; } template EASTL_FORCE_INLINE typename eastl::atomic::value_type atomic_load_cond_explicit(const eastl::atomic* atomicObj, Predicate pred, Order order) EA_NOEXCEPT { - typename eastl::atomic::value_type ret; - for (;;) { - ret = atomicObj->load(order); + typename eastl::atomic::value_type ret = atomicObj->load(order); if (pred(ret)) { - break; + return ret; } EASTL_ATOMIC_CPU_PAUSE(); } - - return ret; } diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/compiler.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/compiler.h index 65a4cd0..fc12879 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/compiler.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/compiler.h @@ -15,7 +15,7 @@ // // Include the compiler specific implementations // -#if defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG) +#if defined(EA_COMPILER_GNUC) || defined(__clang__) #include "gcc/compiler_gcc.h" diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc.h index 90b1ff5..6df8c05 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc.h @@ -173,6 +173,16 @@ struct FixedWidth128 } \ } +/** + * In my own opinion, I found the wording on Microsoft docs a little confusing. + * ExchangeHigh means the top 8 bytes so (ptr + 8). + * ExchangeLow means the low 8 butes so (ptr). + * Endianness does not matter since we are just loading data and comparing data. + * Thought of as memcpy() and memcmp() function calls whereby the layout of the + * data itself is irrelevant. + * Only after we type pun back to the original type, and load from memory does + * the layout of the data matter again. + */ #define EASTL_MSVC_ATOMIC_CMPXCHG_STRONG_INTRIN_128(type, ret, ptr, expected, desired, MemoryOrder) \ { \ union TypePun \ @@ -181,9 +191,7 @@ struct FixedWidth128 \ struct exchange128 \ { \ - EASTL_SYSTEM_BIG_ENDIAN_STATEMENT(__int64 hi, lo); \ - \ - EASTL_SYSTEM_LITTLE_ENDIAN_STATEMENT(__int64 lo, hi); \ + __int64 value[2]; \ }; \ \ struct exchange128 exchangePun; \ @@ -194,7 +202,7 @@ struct FixedWidth128 unsigned char cmpxchgRetChar; \ cmpxchgRetChar = EASTL_MSVC_ATOMIC_CMPXCHG_STRONG_128_OP(cmpxchgRetChar, EASTL_ATOMIC_VOLATILE_TYPE_CAST(__int64, (ptr)), \ EASTL_ATOMIC_TYPE_CAST(__int64, (expected)), \ - typePun.exchangePun.hi, typePun.exchangePun.lo, \ + typePun.exchangePun.value[1], typePun.exchangePun.value[0], \ MemoryOrder); \ \ ret = static_cast(cmpxchgRetChar); \ diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_barrier.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_barrier.h index 02e2d03..90b78a6 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_barrier.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_barrier.h @@ -16,7 +16,9 @@ // void EASTL_COMPILER_ATOMIC_COMPILER_BARRIER() // #define EASTL_COMPILER_ATOMIC_COMPILER_BARRIER() \ - _ReadWriteBarrier() + EA_DISABLE_CLANG_WARNING(-Wdeprecated-declarations) \ + _ReadWriteBarrier() \ + EA_RESTORE_CLANG_WARNING() ///////////////////////////////////////////////////////////////////////////////// diff --git a/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cmpxchg_strong.h b/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cmpxchg_strong.h index 42117a1..8217f23 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cmpxchg_strong.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cmpxchg_strong.h @@ -10,7 +10,6 @@ #pragma once #endif - #if defined(EA_PROCESSOR_X86_64) #define EASTL_MSVC_ATOMIC_CMPXCHG_STRONG_INTRIN_8 _InterlockedCompareExchange8 diff --git a/library/3rdparty/EASTL/include/EASTL/internal/config.h b/library/3rdparty/EASTL/include/EASTL/internal/config.h index c016c92..8dc1420 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/config.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/config.h @@ -89,8 +89,8 @@ /////////////////////////////////////////////////////////////////////////////// #ifndef EASTL_VERSION - #define EASTL_VERSION "3.17.03" - #define EASTL_VERSION_N 31703 + #define EASTL_VERSION "3.18.00" + #define EASTL_VERSION_N 31800 #endif @@ -864,7 +864,7 @@ namespace eastl #if EASTL_INT128_SUPPORTED #define EASTL_INT128_DEFINED 1 - #if defined(__SIZEOF_INT128__) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG) + #if defined(__SIZEOF_INT128__) || defined(EA_COMPILER_GNUC) || defined(__clang__) typedef __int128_t eastl_int128_t; typedef __uint128_t eastl_uint128_t; #else @@ -1008,7 +1008,7 @@ namespace eastl /////////////////////////////////////////////////////////////////////////////// // EASTL_OPERATOR_EQUALS_OTHER_ENABLED // -// Defined as 0 or 1. Default is 0 until such day that it's deemeed safe. +// Defined as 0 or 1. Default is 0 until such day that it's deemed safe. // When enabled, enables operator= for other char types, e.g. for code // like this: // eastl::string8 s8; @@ -1274,7 +1274,7 @@ namespace eastl // useful macro identifier for our type traits implementation. // #ifndef EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE - #if defined(_MSC_VER) && (_MSC_VER >= 1500) // VS2008 or later + #if defined(_MSC_VER) && (_MSC_VER >= 1500) && !defined(EA_COMPILER_CLANG_CL) // VS2008 or later #pragma warning(push, 0) #include #pragma warning(pop) @@ -1283,9 +1283,9 @@ namespace eastl #else #define EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE 0 #endif - #elif defined(EA_COMPILER_CLANG) && defined(__APPLE__) && defined(_CXXCONFIG) // Apple clang but with GCC's libstdc++. + #elif defined(__clang__) && defined(__APPLE__) && defined(_CXXCONFIG) // Apple clang but with GCC's libstdc++. #define EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE 0 - #elif defined(EA_COMPILER_CLANG) + #elif defined(__clang__) #define EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE 1 #elif defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003) && !defined(__GCCXML__) #define EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE 1 @@ -1325,7 +1325,7 @@ namespace eastl // // Defined as 0 or 1; default is 1. // Specifies whether the min and max algorithms are available. -// It may be useful to disable the min and max algorithems because sometimes +// It may be useful to disable the min and max algorithms because sometimes // #defines for min and max exist which would collide with EASTL min and max. // Note that there are already alternative versions of min and max in EASTL // with the min_alt and max_alt functions. You can use these without colliding @@ -1836,14 +1836,14 @@ typedef EASTL_SSIZE_T eastl_ssize_t; // Signed version of eastl_size_t. Concept /// EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE -#if defined(_MSC_VER) && (_MSC_VER >= 1913) // VS2017+ - #define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 1 -#elif defined(EA_COMPILER_CLANG) +#if defined(__clang__) #if !__is_identifier(__has_unique_object_representations) #define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 1 #else #define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 0 #endif +#elif defined(_MSC_VER) && (_MSC_VER >= 1913) // VS2017+ + #define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 1 #else #define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 0 #endif @@ -1873,5 +1873,17 @@ typedef EASTL_SSIZE_T eastl_ssize_t; // Signed version of eastl_size_t. Concept #define EASTL_SYSTEM_LITTLE_ENDIAN_STATEMENT(...) #endif +/// EASTL_CONSTEXPR_BIT_CAST_SUPPORTED +/// eastl::bit_cast, in order to be implemented as constexpr, requires explicit compiler support. +/// This macro defines whether it's possible for bit_cast to be constexpr. +/// +#if (defined(EA_COMPILER_MSVC) && defined(EA_COMPILER_MSVC_VERSION_14_26) && EA_COMPILER_VERSION >= EA_COMPILER_MSVC_VERSION_14_26) \ + || EA_COMPILER_HAS_BUILTIN(__builtin_bit_cast) + #define EASTL_CONSTEXPR_BIT_CAST_SUPPORTED 1 +#else + #define EASTL_CONSTEXPR_BIT_CAST_SUPPORTED 0 +#endif + + #endif // Header include guard diff --git a/library/3rdparty/EASTL/include/EASTL/internal/copy_help.h b/library/3rdparty/EASTL/include/EASTL/internal/copy_help.h index e5fb2ab..67b5d87 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/copy_help.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/copy_help.h @@ -6,12 +6,12 @@ #ifndef EASTL_INTERNAL_COPY_HELP_H #define EASTL_INTERNAL_COPY_HELP_H +#include #if defined(EA_PRAGMA_ONCE_SUPPORTED) #pragma once #endif -#include #include #include #include // memcpy, memcmp, memmove @@ -19,15 +19,15 @@ namespace eastl { - /// move / move_n / move_backward + /// move / move_n / move_backward /// copy / copy_n / copy_backward /// /// We want to optimize move, move_n, move_backward, copy, copy_backward, copy_n to do memmove operations - /// when possible. + /// when possible. /// - /// We could possibly use memcpy, though it has stricter overlap requirements than the move and copy - /// algorithms and would require a runtime if/else to choose it over memmove. In particular, memcpy - /// allows no range overlap at all, whereas move/copy allow output end overlap and move_backward/copy_backward + /// We could possibly use memcpy, though it has stricter overlap requirements than the move and copy + /// algorithms and would require a runtime if/else to choose it over memmove. In particular, memcpy + /// allows no range overlap at all, whereas move/copy allow output end overlap and move_backward/copy_backward /// allow output begin overlap. Despite this it might be useful to use memcpy for any platforms where /// memcpy is significantly faster than memmove, and since in most cases the copy/move operation in fact /// doesn't target overlapping memory and so memcpy would be usable. @@ -36,13 +36,13 @@ namespace eastl /// InputIterator and OutputIterator are of the same type. /// InputIterator and OutputIterator are of type contiguous_iterator_tag or simply are pointers (the two are virtually synonymous). /// is_trivially_copyable::value is true. i.e. the constructor T(const T& t) (or T(T&& t) if present) can be replaced by memmove(this, &t, sizeof(T)) - /// - /// copy normally differs from move, but there is a case where copy is the same as move: when copy is - /// used with a move_iterator. We handle that case here by detecting that copy is being done with a + /// + /// copy normally differs from move, but there is a case where copy is the same as move: when copy is + /// used with a move_iterator. We handle that case here by detecting that copy is being done with a /// move_iterator and redirect it to move (which can take advantage of memmove/memcpy). /// - /// The generic_iterator class is typically used for wrapping raw memory pointers so they can act like - /// formal iterators. Since pointers provide an opportunity for memmove/memcpy operations, we can + /// The generic_iterator class is typically used for wrapping raw memory pointers so they can act like + /// formal iterators. Since pointers provide an opportunity for memmove/memcpy operations, we can /// detect a generic iterator and use it's wrapped type as a pointer if it happens to be one. // Implementation moving copying both trivial and non-trivial data via a lesser iterator than random-access. @@ -61,7 +61,7 @@ namespace eastl // Specialization for copying non-trivial data via a random-access iterator. It's theoretically faster because the compiler can see the count when its a compile-time const. // This specialization converts the random access InputIterator last-first to an integral type. There's simple way for us to take advantage of a random access output iterator, // as the range is specified by the input instead of the output, and distance(first, last) for a non-random-access iterator is potentially slow. - template <> + template <> struct move_and_copy_helper { template @@ -88,7 +88,7 @@ namespace eastl return result; } }; - + // Specialization for moving non-trivial data via a random-access iterator. It's theoretically faster because the compiler can see the count when its a compile-time const. template <> struct move_and_copy_helper @@ -130,9 +130,9 @@ namespace eastl typedef typename eastl::iterator_traits::value_type value_type_input; typedef typename eastl::iterator_traits::value_type value_type_output; - const bool canBeMemmoved = eastl::is_trivially_copyable::value && - eastl::is_same::value && - (eastl::is_pointer::value || eastl::is_same::value) && + const bool canBeMemmoved = eastl::is_trivially_copyable::value && + eastl::is_same::value && + (eastl::is_pointer::value || eastl::is_same::value) && (eastl::is_pointer::value || eastl::is_same::value); return eastl::move_and_copy_helper::move_or_copy(first, last, result); // Need to chose based on the input iterator tag and not the output iterator tag, because containers accept input ranges of iterator types different than self. @@ -149,11 +149,11 @@ namespace eastl /// move /// - /// After this operation the elements in the moved-from range will still contain valid values of the - /// appropriate type, but not necessarily the same values as before the move. + /// After this operation the elements in the moved-from range will still contain valid values of the + /// appropriate type, but not necessarily the same values as before the move. /// Returns the end of the result range. /// Note: When moving between containers, the dest range must be valid; this function doesn't resize containers. - /// Note: if result is within [first, last), move_backward must be used instead of move. + /// Note: if result is within [first, last), move_backward must be used instead of move. /// /// Example usage: /// eastl::move(myArray.begin(), myArray.end(), myDestArray.begin()); @@ -180,7 +180,7 @@ namespace eastl /// starting from first and proceeding to last. For each nonnegative integer n < (last - first), /// performs *(result + n) = *(first + n). /// - /// Returns: result + (last - first). That is, returns the end of the result. Note that this + /// Returns: result + (last - first). That is, returns the end of the result. Note that this /// is different from how memmove/memcpy work, as they return the beginning of the result. /// /// Requires: result shall not be in the range [first, last). But the end of the result range @@ -197,19 +197,4 @@ namespace eastl } } // namespace eastl -#endif // Header include guard - - - - - - - - - - - - - - - +#endif // EASTL_INTERNAL_COPY_HELP_H diff --git a/library/3rdparty/EASTL/include/EASTL/internal/fill_help.h b/library/3rdparty/EASTL/include/EASTL/internal/fill_help.h index 235a24e..07e3b62 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/fill_help.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/fill_help.h @@ -85,7 +85,7 @@ namespace eastl } - #if(defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) && (defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64)) + #if (defined(EA_COMPILER_GNUC) || defined(__clang__)) && (defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64)) #if defined(EA_PROCESSOR_X86_64) template inline void fill(uint64_t* first, uint64_t* last, Value c) @@ -327,7 +327,7 @@ namespace eastl } #endif - #if(defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) && (defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64)) + #if (defined(EA_COMPILER_GNUC) || defined(__clang__)) && (defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64)) #if defined(EA_PROCESSOR_X86_64) template inline uint64_t* fill_n(uint64_t* first, Size n, Value c) diff --git a/library/3rdparty/EASTL/include/EASTL/internal/fixed_pool.h b/library/3rdparty/EASTL/include/EASTL/internal/fixed_pool.h index 5a38004..4d71035 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/fixed_pool.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/fixed_pool.h @@ -1362,12 +1362,11 @@ namespace eastl { } - // Disabled because the default is sufficient. - //fixed_vector_allocator(const fixed_vector_allocator& x) - //{ - // mpPoolBegin = x.mpPoolBegin; - // mOverflowAllocator = x.mOverflowAllocator; - //} + fixed_vector_allocator(const fixed_vector_allocator& x) + { + mpPoolBegin = x.mpPoolBegin; + mOverflowAllocator = x.mOverflowAllocator; + } fixed_vector_allocator& operator=(const fixed_vector_allocator& x) { diff --git a/library/3rdparty/EASTL/include/EASTL/internal/function.h b/library/3rdparty/EASTL/include/EASTL/internal/function.h index 6e857f0..785969d 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/function.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/function.h @@ -5,6 +5,8 @@ #ifndef EASTL_FUNCTION_H #define EASTL_FUNCTION_H +#include + #if defined(EA_PRAGMA_ONCE_SUPPORTED) #pragma once #endif diff --git a/library/3rdparty/EASTL/include/EASTL/internal/function_detail.h b/library/3rdparty/EASTL/include/EASTL/internal/function_detail.h index 7d52d55..3ee3667 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/function_detail.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/function_detail.h @@ -95,7 +95,7 @@ namespace eastl template struct is_functor_inplace_allocatable { - static constexpr bool value = + static EA_CONSTEXPR bool value = sizeof(Functor) <= sizeof(functor_storage) && (eastl::alignment_of_v> % eastl::alignment_of_v) == 0; }; @@ -649,7 +649,7 @@ namespace eastl // We cannot assume that R is default constructible. // This function is called only when the function object CANNOT be called because it is empty, // it will always throw or assert so we never use the return value anyways and neither should the caller. - static R DefaultInvoker(Args... args, const FunctorStorageType& functor) + static R DefaultInvoker(Args... /*args*/, const FunctorStorageType& /*functor*/) { #if EASTL_EXCEPTIONS_ENABLED throw eastl::bad_function_call(); diff --git a/library/3rdparty/EASTL/include/EASTL/internal/functional_base.h b/library/3rdparty/EASTL/include/EASTL/internal/functional_base.h index 669e5fc..ef27800 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/functional_base.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/functional_base.h @@ -6,21 +6,23 @@ #ifndef EASTL_INTERNAL_FUNCTIONAL_BASE_H #define EASTL_INTERNAL_FUNCTIONAL_BASE_H +#include + #if defined(EA_PRAGMA_ONCE_SUPPORTED) #pragma once #endif -#include #include #include #include + namespace eastl { // foward declaration for swap template inline void swap(T& a, T& b) - EA_NOEXCEPT_IF(eastl::is_nothrow_move_constructible::value&& eastl::is_nothrow_move_assignable::value); + EA_NOEXCEPT_IF(eastl::is_nothrow_move_constructible::value && eastl::is_nothrow_move_assignable::value); /// invoke @@ -39,44 +41,47 @@ namespace eastl /// http://en.cppreference.com/w/cpp/utility/functional/invoke /// template - auto invoke_impl(R C::*func, T&& obj, Args&&... args) -> - typename enable_if>::value, + EA_CONSTEXPR auto invoke_impl(R C::*func, T&& obj, Args&&... args) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR((eastl::forward(obj).*func)(eastl::forward(args)...))) + -> typename enable_if>::value, decltype((eastl::forward(obj).*func)(eastl::forward(args)...))>::type { return (eastl::forward(obj).*func)(eastl::forward(args)...); } template - auto invoke_impl(F&& func, Args&&... args) -> decltype(eastl::forward(func)(eastl::forward(args)...)) + EA_CONSTEXPR auto invoke_impl(F&& func, Args&&... args) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(eastl::forward(func)(eastl::forward(args)...))) + -> decltype(eastl::forward(func)(eastl::forward(args)...)) { return eastl::forward(func)(eastl::forward(args)...); } template - auto invoke_impl(R C::*func, T&& obj, Args&&... args) -> decltype(((*eastl::forward(obj)).*func)(eastl::forward(args)...)) + EA_CONSTEXPR auto invoke_impl(R C::*func, T&& obj, Args&&... args) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(((*eastl::forward(obj)).*func)(eastl::forward(args)...))) + -> decltype(((*eastl::forward(obj)).*func)(eastl::forward(args)...)) { return ((*eastl::forward(obj)).*func)(eastl::forward(args)...); } template - auto invoke_impl(M C::*member, T&& obj) -> - typename enable_if< - is_base_of>::value, - decltype(obj.*member) + EA_CONSTEXPR auto invoke_impl(M C::*member, T&& obj) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(eastl::forward(obj).*member)) + -> typename enable_if< + is_base_of>::value, + decltype(eastl::forward(obj).*member) >::type { - return obj.*member; + return eastl::forward(obj).*member; } template - auto invoke_impl(M C::*member, T&& obj) -> decltype((*eastl::forward(obj)).*member) + EA_CONSTEXPR auto invoke_impl(M C::*member, T&& obj) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR((*eastl::forward(obj)).*member)) + -> decltype((*eastl::forward(obj)).*member) { return (*eastl::forward(obj)).*member; } template - inline decltype(auto) invoke(F&& func, Args&&... args) + EA_CONSTEXPR decltype(auto) invoke(F&& func, Args&&... args) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(invoke_impl(eastl::forward(func), eastl::forward(args)...))) { return invoke_impl(eastl::forward(func), eastl::forward(args)...); } @@ -86,9 +91,9 @@ namespace eastl }; template - struct invoke_result_impl>(), eastl::declval()...))>, Args...> + struct invoke_result_impl(), eastl::declval()...))>, Args...> { - typedef decltype(invoke_impl(eastl::declval>(), eastl::declval()...)) type; + typedef decltype(invoke_impl(eastl::declval(), eastl::declval()...)) type; }; template @@ -118,13 +123,40 @@ namespace eastl template struct is_invocable_r : public is_invocable_r_impl {}; - #if EASTL_VARIABLE_TEMPLATES_ENABLED - template - EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool is_invocable_v = is_invocable::value; + template + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool is_invocable_v = is_invocable::value; - template - EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool is_invocable_r_v = is_invocable_r::value; - #endif + template + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool is_invocable_r_v = is_invocable_r::value; + + template + struct is_nothrow_invocable_impl : public eastl::false_type {}; + + template + struct is_nothrow_invocable_impl::type>, Args...> + : public eastl::bool_constant(), eastl::declval()...))> {}; + + template + struct is_nothrow_invocable : public is_nothrow_invocable_impl {}; + + template + struct is_nothrow_invocable_r_impl : public eastl::false_type {}; + + template + struct is_nothrow_invocable_r_impl::type>, Args...> + { + static EA_CONSTEXPR_OR_CONST bool value = eastl::is_convertible::type, R>::value + && eastl::is_nothrow_invocable::value; + }; + + template + struct is_nothrow_invocable_r : public is_nothrow_invocable_r_impl {}; + + template + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool is_no_throw_invocable_v = is_nothrow_invocable::value; + + template + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool is_nothrow_invocable_r_v = is_nothrow_invocable_r::value; /// allocator_arg_t /// @@ -144,9 +176,7 @@ namespace eastl /// such as tuple, function, promise, and packaged_task. /// http://en.cppreference.com/w/cpp/memory/allocator_arg /// - #if !defined(EA_COMPILER_NO_CONSTEXPR) - EA_CONSTEXPR allocator_arg_t allocator_arg = allocator_arg_t(); - #endif + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR allocator_arg_t allocator_arg = allocator_arg_t(); template @@ -210,7 +240,7 @@ namespace eastl template reference_wrapper::reference_wrapper(T &v) EA_NOEXCEPT - : val(addressof(v)) + : val(eastl::addressof(v)) {} template @@ -248,7 +278,7 @@ namespace eastl template reference_wrapper ref(T& t) EA_NOEXCEPT { - return eastl::reference_wrapper(t); + return eastl::reference_wrapper(t); } template @@ -307,16 +337,16 @@ namespace eastl // These have to come after reference_wrapper is defined, but reference_wrapper needs to have a // definition of invoke, so these specializations need to come after everything else has been defined. template - auto invoke_impl(R (C::*func)(Args...), T&& obj, Args&&... args) -> - typename enable_if::type>::value, + EA_CONSTEXPR auto invoke_impl(R C::*func, T&& obj, Args&&... args) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR((obj.get().*func)(eastl::forward(args)...))) + -> typename enable_if>::value, decltype((obj.get().*func)(eastl::forward(args)...))>::type { return (obj.get().*func)(eastl::forward(args)...); } template - auto invoke_impl(M(C::*member), T&& obj) -> - typename enable_if::type>::value, + EA_CONSTEXPR auto invoke_impl(M C::*member, T&& obj) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(obj.get().*member)) + -> typename enable_if>::value, decltype(obj.get().*member)>::type { return obj.get().*member; @@ -386,4 +416,4 @@ namespace eastl } // namespace eastl -#endif // Header include guard +#endif // EASTL_INTERNAL_FUNCTIONAL_BASE_H diff --git a/library/3rdparty/EASTL/include/EASTL/internal/hashtable.h b/library/3rdparty/EASTL/include/EASTL/internal/hashtable.h index 772203c..9f56ed2 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/hashtable.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/hashtable.h @@ -1605,7 +1605,7 @@ namespace eastl typename hashtable::node_pointer hashtable::DoAllocateNodeFromKey(const key_type& key) { -// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0); +// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); node_pointer const pNode = mAllocator.template allocate_node(); EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); @@ -1634,7 +1634,7 @@ namespace eastl typename hashtable::node_pointer hashtable::DoAllocateNodeFromKey(key_type&& key) { -// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0); +// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); node_pointer const pNode = mAllocator.template allocate_node(); EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); @@ -2147,7 +2147,7 @@ namespace eastl typename hashtable::node_pointer hashtable::DoAllocateNode(Args&&... args) { -// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0); +// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); node_pointer const pNode = mAllocator.template allocate_node(); EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); @@ -2331,7 +2331,7 @@ namespace eastl typename hashtable::node_pointer hashtable::DoAllocateNode(value_type&& value) { -// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0); +// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); node_pointer const pNode = mAllocator.template allocate_node(); EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); @@ -2507,7 +2507,7 @@ namespace eastl typename hashtable::node_pointer hashtable::DoAllocateNode(const value_type& value) { -// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0); +// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); node_pointer const pNode = mAllocator.template allocate_node(); EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); @@ -2537,7 +2537,7 @@ namespace eastl hashtable::allocate_uninitialized_node() { // We don't wrap this in try/catch because users of this function are expected to do that themselves as needed. -// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0); +// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); node_pointer const pNode = mAllocator.template allocate_node(); EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); // Leave pNode->mValue uninitialized. @@ -2760,8 +2760,8 @@ namespace eastl inline typename hashtable::insert_return_type hashtable::try_emplace(const key_type& key, Args&&... args) { - return DoInsertValue(has_unique_keys_type(), piecewise_construct, forward_as_tuple(key), - forward_as_tuple(forward(args)...)); + return DoInsertValue(has_unique_keys_type(), piecewise_construct, eastl::forward_as_tuple(key), + eastl::forward_as_tuple(eastl::forward(args)...)); } template ::insert_return_type hashtable::try_emplace(key_type&& key, Args&&... args) { - return DoInsertValue(has_unique_keys_type(), piecewise_construct, forward_as_tuple(eastl::move(key)), - forward_as_tuple(forward(args)...)); + return DoInsertValue(has_unique_keys_type(), piecewise_construct, eastl::forward_as_tuple(eastl::move(key)), + eastl::forward_as_tuple(eastl::forward(args)...)); } template (args)...))); + value_type(piecewise_construct, eastl::forward_as_tuple(key), eastl::forward_as_tuple(eastl::forward(args)...))); return DoGetResultIterator(has_unique_keys_type(), result); } @@ -2795,8 +2795,8 @@ namespace eastl hashtable::try_emplace(const_iterator, key_type&& key, Args&&... args) { insert_return_type result = - DoInsertValue(has_unique_keys_type(), value_type(piecewise_construct, forward_as_tuple(eastl::move(key)), - forward_as_tuple(forward(args)...))); + DoInsertValue(has_unique_keys_type(), value_type(piecewise_construct, eastl::forward_as_tuple(eastl::move(key)), + eastl::forward_as_tuple(eastl::forward(args)...))); return DoGetResultIterator(has_unique_keys_type(), result); } @@ -2909,7 +2909,7 @@ namespace eastl auto iter = find(k); if(iter == end()) { - return insert(value_type(piecewise_construct, forward_as_tuple(k), forward_as_tuple(eastl::forward(obj)))); + return insert(value_type(piecewise_construct, eastl::forward_as_tuple(k), eastl::forward_as_tuple(eastl::forward(obj)))); } else { @@ -2927,7 +2927,7 @@ namespace eastl auto iter = find(k); if(iter == end()) { - return insert(value_type(piecewise_construct, forward_as_tuple(eastl::move(k)), forward_as_tuple(eastl::forward(obj)))); + return insert(value_type(piecewise_construct, eastl::forward_as_tuple(eastl::move(k)), eastl::forward_as_tuple(eastl::forward(obj)))); } else { diff --git a/library/3rdparty/EASTL/include/EASTL/internal/integer_sequence.h b/library/3rdparty/EASTL/include/EASTL/internal/integer_sequence.h index 88cf1b1..2a5539d 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/integer_sequence.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/integer_sequence.h @@ -67,6 +67,36 @@ using make_integer_sequence = typename make_integer_sequence_impl::type; template using index_sequence_for = make_index_sequence; +namespace internal +{ + +template +struct integer_sequence_size_helper; + +template +struct integer_sequence_size_helper> : public integral_constant +{ +}; + +template +struct integer_sequence_size : public integer_sequence_size_helper> +{ +}; + +template +struct index_sequence_size : public integer_sequence_size_helper> +{ +}; + +template +EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR size_t integer_sequence_size_v = integer_sequence_size::value; + +template +EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR size_t index_sequence_size_v = index_sequence_size::value; + + +} // namespace internal + #endif // EASTL_VARIADIC_TEMPLATES_ENABLED } // namespace eastl diff --git a/library/3rdparty/EASTL/include/EASTL/internal/move_help.h b/library/3rdparty/EASTL/include/EASTL/internal/move_help.h index 44c4dec..97990df 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/move_help.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/move_help.h @@ -112,7 +112,7 @@ namespace eastl EA_CPP14_CONSTEXPR typename eastl::remove_reference::type&& move(T&& x) EA_NOEXCEPT { - return ((typename eastl::remove_reference::type&&)x); + return static_cast::type&&>(x); } diff --git a/library/3rdparty/EASTL/include/EASTL/internal/red_black_tree.h b/library/3rdparty/EASTL/include/EASTL/internal/red_black_tree.h index 8e9eda0..111fbb4 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/red_black_tree.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/red_black_tree.h @@ -169,6 +169,7 @@ namespace eastl rbtree_iterator(); explicit rbtree_iterator(const node_type* pNode); rbtree_iterator(const iterator& x); + rbtree_iterator& operator=(const iterator& x); reference operator*() const; pointer operator->() const; @@ -662,6 +663,13 @@ namespace eastl rbtree_iterator::rbtree_iterator(const iterator& x) : mpNode(x.mpNode) { } + template + typename rbtree_iterator::this_type& + rbtree_iterator::operator=(const iterator& x) + { + mpNode = x.mpNode; + return *this; + } template typename rbtree_iterator::reference @@ -1105,7 +1113,7 @@ namespace eastl inline eastl::pair::iterator, bool> rbtree::try_emplace(const key_type& key, Args&&... args) { - return DoInsertValue(has_unique_keys_type(), piecewise_construct, forward_as_tuple(key), forward_as_tuple(forward(args)...)); + return DoInsertValue(has_unique_keys_type(), piecewise_construct, eastl::forward_as_tuple(key), eastl::forward_as_tuple(eastl::forward(args)...)); } template @@ -1113,7 +1121,7 @@ namespace eastl inline eastl::pair::iterator, bool> rbtree::try_emplace(key_type&& key, Args&&... args) { - return DoInsertValue(has_unique_keys_type(), piecewise_construct, forward_as_tuple(eastl::move(key)), forward_as_tuple(forward(args)...)); + return DoInsertValue(has_unique_keys_type(), piecewise_construct, eastl::forward_as_tuple(eastl::move(key)), eastl::forward_as_tuple(eastl::forward(args)...)); } template @@ -1123,7 +1131,7 @@ namespace eastl { return DoInsertValueHint( has_unique_keys_type(), position, - piecewise_construct, forward_as_tuple(key), forward_as_tuple(forward(args)...)); + piecewise_construct, eastl::forward_as_tuple(key), eastl::forward_as_tuple(eastl::forward(args)...)); } template @@ -1133,7 +1141,7 @@ namespace eastl { return DoInsertValueHint( has_unique_keys_type(), position, - piecewise_construct, forward_as_tuple(eastl::move(key)), forward_as_tuple(forward(args)...)); + piecewise_construct, eastl::forward_as_tuple(eastl::move(key)), eastl::forward_as_tuple(eastl::forward(args)...)); } @@ -1180,7 +1188,7 @@ namespace eastl if(iter == end()) { - return insert(value_type(piecewise_construct, forward_as_tuple(k), forward_as_tuple(eastl::forward(obj)))); + return insert(value_type(piecewise_construct, eastl::forward_as_tuple(k), eastl::forward_as_tuple(eastl::forward(obj)))); } else { @@ -1198,7 +1206,7 @@ namespace eastl if(iter == end()) { - return insert(value_type(piecewise_construct, forward_as_tuple(eastl::move(k)), forward_as_tuple(eastl::forward(obj)))); + return insert(value_type(piecewise_construct, eastl::forward_as_tuple(eastl::move(k)), eastl::forward_as_tuple(eastl::forward(obj)))); } else { @@ -1216,7 +1224,7 @@ namespace eastl if(iter == end()) { - return insert(hint, value_type(piecewise_construct, forward_as_tuple(k), forward_as_tuple(eastl::forward(obj)))); + return insert(hint, value_type(piecewise_construct, eastl::forward_as_tuple(k), eastl::forward_as_tuple(eastl::forward(obj)))); } else { @@ -1234,7 +1242,7 @@ namespace eastl if(iter == end()) { - return insert(hint, value_type(piecewise_construct, forward_as_tuple(eastl::move(k)), forward_as_tuple(eastl::forward(obj)))); + return insert(hint, value_type(piecewise_construct, eastl::forward_as_tuple(eastl::move(k)), eastl::forward_as_tuple(eastl::forward(obj)))); } else { diff --git a/library/3rdparty/EASTL/include/EASTL/internal/smart_ptr.h b/library/3rdparty/EASTL/include/EASTL/internal/smart_ptr.h index f1d52e1..8a37950 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/smart_ptr.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/smart_ptr.h @@ -162,7 +162,10 @@ namespace eastl default_delete(const default_delete&, typename eastl::enable_if::value>::type* = 0) EA_NOEXCEPT {} void operator()(T* p) const EA_NOEXCEPT - { delete p; } + { + static_assert(eastl::internal::is_complete_type_v, "Attempting to call the destructor of an incomplete type"); + delete p; + } }; diff --git a/library/3rdparty/EASTL/include/EASTL/internal/thread_support.h b/library/3rdparty/EASTL/include/EASTL/internal/thread_support.h index 80386d2..60272a9 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/thread_support.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/thread_support.h @@ -19,10 +19,12 @@ // // fatal error C1189: is not supported when compiling with /clr or /clr:pure ///////////////////////////////////////////////////////////////////////////////////////////////////// -#if defined(EA_HAVE_CPP11_MUTEX) && !defined(EA_COMPILER_MANAGED_CPP) - #define EASTL_CPP11_MUTEX_ENABLED 1 -#else - #define EASTL_CPP11_MUTEX_ENABLED 0 +#if !defined(EASTL_CPP11_MUTEX_ENABLED) + #if defined(EA_HAVE_CPP11_MUTEX) && !defined(EA_COMPILER_MANAGED_CPP) + #define EASTL_CPP11_MUTEX_ENABLED 1 + #else + #define EASTL_CPP11_MUTEX_ENABLED 0 + #endif #endif #if EASTL_CPP11_MUTEX_ENABLED @@ -77,7 +79,7 @@ EA_DISABLE_VC_WARNING(4625 4626 4275); /////////////////////////////////////////////////////////////////////////////// #if !defined(EASTL_THREAD_SUPPORT_AVAILABLE) - #if defined(EA_COMPILER_CLANG) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)) + #if defined(__clang__) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)) #define EASTL_THREAD_SUPPORT_AVAILABLE 1 #elif defined(EA_COMPILER_MSVC) #define EASTL_THREAD_SUPPORT_AVAILABLE 1 @@ -95,7 +97,7 @@ namespace eastl /// Returns the new value. inline int32_t atomic_increment(int32_t* p32) EA_NOEXCEPT { - #if defined(EA_COMPILER_CLANG) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)) + #if defined(__clang__) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)) return __sync_add_and_fetch(p32, 1); #elif defined(EA_COMPILER_MSVC) static_assert(sizeof(long) == sizeof(int32_t), "unexpected size"); @@ -118,7 +120,7 @@ namespace eastl /// Returns the new value. inline int32_t atomic_decrement(int32_t* p32) EA_NOEXCEPT { - #if defined(EA_COMPILER_CLANG) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)) + #if defined(__clang__) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)) return __sync_add_and_fetch(p32, -1); #elif defined(EA_COMPILER_MSVC) return _InterlockedDecrement((volatile long*)p32); // volatile long cast is OK because int32_t == long on Microsoft platforms. @@ -145,7 +147,7 @@ namespace eastl /// the two as would be the case with simple C code. inline bool atomic_compare_and_swap(int32_t* p32, int32_t newValue, int32_t condition) { - #if defined(EA_COMPILER_CLANG) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)) + #if defined(__clang__) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)) return __sync_bool_compare_and_swap(p32, condition, newValue); #elif defined(EA_COMPILER_MSVC) return ((int32_t)_InterlockedCompareExchange((volatile long*)p32, (long)newValue, (long)condition) == condition); diff --git a/library/3rdparty/EASTL/include/EASTL/internal/type_compound.h b/library/3rdparty/EASTL/include/EASTL/internal/type_compound.h index 178a734..1f85250 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/type_compound.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/type_compound.h @@ -290,7 +290,7 @@ namespace eastl // is_convertible::value; // Generates compiler error. /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_convertible_to))) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_convertible_to))) #define EASTL_TYPE_TRAIT_is_convertible_CONFORMANCE 1 // is_convertible is conforming. // Problem: VC++ reports that int is convertible to short, yet if you construct a short from an int then VC++ generates a warning: @@ -371,7 +371,7 @@ namespace eastl // via 'msl::is_union::value'. The user can force something to be // evaluated as a union via EASTL_DECLARE_UNION. /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_union))) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_union))) #define EASTL_TYPE_TRAIT_is_union_CONFORMANCE 1 // is_union is conforming. template @@ -401,7 +401,7 @@ namespace eastl // distinguish between unions and classes. As a result, is_class // will erroneously evaluate to true for union types. /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_class))) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_class))) #define EASTL_TYPE_TRAIT_is_class_CONFORMANCE 1 // is_class is conforming. template @@ -442,57 +442,6 @@ namespace eastl #endif - /////////////////////////////////////////////////////////////////////// - // is_enum - // - // is_enum::value == true if and only if T is an enumeration type. - // - /////////////////////////////////////////////////////////////////////// - - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_enum))) - #define EASTL_TYPE_TRAIT_is_enum_CONFORMANCE 1 // is_enum is conforming. - - template - struct is_enum : public integral_constant{}; - #else - #define EASTL_TYPE_TRAIT_is_enum_CONFORMANCE 1 // is_enum is conforming. - - struct int_convertible{ int_convertible(int); }; - - template - struct is_enum_helper { template struct nest : public is_convertible{}; }; - - template <> - struct is_enum_helper { template struct nest : public false_type {}; }; - - template - struct is_enum_helper2 - { - typedef type_or::value, is_reference::value, is_class::value> selector; - typedef is_enum_helper helper_t; - typedef typename add_reference::type ref_t; - typedef typename helper_t::template nest result; - }; - - template - struct is_enum : public integral_constant::result::value>{}; - - template <> struct is_enum : public false_type {}; - template <> struct is_enum : public false_type {}; - template <> struct is_enum : public false_type {}; - template <> struct is_enum : public false_type {}; - #endif - - #if EASTL_VARIABLE_TEMPLATES_ENABLED - template - EA_CONSTEXPR bool is_enum_v = is_enum::value; - #endif - - #define EASTL_DECLARE_ENUM(T) namespace eastl{ template <> struct is_enum : public true_type{}; template <> struct is_enum : public true_type{}; } - - - - /////////////////////////////////////////////////////////////////////// // is_polymorphic @@ -503,7 +452,7 @@ namespace eastl // /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_polymorphic))) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_polymorphic))) #define EASTL_TYPE_TRAIT_is_polymorphic_CONFORMANCE 1 // is_polymorphic is conforming. template diff --git a/library/3rdparty/EASTL/include/EASTL/internal/type_fundamental.h b/library/3rdparty/EASTL/include/EASTL/internal/type_fundamental.h index 950d15e..5ff9259 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/type_fundamental.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/type_fundamental.h @@ -139,7 +139,7 @@ namespace eastl #ifndef EA_WCHAR_T_NON_NATIVE // If wchar_t is a native type instead of simply a define to an existing type which is already handled above... template <> struct is_integral_helper : public true_type{}; #endif - #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(__clang__)) template <> struct is_integral_helper<__int128_t> : public true_type{}; template <> struct is_integral_helper<__uint128_t> : public true_type{}; #endif @@ -262,6 +262,59 @@ namespace eastl EA_CONSTEXPR bool is_hat_type_v = is_hat_type::value; #endif + + + /////////////////////////////////////////////////////////////////////// + // is_enum + // + // is_enum::value == true if and only if T is an enumeration type. + // + /////////////////////////////////////////////////////////////////////// + + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_enum))) + #define EASTL_TYPE_TRAIT_is_enum_CONFORMANCE 1 // is_enum is conforming. + + template + struct is_enum : public integral_constant{}; + #else + #define EASTL_TYPE_TRAIT_is_enum_CONFORMANCE 1 // is_enum is conforming. + + struct int_convertible{ int_convertible(int); }; + + template + struct is_enum_helper { template struct nest : public is_convertible{}; }; + + template <> + struct is_enum_helper { template struct nest : public false_type {}; }; + + template + struct is_enum_helper2 + { + typedef type_or::value, is_reference::value, is_class::value> selector; + typedef is_enum_helper helper_t; + typedef typename add_reference::type ref_t; + typedef typename helper_t::template nest result; + }; + + template + struct is_enum : public integral_constant::result::value>{}; + + template <> struct is_enum : public false_type {}; + template <> struct is_enum : public false_type {}; + template <> struct is_enum : public false_type {}; + template <> struct is_enum : public false_type {}; + #endif + + #if EASTL_VARIABLE_TEMPLATES_ENABLED + template + EA_CONSTEXPR bool is_enum_v = is_enum::value; + #endif + + #define EASTL_DECLARE_ENUM(T) namespace eastl{ template <> struct is_enum : public true_type{}; template <> struct is_enum : public true_type{}; } + + + + } // namespace eastl diff --git a/library/3rdparty/EASTL/include/EASTL/internal/type_pod.h b/library/3rdparty/EASTL/include/EASTL/internal/type_pod.h index db78ff6..327a3f2 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/type_pod.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/type_pod.h @@ -25,7 +25,7 @@ namespace eastl // // is_empty cannot be used with union types until is_union can be made to work. /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_empty))) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_empty))) #define EASTL_TYPE_TRAIT_is_empty_CONFORMANCE 1 // is_empty is conforming. template @@ -90,7 +90,7 @@ namespace eastl struct is_pod : public eastl::integral_constant::value) || eastl::is_void::value || eastl::is_scalar::value>{}; EA_RESTORE_VC_WARNING() - #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_pod))) + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_pod))) #define EASTL_TYPE_TRAIT_is_pod_CONFORMANCE 1 // is_pod is conforming. template @@ -128,7 +128,7 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // is_standard_layout // - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(EA_COMPILER_MSVC) && (_MSC_VER >= 1700)) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4006)) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_standard_layout))) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(EA_COMPILER_MSVC) && (_MSC_VER >= 1700)) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4006)) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_standard_layout))) #define EASTL_TYPE_TRAIT_is_standard_layout_CONFORMANCE 1 // is_standard_layout is conforming. template @@ -182,12 +182,12 @@ namespace eastl // can be called without an argument. /////////////////////////////////////////////////////////////////////// - #if defined(_MSC_VER) && (_MSC_VER >= 1600) // VS2010+ + #if defined(_MSC_VER) && (_MSC_VER >= 1600) && !defined(EA_COMPILER_CLANG_CL) // VS2010+ #define EASTL_TYPE_TRAIT_has_trivial_constructor_CONFORMANCE 1 // has_trivial_constructor is conforming. template struct has_trivial_constructor : public eastl::integral_constant::value) && !eastl::is_hat_type::value>{}; - #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_has_trivial_constructor_CONFORMANCE 1 // has_trivial_constructor is conforming. template @@ -242,12 +242,12 @@ namespace eastl // use EASTL_DECLARE_TRIVIAL_COPY to help the compiler. /////////////////////////////////////////////////////////////////////// - #if defined(_MSC_VER) + #if defined(_MSC_VER) && !defined(EA_COMPILER_CLANG_CL) #define EASTL_TYPE_TRAIT_has_trivial_copy_CONFORMANCE 1 // has_trivial_copy is conforming. template struct has_trivial_copy : public eastl::integral_constant::value) && !eastl::is_volatile::value && !eastl::is_hat_type::value>{}; - #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_has_trivial_copy_CONFORMANCE 1 // has_trivial_copy is conforming. template @@ -292,12 +292,12 @@ namespace eastl // can use EASTL_DECLARE_TRIVIAL_ASSIGN to help the compiler. /////////////////////////////////////////////////////////////////////// - #if defined(_MSC_VER) && (_MSC_VER >= 1600) + #if defined(_MSC_VER) && (_MSC_VER >= 1600) && !defined(EA_COMPILER_CLANG_CL) #define EASTL_TYPE_TRAIT_has_trivial_assign_CONFORMANCE 1 // has_trivial_assign is conforming. template struct has_trivial_assign : public integral_constant::value) && !eastl::is_const::value && !eastl::is_volatile::value && !eastl::is_hat_type::value>{}; - #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_has_trivial_assign_CONFORMANCE 1 // has_trivial_assign is conforming. template @@ -341,12 +341,12 @@ namespace eastl // The user can use EASTL_DECLARE_TRIVIAL_DESTRUCTOR to help the compiler. /////////////////////////////////////////////////////////////////////// - #if defined(_MSC_VER) && (_MSC_VER >= 1600) + #if defined(_MSC_VER) && (_MSC_VER >= 1600) && !defined(EA_COMPILER_CLANG_CL) #define EASTL_TYPE_TRAIT_has_trivial_destructor_CONFORMANCE 1 // has_trivial_destructor is conforming. template struct has_trivial_destructor : public eastl::integral_constant::value) && !eastl::is_hat_type::value>{}; - #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_has_trivial_destructor_CONFORMANCE 1 // has_trivial_destructor is conforming. template @@ -412,7 +412,7 @@ namespace eastl // /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_has_nothrow_constructor_CONFORMANCE 1 template @@ -452,7 +452,7 @@ namespace eastl // /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_has_nothrow_copy_CONFORMANCE 1 template @@ -491,7 +491,7 @@ namespace eastl // /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_has_nothrow_assign_CONFORMANCE 1 template @@ -529,7 +529,7 @@ namespace eastl // /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_has_virtual_destructor_CONFORMANCE 1 template @@ -571,7 +571,7 @@ namespace eastl // /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_literal)) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_literal)) #define EASTL_TYPE_TRAIT_is_literal_type_CONFORMANCE 1 template @@ -615,7 +615,7 @@ namespace eastl // /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_abstract))) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_abstract))) #define EASTL_TYPE_TRAIT_is_abstract_CONFORMANCE 1 // is_abstract is conforming. template @@ -672,7 +672,7 @@ namespace eastl // up obj1 are copied into obj2, obj2 shall subsequently hold the // same value as obj1. In other words, you can memcpy/memmove it. /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(_MSC_VER) && (_MSC_VER >= 1700)) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 5003)) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_trivially_copyable))) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(_MSC_VER) && (_MSC_VER >= 1700)) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 5003)) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_trivially_copyable))) #define EASTL_TYPE_TRAIT_is_trivially_copyable_CONFORMANCE 1 // https://connect.microsoft.com/VisualStudio/feedback/details/808827/c-std-is-trivially-copyable-produces-wrong-result-for-arrays @@ -731,7 +731,7 @@ namespace eastl #define EASTL_TYPE_TRAIT_is_constructible_CONFORMANCE 1 - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_constructible))) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_constructible))) template struct is_constructible : public bool_constant<__is_constructible(T, Args...) > {}; #else @@ -850,7 +850,7 @@ namespace eastl // whether the __is_trivially_constructible compiler intrinsic is available. // If the compiler has this trait built-in (which ideally all compilers would have since it's necessary for full conformance) use it. - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_trivially_constructible)) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_trivially_constructible)) template struct is_trivially_constructible @@ -915,7 +915,7 @@ namespace eastl #else // If the compiler has this trait built-in (which ideally all compilers would have since it's necessary for full conformance) use it. - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_trivially_constructible)) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_trivially_constructible)) #define EASTL_TYPE_TRAIT_is_trivially_constructible_CONFORMANCE 1 // We have a problem with clang here as of clang 3.4: __is_trivially_constructible(int[]) is false, yet I believe it should be true. @@ -1380,7 +1380,7 @@ namespace eastl // arrays of unknown bound /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_trivially_assignable)) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_trivially_assignable)) #define EASTL_TYPE_TRAIT_is_trivially_assignable_CONFORMANCE 1 template @@ -1778,7 +1778,7 @@ namespace eastl struct is_trivially_destructible : integral_constant {}; - #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_is_trivially_destructible_CONFORMANCE EASTL_TYPE_TRAIT_is_destructible_CONFORMANCE template diff --git a/library/3rdparty/EASTL/include/EASTL/internal/type_properties.h b/library/3rdparty/EASTL/include/EASTL/internal/type_properties.h index 5276f87..df90fcb 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/type_properties.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/type_properties.h @@ -28,7 +28,7 @@ namespace eastl // /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(_MSC_VER) && (_MSC_VER >= 1700)) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4007)) || defined(EA_COMPILER_CLANG)) // VS2012+ + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(_MSC_VER) && (_MSC_VER >= 1700)) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4007)) || defined(__clang__)) // VS2012+ #define EASTL_TYPE_TRAIT_underlying_type_CONFORMANCE 1 // underlying_type is conforming. template @@ -46,6 +46,25 @@ namespace eastl using underlying_type_t = typename underlying_type::type; #endif + /////////////////////////////////////////////////////////////////////// + // to_underlying + // + // Cast a enum value to its underlying type. + // For example: + // + // enum class MyEnum : uint8_t { Value = 0; } + // auto x = MyEnum::Value; + // std::cout << to_underlying(x); // equivalent to sts::cout << static_cast(x); + /////////////////////////////////////////////////////////////////////// + + #if EASTL_VARIABLE_TEMPLATES_ENABLED && !defined(EA_COMPILER_NO_TEMPLATE_ALIASES) + template + constexpr underlying_type_t to_underlying(T value) noexcept + { + return static_cast>(value); + } + #endif + /////////////////////////////////////////////////////////////////////// // has_unique_object_representations @@ -281,7 +300,7 @@ namespace eastl // /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_base_of))) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || ((defined(__clang__)) && EA_COMPILER_HAS_FEATURE(is_base_of))) #define EASTL_TYPE_TRAIT_is_base_of_CONFORMANCE 1 // is_base_of is conforming. template @@ -374,6 +393,44 @@ namespace eastl EA_CONSTEXPR auto has_equality_v = has_equality::value; #endif + namespace internal + { + /////////////////////////////////////////////////////////////////////// + // is_complete_type + // + // Determines if the specified type is complete + // + // Warning: Be careful when using is_complete_type since the value is fixed at first instantiation. + // Consider the following: + // + // struct Foo; + // is_complete_type_v // false + // struct Foo {}; + // is_complete_type_v // still false + /////////////////////////////////////////////////////////////////////// + + template + struct is_complete_type : public false_type {}; + + template + struct is_complete_type> : public true_type {}; + + template<> + struct is_complete_type : public false_type {}; + template<> + struct is_complete_type : public false_type {}; + template<> + struct is_complete_type : public false_type {}; + template<> + struct is_complete_type : public false_type {}; + + template + struct is_complete_type>> : public true_type {}; + + template + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool is_complete_type_v = is_complete_type::value; + } + } // namespace eastl diff --git a/library/3rdparty/EASTL/include/EASTL/internal/type_transformations.h b/library/3rdparty/EASTL/include/EASTL/internal/type_transformations.h index cffa65e..2d77a55 100644 --- a/library/3rdparty/EASTL/include/EASTL/internal/type_transformations.h +++ b/library/3rdparty/EASTL/include/EASTL/internal/type_transformations.h @@ -111,54 +111,148 @@ namespace eastl // make_signed // // Used to convert an integral type to its signed equivalent, if not already. - // T shall be a (possibly const and/or volatile-qualified) integral type + // T shall be a (possibly const and/or volatile-qualified) integral type // or enumeration but not a bool type.; // - // The user can define their own make_signed overrides for their own + // The user can define their own make_signed overrides for their own // types by making a template specialization like done below and adding // it to the user's code. /////////////////////////////////////////////////////////////////////// - // To do: This implementation needs to be updated to support C++11 conformance (recognition of enums) and - // to support volatile-qualified types. It will probably be useful to have it fail for unsupported types. - #define EASTL_TYPE_TRAIT_make_signed_CONFORMANCE 0 // make_signed is only partially conforming. + #define EASTL_TYPE_TRAIT_make_signed_CONFORMANCE 1 - template struct make_signed { typedef T type; }; + namespace internal + { + template || eastl::is_integral_v> + struct make_signed_helper_0 + { + struct char_helper + { + typedef signed char type; + }; + + struct short_helper + { + typedef signed short type; + }; + + struct int_helper + { + typedef signed int type; + }; + + struct long_helper + { + typedef signed long type; + }; + + struct longlong_helper + { + typedef signed long long type; + }; + struct int128_helper + { + #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(__clang__)) + typedef __int128_t type; + #endif + }; + + struct no_type_helper + { + }; + + typedef typename + eastl::conditional + #else + no_type_helper + #endif + > + > + > + > + >::type type; + }; + + template + struct make_signed_helper_0 + { + struct no_type_helper + { + }; + + typedef no_type_helper type; + }; + + template + struct make_signed_helper_1 + { + typedef typename T::type type; + }; + + template + struct make_signed_helper + { + typedef typename eastl::internal::make_signed_helper_1::type>::type type; + }; + + } // namespace internal + + template + struct make_signed + { + typedef typename eastl::internal::make_signed_helper::type type; + }; + + template <> struct make_signed {}; + template <> struct make_signed { typedef signed char type; }; template <> struct make_signed { typedef signed char type; }; - template <> struct make_signed { typedef const signed char type; }; + template <> struct make_signed { typedef signed short type; }; template <> struct make_signed { typedef signed short type; }; - template <> struct make_signed { typedef const signed short type; }; + template <> struct make_signed { typedef signed int type; }; template <> struct make_signed { typedef signed int type; }; - template <> struct make_signed { typedef const signed int type; }; + template <> struct make_signed { typedef signed long type; }; template <> struct make_signed { typedef signed long type; }; - template <> struct make_signed { typedef const signed long type; }; + template <> struct make_signed { typedef signed long long type; }; template <> struct make_signed { typedef signed long long type; }; - template <> struct make_signed { typedef const signed long long type; }; + #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(__clang__)) + template <> struct make_signed<__int128_t> { typedef __int128_t type; }; + template <> struct make_signed<__uint128_t> { typedef __int128_t type; }; + #endif + #if (defined(CHAR_MAX) && defined(UCHAR_MAX) && (CHAR_MAX == UCHAR_MAX)) // If char is unsigned, we convert char to signed char. However, if char is signed then make_signed returns char itself and not signed char. template <> struct make_signed { typedef signed char type; }; - template <> struct make_signed { typedef signed char type; }; #endif - #ifndef EA_WCHAR_T_NON_NATIVE // If wchar_t is a native type instead of simply a define to an existing type... - #if (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ == 4294967295U)) // If wchar_t is a 32 bit unsigned value... - template<> - struct make_signed - { typedef int32_t type; }; - #elif (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ == 65535)) // If wchar_t is a 16 bit unsigned value... - template<> - struct make_signed - { typedef int16_t type; }; - #elif (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ == 255)) // If wchar_t is an 8 bit unsigned value... - template<> - struct make_signed - { typedef int8_t type; }; - #endif - #endif + template + struct make_signed + { + typedef eastl::add_const_t::type> type; + }; + + template + struct make_signed + { + typedef eastl::add_volatile_t::type> type; + }; + + template + struct make_signed + { + typedef eastl::add_cv_t::type> type; + }; #if EASTL_VARIABLE_TEMPLATES_ENABLED - template + template using make_signed_t = typename make_signed::type; #endif @@ -180,55 +274,155 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // make_unsigned // - // Used to convert an integral type to its signed equivalent, if not already. - // T shall be a (possibly const and/or volatile-qualified) integral type + // Used to convert an integral type to its unsigned equivalent, if not already. + // T shall be a (possibly const and/or volatile-qualified) integral type // or enumeration but not a bool type.; // - // The user can define their own make_signed overrides for their own + // The user can define their own make_unsigned overrides for their own // types by making a template specialization like done below and adding // it to the user's code. /////////////////////////////////////////////////////////////////////// - // To do: This implementation needs to be updated to support C++11 conformance (recognition of enums) and - // to support volatile-qualified types. It will probably be useful to have it fail for unsupported types. - #define EASTL_TYPE_TRAIT_make_unsigned_CONFORMANCE 0 // make_unsigned is only partially conforming. + #define EASTL_TYPE_TRAIT_make_unsigned_CONFORMANCE 1 - template struct make_unsigned { typedef T type; }; + namespace internal + { + template ::value || eastl::is_integral::value> + struct make_unsigned_helper_0 + { + struct char_helper + { + typedef unsigned char type; + }; + + struct short_helper + { + typedef unsigned short type; + }; + + struct int_helper + { + typedef unsigned int type; + }; + + struct long_helper + { + typedef unsigned long type; + }; + + struct longlong_helper + { + typedef unsigned long long type; + }; + + struct int128_helper + { + #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(__clang__)) + typedef __uint128_t type; + #endif + }; + + struct no_type_helper + { + }; + + + typedef typename + eastl::conditional + #else + no_type_helper + #endif + > + > + > + > + >::type type; + }; + + + template + struct make_unsigned_helper_0 + { + struct no_type_helper + { + }; + + typedef no_type_helper type; + }; + + template + struct make_unsigned_helper_1 + { + typedef typename T::type type; + }; + + template + struct make_unsigned_helper + { + typedef typename eastl::internal::make_unsigned_helper_1::type>::type type; + }; + + } // namespace internal + + template + struct make_unsigned + { + typedef typename eastl::internal::make_unsigned_helper::type type; + }; + + template <> struct make_unsigned {}; template <> struct make_unsigned { typedef unsigned char type; }; - template <> struct make_unsigned { typedef const unsigned char type; }; + template <> struct make_unsigned { typedef unsigned char type; }; template <> struct make_unsigned { typedef unsigned short type; }; - template <> struct make_unsigned { typedef const unsigned short type; }; + template <> struct make_unsigned { typedef unsigned short type; }; template <> struct make_unsigned { typedef unsigned int type; }; - template <> struct make_unsigned { typedef const unsigned int type; }; + template <> struct make_unsigned { typedef unsigned int type; }; template <> struct make_unsigned { typedef unsigned long type; }; - template <> struct make_unsigned { typedef const unsigned long type; }; + template <> struct make_unsigned { typedef unsigned long type; }; template <> struct make_unsigned { typedef unsigned long long type; }; - template <> struct make_unsigned { typedef const unsigned long long type; }; + template <> struct make_unsigned { typedef unsigned long long type; }; + #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(__clang__)) + template <> struct make_unsigned<__int128_t> { typedef __uint128_t type; }; + template <> struct make_unsigned<__uint128_t> { typedef __uint128_t type; }; + #endif #if (CHAR_MIN < 0) // If char is signed, we convert char to unsigned char. However, if char is unsigned then make_unsigned returns char itself and not unsigned char. template <> struct make_unsigned { typedef unsigned char type; }; - template <> struct make_unsigned { typedef unsigned char type; }; #endif - #ifndef EA_WCHAR_T_NON_NATIVE // If wchar_t is a native type instead of simply a define to an existing type... - #if (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ != 4294967295U)) // If wchar_t is a 32 bit signed value... - template<> - struct make_unsigned - { typedef uint32_t type; }; - #elif (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ != 65535)) // If wchar_t is a 16 bit signed value... - template<> - struct make_unsigned - { typedef uint16_t type; }; - #elif (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ != 255)) // If wchar_t is an 8 bit signed value... - template<> - struct make_unsigned - { typedef uint8_t type; }; - #endif + #if defined(EA_CHAR8_UNIQUE) && EA_CHAR8_UNIQUE + template <> struct make_unsigned { typedef unsigned char type; }; #endif + template + struct make_unsigned + { + typedef eastl::add_const_t::type> type; + }; + + template + struct make_unsigned + { + typedef eastl::add_volatile_t::type> type; + }; + + template + struct make_unsigned + { + typedef eastl::add_cv_t::type> type; + }; + #if EASTL_VARIABLE_TEMPLATES_ENABLED - template + template using make_unsigned_t = typename make_unsigned::type; #endif diff --git a/library/3rdparty/EASTL/include/EASTL/intrusive_list.h b/library/3rdparty/EASTL/include/EASTL/intrusive_list.h index 18d7e93..dc0129f 100644 --- a/library/3rdparty/EASTL/include/EASTL/intrusive_list.h +++ b/library/3rdparty/EASTL/include/EASTL/intrusive_list.h @@ -146,6 +146,7 @@ namespace eastl intrusive_list_iterator(); explicit intrusive_list_iterator(pointer pNode); // Note that you can also construct an iterator from T via this, since value_type == node_type. intrusive_list_iterator(const iterator& x); + intrusive_list_iterator& operator=(const iterator& x); reference operator*() const; pointer operator->() const; @@ -368,6 +369,13 @@ namespace eastl // Empty } + template + inline typename intrusive_list_iterator::this_type& + intrusive_list_iterator::operator=(const iterator& x) + { + mpNode = x.mpNode; + return *this; + } template inline typename intrusive_list_iterator::reference diff --git a/library/3rdparty/EASTL/include/EASTL/iterator.h b/library/3rdparty/EASTL/include/EASTL/iterator.h index 037f95d..548ef64 100644 --- a/library/3rdparty/EASTL/include/EASTL/iterator.h +++ b/library/3rdparty/EASTL/include/EASTL/iterator.h @@ -41,10 +41,10 @@ EA_DISABLE_VC_WARNING(4217); // Member template functions cannot be used for cop namespace eastl { /// iterator_status_flag - /// - /// Defines the validity status of an iterator. This is primarily used for - /// iterator validation in debug builds. These are implemented as OR-able - /// flags (as opposed to mutually exclusive values) in order to deal with + /// + /// Defines the validity status of an iterator. This is primarily used for + /// iterator validation in debug builds. These are implemented as OR-able + /// flags (as opposed to mutually exclusive values) in order to deal with /// the nature of iterator status. In particular, an iterator may be valid /// but not dereferencable, as in the case with an iterator to container end(). /// An iterator may be valid but also dereferencable, as in the case with an @@ -82,7 +82,7 @@ namespace eastl // struct iterator - template struct iterator { @@ -108,7 +108,7 @@ namespace eastl template struct iterator_traits { - typedef EASTL_ITC_NS::random_access_iterator_tag iterator_category; // To consider: Change this to contiguous_iterator_tag for the case that + typedef EASTL_ITC_NS::random_access_iterator_tag iterator_category; // To consider: Change this to contiguous_iterator_tag for the case that typedef T value_type; // EASTL_ITC_NS is "eastl" instead of "std". typedef ptrdiff_t difference_type; typedef T* pointer; @@ -134,14 +134,14 @@ namespace eastl /// Relies on the class declaring a typedef called wrapped_iterator_type. /// /// Examples of wrapping iterators: - /// reverse_iterator - /// generic_iterator - /// move_iterator + /// reverse_iterator + /// generic_iterator + /// move_iterator /// Examples of non-wrapping iterators: /// iterator /// list::iterator /// char* - /// + /// /// Example behavior: /// is_iterator_wrapper(int*)::value => false /// is_iterator_wrapper(eastl::array*)::value => false @@ -157,7 +157,7 @@ namespace eastl template static eastl::yes_type test(typename U::wrapped_iterator_type*, typename eastl::enable_if::value>::type* = 0); - + public: EA_DISABLE_VC_WARNING(6334) static const bool value = (sizeof(test(NULL)) == sizeof(eastl::yes_type)); @@ -167,11 +167,11 @@ namespace eastl /// unwrap_iterator /// - /// Takes a wrapper Iterator (e.g. move_iterator, reverse_iterator, generic_iterator) instance + /// Takes a wrapper Iterator (e.g. move_iterator, reverse_iterator, generic_iterator) instance /// and returns the wrapped iterator type. If Iterator is not a wrapper (including being a pointer), /// or is not an iterator, then this function returns it as-is. - /// unwrap_iterator unwraps only a single layer of iterator at a time. You need to call it twice, - /// for example, to unwrap two layers of iterators. + /// unwrap_iterator unwraps only a single layer of iterator at a time. You need to call it twice, + /// for example, to unwrap two layers of iterators. /// /// Example usage: /// int* pInt = unwrap_iterator(&pIntArray[15]); @@ -207,13 +207,13 @@ namespace eastl /// reverse_iterator /// /// From the C++ standard: - /// Bidirectional and random access iterators have corresponding reverse - /// iterator adaptors that iterate through the data structure in the - /// opposite direction. They have the same signatures as the corresponding - /// iterators. The fundamental relation between a reverse iterator and its + /// Bidirectional and random access iterators have corresponding reverse + /// iterator adaptors that iterate through the data structure in the + /// opposite direction. They have the same signatures as the corresponding + /// iterators. The fundamental relation between a reverse iterator and its /// corresponding iterator i is established by the identity: /// &*(reverse_iterator(i)) == &*(i - 1). - /// This mapping is dictated by the fact that while there is always a pointer + /// This mapping is dictated by the fact that while there is always a pointer /// past the end of an array, there might not be a valid pointer before the /// beginning of an array. /// @@ -235,7 +235,7 @@ namespace eastl Iterator mIterator; public: - EA_CPP14_CONSTEXPR reverse_iterator() // It's important that we construct mIterator, because if Iterator + EA_CPP14_CONSTEXPR reverse_iterator() // It's important that we construct mIterator, because if Iterator : mIterator() { } // is a pointer, there's a difference between doing it and not. EA_CPP14_CONSTEXPR explicit reverse_iterator(iterator_type i) @@ -248,7 +248,7 @@ namespace eastl EA_CPP14_CONSTEXPR reverse_iterator(const reverse_iterator& ri) : mIterator(ri.base()) { } - // This operator= isn't in the standard, but the the C++ + // This operator= isn't in the standard, but the the C++ // library working group has tentatively approved it, as it // allows const and non-const reverse_iterators to interoperate. template @@ -299,10 +299,10 @@ namespace eastl EA_CPP14_CONSTEXPR reverse_iterator& operator-=(difference_type n) { mIterator += n; return *this; } - // http://cplusplus.github.io/LWG/lwg-defects.html#386, - // http://llvm.org/bugs/show_bug.cgi?id=17883 - // random_access_iterator operator[] is merely required to return something convertible to reference. - // reverse_iterator operator[] can't necessarily know what to return as the underlying iterator + // http://cplusplus.github.io/LWG/lwg-defects.html#386, + // http://llvm.org/bugs/show_bug.cgi?id=17883 + // random_access_iterator operator[] is merely required to return something convertible to reference. + // reverse_iterator operator[] can't necessarily know what to return as the underlying iterator // operator[] may return something other than reference. EA_CPP14_CONSTEXPR reference operator[](difference_type n) const { return mIterator[-n - 1]; } @@ -311,12 +311,12 @@ namespace eastl // The C++ library working group has tentatively approved the usage of two // template parameters (Iterator1 and Iterator2) in order to allow reverse_iterators - // and const_reverse iterators to be comparable. This is a similar issue to the + // and const_reverse iterators to be comparable. This is a similar issue to the // C++ defect report #179 regarding comparison of container iterators and const_iterators. // - // libstdc++ reports that std::relops breaks the usage of two iterator types and if we + // libstdc++ reports that std::relops breaks the usage of two iterator types and if we // want to support relops then we need to also make versions of each of below with - // a single template parameter to placate std::relops. But relops is hardly used due to + // a single template parameter to placate std::relops. But relops is hardly used due to // the troubles it causes and so we are avoiding support here until somebody complains about it. template EA_CPP14_CONSTEXPR inline bool @@ -371,9 +371,9 @@ namespace eastl /// This is a type traits extension utility. /// Given an iterator, tells if it's a reverse_iterator vs anything else. /// If it's a reverse iterator wrapped by another iterator then value is false. - /// To consider: Detect that if it's a move_iterator and unwrap + /// To consider: Detect that if it's a move_iterator and unwrap /// move_iterator so we can detect that underneath it's reverse_iterator. - /// + /// template struct is_reverse_iterator : public eastl::false_type {}; @@ -411,6 +411,9 @@ namespace eastl template class move_iterator // Don't inherit from iterator. { + private: + using WrappedIteratorReference = typename iterator_traits::reference; + public: typedef Iterator iterator_type; typedef iterator_type wrapped_iterator_type; // This is not in the C++ Standard; it's used by use to identify it as a wrapping iterator type. @@ -419,7 +422,9 @@ namespace eastl typedef typename traits_type::value_type value_type; typedef typename traits_type::difference_type difference_type; typedef Iterator pointer; - typedef value_type&& reference; + using reference = conditional_t::value, + remove_reference_t&&, + WrappedIteratorReference>; protected: iterator_type mIterator; @@ -442,8 +447,7 @@ namespace eastl iterator_type base() const { return mIterator; } - reference operator*() const - { return eastl::move(*mIterator); } + reference operator*() const { return static_cast(*mIterator); } pointer operator->() const { return mIterator; } @@ -487,7 +491,7 @@ namespace eastl { return move_iterator(mIterator - n); } move_iterator& operator-=(difference_type n) - { + { mIterator -= n; return *this; } @@ -550,12 +554,12 @@ namespace eastl // make_move_if_noexcept_iterator returns move_iterator if the Iterator is of a noexcept type; - // otherwise returns Iterator as-is. The point of this is to be able to avoid moves that can generate exceptions and instead + // otherwise returns Iterator as-is. The point of this is to be able to avoid moves that can generate exceptions and instead // fall back to copies or whatever the default IteratorType::operator* returns for use by copy/move algorithms. // To consider: merge the conditional expression usage here with the one used by move_if_noexcept, as they are the same condition. #if EASTL_EXCEPTIONS_ENABLED - template ::value_type>::value || - !eastl::is_copy_constructible::value_type>::value, + template ::value_type>::value || + !eastl::is_copy_constructible::value_type>::value, eastl::move_iterator, Iterator>::type> inline IteratorType make_move_if_noexcept_iterator(Iterator i) { return IteratorType(i); } @@ -575,7 +579,7 @@ namespace eastl /// Example usage (though somewhat useless): /// template /// bool IsMoveIterator() { return typename eastl::is_move_iterator::value; } - /// + /// template struct is_move_iterator : public eastl::false_type {}; @@ -603,7 +607,7 @@ namespace eastl /// back_insert_iterator /// - /// A back_insert_iterator is simply a class that acts like an iterator but when you + /// A back_insert_iterator is simply a class that acts like an iterator but when you /// assign a value to it, it calls push_back on the container with the value. /// template @@ -660,7 +664,7 @@ namespace eastl /// front_insert_iterator /// - /// A front_insert_iterator is simply a class that acts like an iterator but when you + /// A front_insert_iterator is simply a class that acts like an iterator but when you /// assign a value to it, it calls push_front on the container with the value. /// template @@ -714,18 +718,18 @@ namespace eastl /// insert_iterator /// - /// An insert_iterator is like an iterator except that when you assign a value to it, + /// An insert_iterator is like an iterator except that when you assign a value to it, /// the insert_iterator inserts the value into the container and increments the iterator. /// - /// insert_iterator is an iterator adaptor that functions as an OutputIterator: - /// assignment through an insert_iterator inserts an object into a container. - /// Specifically, if ii is an insert_iterator, then ii keeps track of a container c and + /// insert_iterator is an iterator adaptor that functions as an OutputIterator: + /// assignment through an insert_iterator inserts an object into a container. + /// Specifically, if ii is an insert_iterator, then ii keeps track of a container c and /// an insertion point p; the expression *ii = x performs the insertion container.insert(p, x). /// - /// If you assign through an insert_iterator several times, then you will be inserting - /// several elements into the underlying container. In the case of a sequence, they will - /// appear at a particular location in the underlying sequence, in the order in which - /// they were inserted: one of the arguments to insert_iterator's constructor is an + /// If you assign through an insert_iterator several times, then you will be inserting + /// several elements into the underlying container. In the case of a sequence, they will + /// appear at a particular location in the underlying sequence, in the order in which + /// they were inserted: one of the arguments to insert_iterator's constructor is an /// iterator p, and the new range will be inserted immediately before p. /// template @@ -738,11 +742,11 @@ namespace eastl protected: Container& container; - iterator_type it; + iterator_type it; public: // This assignment operator is defined more to stop compiler warnings (e.g. VC++ C4512) - // than to be useful. However, it does allow an insert_iterator to be assigned to another + // than to be useful. However, it does allow an insert_iterator to be assigned to another // insert iterator provided that they point to the same container. insert_iterator& operator=(const insert_iterator& x) { @@ -770,7 +774,7 @@ namespace eastl insert_iterator& operator++(int) { return *this; } // This is by design. - }; // insert_iterator + }; // insert_iterator /// inserter @@ -791,7 +795,7 @@ namespace eastl /// This is a type traits extension utility. /// Given an iterator, tells if it's an insert_iterator vs anything else. /// If it's a insert_iterator wrapped by another iterator then value is false. - /// + /// template struct is_insert_iterator : public eastl::false_type {}; @@ -811,6 +815,7 @@ namespace eastl /// iterators (e.g. with list). The former is more efficient. /// template + EA_CONSTEXPR inline typename eastl::iterator_traits::difference_type distance_impl(InputIterator first, InputIterator last, EASTL_ITC_NS::input_iterator_tag) { @@ -825,13 +830,14 @@ namespace eastl } template + EA_CONSTEXPR inline typename eastl::iterator_traits::difference_type distance_impl(RandomAccessIterator first, RandomAccessIterator last, EASTL_ITC_NS::random_access_iterator_tag) { return last - first; } - // Special version defined so that std C++ iterators can be recognized by + // Special version defined so that std C++ iterators can be recognized by // this function. Unfortunately, this function treats all foreign iterators // as InputIterators and thus can seriously hamper performance in the case // of large ranges of bidirectional_iterator_tag iterators. @@ -850,6 +856,7 @@ namespace eastl //} template + EA_CONSTEXPR inline typename eastl::iterator_traits::difference_type distance(InputIterator first, InputIterator last) { @@ -865,8 +872,8 @@ namespace eastl /// advance /// /// Implements the advance() function. There are three versions, one for - /// random access iterators (e.g. with vector), one for bidirectional - /// iterators (list) and one for regular input iterators (e.g. with slist). + /// random access iterators (e.g. with vector), one for bidirectional + /// iterators (list) and one for regular input iterators (e.g. with slist). /// template inline void @@ -920,7 +927,7 @@ namespace eastl i += n; } - // Special version defined so that std C++ iterators can be recognized by + // Special version defined so that std C++ iterators can be recognized by // this function. Unfortunately, this function treats all foreign iterators // as InputIterators and thus can seriously hamper performance in the case // of large ranges of bidirectional_iterator_tag iterators. @@ -948,7 +955,7 @@ namespace eastl // http://en.cppreference.com/w/cpp/iterator/next // template - inline InputIterator + inline InputIterator next(InputIterator it, typename eastl::iterator_traits::difference_type n = 1) { eastl::advance(it, n); @@ -965,7 +972,7 @@ namespace eastl #if defined(EA_COMPILER_CPP11_ENABLED) && EA_COMPILER_CPP11_ENABLED - + // eastl::data // // http://en.cppreference.com/w/cpp/iterator/data @@ -979,7 +986,7 @@ namespace eastl { return c.data(); } template - EA_CPP14_CONSTEXPR T* data(T(&array)[N]) EA_NOEXCEPT + EA_CPP14_CONSTEXPR T* data(T(&array)[N]) EA_NOEXCEPT { return array; } template @@ -991,7 +998,7 @@ namespace eastl // // http://en.cppreference.com/w/cpp/iterator/size // - template + template EA_CPP14_CONSTEXPR auto size(const C& c) -> decltype(c.size()) { return c.size(); } @@ -1018,10 +1025,10 @@ namespace eastl // eastl::empty - // + // // http://en.cppreference.com/w/cpp/iterator/empty // - template + template EA_CPP14_CONSTEXPR auto empty(const Container& c) -> decltype(c.empty()) { return c.empty(); } @@ -1029,7 +1036,7 @@ namespace eastl EA_CPP14_CONSTEXPR bool empty(const T (&)[N]) EA_NOEXCEPT { return false; } - template + template EA_CPP14_CONSTEXPR bool empty(std::initializer_list il) EA_NOEXCEPT { return il.size() == 0; } @@ -1041,13 +1048,13 @@ namespace eastl // // In order to enable eastl::begin and eastl::end, the compiler needs to have conforming support // for argument-dependent lookup if it supports C++11 range-based for loops. The reason for this is - // that in C++11 range-based for loops result in usage of std::begin/std::end, but allow that to + // that in C++11 range-based for loops result in usage of std::begin/std::end, but allow that to // be overridden by argument-dependent lookup: // C++11 Standard, section 6.5.4, paragraph 1. - // "otherwise, begin-expr and end-expr are begin(__range) and end(__range), respectively, - // where begin and end are looked up with argument-dependent lookup (3.4.2). For the + // "otherwise, begin-expr and end-expr are begin(__range) and end(__range), respectively, + // where begin and end are looked up with argument-dependent lookup (3.4.2). For the // purposes of this name lookup, namespace std is an associated namespace." - // It turns out that one compiler has a problem: GCC 4.6. That version added support for + // It turns out that one compiler has a problem: GCC 4.6. That version added support for // range-based for loops but has broken argument-dependent lookup which was fixed in GCC 4.7. // #if (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION == 4006)) @@ -1059,20 +1066,26 @@ namespace eastl #if EASTL_BEGIN_END_ENABLED template EA_CPP14_CONSTEXPR inline auto begin(Container& container) -> decltype(container.begin()) - { + { return container.begin(); } template EA_CPP14_CONSTEXPR inline auto begin(const Container& container) -> decltype(container.begin()) - { + { return container.begin(); } + template + EA_CPP14_CONSTEXPR inline T* begin(T (&arrayObject)[arraySize]) EA_NOEXCEPT + { + return arrayObject; + } + template - EA_CPP14_CONSTEXPR inline auto cbegin(const Container& container) -> decltype(container.begin()) - { - return container.begin(); + EA_CPP14_CONSTEXPR inline auto cbegin(const Container& container) -> decltype(eastl::begin(container)) + { + return eastl::begin(container); } template @@ -1087,10 +1100,16 @@ namespace eastl return container.end(); } + template + EA_CPP14_CONSTEXPR inline T* end(T (&arrayObject)[arraySize]) EA_NOEXCEPT + { + return (arrayObject + arraySize); + } + template - EA_CPP14_CONSTEXPR inline auto cend(const Container& container) -> decltype(container.end()) + EA_CPP14_CONSTEXPR inline auto cend(const Container& container) -> decltype(eastl::end(container)) { - return container.end(); + return eastl::end(container); } template @@ -1129,17 +1148,6 @@ namespace eastl return container.rend(); } - template - EA_CPP14_CONSTEXPR inline T* begin(T (&arrayObject)[arraySize]) - { - return arrayObject; - } - - template - EA_CPP14_CONSTEXPR inline T* end(T (&arrayObject)[arraySize]) - { - return (arrayObject + arraySize); - } template EA_CPP14_CONSTEXPR inline reverse_iterator rbegin(T (&arrayObject)[arraySize]) @@ -1175,10 +1183,10 @@ namespace eastl -// Some compilers (e.g. GCC 4.6) support range-based for loops, but have a bug with +// Some compilers (e.g. GCC 4.6) support range-based for loops, but have a bug with // respect to argument-dependent lookup which results on them unilaterally using std::begin/end -// with range-based for loops. To work around this we #include for this case in -// order to make std::begin/end visible to users of , for portability. +// with range-based for loops. To work around this we #include for this case in +// order to make std::begin/end visible to users of , for portability. #if !EASTL_BEGIN_END_ENABLED && !defined(EA_COMPILER_NO_RANGE_BASED_FOR_LOOP) #include #endif diff --git a/library/3rdparty/EASTL/include/EASTL/list.h b/library/3rdparty/EASTL/include/EASTL/list.h index 680dcad..5e79437 100644 --- a/library/3rdparty/EASTL/include/EASTL/list.h +++ b/library/3rdparty/EASTL/include/EASTL/list.h @@ -771,7 +771,7 @@ namespace eastl inline typename ListBase::node_type* ListBase::DoAllocateNode() { - node_type* pNode = (node_type*)allocate_memory(internalAllocator(), sizeof(node_type), EASTL_ALIGN_OF(T), 0); + node_type* pNode = (node_type*)allocate_memory(internalAllocator(), sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); EASTL_ASSERT(pNode != nullptr); return pNode; } diff --git a/library/3rdparty/EASTL/include/EASTL/memory.h b/library/3rdparty/EASTL/include/EASTL/memory.h index d1bdc49..cf24b41 100644 --- a/library/3rdparty/EASTL/include/EASTL/memory.h +++ b/library/3rdparty/EASTL/include/EASTL/memory.h @@ -1390,7 +1390,7 @@ namespace eastl inline void destroy(ForwardIterator first, ForwardIterator last) { for (; first != last; ++first) - destroy_at(addressof(*first)); + eastl::destroy_at(eastl::addressof(*first)); } @@ -1404,7 +1404,7 @@ namespace eastl ForwardIterator destroy_n(ForwardIterator first, Size n) { for (; n > 0; ++first, --n) - destroy_at(addressof(*first)); + eastl::destroy_at(eastl::addressof(*first)); return first; } diff --git a/library/3rdparty/EASTL/include/EASTL/meta.h b/library/3rdparty/EASTL/include/EASTL/meta.h index 09880b7..545354d 100644 --- a/library/3rdparty/EASTL/include/EASTL/meta.h +++ b/library/3rdparty/EASTL/include/EASTL/meta.h @@ -36,24 +36,24 @@ namespace eastl template struct get_type_index { - static const int value = is_same_v ? I : get_type_index::value; + static EA_CONSTEXPR_OR_CONST int value = is_same_v ? I : get_type_index::value; }; template struct get_type_index { - static const int value = -1; + static EA_CONSTEXPR_OR_CONST int value = -1; }; } template struct get_type_index { - static const int value = Internal::get_type_index<0, T, Types...>::value; + static EA_CONSTEXPR_OR_CONST int value = Internal::get_type_index<0, T, Types...>::value; }; template - constexpr int get_type_index_v = get_type_index::value; + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR int get_type_index_v = get_type_index::value; //////////////////////////////////////////////////////////////////////////////////////////// @@ -77,7 +77,7 @@ namespace eastl //////////////////////////////////////////////////////////////////////////////////////////// - // type_count_v + // type_count_v // // Returns the number of occurrences of type T in a typelist. // @@ -87,33 +87,37 @@ namespace eastl template struct type_count { - static const int value = (is_same_v ? 1 : 0) + type_count::value; + static EA_CONSTEXPR_OR_CONST int value = (is_same_v ? 1 : 0) + type_count::value; }; - template struct type_count { static const int value = 0; }; + template + struct type_count + { + static EA_CONSTEXPR_OR_CONST int value = 0; + }; template - constexpr int type_count_v = type_count::value; + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR int type_count_v = type_count::value; //////////////////////////////////////////////////////////////////////////////////////////// // duplicate_type_check_v - // + // // Checks if a type T occurs in a typelist more than once. // template struct duplicate_type_check { - static const bool value = (type_count::value == 1); + static EA_CONSTEXPR_OR_CONST bool value = (type_count::value == 1); }; template - constexpr bool duplicate_type_check_v = duplicate_type_check::value; + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool duplicate_type_check_v = duplicate_type_check::value; ////////////////////////////////////////////////////////////////////////////////// - // type_list + // type_list // // type_list is a simple struct that allows us to pass template parameter packs // around in a single struct, and deduce parameter packs from function arguments @@ -170,8 +174,8 @@ namespace eastl //////////////////////////////////////////////////////////////////////////////////////////// - // overload_resolution_t - // + // overload_resolution_t + // // Given an input type and a typelist (which is a stand-in for alternative // function overloads) this traits will return the same type chosen as if // overload_resolution has selected a function to run. @@ -215,8 +219,29 @@ namespace eastl template using overload_resolution_t = typename overload_resolution, OverloadSet>::type; - } // namespace meta + + //////////////////////////////////////////////////////////////////////////////////////////// + // double_pack_expansion + // + // MSVC 2017 has a hard time expanding two packs of different lengths. + // This is a helper meant to coerce MSVC 2017 into doing the expansion by adding another level + // of indirection. + // + + template + struct double_pack_expansion; + + template + struct double_pack_expansion, I> + { + using type = index_sequence; + }; + + template + using double_pack_expansion_t = typename double_pack_expansion::type; + + + } // namespace meta } // namespace eastl #endif // EASTL_META_H - diff --git a/library/3rdparty/EASTL/include/EASTL/numeric_limits.h b/library/3rdparty/EASTL/include/EASTL/numeric_limits.h index c2770c9..e991e7e 100644 --- a/library/3rdparty/EASTL/include/EASTL/numeric_limits.h +++ b/library/3rdparty/EASTL/include/EASTL/numeric_limits.h @@ -57,7 +57,7 @@ EA_DISABLE_VC_WARNING(4310 4296) // Indicates whether we need to define our own implementations of inf, nan, snan, denorm floating point constants. // #if !defined(EASTL_CUSTOM_FLOAT_CONSTANTS_REQUIRED) - #if (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG) && defined(__FLT_MIN__)) || defined(_CPPLIB_VER) // __FLT_MIN__ detects if it's really GCC/clang and not a mimic. _CPPLIB_VER (Dinkumware) covers VC++, and Microsoft platforms. + #if (defined(EA_COMPILER_GNUC) || defined(__clang__) && defined(__FLT_MIN__)) || defined(_CPPLIB_VER) // __FLT_MIN__ detects if it's really GCC/clang and not a mimic. _CPPLIB_VER (Dinkumware) covers VC++, and Microsoft platforms. #define EASTL_CUSTOM_FLOAT_CONSTANTS_REQUIRED 0 #else #define EASTL_CUSTOM_FLOAT_CONSTANTS_REQUIRED 1 @@ -1213,7 +1213,7 @@ namespace eastl }; - #if (EA_COMPILER_INTMAX_SIZE >= 16) && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) // If __int128_t/__uint128_t is supported... + #if (EA_COMPILER_INTMAX_SIZE >= 16) && (defined(EA_COMPILER_GNUC) || defined(__clang__)) // If __int128_t/__uint128_t is supported... // numeric_limits<__uint128_t> template<> struct numeric_limits<__uint128_t> @@ -1391,7 +1391,7 @@ namespace eastl static value_type denorm_min() { return Internal::gFloatDenorm; } - #elif (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) && defined(__FLT_MIN__) + #elif (defined(EA_COMPILER_GNUC) || defined(__clang__)) && defined(__FLT_MIN__) static EA_CONSTEXPR value_type min() { return __FLT_MIN__; } @@ -1509,7 +1509,7 @@ namespace eastl static value_type denorm_min() { return Internal::gDoubleDenorm; } - #elif (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) && defined(__DBL_MIN__) + #elif (defined(EA_COMPILER_GNUC) || defined(__clang__)) && defined(__DBL_MIN__) static EA_CONSTEXPR value_type min() { return __DBL_MIN__; } @@ -1627,7 +1627,7 @@ namespace eastl static value_type denorm_min() { return Internal::gLongDoubleDenorm; } - #elif (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) && defined(__LDBL_MIN__) + #elif (defined(EA_COMPILER_GNUC) || defined(__clang__)) && defined(__LDBL_MIN__) static EA_CONSTEXPR value_type min() { return __LDBL_MIN__; } diff --git a/library/3rdparty/EASTL/include/EASTL/optional.h b/library/3rdparty/EASTL/include/EASTL/optional.h index e967f98..763bfd8 100644 --- a/library/3rdparty/EASTL/include/EASTL/optional.h +++ b/library/3rdparty/EASTL/include/EASTL/optional.h @@ -111,7 +111,7 @@ namespace eastl inline explicit optional_storage(in_place_t, Args&&... args) : engaged(true) { - ::new (eastl::addressof(val)) T{std::forward(args)...}; + ::new (eastl::addressof(val)) T{eastl::forward(args)...}; } template release(); + } // else if mpValue is non-NULL then we just lose it because it wasn't actually shared (can happen with // shared_ptr(const shared_ptr& sharedPtr, element_type* pValue) constructor). diff --git a/library/3rdparty/EASTL/include/EASTL/slist.h b/library/3rdparty/EASTL/include/EASTL/slist.h index 2796692..1dbb44f 100644 --- a/library/3rdparty/EASTL/include/EASTL/slist.h +++ b/library/3rdparty/EASTL/include/EASTL/slist.h @@ -679,7 +679,7 @@ namespace eastl template inline SListNode* SListBase::DoAllocateNode() { - return (node_type*)allocate_memory(internalAllocator(), sizeof(node_type), EASTL_ALIGN_OF(T), 0); + return (node_type*)allocate_memory(internalAllocator(), sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); } diff --git a/library/3rdparty/EASTL/include/EASTL/sort.h b/library/3rdparty/EASTL/include/EASTL/sort.h index 5b3fe6e..60cfcd8 100644 --- a/library/3rdparty/EASTL/include/EASTL/sort.h +++ b/library/3rdparty/EASTL/include/EASTL/sort.h @@ -305,7 +305,7 @@ namespace eastl { iBack = iCurrent = iSorted; - for(iBack -= nSpace; (iCurrent != iInsertFirst) && compare(*iCurrent, *iBack); iCurrent = iBack, iBack -= nSpace) + for(; (iCurrent != iInsertFirst) && compare(*iCurrent, *(iBack -= nSpace)); iCurrent = iBack) { EASTL_VALIDATE_COMPARE(!compare(*iBack, *iCurrent)); // Validate that the compare function is sane. eastl::iter_swap(iCurrent, iBack); @@ -439,7 +439,7 @@ namespace eastl if (lastSortedEnd < 1) { - lastSortedEnd = is_sorted_until(first, last, compare) - first; + lastSortedEnd = eastl::is_sorted_until(first, last, compare) - first; } // Sort the region unless lastSortedEnd indicates it is already sorted. @@ -1178,7 +1178,7 @@ namespace eastl { for(;; ++curr) { - if(curr == (size - 1)) // If we are at the end of the data... this run is done. + if(curr >= (size - 1)) // If we are at the end of the data... this run is done. break; if(compare(*(first + curr), *(first + curr - 1))) // If this item is not in order... this run is done. @@ -1189,7 +1189,7 @@ namespace eastl { for(;; ++curr) { - if(curr == (size - 1)) // If we are at the end of the data... this run is done. + if(curr >= (size - 1)) // If we are at the end of the data... this run is done. break; if(!compare(*(first + curr), *(first + curr - 1))) // If this item is not in order... this run is done. @@ -1653,8 +1653,8 @@ namespace eastl IntegerType) { RandomAccessIterator srcFirst = first; - constexpr size_t numBuckets = 1 << DigitBits; - constexpr IntegerType bucketMask = numBuckets - 1; + EA_CONSTEXPR_OR_CONST size_t numBuckets = 1 << DigitBits; + EA_CONSTEXPR_OR_CONST IntegerType bucketMask = numBuckets - 1; // The alignment of this variable isn't required; it merely allows the code below to be faster on some platforms. uint32_t EA_PREFIX_ALIGN(EASTL_PLATFORM_PREFERRED_ALIGNMENT) bucketSize[numBuckets]; diff --git a/library/3rdparty/EASTL/include/EASTL/span.h b/library/3rdparty/EASTL/include/EASTL/span.h index 1f3b9b4..9c47f5b 100644 --- a/library/3rdparty/EASTL/include/EASTL/span.h +++ b/library/3rdparty/EASTL/include/EASTL/span.h @@ -76,7 +76,7 @@ namespace eastl static EA_CONSTEXPR size_t extent = Extent; // constructors / destructor - EA_CONSTEXPR span() EA_NOEXCEPT = default; + EA_CONSTEXPR span() EA_NOEXCEPT; EA_CONSTEXPR span(const span& other) EA_NOEXCEPT = default; EA_CONSTEXPR span(pointer ptr, index_type count); EA_CONSTEXPR span(pointer pBegin, pointer pEnd); @@ -86,9 +86,14 @@ namespace eastl EA_CPP14_CONSTEXPR span& operator=(const span& other) EA_NOEXCEPT = default; // conversion constructors for c-array and eastl::array - template EA_CONSTEXPR span(element_type (&arr)[N]) EA_NOEXCEPT; - template EA_CONSTEXPR span(eastl::array& arr) EA_NOEXCEPT; - template EA_CONSTEXPR span(const eastl::array& arr) EA_NOEXCEPT; + template > + EA_CONSTEXPR span(element_type (&arr)[N]) EA_NOEXCEPT; + + template > + EA_CONSTEXPR span(eastl::array& arr) EA_NOEXCEPT; + + template > + EA_CONSTEXPR span(const eastl::array& arr) EA_NOEXCEPT; // SfinaeForGenericContainers // @@ -198,34 +203,43 @@ namespace eastl // ctor implementations /////////////////////////////////////////////////////////////////////////// + + template + EA_CONSTEXPR span::span() EA_NOEXCEPT + { + static_assert(Extent == dynamic_extent || Extent == 0, "impossible to default construct a span with a fixed Extent different than 0"); + } + template EA_CONSTEXPR span::span(pointer ptr, index_type size) : mpData(ptr), mnSize(size) { + EASTL_ASSERT_MSG(Extent == dynamic_extent || Extent == mnSize, "impossible to create a span with a fixed Extent different than the size of the supplied buffer"); } template EA_CONSTEXPR span::span(pointer pBegin, pointer pEnd) : mpData(pBegin), mnSize(static_cast(pEnd - pBegin)) { + EASTL_ASSERT_MSG(Extent == dynamic_extent || Extent == mnSize, "impossible to create a span with a fixed Extent different than the size of the supplied buffer"); } template - template + template EA_CONSTEXPR span::span(element_type(&arr)[N]) EA_NOEXCEPT : span(arr, static_cast(N)) { } template - template + template EA_CONSTEXPR span::span(eastl::array &arr) EA_NOEXCEPT : span(arr.data(), arr.size()) { } template - template + template EA_CONSTEXPR span::span(const eastl::array& arr) EA_NOEXCEPT : span(arr.data(), arr.size()) { @@ -368,7 +382,7 @@ namespace eastl template EA_CPP14_CONSTEXPR span::element_type, Count> span::first() const { - EASTL_ASSERT_MSG(bounds_check(Count), "undefined behavior accessing out of bounds"); + EASTL_ASSERT_MSG(Count <= size(), "undefined behavior accessing out of bounds"); return {data(), static_cast(Count)}; } @@ -376,7 +390,7 @@ namespace eastl EA_CPP14_CONSTEXPR span::element_type, dynamic_extent> span::first(size_t sz) const { - EASTL_ASSERT_MSG(bounds_check(sz), "undefined behavior accessing out of bounds"); + EASTL_ASSERT_MSG(sz <= size(), "undefined behavior accessing out of bounds"); return {data(), static_cast(sz)}; } @@ -384,7 +398,7 @@ namespace eastl template EA_CPP14_CONSTEXPR span::element_type, Count> span::last() const { - EASTL_ASSERT_MSG(bounds_check(Count), "undefined behavior accessing out of bounds"); + EASTL_ASSERT_MSG(Count <= size(), "undefined behavior accessing out of bounds"); return {data() + size() - Count, static_cast(Count)}; } @@ -392,7 +406,7 @@ namespace eastl EA_CPP14_CONSTEXPR span::element_type, dynamic_extent> span::last(size_t sz) const { - EASTL_ASSERT_MSG(bounds_check(sz), "undefined behavior accessing out of bounds"); + EASTL_ASSERT_MSG(sz <= size(), "undefined behavior accessing out of bounds"); return {data() + size() - sz, static_cast(sz)}; } @@ -401,7 +415,7 @@ namespace eastl EA_CONSTEXPR span::element_type, Internal::SubspanExtent::value> span::subspan() const { - EASTL_ASSERT_MSG(bounds_check(Offset), "undefined behaviour accessing out of bounds"); + EASTL_ASSERT_MSG(Offset <= size(), "undefined behaviour accessing out of bounds"); EASTL_ASSERT_MSG(Count == dynamic_extent || Count <= (size() - Offset), "undefined behaviour exceeding size of span"); return {data() + Offset, eastl_size_t(Count == dynamic_extent ? size() - Offset : Count)}; @@ -411,16 +425,16 @@ namespace eastl EA_CONSTEXPR span::element_type, dynamic_extent> span::subspan(size_t offset, size_t count) const { - EASTL_ASSERT_MSG(bounds_check(offset), "undefined behaviour accessing out of bounds"); + EASTL_ASSERT_MSG(offset <= size(), "undefined behaviour accessing out of bounds"); EASTL_ASSERT_MSG(count == dynamic_extent || count <= (size() - offset), "undefined behaviour exceeding size of span"); return {data() + offset, eastl_size_t(count == dynamic_extent ? size() - offset : count)}; } template - EA_CONSTEXPR bool span::bounds_check(size_t sz) const + EA_CONSTEXPR bool span::bounds_check(size_t offset) const { - return (sz >= 0 && sz < size()); + return offset < size(); } } diff --git a/library/3rdparty/EASTL/include/EASTL/string.h b/library/3rdparty/EASTL/include/EASTL/string.h index ad4c521..7d45375 100644 --- a/library/3rdparty/EASTL/include/EASTL/string.h +++ b/library/3rdparty/EASTL/include/EASTL/string.h @@ -30,7 +30,7 @@ // trick of using: basic_string(x).swap(x); // - basic_string has a force_size() function, which unilaterally moves the string // end position (mpEnd) to the given location. Useful for when the user writes -// into the string via some extenal means such as C strcpy or sprintf. +// into the string via some external means such as C strcpy or sprintf. // - basic_string substr() deviates from the standard and returns a string with // a copy of this->get_allocator() /////////////////////////////////////////////////////////////////////////////// @@ -64,7 +64,7 @@ // - A reference count needs to exist with the string, which increases string memory usage. // - With thread safety, atomic operations and mutex locks are expensive, especially // on weaker memory systems such as console gaming platforms. -// - All non-const string accessor functions need to do a sharing check the the +// - All non-const string accessor functions need to do a sharing check then the // first such check needs to detach the string. Similarly, all string assignments // need to do a sharing check as well. If you access the string before doing an // assignment, the assignment doesn't result in a shared string, because the string @@ -316,19 +316,19 @@ namespace eastl // Masks used to determine if we are in SSO or Heap #ifdef EA_SYSTEM_BIG_ENDIAN // Big Endian use LSB, unless we want to reorder struct layouts on endianness, Bit is set when we are in Heap - static constexpr size_type kHeapMask = 0x1; - static constexpr size_type kSSOMask = 0x1; + static EA_CONSTEXPR_OR_CONST size_type kHeapMask = 0x1; + static EA_CONSTEXPR_OR_CONST size_type kSSOMask = 0x1; #else // Little Endian use MSB - static constexpr size_type kHeapMask = ~(size_type(~size_type(0)) >> 1); - static constexpr size_type kSSOMask = 0x80; + static EA_CONSTEXPR_OR_CONST size_type kHeapMask = ~(size_type(~size_type(0)) >> 1); + static EA_CONSTEXPR_OR_CONST size_type kSSOMask = 0x80; #endif public: #ifdef EA_SYSTEM_BIG_ENDIAN - static constexpr size_type kMaxSize = (~kHeapMask) >> 1; + static EA_CONSTEXPR_OR_CONST size_type kMaxSize = (~kHeapMask) >> 1; #else - static constexpr size_type kMaxSize = ~kHeapMask; + static EA_CONSTEXPR_OR_CONST size_type kMaxSize = ~kHeapMask; #endif protected: @@ -356,7 +356,7 @@ namespace eastl // The view of memory when the string data is able to store the string data locally (without a heap allocation). struct SSOLayout { - static constexpr size_type SSO_CAPACITY = (sizeof(HeapLayout) - sizeof(char)) / sizeof(value_type); + static EA_CONSTEXPR_OR_CONST size_type SSO_CAPACITY = (sizeof(HeapLayout) - sizeof(char)) / sizeof(value_type); // mnSize must correspond to the last byte of HeapLayout.mnCapacity, so we don't want the compiler to insert // padding after mnSize if sizeof(value_type) != 1; Also ensures both layouts are the same size. diff --git a/library/3rdparty/EASTL/include/EASTL/tuple.h b/library/3rdparty/EASTL/include/EASTL/tuple.h index f9611e2..9d27bff 100644 --- a/library/3rdparty/EASTL/include/EASTL/tuple.h +++ b/library/3rdparty/EASTL/include/EASTL/tuple.h @@ -199,11 +199,11 @@ 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::value - explicit TupleLeaf(ValueType&& v) : mValue(move(v)) {} + explicit TupleLeaf(ValueType&& v) : mValue(eastl::move(v)) {} template ::value>::type> explicit TupleLeaf(T&& t) - : mValue(forward(t)) + : mValue(eastl::forward(t)) { } @@ -216,7 +216,7 @@ namespace Internal template TupleLeaf& operator=(T&& t) { - mValue = forward(t); + mValue = eastl::forward(t); return *this; } @@ -243,7 +243,7 @@ namespace Internal template ::value>::type> explicit TupleLeaf(T&& t) - : mValue(forward(t)) + : mValue(eastl::forward(t)) { } @@ -260,7 +260,7 @@ namespace Internal template TupleLeaf& operator=(T&& t) { - mValue = forward(t); + mValue = eastl::forward(t); return *this; } @@ -288,7 +288,7 @@ namespace Internal template ::value>::type> explicit TupleLeaf(T&& t) - : ValueType(forward(t)) + : ValueType(eastl::forward(t)) { } @@ -301,7 +301,7 @@ namespace Internal template TupleLeaf& operator=(T&& t) { - ValueType::operator=(forward(t)); + ValueType::operator=(eastl::forward(t)); return *this; } @@ -381,13 +381,13 @@ namespace Internal // template explicit TupleImpl(integer_sequence, TupleTypes, ValueTypes&&... values) - : TupleLeaf(forward(values))... + : TupleLeaf(eastl::forward(values))... { } template TupleImpl(OtherTuple&& t) - : TupleLeaf(forward>>(get(t)))... + : TupleLeaf(eastl::forward>>(get(t)))... { } @@ -395,7 +395,7 @@ namespace Internal TupleImpl& operator=(OtherTuple&& t) { swallow(TupleLeaf::operator=( - forward>>(get(t)))...); + eastl::forward>>(get(t)))...); return *this; } @@ -664,7 +664,7 @@ namespace Internal template static inline ResultType DoCat2(Tuple1&& t1, Tuple2&& t2) { - return ResultType(get(forward(t1))..., get(forward(t2))...); + return ResultType(get(eastl::forward(t1))..., get(eastl::forward(t2))...); } }; @@ -683,7 +683,7 @@ namespace Internal template static inline ResultType DoCat2(Tuple1&& t1, Tuple2&& t2) { - return TCI::DoCat2(forward(t1), forward(t2)); + return TCI::DoCat2(eastl::forward(t1), eastl::forward(t2)); } }; @@ -701,8 +701,8 @@ namespace Internal static inline ResultType DoCat(TupleArg1&& t1, TupleArg2&& t2, TupleArgsRest&&... ts) { return TupleCat::DoCat( - TupleCat2::DoCat2(forward(t1), forward(t2)), - forward(ts)...); + TupleCat2::DoCat2(eastl::forward(t1), eastl::forward(t2)), + eastl::forward(ts)...); } }; @@ -715,7 +715,7 @@ namespace Internal template static inline ResultType DoCat(TupleArg1&& t1, TupleArg2&& t2) { - return TC2::DoCat2(forward(t1), forward(t2)); + return TC2::DoCat2(eastl::forward(t1), eastl::forward(t2)); } }; } // namespace Internal @@ -755,23 +755,23 @@ class tuple template = 0> EA_CONSTEXPR tuple(U&& u, Us&&... us) - : mImpl(make_index_sequence{}, Internal::MakeTupleTypes_t{}, forward(u), - forward(us)...) + : mImpl(make_index_sequence{}, Internal::MakeTupleTypes_t{}, eastl::forward(u), + eastl::forward(us)...) { } template = 0> explicit EA_CONSTEXPR tuple(U&& u, Us&&... us) - : mImpl(make_index_sequence{}, Internal::MakeTupleTypes_t{}, forward(u), - forward(us)...) + : mImpl(make_index_sequence{}, Internal::MakeTupleTypes_t{}, eastl::forward(u), + eastl::forward(us)...) { } template ::value, bool>::type = false> tuple(OtherTuple&& t) - : mImpl(forward(t)) + : mImpl(eastl::forward(t)) { } @@ -779,7 +779,7 @@ class tuple typename enable_if::value, bool>::type = false> tuple& operator=(OtherTuple&& t) { - mImpl.operator=(forward(t)); + mImpl.operator=(eastl::forward(t)); return *this; } @@ -831,7 +831,7 @@ inline const_tuple_element_t>& get(const tuple& t) template inline tuple_element_t>&& get(tuple&& t) { - return get(move(t.mImpl)); + return get(eastl::move(t.mImpl)); } template @@ -849,7 +849,7 @@ inline const T& get(const tuple& t) template inline T&& get(tuple&& t) { - return get(move(t.mImpl)); + return get(eastl::move(t.mImpl)); } template @@ -886,7 +886,7 @@ template inline bool operator>=(const tuple inline typename Internal::TupleCat::ResultType tuple_cat(Tuples&&... ts) { - return Internal::TupleCat::DoCat(forward(ts)...); + return Internal::TupleCat::DoCat(eastl::forward(ts)...); } @@ -896,7 +896,7 @@ inline typename Internal::TupleCat::ResultType tuple_cat(Tuples&&... template inline EA_CONSTEXPR tuple...> make_tuple(Ts&&... values) { - return tuple...>(forward(values)...); + return tuple...>(eastl::forward(values)...); } @@ -906,7 +906,7 @@ inline EA_CONSTEXPR tuple...> make_tuple(Ts&&... template inline EA_CONSTEXPR tuple forward_as_tuple(Ts&&... ts) EA_NOEXCEPT { - return tuple(forward(ts)...); + return tuple(eastl::forward(ts)...); } @@ -957,14 +957,14 @@ namespace detail template EA_CONSTEXPR decltype(auto) apply_impl(F&& f, Tuple&& t, index_sequence) { - return invoke(forward(f), get(forward(t))...); + return invoke(eastl::forward(f), get(eastl::forward(t))...); } } // namespace detail template EA_CONSTEXPR decltype(auto) apply(F&& f, Tuple&& t) { - return detail::apply_impl(forward(f), forward(t), + return detail::apply_impl(eastl::forward(f), eastl::forward(t), make_index_sequence>>{}); } diff --git a/library/3rdparty/EASTL/include/EASTL/type_traits.h b/library/3rdparty/EASTL/include/EASTL/type_traits.h index 68a388d..2cf5d7a 100644 --- a/library/3rdparty/EASTL/include/EASTL/type_traits.h +++ b/library/3rdparty/EASTL/include/EASTL/type_traits.h @@ -500,13 +500,8 @@ namespace eastl struct conjunction : conditional, B>::type {}; #if EASTL_VARIABLE_TEMPLATES_ENABLED - #if EASTL_INLINE_VARIABLE_ENABLED - template - inline constexpr bool conjunction_v = conjunction::value; - #else - template - static const constexpr bool conjunction_v = conjunction::value; - #endif + template + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool conjunction_v = conjunction::value; #endif @@ -529,13 +524,8 @@ namespace eastl struct disjunction : conditional>::type {}; #if EASTL_VARIABLE_TEMPLATES_ENABLED - #if EASTL_INLINE_VARIABLE_ENABLED - template - inline constexpr bool disjunction_v = disjunction::value; - #else - template - static const constexpr bool disjunction_v = disjunction::value; - #endif + template + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool disjunction_v = disjunction::value; #endif @@ -552,13 +542,8 @@ namespace eastl struct negation : eastl::bool_constant {}; #if EASTL_VARIABLE_TEMPLATES_ENABLED - #if EASTL_INLINE_VARIABLE_ENABLED - template - inline constexpr bool negation_v = negation::value; - #else - template - static const constexpr bool negation_v = negation::value; - #endif + template + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool negation_v = negation::value; #endif @@ -674,15 +659,16 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // is_reference // - // is_reference::value == true if and only if T is a reference type. + // is_reference::value == true if and only if T is a reference type (l-value reference or r-value reference). // This category includes reference to function types. // /////////////////////////////////////////////////////////////////////// #define EASTL_TYPE_TRAIT_is_reference_CONFORMANCE 1 // is_reference is conforming; doesn't make mistakes. - template struct is_reference : public eastl::false_type{}; - template struct is_reference : public eastl::true_type{}; + template struct is_reference : public eastl::false_type{}; + template struct is_reference : public eastl::true_type{}; + template struct is_reference : public eastl::true_type{}; #if EASTL_VARIABLE_TEMPLATES_ENABLED template @@ -831,9 +817,11 @@ namespace eastl // // The add_reference transformation trait adds a level of indirection // by reference to the type to which it is applied. For a given type T, - // add_reference::type is equivalent to T& if is_reference::value == false, + // add_reference::type is equivalent to T& if is_lvalue_reference::value == false, // and T otherwise. // + // Note: due to the reference collapsing rules, if you supply an r-value reference such as T&&, it will collapse to T&. + // /////////////////////////////////////////////////////////////////////// #define EASTL_TYPE_TRAIT_add_reference_CONFORMANCE 1 // add_reference is conforming. diff --git a/library/3rdparty/EASTL/include/EASTL/unique_ptr.h b/library/3rdparty/EASTL/include/EASTL/unique_ptr.h index 562e2c4..c5d2480 100644 --- a/library/3rdparty/EASTL/include/EASTL/unique_ptr.h +++ b/library/3rdparty/EASTL/include/EASTL/unique_ptr.h @@ -88,6 +88,7 @@ namespace eastl template > class unique_ptr { + static_assert(!is_rvalue_reference::value, "The supplied Deleter cannot be a r-value reference."); public: typedef Deleter deleter_type; typedef T element_type; @@ -130,7 +131,7 @@ namespace eastl /// Example usage: /// eastl::smart_ptr_deleter del; /// unique_ptr ptr(new int(3), del); - unique_ptr(pointer pValue, typename eastl::conditional::value, deleter_type, typename eastl::add_lvalue_reference::type>::type deleter) EA_NOEXCEPT + unique_ptr(pointer pValue, typename eastl::conditional::value, deleter_type, typename eastl::add_lvalue_reference::type>::type deleter) EA_NOEXCEPT : mPair(pValue, deleter) {} /// unique_ptr @@ -140,7 +141,7 @@ namespace eastl unique_ptr(pointer pValue, typename eastl::remove_reference::type&& deleter) EA_NOEXCEPT : mPair(pValue, eastl::move(deleter)) { - static_assert(!eastl::is_reference::value, "deleter_type reference refers to an rvalue deleter. The reference will probably become invalid before used. Change the deleter_type to not be a reference or construct with permanent deleter."); + static_assert(!eastl::is_lvalue_reference::value, "deleter_type reference refers to an rvalue deleter. The reference will probably become invalid before used. Change the deleter_type to not be a reference or construct with permanent deleter."); } /// unique_ptr @@ -157,7 +158,7 @@ namespace eastl /// unique_ptr ptr(new int(3)); /// unique_ptr newPtr = eastl::move(ptr); template - unique_ptr(unique_ptr&& u, typename enable_if::value && is_convertible::pointer, pointer>::value && is_convertible::value && (is_same::value || !is_reference::value)>::type* = 0) EA_NOEXCEPT + unique_ptr(unique_ptr&& u, typename enable_if::value && is_convertible::pointer, pointer>::value && is_convertible::value && (is_same::value || !is_lvalue_reference::value)>::type* = 0) EA_NOEXCEPT : mPair(u.release(), eastl::forward(u.get_deleter())) {} /// unique_ptr @@ -383,7 +384,7 @@ namespace eastl } template - unique_ptr(P pArray, typename eastl::conditional::value, deleter_type, + unique_ptr(P pArray, typename eastl::conditional::value, deleter_type, typename eastl::add_lvalue_reference::type>::type deleter, typename eastl::enable_if::value>::type* = 0) EA_NOEXCEPT : mPair(pArray, deleter) {} @@ -392,7 +393,7 @@ namespace eastl unique_ptr(P pArray, typename eastl::remove_reference::type&& deleter, eastl::enable_if_t::value>* = 0) EA_NOEXCEPT : mPair(pArray, eastl::move(deleter)) { - static_assert(!eastl::is_reference::value, "deleter_type reference refers to an rvalue deleter. The reference will probably become invalid before used. Change the deleter_type to not be a reference or construct with permanent deleter."); + static_assert(!eastl::is_lvalue_reference::value, "deleter_type reference refers to an rvalue deleter. The reference will probably become invalid before used. Change the deleter_type to not be a reference or construct with permanent deleter."); } unique_ptr(this_type&& x) EA_NOEXCEPT @@ -401,7 +402,7 @@ namespace eastl template unique_ptr(unique_ptr&& u, typename enable_if::pointer>::value && eastl::is_convertible::value && - (!eastl::is_reference::value || eastl::is_same::value)>::type* = 0) EA_NOEXCEPT + (!eastl::is_lvalue_reference::value || eastl::is_same::value)>::type* = 0) EA_NOEXCEPT : mPair(u.release(), eastl::forward(u.get_deleter())) {} this_type& operator=(this_type&& x) EA_NOEXCEPT diff --git a/library/3rdparty/EASTL/include/EASTL/utility.h b/library/3rdparty/EASTL/include/EASTL/utility.h index 4f6c357..a91ce8c 100644 --- a/library/3rdparty/EASTL/include/EASTL/utility.h +++ b/library/3rdparty/EASTL/include/EASTL/utility.h @@ -413,7 +413,7 @@ namespace eastl // // See bug submitted to LLVM for more details. // https://bugs.llvm.org/show_bug.cgi?id=38374 - #if !defined(EA_COMPILER_CLANG) + #if !defined(__clang__) template using single_pair_ctor_sfinae = eastl::enable_if_t>; #else @@ -789,7 +789,7 @@ namespace eastl template static EA_CONSTEXPR T1&& getInternal(pair&& p) { - return forward(p.first); + return eastl::forward(p.first); } }; @@ -811,7 +811,7 @@ namespace eastl template static EA_CONSTEXPR T2&& getInternal(pair&& p) { - return forward(p.second); + return eastl::forward(p.second); } }; @@ -830,7 +830,7 @@ namespace eastl template tuple_element_t>&& get(pair&& p) { - return GetPair::getInternal(move(p)); + return GetPair::getInternal(eastl::move(p)); } #endif // EASTL_TUPLE_ENABLED diff --git a/library/3rdparty/EASTL/include/EASTL/variant.h b/library/3rdparty/EASTL/include/EASTL/variant.h index 73460ac..6e77928 100644 --- a/library/3rdparty/EASTL/include/EASTL/variant.h +++ b/library/3rdparty/EASTL/include/EASTL/variant.h @@ -10,12 +10,12 @@ // // As with unions, if a variant holds a value of some object type T, the object // representation of T is allocated directly within the object representation of -// the variant itself. +// the variant itself. // // Variant is not allowed to allocate additional (dynamic) memory. // // A variant is not permitted to hold references, arrays, or the type void. -// Empty variants are also ill-formed (variant can be used instead). +// Empty variants are also ill-formed (variant can be used instead). // // A variant is permitted to hold the same type more than once, and to hold // differently cv-qualified versions of the same type. As with unions, the @@ -48,7 +48,7 @@ // * strong exception guarantees as specified (we punted on the assignment problem). // if an exception is thrown during assignment its undefined behaviour in our implementation. // -// Reference: +// Reference: // * http://en.cppreference.com/w/cpp/utility/variant // * https://thenewcpp.wordpress.com/2012/02/15/variadic-templates-part-3-or-how-i-wrote-a-variant-class/ /////////////////////////////////////////////////////////////////////////// @@ -65,6 +65,13 @@ #include #include #include +#include + +#if EASTL_EXCEPTIONS_ENABLED + #include + #include +#endif + #if defined(EA_PRAGMA_ONCE_SUPPORTED) #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. @@ -83,7 +90,7 @@ namespace eastl /////////////////////////////////////////////////////////////////////////// // default_construct_if_supported // - // Utility class to remove default constructor calls for types that + // Utility class to remove default constructor calls for types that // do not support default construction. // // We can remove these utilities when C++17 'constexpr if' is available. @@ -106,7 +113,7 @@ namespace eastl /////////////////////////////////////////////////////////////////////////// // destroy_if_supported // - // Utility class to remove default constructor calls for types that + // Utility class to remove default constructor calls for types that // do not support default construction. // // We can remove these utilities when C++17 'constexpr if' is available. @@ -129,7 +136,7 @@ namespace eastl /////////////////////////////////////////////////////////////////////////// // copy_if_supported // - // Utility class to remove copy constructor calls for types that + // Utility class to remove copy constructor calls for types that // do not support copying. // // We can remove these utilities when C++17 'constexpr if' is available. @@ -152,7 +159,7 @@ namespace eastl /////////////////////////////////////////////////////////////////////////// // move_if_supported // - // Utility class to remove move constructor calls for types that + // Utility class to remove move constructor calls for types that // do not support moves. // // We can remove these utilities when C++17 'constexpr if' is available. @@ -171,17 +178,13 @@ namespace eastl { static void call(T* pThis, T* pOther) {} // intentionally blank }; - } // namespace internal + } // namespace internal /////////////////////////////////////////////////////////////////////////// // 20.7.3, variant_npos // - #ifdef EA_COMPILER_NO_INLINE_VARIABLES - static EA_CONSTEXPR const size_t variant_npos = size_t(-1); - #else - inline EA_CONSTEXPR size_t variant_npos = -1; - #endif + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR size_t variant_npos = size_t(-1); /////////////////////////////////////////////////////////////////////////// @@ -233,10 +236,10 @@ namespace eastl template <> struct hash { size_t operator()(monostate) const { return static_cast(-0x42); } }; - + /////////////////////////////////////////////////////////////////////////// // variant_storage - // + // // This is a utility class to simplify the implementation of a storage type // for a distriminted union. This utility handles the alignment, size // requirements, and data access required by the variant type. @@ -322,33 +325,33 @@ namespace eastl public: variant_storage() { - DoOp(StorageOp::DEFAULT_CONSTRUCT); + DoOp(StorageOp::DEFAULT_CONSTRUCT); } ~variant_storage() { - DoOp(StorageOp::DESTROY); + DoOp(StorageOp::DESTROY); } variant_storage(const variant_storage& other) { - DoOp(StorageOp::COPY, other); + DoOp(StorageOp::COPY, other); } variant_storage(variant_storage&& other) { - DoOp(StorageOp::MOVE, other); + DoOp(StorageOp::MOVE, other); } variant_storage& operator=(const variant_storage& other) { - DoOp(StorageOp::COPY, other); + DoOp(StorageOp::COPY, other); return *this; } variant_storage& operator=(variant_storage&& other) { - DoOp(StorageOp::MOVE, eastl::move(other)); + DoOp(StorageOp::MOVE, eastl::move(other)); return *this; } @@ -357,7 +360,7 @@ namespace eastl { // NOTE(rparolin): If this assert fires there is an EASTL problem picking the size of the local buffer which // variant_storage used to store types. The size selected should be large enough to hold the largest type in - // the user provided variant type-list. + // the user provided variant type-list. static_assert(sizeof(aligned_storage_impl_t) >= sizeof(T), "T is larger than local buffer size"); using RT = remove_reference_t; @@ -372,7 +375,7 @@ namespace eastl { // NOTE(rparolin): If this assert fires there is an EASTL problem picking the size of the local buffer which // variant_storage used to store types. The size selected should be large enough to hold the largest type in - // the user provided variant type-list. + // the user provided variant type-list. static_assert(sizeof(aligned_storage_impl_t) >= sizeof(T), "T is larger than local buffer size"); using RT = remove_reference_t; @@ -398,7 +401,7 @@ namespace eastl void destroy() { - DoOp(StorageOp::DESTROY); + DoOp(StorageOp::DESTROY); } }; @@ -430,7 +433,7 @@ namespace eastl { // NOTE(rparolin): If this assert fires there is an EASTL problem picking the size of the local buffer which // variant_storage used to store types. The size selected should be large enough to hold the largest type in - // the user provided variant type-list. + // the user provided variant type-list. static_assert(sizeof(aligned_storage_impl_t) >= sizeof(T), "T is larger than local buffer size"); new (&mBuffer) remove_reference_t(eastl::forward(args)...); @@ -442,7 +445,7 @@ namespace eastl { // NOTE(rparolin): If this assert fires there is an EASTL problem picking the size of the local buffer which // variant_storage used to store types. The size selected should be large enough to hold the largest type in - // the user provided variant type-list. + // the user provided variant type-list. static_assert(sizeof(aligned_storage_impl_t) >= sizeof(T), "T is larger than local buffer size"); new (&mBuffer) remove_reference_t(il, eastl::forward(args)...); @@ -468,7 +471,7 @@ namespace eastl /////////////////////////////////////////////////////////////////////////// - // 20.7.2, forward-declaration for types that depend on the variant + // 20.7.2, forward-declaration for types that depend on the variant // template class variant; @@ -477,18 +480,19 @@ namespace eastl /////////////////////////////////////////////////////////////////////////// // 20.7.3, variant_size, variant_size_v helper classes // - template struct variant_size; + template struct variant_size; template struct variant_size : integral_constant::value> {}; template struct variant_size : integral_constant::value> {}; template struct variant_size : integral_constant::value> {}; template struct variant_size> : integral_constant {}; // variant_size_v template alias - template EA_CONSTEXPR size_t variant_size_v = variant_size::value; + template + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR size_t variant_size_v = variant_size::value; /////////////////////////////////////////////////////////////////////////// - // variant_alternative_helper + // variant_alternative_helper // // This helper does the heavy lifting of traversing the variadic type list // and retrieving the type at the user provided index. @@ -512,9 +516,9 @@ namespace eastl template struct variant_alternative> : variant_alternative_helper {}; // ISO required cv-qualifer specializations - template struct variant_alternative : add_cv_t> {}; - template struct variant_alternative : add_volatile_t> {}; - template struct variant_alternative : add_cv_t> {}; + template struct variant_alternative : add_const::type> {}; + template struct variant_alternative : add_volatile::type> {}; + template struct variant_alternative : add_cv::type> {}; // variant_alternative_t template alias template using variant_alternative_t = typename variant_alternative::type; @@ -529,7 +533,7 @@ namespace eastl /////////////////////////////////////////////////////////////////////////// - // get_if + // get_if // template EA_CONSTEXPR add_pointer_t>> get_if(variant* pv) EA_NOEXCEPT @@ -563,15 +567,14 @@ namespace eastl /////////////////////////////////////////////////////////////////////////// - // get + // get // template EA_CONSTEXPR variant_alternative_t>& get(variant& v) { static_assert(I < sizeof...(Types), "get is ill-formed if I is not a valid index in the variant typelist"); using return_type = add_pointer_t>>; - - EASTL_ASSERT(v.index() == I); + return *v.mStorage.template get_as(); } @@ -580,8 +583,7 @@ namespace eastl { static_assert(I < sizeof...(Types), "get is ill-formed if I is not a valid index in the variant typelist"); using return_type = add_pointer_t>>; - - EASTL_ASSERT(v.index() == I); + return eastl::move(*v.mStorage.template get_as()); } @@ -590,8 +592,7 @@ namespace eastl { static_assert(I < sizeof...(Types), "get is ill-formed if I is not a valid index in the variant typelist"); using return_type = add_pointer_t>>; - - EASTL_ASSERT(v.index() == I); + return *v.mStorage.template get_as(); } @@ -600,8 +601,7 @@ namespace eastl { static_assert(I < sizeof...(Types), "get is ill-formed if I is not a valid index in the variant typelist"); using return_type = add_pointer_t>>; - - EASTL_ASSERT(v.index() == I); + return eastl::move(*v.mStorage.template get_as()); } @@ -616,7 +616,7 @@ namespace eastl EA_CONSTEXPR T&& get(variant&& v) { static_assert(I < sizeof...(Types), "get is ill-formed if I is not a valid index in the variant typelist"); - return get(v); + return get(eastl::move(v)); } template > @@ -649,7 +649,7 @@ namespace eastl // 20.7.2, variant // template - class variant + class variant { static_assert(sizeof...(Types) > 0, "variant must have at least 1 type (empty variants are ill-formed)"); static_assert(disjunction_v...> == false, "variant does not allow void as an alternative type"); @@ -665,7 +665,7 @@ namespace eastl // variant_index_t mIndex; variant_storage_t mStorage; - + public: /////////////////////////////////////////////////////////////////////////// // 20.7.2.1, constructors @@ -727,7 +727,7 @@ namespace eastl class... Args, class = enable_if_t, is_constructible>, T>> EA_CPP14_CONSTEXPR explicit variant(in_place_type_t, Args&&... args) - : variant(in_place>, forward(args)...) + : variant(in_place>, eastl::forward(args)...) {} template < @@ -736,7 +736,7 @@ namespace eastl class... Args, class = enable_if_t, is_constructible>, T>> EA_CPP14_CONSTEXPR explicit variant(in_place_type_t, std::initializer_list il, Args&&... args) - : variant(in_place>, il, forward(args)...) + : variant(in_place>, il, eastl::forward(args)...) {} template , Args&&... args) : mIndex(I) { - mStorage.template set_as>(forward(args)...); + mStorage.template set_as>(eastl::forward(args)...); } template , std::initializer_list il, Args&&... args) : mIndex(I) { - mStorage.template set_as>(il, forward(args)...); + mStorage.template set_as>(il, eastl::forward(args)...); } @@ -812,10 +812,16 @@ namespace eastl variant_alternative_t& emplace(Args&&... args) { if (!valueless_by_exception()) + { mStorage.destroy(); - mIndex = static_cast(I); + #if EASTL_EXCEPTIONS_ENABLED + mIndex = static_cast(variant_npos); + #endif + } + mStorage.template set_as(eastl::forward(args)...); + mIndex = static_cast(I); return *reinterpret_cast(&mStorage.mBuffer); } @@ -833,10 +839,16 @@ namespace eastl variant_alternative_t& emplace(std::initializer_list il, Args&&... args) { if (!valueless_by_exception()) + { mStorage.destroy(); - mIndex = static_cast(I); + #if EASTL_EXCEPTIONS_ENABLED + mIndex = static_cast(variant_npos); + #endif + } + mStorage.template set_as(il, eastl::forward(args)...); + mIndex = static_cast(I); return *reinterpret_cast(&mStorage.mBuffer); } @@ -900,14 +912,29 @@ namespace eastl /////////////////////////////////////////////////////////////////////////// // 20.7.2.5, value status // - EA_CONSTEXPR size_t index() const EA_NOEXCEPT { return valueless_by_exception() ? variant_npos : mIndex; } - EA_CONSTEXPR bool valueless_by_exception() const EA_NOEXCEPT { return mIndex == variant_npos; } + EA_CONSTEXPR size_t index() const EA_NOEXCEPT + { + #if EASTL_EXCEPTIONS_ENABLED + return valueless_by_exception() ? variant_npos : mIndex; + #else + return mIndex; + #endif + } + + EA_CONSTEXPR bool valueless_by_exception() const EA_NOEXCEPT + { + #if EASTL_EXCEPTIONS_ENABLED + return mIndex == variant_npos; + #else + return false; + #endif + } /////////////////////////////////////////////////////////////////////////// // 20.7.2.6, swap // - void swap(variant& other) + void swap(variant& other) EA_NOEXCEPT(conjunction_v..., is_nothrow_swappable...>) { eastl::swap(mIndex, other.mIndex); @@ -930,12 +957,13 @@ namespace eastl // 20.7.9, swap // template - void swap(variant& lhs, variant& rhs) + void swap(variant& lhs, variant& rhs) EA_NOEXCEPT(EA_NOEXCEPT(lhs.swap(rhs))) { lhs.swap(rhs); } + // visit is a bit convoluted, in order to fulfill a few requirements: // - It must support visiting multiple variants using a single visitor and a single function call. The // visitor in this case should have one function for each possible combination of types: @@ -953,149 +981,355 @@ namespace eastl // // - It must be declared constexpr // - It must be constant-time for the case of visiting a single variant - // - It must allow different return types in the visitor, as long as they are all convertible // - // visitor_caller is responsible for the mechanics of visit. Each visitor_caller creates an array of - // functions which call get() on the variant (where I is the array index), then add the returned reference - // to a tuple of arguments. The final visitor_caller calls invoke() with the visitor and the unpacked - // arguments. + // - 20.7.7 states that variant visitation requires all combinations of visitors to return the same type. + // + // NOTE(mwinkler): + // Visit creates an N-Dimensional matrix whereby each dimension is M wide. + // Where N == sizeof...(Variants) and M == variant_size_v + // + // variant v; + // visit(Visitor{}, v, v); + // + // This creates a 3x3 matrix of potential visitors. + // The argument indices into the variants are as follows. + // [0, 0], [0, 1], [0, 2] + // [1, 0], [1, 1], [1, 2] + // [2, 0], [2, 1], [2, 2] + // + // These indices are compile-time constants but the variants have a runtime index. + // Therefore we must instantiate an NxNxN... matrix of function pointers who are + // templated on the indices based on their position in the matrix and then + // at runtime index into the array to call the correct function pointer that can + // get the correct alternatives in the variants. + // + // There are a couple of ways to do this. We can construct the matrix bottom up or top down. + // + // Constructing a matrix bottom up would look something as follows. + // + // make_visitor_matrix_recurse(eastl::index_sequence<>{}, eastl::make_index_sequence>>{}...); + // + // make_visitor_matrix_recurse(eastl::index_sequence) { return templated function pointer on Is... } + // + // make_visitor_matrix_recurse(eastl::index_sequence, eastl::index_sequence, RestIndex... rest) + // return make_array(make_visitor_matrix_recurse(eastl::index_sequence{}, rest...)...); + // + // Essentially we construct the matrix bottom up, row by row of indices and return an array of function pointers. + // The end result is a NxNxN... array on the stack which can be indexed by each variant in order as follows, + // array[v0.index()][v1.index()][vn.index()](); + // + // The downside with this approach is the massive NxNxN... array that is created on the stack. + // + // The other approach is to build the matrix top down and use tail recursion to ensure there is only one + // N sized array on the stack. The downside here is the extra function calls, but we feel this approach provides + // a good balance between performance and memory usage. // - // This allows us to look up each appropriate get() function in constant time using the variant's index. - template - struct visitor_caller + // We construct the matrix top down by first creating an N sized array that is indexed by the first variant. + // This calls a function that recursively creates another N sized array that is indexed by the second variant. + // The recursion continues until we reach the base case which is the last variant. At this point we know + // the compile-time value of the N indices needed to get each alternative from each variant to invoke the visitor upon. + // Essentially we create a tree of function pointers like so. + // + // + // +------------------------------------------------------------------+ + // | | + // | 0 1 N | + // | | + // | | + // +----+---------------------------+---------------------------------+ + // | | + // | | + // | | + // | | + // | | + // +--------------------------+-----------------+ +----+------------------------------------+ + // | | | | + // |0,0 0,1 0,N| |1,0 1,1 1,N| + // | | | | + // | | | | + // +--------------------------------------------+ +-----------------------------------------+ + // + // Essentially each call creates a N sized array of function pointers that is the concatention of the indices known so far + // and the index of itself in the array whereby the leaf function pointer does the final invoke of the visitor. + // + + // Since decltype() is not one of the contexts where an overloaded function can be used without arguments; + // We use this function to deduce the function pointer types. + // We also return an eastl::array<> since we cannot return C-style arrays as value types. + template + static EA_CONSTEXPR array, 1> make_visitor_array(T&& t) { - // @visitor, @variant and @variants are all the arguments to the initial visit() function. - // @args is the tuple of arguments which have been retrieved by any previous visitor_callers. - // - // The two unnamed index_sequence parameters let us deduce two different sets of indices - // as parameter packs - one for the arguments and one for the array of call_next functions. - // This is necessary so we can create the constexpr array of functions which call - // get(variant) based on the array index, and so we can unpack the final of arguments by - // calling get(args) for each index in args. - template - static decltype(auto) EA_CONSTEXPR call_next(Visitor&& visitor, - index_sequence, - index_sequence, - ArgsTuple&& args, - Variant&& variant, - Variants&&... variants) - { - // Call the appropriate get() function on the variant, and pack the result into a new tuple along with - // all of the previous arguments. Then call the next visitor_caller with the new argument added, - // and the current variant removed. - return visitor_caller::call( - forward(visitor), - index_sequence(), - index_sequence(), - make_tuple(get(forward(args))..., get(forward(variant))), - forward(variants)... - ); + return { { eastl::forward(t) } }; + } + + template + static EA_CONSTEXPR array, sizeof...(Ts) + 1> make_visitor_array(T&& t, Ts&&... ts) + { + static_assert(conjunction_v, decay_t>...>, "`visit` variant visitation requires that all visitors have the same return type!"); + + return { { eastl::forward(t), eastl::forward(ts)... } }; + } + + + template = 0> + static EA_CONSTEXPR decltype(auto) get_variant_n(Variant&& variant, Variants&&... variants) + { + return eastl::forward(variant); + } + + template = 0> + static EA_CONSTEXPR decltype(auto) get_variant_n(Variant&& variant, Variants&&... variants) + { + return get_variant_n(eastl::forward(variants)...); + } + + + template + static EA_CONSTEXPR decltype(auto) call_visitor_at_index(Array&& array, Index index, Visitor&& visitor, Variants&&... variants) + { + return array[static_cast(index)](eastl::forward(visitor), eastl::forward(variants)...); + } + + template + static EA_CONSTEXPR decltype(auto) call_visitor_at(Array&& array, Visitor&& visitor, Variants&&... variants) + { + return call_visitor_at_index(eastl::forward(array), + get_variant_n(eastl::forward(variants)...).index(), + eastl::forward(visitor), + eastl::forward(variants)...); + } + + + // abstracts calling visit on 2 or more variants + template + struct visitor_caller_n; + + template + struct visitor_caller_n, Visitor, Variants...> + { + using return_type = invoke_result_t>...>; + + template + static EA_CONSTEXPR return_type invoke_visitor_leaf(Visitor&& visitor, Variants&&... variants) + { + return eastl::invoke(eastl::forward(visitor), + eastl::get(eastl::forward(variants))...); } - // Arguments are the same as for call_next (see above). - template - static decltype(auto) EA_CPP14_CONSTEXPR call(Visitor&& visitor, - index_sequence, - index_sequence, - ArgsTuple&& args, - Variant&& variant, - Variants&&... variants) - { - // Deduce the type of the inner array of call_next functions - using return_type = decltype(call_next<0>( - forward(visitor), - index_sequence(), - index_sequence(), - forward(args), - forward(variant), - forward(variants)...) - ); - - using next_type = return_type (*)( - Visitor&&, - index_sequence, - index_sequence, - ArgsTuple&&, - Variant&&, - Variants&&... - ); - - // Create an array of call_next<0>, call_next<1>, ... , call_next - // where N = variant_size. - EA_CPP14_CONSTEXPR next_type next[] = { static_cast(call_next)... }; - - // call_next() with the correct index for the variant. - return next[variant.index()]( - forward(visitor), - index_sequence(), - index_sequence(), - forward(args), - forward(variant), - forward(variants)... - ); + template + static EA_CONSTEXPR auto make_invoke_visitor_leaf(index_sequence) + { + return &invoke_visitor_leaf; + } + + + template + static EA_CONSTEXPR return_type invoke_visitor_recurse(Visitor&& visitor, Variants&&... variants) + { + return call(index_sequence{}, + eastl::forward(visitor), + eastl::forward(variants)...); + } + + template + static EA_CONSTEXPR auto make_invoke_visitor_recurse(index_sequence) + { + return &invoke_visitor_recurse; } + + + template + 1 == sizeof...(Variants), int> = 0> + static EA_CPP14_CONSTEXPR decltype(auto) call(VariantArgIndexSequence, Visitor&& visitor, Variants&&... variants) + { + EA_CPP14_CONSTEXPR auto callers = make_visitor_array(make_invoke_visitor_leaf(meta::double_pack_expansion_t{})...); + + return call_visitor_at>(eastl::move(callers), + eastl::forward(visitor), + eastl::forward(variants)...); + } + + template + 1 != sizeof...(Variants), int> = 0> + static EA_CPP14_CONSTEXPR decltype(auto) call(VariantArgIndexSequence, Visitor&& visitor, Variants&&... variants) + { + EA_CPP14_CONSTEXPR auto callers = make_visitor_array(make_invoke_visitor_recurse(meta::double_pack_expansion_t{})...); + + return call_visitor_at>(eastl::move(callers), + eastl::forward(visitor), + eastl::forward(variants)...); + } + }; - template - struct visitor_caller + template + static EA_CONSTEXPR decltype(auto) call_initial_n(VariantIndexSequence, Visitor&& visitor, Variants&&... variants) { - // Invoke the correct visitor for a given variant index, and call the correct get() function to retrieve - // the argument. Unpack any additional arguments from earlier visitor_callers (see above). - template - static decltype(auto) EA_CONSTEXPR invoke_visitor(Visitor&& visitor, index_sequence, ArgsTuple&& args, Variant&& variant) - { - return static_cast(invoke( - forward(visitor), - get(forward(args))..., - get(forward(variant)) - )); + return visitor_caller_n::call(index_sequence<>{}, eastl::forward(visitor), eastl::forward(variants)...); + } + + + // abstracts calling visit on 2 or more variants with return types convertible to R + template + struct visitor_caller_n_r; + + template + struct visitor_caller_n_r, Visitor, Variants...> + { + template + struct visitor_leaf_r + { + static EA_CONSTEXPR R_ invoke_visitor_leaf_r(Visitor&& visitor, Variants&&... variants) + { + return eastl::invoke(eastl::forward(visitor), + eastl::get(eastl::forward(variants))...); + } + }; + + // void return type must discard the return values of the visitor even if the visitor returns a value. + template + struct visitor_leaf_r + { + static EA_CONSTEXPR void invoke_visitor_leaf_r(Visitor&& visitor, Variants&&... variants) + { + eastl::invoke(eastl::forward(visitor), + eastl::get(eastl::forward(variants))...); + } + }; + template struct visitor_leaf_r : public visitor_leaf_r {}; + template struct visitor_leaf_r : public visitor_leaf_r {}; + template struct visitor_leaf_r : public visitor_leaf_r {}; + + template + static EA_CONSTEXPR auto make_invoke_visitor_leaf_r(index_sequence) + { + return &visitor_leaf_r::invoke_visitor_leaf_r; } - // The final call() in the recursion. - // - // By this point, expands to <0 .. N - 2> where N is the number of arguments to the - // final invoke() call. This corresponds to each element in @args, so `get(args)...` - // expands to `get<0>(args), get<1>(args), ... , get(args)`. The final argument is selected - // based on the final array index, leaving us with a sequence of arguments from 0 .. N - 1. - // - // is the same as in earlier calls - it expands to <0 .. I - 1> where I is the - // number of alternatives in the variant. This lets us call the correct `get` based on the - // final variant index, as we did for all earlier calls. - template - static decltype(auto) EA_CPP14_CONSTEXPR call(Visitor&& visitor, index_sequence, index_sequence, ArgsTuple&& args, Variant&& variant) - { - // MSVC isn't able to handle the nested pack expansion required here, so we have to just use the - // return type of the first visitor function instead of the common_type of all possible visitor - // functions. This means we can't handle the case where visitor functions return different (but - // compatible) types. This is unlikely to be a common case, but we might be able to get around it - // if it's a big issue. - // - // TODO: we should reevaluate this on future compiler releases - #if defined(EA_COMPILER_MSVC) - using return_type = invoke_result_t(args))..., decltype(get<0>(variant))>; - #else - // If we're on a compiler that can take it, determine the common_type between all possible visitor - // invocations. - using return_type = common_type_t< - invoke_result_t(args))..., decltype(get(variant))>... - >; - #endif - using caller_type = return_type (*)(Visitor&&, index_sequence, ArgsTuple&&, Variant&&); + template + struct visitor_recurse_r + { + static EA_CONSTEXPR R_ invoke_visitor_recurse_r(Visitor&& visitor, Variants&&... variants) + { + return call_r(index_sequence{}, + eastl::forward(visitor), + eastl::forward(variants)...); + } + }; - // Create the final array of invoke_visitor<0>, invoke_visitor<1>, ... , invoke_visitor - // where N = variant_size - EA_CPP14_CONSTEXPR caller_type callers[] = { invoke_visitor... }; + template + static EA_CONSTEXPR auto make_invoke_visitor_recurse_r(index_sequence) + { + return &visitor_recurse_r::invoke_visitor_recurse_r; + } - return callers[forward(variant).index()]( - forward(visitor), - index_sequence(), - forward(args), - forward(variant) - ); + + template + 1 == sizeof...(Variants), int> = 0> + static EA_CPP14_CONSTEXPR decltype(auto) call_r(VariantArgIndexSequence, Visitor&& visitor, Variants&&... variants) + { + EA_CPP14_CONSTEXPR auto callers = make_visitor_array(make_invoke_visitor_leaf_r(meta::double_pack_expansion_t{})...); + + return call_visitor_at>(eastl::move(callers), + eastl::forward(visitor), + eastl::forward(variants)...); + } + + template + 1 != sizeof...(Variants), int> = 0> + static EA_CPP14_CONSTEXPR decltype(auto) call_r(VariantArgIndexSequence, Visitor&& visitor, Variants&&... variants) + { + EA_CPP14_CONSTEXPR auto callers = make_visitor_array(make_invoke_visitor_recurse_r(meta::double_pack_expansion_t{})...); + + return call_visitor_at>(eastl::move(callers), + eastl::forward(visitor), + eastl::forward(variants)...); + } + + }; + + template + static EA_CONSTEXPR decltype(auto) call_initial_n_r(VariantIndexSequence, Visitor&& visitor, Variants&&... variants) + { + return visitor_caller_n_r::call_r(index_sequence<>{}, eastl::forward(visitor), eastl::forward(variants)...); + } + + + // abstracts calling visit on a single variant + struct visitor_caller_one + { + + template + static EA_CONSTEXPR decltype(auto) invoke_visitor(Visitor&& visitor, Variant&& variant) + { + return eastl::invoke(eastl::forward(visitor), + eastl::get(eastl::forward(variant))); + } + + template + static EA_CPP14_CONSTEXPR decltype(auto) call_index(Visitor&& visitor, Variant&& variant, index_sequence) + { + EA_CPP14_CONSTEXPR auto callers = make_visitor_array((&invoke_visitor)...); + + return call_visitor_at_index(eastl::move(callers), eastl::forward(variant).index(), + eastl::forward(visitor), eastl::forward(variant)); + } + + template + static EA_CONSTEXPR decltype(auto) call(Visitor&& visitor, Variant&& variant) + { + return call_index(eastl::forward(visitor), + eastl::forward(variant), + make_index_sequence>>{}); + } + + }; + + template + struct visitor_r + { + template + static EA_CONSTEXPR R invoke_visitor_r(Visitor&& visitor, Variant&& variant) + { + return eastl::invoke(eastl::forward(visitor), + eastl::get(eastl::forward(variant))); } }; + // void return type must discard the return values of the visitor even if the visitor returns a value. + template <> + struct visitor_r + { + template + static EA_CONSTEXPR void invoke_visitor_r(Visitor&& visitor, Variant&& variant) + { + eastl::invoke(eastl::forward(visitor), + eastl::get(eastl::forward(variant))); + } + }; + + template<> struct visitor_r : public visitor_r {}; + template<> struct visitor_r : public visitor_r {}; + template<> struct visitor_r : public visitor_r {}; + + // abstracts calling visit on a single variant with return types convertible to R + struct visitor_caller_one_r + { + template + static EA_CPP14_CONSTEXPR decltype(auto) call_index_r(Visitor&& visitor, Variant&& variant, eastl::index_sequence) + { + EA_CPP14_CONSTEXPR auto callers = make_visitor_array(&visitor_r::template invoke_visitor_r...); + + return callers[static_cast(eastl::forward(variant).index())](eastl::forward(visitor), + eastl::forward(variant)); + } + + template + static EA_CONSTEXPR decltype(auto) call_r(Visitor&& visitor, Variant&& variant) + { + return call_index_r(eastl::forward(visitor), eastl::forward(variant), eastl::make_index_sequence>>()); + } + + }; + + /////////////////////////////////////////////////////////////////////////// // 20.7.6, visitation // @@ -1111,24 +1345,80 @@ namespace eastl // visit(MyVisitor{}, v); // calls MyVisitor::operator()(string) {} // + template + static EA_CPP14_CONSTEXPR void visit_throw_bad_variant_access(Variants&&... variants) + { + #if EASTL_EXCEPTIONS_ENABLED + using bool_array_type = bool[]; + bool badAccess = false; + + (void)bool_array_type{ (badAccess |= eastl::forward(variants).valueless_by_exception(), false)... }; + + if (badAccess) + { + throw bad_variant_access(); + } + #endif + } + + template + static EA_CONSTEXPR void visit_static_assert_check(Variants&&... variants) + { + static_assert(sizeof...(Variants) > 0, "`visit` at least one variant instance must be passed as an argument to the visit function"); + + using variant_type = decay_t>; + static_assert(conjunction_v>...>, + "`visit` all variants passed to eastl::visit() must have the same type"); + } + + // visit // - template - EA_CONSTEXPR decltype(auto) visit(Visitor&& visitor, Variants&&... variants) + template + EA_CPP14_CONSTEXPR decltype(auto) visit(Visitor&& visitor, Variant&& variant) + { + visit_static_assert_check(eastl::forward(variant)); + + visit_throw_bad_variant_access(eastl::forward(variant)); + + return visitor_caller_one::call(eastl::forward(visitor), + eastl::forward(variant)); + } + + template + EA_CPP14_CONSTEXPR decltype(auto) visit(Visitor&& visitor, Variants&&... variants) + { + visit_static_assert_check(eastl::forward(variants)...); + + visit_throw_bad_variant_access(eastl::forward(variants)...); + + return call_initial_n(make_index_sequence>>>{}, + eastl::forward(visitor), + eastl::forward(variants)...); + + } + + template , int> = 0> + EA_CPP14_CONSTEXPR R visit(Visitor&& visitor, Variant&& variant) + { + visit_static_assert_check(eastl::forward(variant)); + + visit_throw_bad_variant_access(eastl::forward(variant)); + + return visitor_caller_one_r::call_r(eastl::forward(visitor), + eastl::forward(variant)); + } + + template , int> = 0> + EA_CPP14_CONSTEXPR R visit(Visitor&& visitor, Variants&&... variants) { - static_assert(sizeof...(Variants) > 0, "at least one variant instance must be passed as an argument to the visit function"); - - using variant_type = remove_reference_t>; - static_assert(conjunction_v>...>, - "all variants passed to eastl::visit() must have the same type"); - - return visitor_caller::call( - forward(visitor), - index_sequence<>(), - make_index_sequence>(), - tuple<>(), - forward(variants)... - ); + visit_static_assert_check(eastl::forward(variants)...); + + visit_throw_bad_variant_access(eastl::forward(variants)...); + + return call_initial_n_r(make_index_sequence>>>{}, + eastl::forward(visitor), + eastl::forward(variants)...); } @@ -1138,42 +1428,46 @@ namespace eastl namespace internal { - template - EA_CPP14_CONSTEXPR bool Compare(const variant& lhs, const variant& rhs, Predicate predicate) + // For relational operators we do not need to create the NxN matrix of comparisons since we know already + // that both the lhs and rhs variants have the same index. We just need to compare the value of the types at that + // index for equality. Therefore the visitation is simpler than visit() for relational operators. + // + struct variant_relational_comparison { - return visit(predicate, lhs, rhs); - } - // For variant visitation, we need to have a comparison function for all possible combinations of types, - // eg. for variant, our comparator needs: - // - // bool operator()(int, int); - // bool operator()(int, string); - // bool operator()(string, int); - // bool operator()(string, string); - // - // Even though we never call the mixed-type versions of these functions when comparing variants, we - // need them in order to compile visit(). So this struct forwards the good comparisons to the appropriate - // comparison, and asserts that we never call the bad comparisons. - template - struct variant_comparison : public C - { - template , eastl::decay_t>>> - auto operator()(const A& a, const B& b) + template + static EA_CONSTEXPR bool invoke_relational_visitor(const Variant& lhs, const Variant& rhs) { - return C::operator()(a, b); + return eastl::invoke(Compare{}, eastl::get(lhs), eastl::get(rhs)); } - template , eastl::decay_t>>> - bool operator()(const A&, const B&) + template + static EA_CPP14_CONSTEXPR bool call_index(const Variant& lhs, const Variant& rhs, eastl::index_sequence) { - EASTL_ASSERT_MSG(false, "eastl::variant<> comparison function called on two different types at different indices! This is a library bug! Please file bug report."); - return false; + using invoke_relational_visitor_func_ptr = bool (*)(const Variant&, const Variant&); + + EA_CPP14_CONSTEXPR invoke_relational_visitor_func_ptr visitors[] = { static_cast(&invoke_relational_visitor)... }; + + return visitors[lhs.index()](lhs, rhs); + } + + template + static EA_CONSTEXPR bool call(const Variant& lhs, const Variant& rhs) + { + return call_index(lhs, rhs, eastl::make_index_sequence>>()); } + }; + template + static EA_CONSTEXPR bool CompareVariantRelational(const Variant& lhs, const Variant& rhs) + { + return variant_relational_comparison::call(lhs, rhs); + } + } // namespace internal + /////////////////////////////////////////////////////////////////////////// // 20.7.5, relational operators // @@ -1182,7 +1476,17 @@ namespace eastl { if (lhs.index() != rhs.index()) return false; if (lhs.valueless_by_exception()) return true; - return internal::Compare(lhs, rhs, internal::variant_comparison>{}); + + return internal::CompareVariantRelational>(lhs, rhs); + } + + template + EA_CPP14_CONSTEXPR bool operator!=(const variant& lhs, const variant& rhs) + { + if (lhs.index() != rhs.index()) return true; + if (lhs.valueless_by_exception()) return false; + + return internal::CompareVariantRelational>(lhs, rhs); } template @@ -1192,15 +1496,8 @@ namespace eastl if (lhs.valueless_by_exception()) return true; if (lhs.index() < rhs.index()) return true; if (lhs.index() > rhs.index()) return false; - return internal::Compare(lhs, rhs, internal::variant_comparison>{}); - } - template - EA_CPP14_CONSTEXPR bool operator!=(const variant& lhs, const variant& rhs) - { - if (lhs.index() != rhs.index()) return true; - if (lhs.valueless_by_exception()) return false; - return internal::Compare(lhs, rhs, internal::variant_comparison>{}); + return internal::CompareVariantRelational>(lhs, rhs); } template @@ -1210,17 +1507,19 @@ namespace eastl if (rhs.valueless_by_exception()) return true; if (lhs.index() > rhs.index()) return true; if (lhs.index() < rhs.index()) return false; - return internal::Compare(lhs, rhs, internal::variant_comparison>{}); + + return internal::CompareVariantRelational>(lhs, rhs); } template EA_CPP14_CONSTEXPR bool operator<=(const variant& lhs, const variant& rhs) { - if (rhs.valueless_by_exception()) return true; - if (lhs.valueless_by_exception()) return false; + if (lhs.valueless_by_exception()) return true; + if (rhs.valueless_by_exception()) return false; if (lhs.index() < rhs.index()) return true; if (lhs.index() > rhs.index()) return false; - return internal::Compare(lhs, rhs, internal::variant_comparison>{}); + + return internal::CompareVariantRelational>(lhs, rhs); } template @@ -1230,11 +1529,12 @@ namespace eastl if (lhs.valueless_by_exception()) return false; if (lhs.index() > rhs.index()) return true; if (lhs.index() < rhs.index()) return false; - return internal::Compare(lhs, rhs, internal::variant_comparison>{}); + + return internal::CompareVariantRelational>(lhs, rhs); } + } // namespace eastl EA_RESTORE_VC_WARNING() #endif // EASTL_VARIANT_H - diff --git a/library/3rdparty/EASTL/include/EASTL/vector.h b/library/3rdparty/EASTL/include/EASTL/vector.h index 397ad2c..c4bed7b 100644 --- a/library/3rdparty/EASTL/include/EASTL/vector.h +++ b/library/3rdparty/EASTL/include/EASTL/vector.h @@ -1754,7 +1754,7 @@ namespace eastl { // and some functions that need to clear our capacity (e.g. operator=) aren't supposed to require default-constructibility. clear(); this_type temp(eastl::move(*this)); // This is the simplest way to accomplish this, - swap(temp); // and it is as efficient as any other. + swap(temp); // and it is as efficient as any other. } @@ -1919,7 +1919,7 @@ namespace eastl pointer pNewEnd = allocator_type::to_raw(pNewData); try { // To do: We are not handling exceptions properly below. In particular we don't want to - // call eastl::destruct on the entire range if only the first part of the range was costructed. + // call eastl::destruct on the entire range if only the first part of the range was constructed. ::new((void*)(pNewData + nPosSize)) value_type(eastl::forward(args)...); // Because the old data is potentially being moved rather than copied, we need to move. pNewEnd = NULL; // Set to NULL so that in catch we can tell the exception occurred during the next call. pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(allocator_type::to_raw(mpBegin), destPosition, allocator_type::to_raw(pNewData)); // the value first, because it might possibly be a reference to the old data being moved. diff --git a/library/3rdparty/EASTL/source/numeric_limits.cpp b/library/3rdparty/EASTL/source/numeric_limits.cpp index 7b7bf2f..4eed54e 100644 --- a/library/3rdparty/EASTL/source/numeric_limits.cpp +++ b/library/3rdparty/EASTL/source/numeric_limits.cpp @@ -39,7 +39,7 @@ #endif -#if defined(_MSC_VER) +#if defined(_MSC_VER) && !defined(EA_COMPILER_CLANG_CL) // VC++ has a long-standing bug: it fails to allow the definition of static const member variables // outside the declaration within the class. The C++ Standard actually requires that they be defined // and some other compilers fail to link if they aren't. So we simply don't define the members for VC++. @@ -442,7 +442,7 @@ EA_CONSTEXPR_OR_CONST bool numeric_limits::is_iec559; // __uint128_t - #if (EA_COMPILER_INTMAX_SIZE >= 16) && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) // If __int128_t/__uint128_t is supported... + #if (EA_COMPILER_INTMAX_SIZE >= 16) && (defined(EA_COMPILER_GNUC) || defined(__clang__)) // If __int128_t/__uint128_t is supported... EA_CONSTEXPR_OR_CONST bool numeric_limits<__uint128_t>::is_specialized; EA_CONSTEXPR_OR_CONST int numeric_limits<__uint128_t>::digits; EA_CONSTEXPR_OR_CONST int numeric_limits<__uint128_t>::digits10; @@ -468,7 +468,7 @@ #endif // __int128_t - #if (EA_COMPILER_INTMAX_SIZE >= 16) && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) // If __int128_t/__uint128_t is supported... + #if (EA_COMPILER_INTMAX_SIZE >= 16) && (defined(EA_COMPILER_GNUC) || defined(__clang__)) // If __int128_t/__uint128_t is supported... EA_CONSTEXPR_OR_CONST bool numeric_limits<__int128_t>::is_specialized; EA_CONSTEXPR_OR_CONST int numeric_limits<__int128_t>::digits; EA_CONSTEXPR_OR_CONST int numeric_limits<__int128_t>::digits10; diff --git a/library/3rdparty/EASTL/source/red_black_tree.cpp b/library/3rdparty/EASTL/source/red_black_tree.cpp index b7887f3..d9797b9 100644 --- a/library/3rdparty/EASTL/source/red_black_tree.cpp +++ b/library/3rdparty/EASTL/source/red_black_tree.cpp @@ -125,7 +125,8 @@ namespace eastl /// RBTreeRotateLeft /// Does a left rotation about the given node. /// If you want to understand tree rotation, any book on algorithms will - /// discussion the topic in good detail. + /// discuss the topic in detail. + /// rbtree_node_base* RBTreeRotateLeft(rbtree_node_base* pNode, rbtree_node_base* pNodeRoot) { rbtree_node_base* const pNodeTemp = pNode->mpNodeRight; @@ -154,7 +155,8 @@ namespace eastl /// RBTreeRotateRight /// Does a right rotation about the given node. /// If you want to understand tree rotation, any book on algorithms will - /// discussion the topic in good detail. + /// discuss the topic in detail. + /// rbtree_node_base* RBTreeRotateRight(rbtree_node_base* pNode, rbtree_node_base* pNodeRoot) { rbtree_node_base* const pNodeTemp = pNode->mpNodeLeft; diff --git a/library/3rdparty/EASTL/source/thread_support.cpp b/library/3rdparty/EASTL/source/thread_support.cpp index 1b03629..547e588 100644 --- a/library/3rdparty/EASTL/source/thread_support.cpp +++ b/library/3rdparty/EASTL/source/thread_support.cpp @@ -49,7 +49,11 @@ namespace eastl pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); - pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE); + + #if defined(EA_HAVE_pthread_mutexattr_setpshared_DECL) + pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE); + #endif + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&mMutex, &attr); pthread_mutexattr_destroy(&attr); diff --git a/library/3rdparty/EASTL/test/source/EASTLTest.h b/library/3rdparty/EASTL/test/source/EASTLTest.h index 1cb298b..1908f5f 100644 --- a/library/3rdparty/EASTL/test/source/EASTLTest.h +++ b/library/3rdparty/EASTL/test/source/EASTLTest.h @@ -82,6 +82,7 @@ int TestVectorMap(); int TestVectorSet(); int TestAtomicBasic(); int TestAtomicAsm(); +int TestBitcast(); // Now enable warnings as desired. diff --git a/library/3rdparty/EASTL/test/source/TestAlgorithm.cpp b/library/3rdparty/EASTL/test/source/TestAlgorithm.cpp index 1e0a3bb..142d45e 100644 --- a/library/3rdparty/EASTL/test/source/TestAlgorithm.cpp +++ b/library/3rdparty/EASTL/test/source/TestAlgorithm.cpp @@ -79,8 +79,8 @@ namespace enum TestMinMaxEnum { - teX = 0, - teY = 3 + teX = 0, + teY = 3 }; @@ -593,11 +593,11 @@ static int TestMinMax() { // template - // eastl::pair + // eastl::pair // minmax_element(ForwardIterator first, ForwardIterator last) // // template - // eastl::pair + // eastl::pair // minmax_element(ForwardIterator first, ForwardIterator last, Compare compare) int intArray[] = { 5, -2, 1, 5, 6, 5 }; @@ -606,15 +606,15 @@ static int TestMinMax() EATEST_VERIFY((*result.first == -2) && (*result.second == 6)); - // template + // template // eastl::pair // minmax(const T& a, const T& b) // - // template + // template // eastl::pair // minmax(const T& a, const T& b, Compare comp) - // The VC++ compiler is broken in such a way that it can't compile the following without generating a warning: + // The VC++ compiler is broken in such a way that it can't compile the following without generating a warning: // warning C4413: 'eastl::pair::first' : reference member is initialized to a temporary that doesn't persist after the constructor exits. // The Microsoft standard library definition of minmax doesn't generate this warning... because that minmax is broken and non-conforming. I think they // made it the way they did because of the aforementioned compiler bug. @@ -883,7 +883,7 @@ int TestAlgorithm() eastl::string in = "123456"; eastl::string out; - + eastl::copy_n(in.begin(), 4, eastl::back_inserter(out)); EATEST_VERIFY(out == "1234"); } @@ -913,7 +913,7 @@ int TestAlgorithm() for(eastl_size_t i = 0; i < 4; i++) src.push_back(eastl::string(1, (char8_t)('0' + i))); eastl::vector dest(src.size()); - + eastl::move(src.begin(), src.end(), dest.begin()); EATEST_VERIFY((dest[0] == "0") && (dest[3] == "3")); EATEST_VERIFY(src[0].empty() && src[3].empty()); @@ -925,7 +925,7 @@ int TestAlgorithm() for(eastl_size_t i = 0; i < 4; i++) src.push_back(eastl::string(1, (char8_t)('0' + i))); eastl::vector dest(src.size()); - + eastl::move_backward(src.begin(), src.end(), dest.end()); EATEST_VERIFY((dest[0] == "0") && (dest[3] == "3")); EATEST_VERIFY(src[0].empty() && src[3].empty()); @@ -954,7 +954,7 @@ int TestAlgorithm() // Count all items whose value is less than three. ptrdiff_t n = count_if(intArray, intArray, bind2nd(less(), (int)3)); // No-op EATEST_VERIFY(n == 0); - n = count_if(intArray, intArray + 12, bind2nd(less(), (int)3)); + n = count_if(intArray, intArray + 12, bind2nd(less(), (int)3)); EATEST_VERIFY(n == 5); @@ -963,7 +963,7 @@ int TestAlgorithm() n = count_if(toArray, toArray, bind2nd(less(), TestObject(3))); // No-op EATEST_VERIFY(n == 0); - n = count_if(toArray, toArray + 6, bind2nd(less(), TestObject(3))); + n = count_if(toArray, toArray + 6, bind2nd(less(), TestObject(3))); EATEST_VERIFY(n == 3); @@ -978,7 +978,7 @@ int TestAlgorithm() n = count_if(intList.begin(), intList.begin(), bind2nd(less(), (int)3)); // No-op EATEST_VERIFY(n == 0); - n = count_if(intList.begin(), intList.end(), bind2nd(less(), (int)3)); + n = count_if(intList.begin(), intList.end(), bind2nd(less(), (int)3)); EATEST_VERIFY(n == 3); } @@ -1181,12 +1181,12 @@ int TestAlgorithm() // The list is now: { 5, 2, 1, 2, 3, 4 } slist::iterator it = find_if(intList.begin(), intList.begin(), bind2nd(equal_to(), (int)1)); // No-op EATEST_VERIFY(it == intList.begin()); - it = find_if(intList.begin(), intList.end(), bind2nd(equal_to(), (int)1)); + it = find_if(intList.begin(), intList.end(), bind2nd(equal_to(), (int)1)); EATEST_VERIFY(*it == 1); - it = find_if(intList.begin(), intList.end(), bind2nd(equal_to(), (int)99)); + it = find_if(intList.begin(), intList.end(), bind2nd(equal_to(), (int)99)); EATEST_VERIFY(it == intList.end()); - it = find_if_not(intList.begin(), intList.end(), bind2nd(equal_to(), (int)5)); + it = find_if_not(intList.begin(), intList.end(), bind2nd(equal_to(), (int)5)); EATEST_VERIFY(*it == 2); } @@ -2162,7 +2162,98 @@ int TestAlgorithm() } + // set_difference_2 { + // template + // void set_difference_2(InputIterator1 first1, InputIterator1 last1, + // InputIterator2 first2, InputIterator2 last2, + // OutputIterator result1, OutputIterator result2) + { + const eastl::vector v1 = {1, 2, 4, 5, 7, 7, 9}; + const eastl::vector v2 = { 2, 6, 9}; + eastl::vector only_v1, only_v2; + + eastl::set_difference_2(v1.begin(), v1.end(), v2.begin(), v2.end(), + eastl::inserter(only_v1, only_v1.begin()), + eastl::inserter(only_v2, only_v2.begin())); + + EATEST_VERIFY((only_v1 == eastl::vector{1, 4, 5, 7, 7})); + EATEST_VERIFY((only_v2 == eastl::vector{6})); + } + + // template + // void set_difference_2(InputIterator1 first1, InputIterator1 last1, + // InputIterator2 first2, InputIterator2 last2, + // OutputIterator result1, OutputIterator result2, Compare compare) + { + struct local + { + int data = -1; + bool operator==(const local& other) const + { return data == other.data; } + }; + + const eastl::vector v1 = {{1}, {2}, {4}, {5}, {7}, {7}, {9}}; + const eastl::vector v2 = { {2}, {6}, {9}}; + eastl::vector only_v1, only_v2; + + eastl::set_difference_2(v1.begin(), v1.end(), v2.begin(), v2.end(), + eastl::inserter(only_v1, only_v1.begin()), + eastl::inserter(only_v2, only_v2.begin()), + [](const local& lhs, const local& rhs) { return lhs.data < rhs.data; }); + + EATEST_VERIFY((only_v1 == eastl::vector{{1}, {4}, {5}, {7}, {7}})); + EATEST_VERIFY((only_v2 == eastl::vector{{6}})); + } + } + + + // set_decomposition + { + // OutputIterator3 set_decomposition(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, + // OutputIterator1 result1, OutputIterator2 result2, OutputIterator3 result3) + { + const eastl::vector v1 = {1, 2, 4, 5, 7, 7, 9}; + const eastl::vector v2 = { 2, 6, 9}; + eastl::vector only_v1, only_v2, intersection; + + eastl::set_decomposition(v1.begin(), v1.end(), v2.begin(), v2.end(), + eastl::inserter(only_v1, only_v1.begin()), + eastl::inserter(only_v2, only_v2.begin()), + eastl::inserter(intersection, intersection.begin())); + + EATEST_VERIFY((only_v1 == eastl::vector{1, 4, 5, 7, 7})); + EATEST_VERIFY((only_v2 == eastl::vector{6})); + EATEST_VERIFY((intersection == eastl::vector{2, 9})); + } + + // OutputIterator3 set_decomposition(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, + // OutputIterator1 result1, OutputIterator2 result2, OutputIterator3 result3, Compare compare) + { + struct local + { + int data = -1; + bool operator==(const local& other) const + { return data == other.data; } + }; + + const eastl::vector v1 = {{1}, {2}, {4}, {5}, {7}, {7}, {9}}; + const eastl::vector v2 = { {2}, {6}, {9}}; + eastl::vector only_v1, only_v2, intersection; + + eastl::set_decomposition(v1.begin(), v1.end(), v2.begin(), v2.end(), + eastl::inserter(only_v1, only_v1.begin()), + eastl::inserter(only_v2, only_v2.begin()), + eastl::inserter(intersection, intersection.begin()), + [](const local& lhs, const local& rhs) { return lhs.data < rhs.data; }); + + EATEST_VERIFY((only_v1 == eastl::vector{{1}, {4}, {5}, {7}, {7}})); + EATEST_VERIFY((only_v2 == eastl::vector{{6}})); + EATEST_VERIFY((intersection == eastl::vector{{2}, {9}})); + } + } + + { // template // bool is_permutation(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2) diff --git a/library/3rdparty/EASTL/test/source/TestAllocator.cpp b/library/3rdparty/EASTL/test/source/TestAllocator.cpp index 8cfaadd..85f5adf 100644 --- a/library/3rdparty/EASTL/test/source/TestAllocator.cpp +++ b/library/3rdparty/EASTL/test/source/TestAllocator.cpp @@ -129,7 +129,6 @@ static int TestFixedAllocator() typedef eastl::list IntList; typedef IntList::node_type IntListNode; - IntList intList1; const size_t kAlignOfIntListNode = EA_ALIGN_OF(IntListNode); // ensure the fixed buffer contains the default value that will be replaced @@ -140,6 +139,8 @@ static int TestFixedAllocator() EATEST_VERIFY(buffer1[i].mValue == DEFAULT_VALUE); } + IntList intList1; + // replace all the values in the local buffer with the test value intList1.get_allocator().init(buffer1, sizeof(buffer1), sizeof(IntListNode), kAlignOfIntListNode); for (size_t i = 0; i < kBufferCount; i++) diff --git a/library/3rdparty/EASTL/test/source/TestAtomicBasic.cpp b/library/3rdparty/EASTL/test/source/TestAtomicBasic.cpp index d082e35..166b030 100644 --- a/library/3rdparty/EASTL/test/source/TestAtomicBasic.cpp +++ b/library/3rdparty/EASTL/test/source/TestAtomicBasic.cpp @@ -1,3985 +1,4083 @@ -///////////////////////////////////////////////////////////////////////////// -// Copyright (c) Electronic Arts Inc. All rights reserved. -///////////////////////////////////////////////////////////////////////////// - - -#include "EASTLTest.h" - -#include - - -/** - * This is a basic test suite that tests all functionality is implemented - * and that all operations do as expected. - * I.E. fetch_add returns the previous value and add_fetch returns the current value - */ - -class AtomicStandaloneBasicTest -{ -public: - - int RunTest() - { - AtomicSignalFence(); - - AtomicThreadFence(); - - AtomicCpuPause(); - - AtomicCompilerBarrier(); - - return nErrorCount; - } - -private: - - void AtomicSignalFence(); - - void AtomicThreadFence(); - - void AtomicCpuPause(); - - void AtomicCompilerBarrier(); - -private: - - int nErrorCount = 0; -}; - -void AtomicStandaloneBasicTest::AtomicSignalFence() -{ - eastl::atomic_signal_fence(eastl::memory_order_relaxed); - - eastl::atomic_signal_fence(eastl::memory_order_acquire); - - eastl::atomic_signal_fence(eastl::memory_order_release); - - eastl::atomic_signal_fence(eastl::memory_order_acq_rel); - - eastl::atomic_signal_fence(eastl::memory_order_seq_cst); -} - -void AtomicStandaloneBasicTest::AtomicThreadFence() -{ - eastl::atomic_thread_fence(eastl::memory_order_relaxed); - - eastl::atomic_thread_fence(eastl::memory_order_acquire); - - eastl::atomic_thread_fence(eastl::memory_order_release); - - eastl::atomic_thread_fence(eastl::memory_order_acq_rel); - - eastl::atomic_thread_fence(eastl::memory_order_seq_cst); -} - -void AtomicStandaloneBasicTest::AtomicCpuPause() -{ - eastl::cpu_pause(); -} - -void AtomicStandaloneBasicTest::AtomicCompilerBarrier() -{ - eastl::compiler_barrier(); - - { - bool ret = false; - eastl::compiler_barrier_data_dependency(ret); - } -} - -class AtomicFlagBasicTest -{ -public: - - using AtomicType = eastl::atomic_flag; - using BoolType = bool; - - int RunTest() - { - TestAtomicFlagCtor(); - - TestAtomicFlagClear(); - - TestAtomicFlagTestAndSet(); - - TestAtomicFlagTest(); - - TestAllMemoryOrders(); - - TestAtomicFlagStandalone(); - - return nErrorCount; - } - -private: - - void TestAtomicFlagCtor(); - - void TestAtomicFlagClear(); - - void TestAtomicFlagTestAndSet(); - - void TestAtomicFlagTest(); - - void TestAllMemoryOrders(); - - void TestAtomicFlagStandalone(); - -private: - - int nErrorCount = 0; -}; - -void AtomicFlagBasicTest::TestAtomicFlagCtor() -{ - { - AtomicType atomic; - - VERIFY(atomic.test(eastl::memory_order_relaxed) == false); - } - - { - AtomicType atomic{ false }; - - VERIFY(atomic.test(eastl::memory_order_relaxed) == false); - } - - { - AtomicType atomic{ true }; - - VERIFY(atomic.test(eastl::memory_order_relaxed) == true); - } -} - -void AtomicFlagBasicTest::TestAtomicFlagClear() -{ - { - AtomicType atomic; - - atomic.clear(eastl::memory_order_relaxed); - - VERIFY(atomic.test(eastl::memory_order_relaxed) == false); - } - - { - AtomicType atomic{ true }; - - atomic.clear(eastl::memory_order_relaxed); - - VERIFY(atomic.test(eastl::memory_order_relaxed) == false); - } -} - -void AtomicFlagBasicTest::TestAtomicFlagTestAndSet() -{ - { - AtomicType atomic; - - BoolType ret = atomic.test_and_set(eastl::memory_order_relaxed); - - VERIFY(ret == false); - - VERIFY(atomic.test(eastl::memory_order_relaxed) == true); - } - - { - AtomicType atomic{ true }; - - BoolType ret = atomic.test_and_set(eastl::memory_order_relaxed); - - VERIFY(ret == true); - - VERIFY(atomic.test(eastl::memory_order_relaxed) == true); - } -} - -void AtomicFlagBasicTest::TestAtomicFlagTest() -{ - { - AtomicType atomic; - - VERIFY(atomic.test(eastl::memory_order_relaxed) == false); - } - - { - AtomicType atomic{ true }; - - VERIFY(atomic.test(eastl::memory_order_relaxed) == true); - } -} - -void AtomicFlagBasicTest::TestAllMemoryOrders() -{ - { - AtomicType atomic; - - atomic.clear(); - - atomic.clear(eastl::memory_order_relaxed); - - atomic.clear(eastl::memory_order_release); - - atomic.clear(eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - atomic.test_and_set(); - - atomic.test_and_set(eastl::memory_order_relaxed); - - atomic.test_and_set(eastl::memory_order_acquire); - - atomic.test_and_set(eastl::memory_order_release); - - atomic.test_and_set(eastl::memory_order_acq_rel); - - atomic.test_and_set(eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - BoolType ret = atomic.test(); - - ret = atomic.test(eastl::memory_order_relaxed); - - ret = atomic.test(eastl::memory_order_acquire); - - ret = atomic.test(eastl::memory_order_seq_cst); - } -} - -void AtomicFlagBasicTest::TestAtomicFlagStandalone() -{ - { - AtomicType atomic; - - BoolType ret = atomic_flag_test_and_set(&atomic); - - ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_relaxed); - - ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_acquire); - - ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_release); - - ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_acq_rel); - - ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - atomic_flag_clear(&atomic); - - atomic_flag_clear_explicit(&atomic, eastl::memory_order_relaxed); - - atomic_flag_clear_explicit(&atomic, eastl::memory_order_release); - - atomic_flag_clear_explicit(&atomic, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - BoolType ret = atomic_flag_test(&atomic); - - ret = atomic_flag_test_explicit(&atomic, eastl::memory_order_relaxed); - - ret = atomic_flag_test_explicit(&atomic, eastl::memory_order_acquire); - - ret = atomic_flag_test_explicit(&atomic, eastl::memory_order_seq_cst); - } -} - -class AtomicVoidPointerBasicTest -{ -public: - - using AtomicType = eastl::atomic; - using PtrType = void*; - - int RunTest() - { - TestAtomicCtor(); - - TestAssignmentOperators(); - - TestIsLockFree(); - - TestStore(); - - TestLoad(); - - TestExchange(); - - TestCompareExchangeWeak(); - - TestCompareExchangeStrong(); - - TestAllMemoryOrders(); - - return nErrorCount; - } - -private: - - void TestAtomicCtor(); - - void TestAssignmentOperators(); - - void TestIsLockFree(); - - void TestStore(); - - void TestLoad(); - - void TestExchange(); - - void TestCompareExchangeWeak(); - - void TestCompareExchangeStrong(); - - void TestAllMemoryOrders(); - -private: - - int nErrorCount = 0; -}; - -void AtomicVoidPointerBasicTest::TestAtomicCtor() -{ - { - AtomicType atomic; - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } - - { - AtomicType atomic{ (PtrType)0x04 }; - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x04); - } -} - -void AtomicVoidPointerBasicTest::TestAssignmentOperators() -{ - { - AtomicType atomic; - - PtrType ret = atomic = (PtrType)0x04; - - VERIFY(ret == (PtrType)0x04); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x04); - } - - { - AtomicType atomic; - - PtrType ret = atomic = (PtrType)0x0; - - VERIFY(ret == (PtrType)0x0); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } -} - -void AtomicVoidPointerBasicTest::TestIsLockFree() -{ - { - AtomicType atomic; - - VERIFY(atomic.is_lock_free() == true); - - VERIFY(atomic.is_always_lock_free == true); - } -} - -void AtomicVoidPointerBasicTest::TestStore() -{ - { - PtrType val = (PtrType)0x0; - AtomicType atomic; - - atomic.store(val, eastl::memory_order_relaxed); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == val); - } - - { - PtrType val = (PtrType)0x4; - AtomicType atomic; - - atomic.store(val, eastl::memory_order_relaxed); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == val); - } -} - -void AtomicVoidPointerBasicTest::TestLoad() -{ - { - AtomicType atomic{ (PtrType)0x4 }; - - PtrType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic == (PtrType)0x4); - } -} - -void AtomicVoidPointerBasicTest::TestExchange() -{ - { - AtomicType atomic; - - PtrType ret = atomic.exchange((PtrType)0x4, eastl::memory_order_release); - - VERIFY(ret == (PtrType)0x0); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } -} - -void AtomicVoidPointerBasicTest::TestCompareExchangeWeak() -{ - { - AtomicType atomic; - - PtrType observed = (PtrType)0x0; - bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - if (ret) - { - VERIFY(ret == true); - VERIFY(observed == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - } - - { - AtomicType atomic; - - PtrType observed = (PtrType)0x4; - bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - VERIFY(ret == false); - VERIFY(observed == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } -} - -void AtomicVoidPointerBasicTest::TestCompareExchangeStrong() -{ - { - AtomicType atomic; - - PtrType observed = (PtrType)0x0; - bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - VERIFY(ret == true); - VERIFY(observed == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - - { - AtomicType atomic; - - PtrType observed = (PtrType)0x4; - bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - VERIFY(ret == false); - VERIFY(observed == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } -} - -void AtomicVoidPointerBasicTest::TestAllMemoryOrders() -{ - { - AtomicType atomic; - PtrType val = (PtrType)0x4; - - atomic.store(val); - - atomic.store(val, eastl::memory_order_relaxed); - - atomic.store(val, eastl::memory_order_release); - - atomic.store(val, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - PtrType ret = atomic.load(); - - ret = atomic.load(eastl::memory_order_relaxed); - - ret = atomic.load(eastl::memory_order_acquire); - - ret = atomic.load(eastl::memory_order_seq_cst); - - ret = atomic.load(eastl::memory_order_read_depends); - } - - { - AtomicType atomic; - - PtrType ret = atomic.exchange((PtrType)0x4); - - ret = atomic.exchange((PtrType)0x4, eastl::memory_order_relaxed); - - ret = atomic.exchange((PtrType)0x4, eastl::memory_order_acquire); - - ret = atomic.exchange((PtrType)0x4, eastl::memory_order_release); - - ret = atomic.exchange((PtrType)0x4, eastl::memory_order_acq_rel); - - ret = atomic.exchange((PtrType)0x4, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - PtrType observed = (PtrType)0x0; - - bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_release); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - PtrType observed = (PtrType)0x0; - - bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_release); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - PtrType observed = (PtrType)0x0; - bool ret; - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_release, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - PtrType observed = (PtrType)0x0; - bool ret; - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_release, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); - } -} - -class AtomicPointerBasicTest -{ -public: - - using AtomicType = eastl::atomic; - using PtrType = uint32_t*; - - int RunTest() - { - TestAtomicCtor(); - - TestAssignmentOperators(); - - TestIsLockFree(); - - TestStore(); - - TestLoad(); - - TestExchange(); - - TestCompareExchangeWeak(); - - TestCompareExchangeStrong(); - - TestAllMemoryOrders(); - - TestFetchAdd(); - TestAddFetch(); - - TestFetchSub(); - TestSubFetch(); - - TestAtomicPointerStandalone(); - - return nErrorCount; - } - -private: - - void TestAtomicCtor(); - - void TestAssignmentOperators(); - - void TestIsLockFree(); - - void TestStore(); - - void TestLoad(); - - void TestExchange(); - - void TestCompareExchangeWeak(); - - void TestCompareExchangeStrong(); - - void TestAllMemoryOrders(); - - void TestFetchAdd(); - void TestAddFetch(); - - void TestFetchSub(); - void TestSubFetch(); - - void TestAtomicPointerStandalone(); - -private: - - int nErrorCount = 0; -}; - -void AtomicPointerBasicTest::TestAtomicCtor() -{ - { - AtomicType atomic{}; - - PtrType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == nullptr); - } - - { - AtomicType atomic{ (PtrType)0x4 }; - - PtrType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x4); - } -} - -void AtomicPointerBasicTest::TestAssignmentOperators() -{ - { - PtrType val = (PtrType)0x4; - AtomicType atomic{val}; - - PtrType expected = (PtrType)0x8; - - PtrType ret = atomic = expected; - - VERIFY(ret == expected); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } - - { - PtrType val = (PtrType)0x0; - AtomicType atomic{val}; - - PtrType ret = atomic = val; - - VERIFY(ret == val); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == val); - } - - { - PtrType val = (PtrType)0x4; - AtomicType atomic{val}; - - PtrType expected = (PtrType)0x8; - PtrType ret = ++atomic; - - VERIFY(ret == expected); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } - - { - PtrType val = (PtrType)0x4; - - - AtomicType atomic{val}; - - PtrType expected = (PtrType)0x8; - PtrType ret = atomic++; - - VERIFY(ret == val); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } - - { - PtrType val = (PtrType)0x4; - AtomicType atomic{val}; - - PtrType expected = (PtrType)0x10; - PtrType ret = atomic += 3; - - VERIFY(ret == expected); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } - - { - PtrType val = (PtrType)0x4; - AtomicType atomic{val}; - - PtrType expected = (PtrType)0x4; - PtrType ret = atomic += 0; - - VERIFY(ret == expected); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } - - { - PtrType val = (PtrType)0x4; - AtomicType atomic{val}; - - PtrType expected = (PtrType)0x0; - PtrType ret = atomic -= 1; - - VERIFY(ret == expected); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } - - { - PtrType val = (PtrType)0x4; - AtomicType atomic{val}; - - PtrType expected = (PtrType)0x4; - PtrType ret = atomic -= 0; - - VERIFY(ret == expected); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } -} - -void AtomicPointerBasicTest::TestIsLockFree() -{ - { - AtomicType atomic; - - VERIFY(atomic.is_lock_free() == true); - - VERIFY(atomic.is_always_lock_free == true); - } -} - -void AtomicPointerBasicTest::TestStore() -{ - { - PtrType val = (PtrType)0x0; - AtomicType atomic; - - atomic.store(val, eastl::memory_order_relaxed); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == val); - } - - { - PtrType val = (PtrType)0x4; - AtomicType atomic; - - atomic.store(val, eastl::memory_order_relaxed); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == val); - } -} - -void AtomicPointerBasicTest::TestLoad() -{ - { - AtomicType atomic{ (PtrType)0x4 }; - - PtrType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic == (PtrType)0x4); - } -} - -void AtomicPointerBasicTest::TestCompareExchangeWeak() -{ - { - AtomicType atomic; - - PtrType observed = (PtrType)0x0; - bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - if (ret) - { - VERIFY(ret == true); - VERIFY(observed == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - } - - { - AtomicType atomic; - - PtrType observed = (PtrType)0x4; - bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - VERIFY(ret == false); - VERIFY(observed == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } -} - -void AtomicPointerBasicTest::TestCompareExchangeStrong() -{ - { - AtomicType atomic; - - PtrType observed = (PtrType)0x0; - bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - VERIFY(ret == true); - VERIFY(observed == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - - { - AtomicType atomic; - - PtrType observed = (PtrType)0x4; - bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - VERIFY(ret == false); - VERIFY(observed == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } -} - -void AtomicPointerBasicTest::TestExchange() -{ - { - AtomicType atomic; - - PtrType ret = atomic.exchange((PtrType)0x4, eastl::memory_order_release); - - VERIFY(ret == (PtrType)0x0); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } -} - -void AtomicPointerBasicTest::TestAllMemoryOrders() -{ - { - AtomicType atomic; - PtrType val = (PtrType)0x4; - - atomic.store(val); - - atomic.store(val, eastl::memory_order_relaxed); - - atomic.store(val, eastl::memory_order_release); - - atomic.store(val, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - PtrType ret = atomic.load(); - - ret = atomic.load(eastl::memory_order_relaxed); - - ret = atomic.load(eastl::memory_order_acquire); - - ret = atomic.load(eastl::memory_order_seq_cst); - - ret = atomic.load(eastl::memory_order_read_depends); - } - - { - AtomicType atomic; - - PtrType ret = atomic.fetch_add(0); - - ret = atomic.fetch_add(0, eastl::memory_order_relaxed); - - ret = atomic.fetch_add(0, eastl::memory_order_acquire); - - ret = atomic.fetch_add(0, eastl::memory_order_release); - - ret = atomic.fetch_add(0, eastl::memory_order_acq_rel); - - ret = atomic.fetch_add(0, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - PtrType ret = atomic.fetch_sub(0); - - ret = atomic.fetch_sub(0, eastl::memory_order_relaxed); - - ret = atomic.fetch_sub(0, eastl::memory_order_acquire); - - ret = atomic.fetch_sub(0, eastl::memory_order_release); - - ret = atomic.fetch_sub(0, eastl::memory_order_acq_rel); - - ret = atomic.fetch_sub(0, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - PtrType ret = atomic.add_fetch(0); - - ret = atomic.add_fetch(0, eastl::memory_order_relaxed); - - ret = atomic.add_fetch(0, eastl::memory_order_acquire); - - ret = atomic.add_fetch(0, eastl::memory_order_release); - - ret = atomic.add_fetch(0, eastl::memory_order_acq_rel); - - ret = atomic.add_fetch(0, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - PtrType ret = atomic.sub_fetch(0); - - ret = atomic.sub_fetch(0, eastl::memory_order_relaxed); - - ret = atomic.sub_fetch(0, eastl::memory_order_acquire); - - ret = atomic.sub_fetch(0, eastl::memory_order_release); - - ret = atomic.sub_fetch(0, eastl::memory_order_acq_rel); - - ret = atomic.sub_fetch(0, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - PtrType ret = atomic.exchange((PtrType)0x4); - - ret = atomic.exchange((PtrType)0x4, eastl::memory_order_relaxed); - - ret = atomic.exchange((PtrType)0x4, eastl::memory_order_acquire); - - ret = atomic.exchange((PtrType)0x4, eastl::memory_order_release); - - ret = atomic.exchange((PtrType)0x4, eastl::memory_order_acq_rel); - - ret = atomic.exchange((PtrType)0x4, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - PtrType observed = (PtrType)0x0; - - bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_release); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - PtrType observed = (PtrType)0x0; - - bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_release); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - PtrType observed = (PtrType)0x0; - bool ret; - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_release, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - PtrType observed = (PtrType)0x0; - bool ret; - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_release, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); - } -} - -void AtomicPointerBasicTest::TestFetchAdd() -{ - { - PtrType val = (PtrType)0x4; - AtomicType atomic{ val }; - - PtrType ret = atomic.fetch_add(1, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x8); - } - - { - PtrType val = (PtrType)0x4; - AtomicType atomic{ val }; - - PtrType ret = atomic.fetch_add(0, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } -} - -void AtomicPointerBasicTest::TestAddFetch() -{ - { - PtrType val = (PtrType)0x4; - AtomicType atomic{ val }; - - PtrType ret = atomic.add_fetch(1, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x8); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x8); - } - - { - PtrType val = (PtrType)0x4; - AtomicType atomic{ val }; - - PtrType ret = atomic.add_fetch(0, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } -} - -void AtomicPointerBasicTest::TestFetchSub() -{ - { - PtrType val = (PtrType)0x4; - AtomicType atomic{ val }; - - PtrType ret = atomic.fetch_sub(1, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } - - { - PtrType val = (PtrType)0x4; - AtomicType atomic{ val }; - - PtrType ret = atomic.fetch_sub(0, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } -} - -void AtomicPointerBasicTest::TestSubFetch() -{ - { - PtrType val = (PtrType)0x4; - AtomicType atomic{ val }; - - PtrType ret = atomic.sub_fetch(1, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x0); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } - - { - PtrType val = (PtrType)0x4; - AtomicType atomic{ val }; - - PtrType ret = atomic.sub_fetch(0, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } -} - -void AtomicPointerBasicTest::TestAtomicPointerStandalone() -{ - { - AtomicType atomic; - - VERIFY(atomic_is_lock_free(&atomic) == true); - } - - { - AtomicType atomic; - PtrType val = (PtrType)0x4; - - atomic_store(&atomic, val); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == val); - } - - { - AtomicType atomic; - PtrType val = (PtrType)0x4; - - atomic_store_explicit(&atomic, val, eastl::memory_order_relaxed); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == val); - } - - { - AtomicType atomic; - - PtrType ret = atomic_load(&atomic); - - VERIFY(ret == (PtrType)0x0); - } - - { - AtomicType atomic; - - PtrType ret = atomic_load_explicit(&atomic, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x0); - } - - { - AtomicType atomic; - - PtrType ret = atomic_load_cond(&atomic, [](PtrType val) { return true; }); - - VERIFY(ret == (PtrType)0x0); - } - - { - AtomicType atomic; - - PtrType ret = atomic_load_cond_explicit(&atomic, [](PtrType val) { return true; }, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x0); - } - - { - AtomicType atomic; - - PtrType ret = atomic_exchange(&atomic, (PtrType)0x4); - - VERIFY(ret == (PtrType)0x0); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - - { - AtomicType atomic; - - PtrType ret = atomic_exchange_explicit(&atomic, (PtrType)0x4, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x0); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - - { - AtomicType atomic; - - PtrType ret = atomic_add_fetch(&atomic, 1); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - - { - AtomicType atomic; - - PtrType ret = atomic_add_fetch_explicit(&atomic, 1, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - - { - AtomicType atomic; - - PtrType ret = atomic_fetch_add(&atomic, 1); - - VERIFY(ret == (PtrType)0x0); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - - { - AtomicType atomic; - - PtrType ret = atomic_fetch_add_explicit(&atomic, 1, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x0); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - - { - AtomicType atomic{ (PtrType)0x4 }; - - PtrType ret = atomic_fetch_sub(&atomic, 1); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } - - { - AtomicType atomic{ (PtrType)0x4 }; - - PtrType ret = atomic_fetch_sub_explicit(&atomic, 1, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } - - { - AtomicType atomic{ (PtrType)0x4 }; - - PtrType ret = atomic_sub_fetch(&atomic, 1); - - VERIFY(ret == (PtrType)0x0); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } - - { - AtomicType atomic{ (PtrType)0x4 }; - - PtrType ret = atomic_sub_fetch_explicit(&atomic, 1, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x0); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } - - { - AtomicType atomic; - - PtrType expected = (PtrType)0x0; - bool ret = atomic_compare_exchange_strong(&atomic, &expected, (PtrType)0x4); - - VERIFY(ret == true); - - VERIFY(expected == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - - { - AtomicType atomic; - - PtrType expected = (PtrType)0x0; - bool ret = atomic_compare_exchange_strong_explicit(&atomic, &expected, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - VERIFY(ret == true); - - VERIFY(expected == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - - { - AtomicType atomic; - - PtrType expected = (PtrType)0x0; - bool ret = atomic_compare_exchange_weak(&atomic, &expected, (PtrType)0x4); - - if (ret) - { - VERIFY(ret == true); - - VERIFY(expected == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - } - - { - AtomicType atomic; - - PtrType expected = (PtrType)0x0; - bool ret = atomic_compare_exchange_weak_explicit(&atomic, &expected, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - if (ret) - { - VERIFY(ret == true); - - VERIFY(expected == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - } -} - -struct AtomicNonTriviallyConstructible -{ - AtomicNonTriviallyConstructible() - : a(0) - , b(0) - { - } - - AtomicNonTriviallyConstructible(uint16_t a, uint16_t b) - : a(a) - , b(b) - { - } - - friend bool operator==(const AtomicNonTriviallyConstructible& a, const AtomicNonTriviallyConstructible& b) - { - return a.a == b.a && a.b == b.b; - } - - uint16_t a; - uint16_t b; -}; - -struct AtomicNonTriviallyConstructibleNoExcept -{ - AtomicNonTriviallyConstructibleNoExcept() noexcept - : a(0) - , b(0) - { - } - - AtomicNonTriviallyConstructibleNoExcept(uint16_t a, uint16_t b) noexcept - : a(a) - , b(b) - { - } - - friend bool operator==(const AtomicNonTriviallyConstructibleNoExcept& a, const AtomicNonTriviallyConstructibleNoExcept& b) - { - return a.a == b.a && a.b == b.b; - } - - uint16_t a; - uint16_t b; -}; - -struct AtomicUserType16 -{ - uint8_t a; - uint8_t b; - - friend bool operator==(const AtomicUserType16& a, const AtomicUserType16& b) - { - return (a.a == b.a) && (a.b == b.b); - } -}; - -struct AtomicUserType128 -{ - uint32_t a; - uint32_t b; - uint32_t c; - uint32_t d; - - AtomicUserType128() = default; - - AtomicUserType128(const AtomicUserType128&) = default; - - AtomicUserType128(uint32_t a, uint32_t b) - : a(a) - , b(b) - , c(0) - , d(0) - { - } - - AtomicUserType128& operator=(const AtomicUserType128&) = default; - - friend bool operator==(const AtomicUserType128& a, const AtomicUserType128& b) - { - return (a.a == b.a) && (a.b == b.b) && (a.c == b.c) && (a.d == b.d); - } -}; - -template -class AtomicUserTypeBasicTest -{ -public: - - using AtomicType = eastl::atomic; - using UserType = T; - - int RunTest() - { - TestAtomicCtor(); - - TestAssignmentOperators(); - - TestIsLockFree(); - - TestStore(); - - TestLoad(); - - TestExchange(); - - TestCompareExchangeWeak(); - - TestCompareExchangeStrong(); - - TestAllMemoryOrders(); - - return nErrorCount; - } - -private: - - void TestAtomicCtor(); - - void TestAssignmentOperators(); - - void TestIsLockFree(); - - void TestStore(); - - void TestLoad(); - - void TestExchange(); - - void TestCompareExchangeWeak(); - - void TestCompareExchangeStrong(); - - void TestAllMemoryOrders(); - -private: - - int nErrorCount = 0; -}; - -template -void AtomicUserTypeBasicTest::TestAtomicCtor() -{ - { - AtomicType atomic; - UserType expected{0, 0}; - - UserType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == expected); - } - - { - AtomicType atomic{ {5, 8} }; - UserType expected{5, 8}; - - UserType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == expected); - } -} - -template -void AtomicUserTypeBasicTest::TestAssignmentOperators() -{ - { - AtomicType atomic; - UserType expected{5, 6}; - - atomic = {5, 6}; - - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } - - { - AtomicType atomic; - UserType expected{0, 0}; - - atomic = {0, 0}; - - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } -} - -template -void AtomicUserTypeBasicTest::TestIsLockFree() -{ - { - AtomicType atomic; - - VERIFY(atomic.is_lock_free() == true); - - VERIFY(AtomicType::is_always_lock_free == true); - } -} - -template -void AtomicUserTypeBasicTest::TestStore() -{ - { - AtomicType atomic; - UserType expected{5, 6}; - - atomic.store(expected, eastl::memory_order_relaxed); - - UserType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == expected); - } - - { - AtomicType atomic; - UserType expected{5, 6}; - - atomic.store({5, 6}, eastl::memory_order_relaxed); - - UserType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == expected); - } -} - -template -void AtomicUserTypeBasicTest::TestLoad() -{ - { - AtomicType atomic; - UserType expected{0, 0}; - - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - - VERIFY(atomic == expected); - } - - { - AtomicType atomic{ {5, 6} }; - UserType expected{5, 6}; - - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - - VERIFY(atomic == expected); - } -} - -template -void AtomicUserTypeBasicTest::TestExchange() -{ - { - AtomicType atomic; - UserType expected{0, 0}; - - UserType ret = atomic.exchange({0, 0}, eastl::memory_order_relaxed); - - VERIFY(ret == expected); - } - - { - AtomicType atomic; - UserType expected{0, 0}; - UserType expected2{0, 1}; - - UserType ret = atomic.exchange({0, 1}, eastl::memory_order_relaxed); - - VERIFY(ret == expected); - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected2); - } -} - -template -void AtomicUserTypeBasicTest::TestCompareExchangeWeak() -{ - { - AtomicType atomic; - - UserType observed{0, 0}; - bool ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_relaxed); - - UserType expected{0, 0}; - if (ret) - { - VERIFY(ret == true); - VERIFY(observed == expected); - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } - } - - { - AtomicType atomic; - - UserType observed{0, 0}; - bool ret = atomic.compare_exchange_weak(observed, {0, 1}, eastl::memory_order_relaxed); - - UserType expected{0, 1}; - UserType expected2{0, 0}; - if (ret) - { - VERIFY(ret == true); - VERIFY(observed == expected2); - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } - } - - { - AtomicType atomic; - - UserType observed{0, 1}; - bool ret = atomic.compare_exchange_weak(observed, {0, 1}, eastl::memory_order_relaxed); - - UserType expected{0, 0}; - - VERIFY(ret == false); - VERIFY(observed == expected); - } -} - -template -void AtomicUserTypeBasicTest::TestCompareExchangeStrong() -{ - { - AtomicType atomic; - - UserType observed{0, 0}; - bool ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_relaxed); - - UserType expected{0, 0}; - - VERIFY(ret == true); - VERIFY(observed == expected); - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } - - { - AtomicType atomic; - - UserType observed{0, 0}; - bool ret = atomic.compare_exchange_strong(observed, {0, 1}, eastl::memory_order_relaxed); - - UserType expected{0, 1}; - UserType expected2{0, 0}; - - VERIFY(ret == true); - VERIFY(observed == expected2); - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } - - { - AtomicType atomic; - - UserType observed{0, 1}; - bool ret = atomic.compare_exchange_strong(observed, {0, 1}, eastl::memory_order_relaxed); - - UserType expected{0, 0}; - - VERIFY(ret == false); - VERIFY(observed == expected); - } -} - -template -void AtomicUserTypeBasicTest::TestAllMemoryOrders() -{ - { - AtomicType atomic; - UserType val{0, 1}; - - atomic.store(val); - - atomic.store(val, eastl::memory_order_relaxed); - - atomic.store(val, eastl::memory_order_release); - - atomic.store(val, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - UserType ret = atomic.load(); - - ret = atomic.load(eastl::memory_order_relaxed); - - ret = atomic.load(eastl::memory_order_acquire); - - ret = atomic.load(eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - UserType ret = atomic.exchange({0, 1}); - - ret = atomic.exchange({0, 0}, eastl::memory_order_relaxed); - - ret = atomic.exchange({0, 0}, eastl::memory_order_acquire); - - ret = atomic.exchange({0, 0}, eastl::memory_order_release); - - ret = atomic.exchange({0, 0}, eastl::memory_order_acq_rel); - - ret = atomic.exchange({0, 0}, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - UserType observed{0, 0}; - - bool ret = atomic.compare_exchange_weak(observed, {0, 0}); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_release); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acq_rel); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - UserType observed{0, 0}; - - bool ret = atomic.compare_exchange_strong(observed, {0, 0}); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_release); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acq_rel); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - UserType observed{0, 0}; - bool ret; - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acquire, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acquire, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_release, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acq_rel, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - UserType observed{0, 0}; - bool ret; - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acquire, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acquire, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_release, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acq_rel, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); - } -} - - -class AtomicBoolBasicTest -{ -public: - - using AtomicType = eastl::atomic; - using BoolType = bool; - - int RunTest() - { - TestAtomicCtor(); - - TestAssignmentOperators(); - - TestIsLockFree(); - - TestStore(); - - TestLoad(); - - TestExchange(); - - TestCompareExchangeWeak(); - - TestCompareExchangeStrong(); - - TestAllMemoryOrders(); - - return nErrorCount; - } - -private: - - void TestAtomicCtor(); - - void TestAssignmentOperators(); - - void TestIsLockFree(); - - void TestStore(); - - void TestLoad(); - - void TestExchange(); - - void TestCompareExchangeWeak(); - - void TestCompareExchangeStrong(); - - void TestAllMemoryOrders(); - -private: - - int nErrorCount = 0; -}; - -void AtomicBoolBasicTest::TestAtomicCtor() -{ - { - AtomicType atomic{ false }; - - BoolType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == false); - } - - { - AtomicType atomic{ true }; - - BoolType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == true); - } - - { - AtomicType atomic; - - BoolType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == false); - } - - { - AtomicType atomic{}; - - BoolType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == false); - } -} - -void AtomicBoolBasicTest::TestAssignmentOperators() -{ - { - AtomicType atomic; - - BoolType ret = atomic = true; - - VERIFY(ret == true); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == true); - } -} - -void AtomicBoolBasicTest::TestIsLockFree() -{ - { - AtomicType atomic; - - bool ret = atomic.is_lock_free(); - - VERIFY(ret == true); - - VERIFY(AtomicType::is_always_lock_free == true); - } -} - -void AtomicBoolBasicTest::TestStore() -{ - { - AtomicType atomic; - - atomic.store(true, eastl::memory_order_relaxed); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == true); - } -} - -void AtomicBoolBasicTest::TestLoad() -{ - { - AtomicType atomic; - - VERIFY(atomic.load(eastl::memory_order_relaxed) == false); - - VERIFY(atomic == false); - } - - { - AtomicType atomic{ true }; - - VERIFY(atomic.load(eastl::memory_order_relaxed) == true); - - VERIFY(atomic == true); - } -} - -void AtomicBoolBasicTest::TestExchange() -{ - { - AtomicType atomic; - - BoolType ret = atomic.exchange(false, eastl::memory_order_relaxed); - - VERIFY(ret == false); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == false); - } - - { - AtomicType atomic; - - BoolType ret = atomic.exchange(true, eastl::memory_order_relaxed); - - VERIFY(ret == false); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == true); - } -} - -void AtomicBoolBasicTest::TestCompareExchangeWeak() -{ - { - AtomicType atomic{ false }; - - BoolType observed = false; - bool ret = atomic.compare_exchange_weak(observed, false, eastl::memory_order_relaxed); - - if (ret) - { - VERIFY(ret == true); - VERIFY(observed == false); - VERIFY(atomic.load(eastl::memory_order_relaxed) == false); - } - } - - { - AtomicType atomic{ false }; - - BoolType observed = false; - bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); - - if (ret) - { - VERIFY(ret == true); - VERIFY(observed == false); - VERIFY(atomic.load(eastl::memory_order_relaxed) == true); - } - } - - { - AtomicType atomic{ false }; - - BoolType observed = true; - bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); - - VERIFY(ret == false); - VERIFY(observed == false); - } -} - -void AtomicBoolBasicTest::TestCompareExchangeStrong() -{ - { - AtomicType atomic{ false }; - - BoolType observed = false; - bool ret = atomic.compare_exchange_weak(observed, false, eastl::memory_order_relaxed); - - VERIFY(ret == true); - VERIFY(observed == false); - VERIFY(atomic.load(eastl::memory_order_relaxed) == false); - } - - { - AtomicType atomic{ false }; - - BoolType observed = false; - bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); - - VERIFY(ret == true); - VERIFY(observed == false); - VERIFY(atomic.load(eastl::memory_order_relaxed) == true); - } - - { - AtomicType atomic{ false }; - - BoolType observed = true; - bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); - - VERIFY(ret == false); - VERIFY(observed == false); - } -} - -void AtomicBoolBasicTest::TestAllMemoryOrders() -{ - { - AtomicType atomic; - - atomic.store(true); - - atomic.store(true, eastl::memory_order_relaxed); - - atomic.store(true, eastl::memory_order_release); - - atomic.store(true, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - BoolType ret = atomic.load(); - - ret = atomic.load(eastl::memory_order_relaxed); - - ret = atomic.load(eastl::memory_order_acquire); - - ret = atomic.load(eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - BoolType ret = atomic.exchange(true); - - ret = atomic.exchange(true, eastl::memory_order_relaxed); - - ret = atomic.exchange(true, eastl::memory_order_acquire); - - ret = atomic.exchange(true, eastl::memory_order_release); - - ret = atomic.exchange(true, eastl::memory_order_acq_rel); - - ret = atomic.exchange(true, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - BoolType observed = false; - bool ret = atomic.compare_exchange_weak(observed, true); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_release); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acq_rel); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - BoolType observed = false; - bool ret = atomic.compare_exchange_strong(observed, true); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_release); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acq_rel); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - BoolType observed = false; - bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acquire, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acquire, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_release, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acq_rel, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - BoolType observed = false; - bool ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acquire, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acquire, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_release, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acq_rel, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); - } -} - - -template -class AtomicIntegralBasicTest -{ -public: - - using AtomicType = eastl::atomic; - using IntegralType = T; - - int RunTest() - { - TestAtomicCtor(); - - TestAtomicFetchAdd(); - TestAtomicAddFetch(); - - TestAtomicFetchSub(); - TestAtomicSubFetch(); - - TestAtomicFetchAnd(); - TestAtomicAndFetch(); - - TestAtomicFetchOr(); - TestAtomicOrFetch(); - - TestAtomicFetchXor(); - TestAtomicXorFetch(); - - TestAssignmentOperators(); - - TestIsLockFree(); - - TestStore(); - - TestLoad(); - - TestExchange(); - - TestCompareExchangeWeak(); - - TestCompareExchangeStrong(); - - TestAllMemoryOrders(); - - TestAtomicStandalone(); - - return nErrorCount; - } - -private: - - void TestAtomicCtor(); - - void TestAtomicFetchAdd(); - void TestAtomicAddFetch(); - - void TestAtomicFetchSub(); - void TestAtomicSubFetch(); - - void TestAtomicFetchAnd(); - void TestAtomicAndFetch(); - - void TestAtomicFetchOr(); - void TestAtomicOrFetch(); - - void TestAtomicFetchXor(); - void TestAtomicXorFetch(); - - void TestAssignmentOperators(); - - void TestIsLockFree(); - - void TestStore(); - - void TestLoad(); - - void TestExchange(); - - void TestCompareExchangeWeak(); - - void TestCompareExchangeStrong(); - - void TestAllMemoryOrders(); - - void TestAtomicStandalone(); - -private: - - int nErrorCount = 0; -}; - -template -void AtomicIntegralBasicTest::TestAtomicCtor() -{ - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 1 }; - - IntegralType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 1); - } - - { - AtomicType atomic{ 20 }; - - IntegralType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 20); - } - - { - AtomicType atomic; - - IntegralType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } -} - -template -void AtomicIntegralBasicTest::TestAtomicFetchAdd() -{ - { - AtomicType atomic; - - IntegralType ret = atomic.fetch_add(1, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic.fetch_add(0, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 5 }; - - IntegralType ret = atomic.fetch_add(0, eastl::memory_order_relaxed); - - VERIFY(ret == 5); - - ret = atomic.fetch_add(4, eastl::memory_order_relaxed); - - VERIFY(ret == 5); - - ret = atomic.fetch_add(1, eastl::memory_order_relaxed); - - VERIFY(ret == 9); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 10); - } -} - -template -void AtomicIntegralBasicTest::TestAtomicAddFetch() -{ - { - AtomicType atomic; - - IntegralType ret = atomic.add_fetch(1, eastl::memory_order_relaxed); - - VERIFY(ret == 1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic.add_fetch(0, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 5 }; - - IntegralType ret = atomic.add_fetch(0, eastl::memory_order_relaxed); - - VERIFY(ret == 5); - - ret = atomic.add_fetch(4, eastl::memory_order_relaxed); - - VERIFY(ret == 9); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 9); - } -} - -template -void AtomicIntegralBasicTest::TestAtomicFetchSub() -{ - { - AtomicType atomic{ 1 }; - - IntegralType ret = atomic.fetch_sub(1, eastl::memory_order_relaxed); - - VERIFY(ret == 1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 1 }; - - IntegralType ret = atomic.fetch_sub(0, eastl::memory_order_relaxed); - - VERIFY(ret == 1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 1); - } - - { - AtomicType atomic{ 5 }; - - IntegralType ret = atomic.fetch_sub(2, eastl::memory_order_relaxed); - - VERIFY(ret == 5); - - ret = atomic.fetch_sub(1, eastl::memory_order_relaxed); - - VERIFY(ret == 3); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 2); - } -} - -template -void AtomicIntegralBasicTest::TestAtomicSubFetch() -{ - { - AtomicType atomic{ 1 }; - - IntegralType ret = atomic.sub_fetch(1, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 1 }; - - IntegralType ret = atomic.sub_fetch(0, eastl::memory_order_relaxed); - - VERIFY(ret == 1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 1); - } - - { - AtomicType atomic{ 5 }; - - IntegralType ret = atomic.sub_fetch(2, eastl::memory_order_relaxed); - - VERIFY(ret == 3); - - ret = atomic.sub_fetch(1, eastl::memory_order_relaxed); - - VERIFY(ret == 2); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 2); - } -} - -template -void AtomicIntegralBasicTest::TestAtomicFetchAnd() -{ - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic.fetch_and(0x0, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic.fetch_and(0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 0xF }; - - IntegralType ret = atomic.fetch_and(0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0xF); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0X1); - } - - { - AtomicType atomic{ 0xF }; - - IntegralType ret = atomic.fetch_and(0xF0, eastl::memory_order_relaxed); - - VERIFY(ret == 0xF); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - } -} - -template -void AtomicIntegralBasicTest::TestAtomicAndFetch() -{ - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic.and_fetch(0x0, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic.and_fetch(0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 0xF }; - - IntegralType ret = atomic.and_fetch(0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - } - - { - AtomicType atomic{ 0xF }; - - IntegralType ret = atomic.and_fetch(0xF0, eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - } -} - -template -void AtomicIntegralBasicTest::TestAtomicFetchOr() -{ - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic.fetch_or(0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic.fetch_or(0x0, eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic.fetch_or(0x2, eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x3); - } -} - -template -void AtomicIntegralBasicTest::TestAtomicOrFetch() -{ - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic.or_fetch(0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic.or_fetch(0x0, eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic.or_fetch(0x2, eastl::memory_order_relaxed); - - VERIFY(ret == 0x3); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x3); - } -} - -template -void AtomicIntegralBasicTest::TestAtomicFetchXor() -{ - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic.fetch_xor(0x0, eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic.fetch_xor(0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - } - - { - AtomicType atomic{ 0x0 }; - - IntegralType ret = atomic.fetch_xor(0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - } -} - -template -void AtomicIntegralBasicTest::TestAtomicXorFetch() -{ - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic.xor_fetch(0x0, eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic.xor_fetch(0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - } - - { - AtomicType atomic{ 0x0 }; - - IntegralType ret = atomic.xor_fetch(0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - } -} - -template -void AtomicIntegralBasicTest::TestAssignmentOperators() -{ - { - AtomicType atomic{ 0 }; - - IntegralType ret = (atomic = 5); - - VERIFY(ret == 5); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 5); - } - - { - AtomicType atomic{ 0 }; - - IntegralType ret = ++atomic; - - VERIFY(ret == 1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 1); - } - - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic++; - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 1); - } - - { - AtomicType atomic{ 1 }; - - IntegralType ret = --atomic; - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 1 }; - - IntegralType ret = atomic--; - - VERIFY(ret == 1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic += 5; - - VERIFY(ret == 5); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 5); - } - - { - AtomicType atomic{ 5 }; - - IntegralType ret = atomic -= 3; - - VERIFY(ret == 2); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 2); - } - - { - AtomicType atomic{ 0x0 }; - - IntegralType ret = atomic |= 0x1; - - VERIFY(ret == 0x1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic &= 0x1; - - VERIFY(ret == 0x1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic ^= 0x1; - - VERIFY(ret == 0x0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - } -} - -template -void AtomicIntegralBasicTest::TestIsLockFree() -{ - { - const AtomicType atomic{ 5 }; - - VERIFY(atomic.is_lock_free() == true); - - VERIFY(AtomicType::is_always_lock_free == true); - } -} - -template -void AtomicIntegralBasicTest::TestStore() -{ - { - AtomicType atomic{ 0 }; - - atomic.store(0, eastl::memory_order_relaxed); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); - } - - { - AtomicType atomic{ 0 }; - - atomic.store(1, eastl::memory_order_relaxed); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } -} - -template -void AtomicIntegralBasicTest::TestLoad() -{ - { - AtomicType atomic{ 0 }; - - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); - - bool ret = atomic == 0; - VERIFY(ret == true); - - VERIFY(atomic == 0); - } - - { - AtomicType atomic{ 5 }; - - VERIFY(atomic.load(eastl::memory_order_relaxed) == 5); - - bool ret = atomic == 5; - VERIFY(ret == true); - - VERIFY(atomic == 5); - } -} - -template -void AtomicIntegralBasicTest::TestExchange() -{ - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic.exchange(0, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic.exchange(1, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 1); - } -} - -template -void AtomicIntegralBasicTest::TestCompareExchangeWeak() -{ - { - AtomicType atomic{ 0 }; - - IntegralType observed = 0; - bool ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_relaxed); - - if (ret == true) - { - VERIFY(ret == true); - VERIFY(observed == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - } - - { - AtomicType atomic{ 0 }; - - IntegralType observed = 1; - bool ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_relaxed); - - VERIFY(ret == false); - VERIFY(observed == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); - } -} - -template -void AtomicIntegralBasicTest::TestCompareExchangeStrong() -{ - { - AtomicType atomic{ 0 }; - - IntegralType observed = 0; - bool ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_relaxed); - - VERIFY(ret == true); - VERIFY(observed == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - - { - AtomicType atomic{ 0 }; - - IntegralType observed = 1; - bool ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_relaxed); - - VERIFY(ret == false); - VERIFY(observed == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); - } -} - -template -void AtomicIntegralBasicTest::TestAllMemoryOrders() -{ - { - AtomicType atomic{}; - - atomic.store(1); - - atomic.store(1, eastl::memory_order_relaxed); - - atomic.store(1, eastl::memory_order_release); - - atomic.store(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.load(); - - ret = atomic.load(eastl::memory_order_relaxed); - - ret = atomic.load(eastl::memory_order_acquire); - - ret = atomic.load(eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.exchange(1); - - ret = atomic.exchange(1, eastl::memory_order_relaxed); - - ret = atomic.exchange(1, eastl::memory_order_acquire); - - ret = atomic.exchange(1, eastl::memory_order_release); - - ret = atomic.exchange(1, eastl::memory_order_acq_rel); - - ret = atomic.exchange(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.fetch_add(1); - - ret = atomic.fetch_add(1, eastl::memory_order_relaxed); - - ret = atomic.fetch_add(1, eastl::memory_order_acquire); - - ret = atomic.fetch_add(1, eastl::memory_order_release); - - ret = atomic.fetch_add(1, eastl::memory_order_acq_rel); - - ret = atomic.fetch_add(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.add_fetch(1); - - ret = atomic.add_fetch(1, eastl::memory_order_relaxed); - - ret = atomic.add_fetch(1, eastl::memory_order_acquire); - - ret = atomic.add_fetch(1, eastl::memory_order_release); - - ret = atomic.add_fetch(1, eastl::memory_order_acq_rel); - - ret = atomic.add_fetch(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.fetch_sub(1); - - ret = atomic.fetch_sub(1, eastl::memory_order_relaxed); - - ret = atomic.fetch_sub(1, eastl::memory_order_acquire); - - ret = atomic.fetch_sub(1, eastl::memory_order_release); - - ret = atomic.fetch_sub(1, eastl::memory_order_acq_rel); - - ret = atomic.fetch_sub(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.sub_fetch(1); - - ret = atomic.sub_fetch(1, eastl::memory_order_relaxed); - - ret = atomic.sub_fetch(1, eastl::memory_order_acquire); - - ret = atomic.sub_fetch(1, eastl::memory_order_release); - - ret = atomic.sub_fetch(1, eastl::memory_order_acq_rel); - - ret = atomic.sub_fetch(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.fetch_and(1); - - ret = atomic.fetch_and(1, eastl::memory_order_relaxed); - - ret = atomic.fetch_and(1, eastl::memory_order_acquire); - - ret = atomic.fetch_and(1, eastl::memory_order_release); - - ret = atomic.fetch_and(1, eastl::memory_order_acq_rel); - - ret = atomic.fetch_and(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.and_fetch(1); - - ret = atomic.and_fetch(1, eastl::memory_order_relaxed); - - ret = atomic.and_fetch(1, eastl::memory_order_acquire); - - ret = atomic.and_fetch(1, eastl::memory_order_release); - - ret = atomic.and_fetch(1, eastl::memory_order_acq_rel); - - ret = atomic.and_fetch(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.fetch_or(1); - - ret = atomic.fetch_or(1, eastl::memory_order_relaxed); - - ret = atomic.fetch_or(1, eastl::memory_order_acquire); - - ret = atomic.fetch_or(1, eastl::memory_order_release); - - ret = atomic.fetch_or(1, eastl::memory_order_acq_rel); - - ret = atomic.fetch_or(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.or_fetch(1); - - ret = atomic.or_fetch(1, eastl::memory_order_relaxed); - - ret = atomic.or_fetch(1, eastl::memory_order_acquire); - - ret = atomic.or_fetch(1, eastl::memory_order_release); - - ret = atomic.or_fetch(1, eastl::memory_order_acq_rel); - - ret = atomic.or_fetch(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.fetch_xor(1); - - ret = atomic.fetch_xor(1, eastl::memory_order_relaxed); - - ret = atomic.fetch_xor(1, eastl::memory_order_acquire); - - ret = atomic.fetch_xor(1, eastl::memory_order_release); - - ret = atomic.fetch_xor(1, eastl::memory_order_acq_rel); - - ret = atomic.fetch_xor(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.xor_fetch(1); - - ret = atomic.xor_fetch(1, eastl::memory_order_relaxed); - - ret = atomic.xor_fetch(1, eastl::memory_order_acquire); - - ret = atomic.xor_fetch(1, eastl::memory_order_release); - - ret = atomic.xor_fetch(1, eastl::memory_order_acq_rel); - - ret = atomic.xor_fetch(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType observed = 0; - bool ret; - - ret = atomic.compare_exchange_weak(observed, 1); - - ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_release); - - ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_acq_rel); - - ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType observed = 0; - bool ret; - - ret = atomic.compare_exchange_strong(observed, 1); - - ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_release); - - ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_acq_rel); - - ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType observed = 0; - bool ret; - - ret = atomic.compare_exchange_weak(observed, 1, - eastl::memory_order_relaxed, - eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, 1, - eastl::memory_order_acquire, - eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, 1, - eastl::memory_order_acquire, - eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, 1, - eastl::memory_order_release, - eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, 1, - eastl::memory_order_acq_rel, - eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, 1, - eastl::memory_order_acq_rel, - eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, 1, - eastl::memory_order_seq_cst, - eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, 1, - eastl::memory_order_seq_cst, - eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, 1, - eastl::memory_order_seq_cst, - eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType observed = 0; - bool ret; - - ret = atomic.compare_exchange_strong(observed, 1, - eastl::memory_order_relaxed, - eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, 1, - eastl::memory_order_acquire, - eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, 1, - eastl::memory_order_acquire, - eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, 1, - eastl::memory_order_release, - eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, 1, - eastl::memory_order_acq_rel, - eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, 1, - eastl::memory_order_acq_rel, - eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, 1, - eastl::memory_order_seq_cst, - eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, 1, - eastl::memory_order_seq_cst, - eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, 1, - eastl::memory_order_seq_cst, - eastl::memory_order_seq_cst); - } - -} - -template -void AtomicIntegralBasicTest::TestAtomicStandalone() -{ - { - AtomicType atomic; - - IntegralType expected = 0; - bool ret = atomic_compare_exchange_weak(&atomic, &expected, 1); - - if (ret) - { - VERIFY(ret == true); - - VERIFY(expected == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - } - - { - AtomicType atomic; - - IntegralType expected = 0; - bool ret = atomic_compare_exchange_weak_explicit(&atomic, &expected, 1, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - if (ret) - { - VERIFY(ret == true); - - VERIFY(expected == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - } - - { - AtomicType atomic; - - IntegralType expected = 0; - bool ret = atomic_compare_exchange_strong(&atomic, &expected, 1); - - VERIFY(ret == true); - - VERIFY(expected == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - - { - AtomicType atomic; - - IntegralType expected = 0; - bool ret = atomic_compare_exchange_strong_explicit(&atomic, &expected, 1, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - VERIFY(ret == true); - - VERIFY(expected == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_fetch_xor(&atomic, 0x1); - - VERIFY(ret == 0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_fetch_xor_explicit(&atomic, 0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_xor_fetch(&atomic, 0x1); - - VERIFY(ret == 0x1); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_xor_fetch_explicit(&atomic, 0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_fetch_or(&atomic, 0x1); - - VERIFY(ret == 0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_fetch_or_explicit(&atomic, 0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_or_fetch(&atomic, 0x1); - - VERIFY(ret == 0x1); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_or_fetch_explicit(&atomic, 0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic_fetch_and(&atomic, 0x0); - - VERIFY(ret == 0x1); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x0); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic_fetch_and_explicit(&atomic, 0x0, eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x0); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic_and_fetch(&atomic, 0x0); - - VERIFY(ret == 0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x0); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic_and_fetch_explicit(&atomic, 0x0, eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x0); - } - - { - AtomicType atomic{ 1 }; - - IntegralType ret = atomic_fetch_sub(&atomic, 1); - - VERIFY(ret == 1); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); - } - - { - AtomicType atomic{ 1 }; - - IntegralType ret = atomic_fetch_sub_explicit(&atomic, 1, eastl::memory_order_relaxed); - - VERIFY(ret == 1); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); - } - - { - AtomicType atomic{ 1 }; - - IntegralType ret = atomic_sub_fetch(&atomic, 1); - - VERIFY(ret == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); - } - - { - AtomicType atomic{ 1 }; - - IntegralType ret = atomic_sub_fetch_explicit(&atomic, 1, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_fetch_add(&atomic, 1); - - VERIFY(ret == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_fetch_add_explicit(&atomic, 1, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_add_fetch(&atomic, 1); - - VERIFY(ret == 1); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_add_fetch_explicit(&atomic, 1, eastl::memory_order_relaxed); - - VERIFY(ret == 1); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_exchange(&atomic, 1); - - VERIFY(ret == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_exchange_explicit(&atomic, 1, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_load(&atomic); - - VERIFY(ret == 0); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_load_explicit(&atomic, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_load_cond(&atomic, [](IntegralType val) { return true; }); - - VERIFY(ret == 0); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_load_cond_explicit(&atomic, [](IntegralType val) { return true; }, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic; - - atomic_store(&atomic, 1); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - - { - AtomicType atomic; - - atomic_store_explicit(&atomic, 1, eastl::memory_order_relaxed); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - - { - AtomicType atomic; - - VERIFY(atomic_is_lock_free(&atomic) == true); - } -} - -struct AtomicNonDefaultConstructible -{ - AtomicNonDefaultConstructible(uint8_t a) - : a(a) - { - } - - friend bool operator==(const AtomicNonDefaultConstructible& a, const AtomicNonDefaultConstructible& b) - { - return a.a == b.a; - } - - uint8_t a; -}; - -#if defined(EASTL_ATOMIC_HAS_8BIT) - -int TestAtomicNonDefaultConstructible() -{ - int nErrorCount = 0; - - { - eastl::atomic atomic{AtomicNonDefaultConstructible{(uint8_t)3}}; - - VERIFY(atomic.load() == AtomicNonDefaultConstructible{(uint8_t)3}); - } - - { - eastl::atomic atomic{AtomicNonDefaultConstructible{(uint8_t)3}}; - - atomic.store(AtomicNonDefaultConstructible{(uint8_t)4}); - - VERIFY(atomic.load() == AtomicNonDefaultConstructible{(uint8_t)4}); - } - - return nErrorCount; -} - -#endif - -struct Atomic128LoadType -{ - friend bool operator==(const Atomic128LoadType& a, const Atomic128LoadType& b) - { - return a.a == b.a && a.b == b.b && a.c == b.c && a.d == b.d; - } - - uint32_t a, b, c, d; -}; - -#if defined(EASTL_ATOMIC_HAS_128BIT) - -int TestAtomic128Loads() -{ - int nErrorCount = 0; - - { - eastl::atomic atomic{Atomic128LoadType{1, 1, 0, 0}}; - - VERIFY((atomic.load() == Atomic128LoadType{1, 1, 0, 0})); - } - - { - eastl::atomic atomic{Atomic128LoadType{0, 0, 1, 1}}; - - VERIFY((atomic.load() == Atomic128LoadType{0, 0, 1, 1})); - } - - { - eastl::atomic atomic{Atomic128LoadType{0, 1, 0, 1}}; - - VERIFY((atomic.load() == Atomic128LoadType{0, 1, 0, 1})); - } - - { - eastl::atomic atomic{Atomic128LoadType{1, 0, 1, 0}}; - - VERIFY((atomic.load() == Atomic128LoadType{1, 0, 1, 0})); - } - - return nErrorCount; -} - -#endif - -int TestAtomicBasic() -{ - int nErrorCount = 0; - - #if defined(EASTL_ATOMIC_HAS_8BIT) - { - AtomicIntegralBasicTest u8AtomicTest; - - nErrorCount += u8AtomicTest.RunTest(); - } - #endif - - #if defined(EASTL_ATOMIC_HAS_16BIT) - { - AtomicIntegralBasicTest u16AtomicTest; - - nErrorCount += u16AtomicTest.RunTest(); - } - #endif - - #if defined(EASTL_ATOMIC_HAS_32BIT) - { - AtomicIntegralBasicTest u32AtomicTest; - - nErrorCount += u32AtomicTest.RunTest(); - } - #endif - - #if defined(EASTL_ATOMIC_HAS_64BIT) - { - AtomicIntegralBasicTest u64AtomicTest; - - nErrorCount += u64AtomicTest.RunTest(); - } - #endif - - #if defined(EASTL_ATOMIC_HAS_128BIT) && (defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) - { - AtomicIntegralBasicTest<__uint128_t> u128AtomicTest; - - nErrorCount += u128AtomicTest.RunTest(); - } - - { - AtomicIntegralBasicTest u128AtomicTest; - - nErrorCount += u128AtomicTest.RunTest(); - } - #endif - - { - AtomicBoolBasicTest boolAtomicTest; - - nErrorCount += boolAtomicTest.RunTest(); - } - - #if defined(EASTL_ATOMIC_HAS_16BIT) - { - AtomicUserTypeBasicTest userTypeAtomicTest; - - nErrorCount += userTypeAtomicTest.RunTest(); - } - #endif - - #if defined(EASTL_ATOMIC_HAS_32BIT) - { - AtomicUserTypeBasicTest userTypeAtomicTest; - - nErrorCount += userTypeAtomicTest.RunTest(); - } - - { - AtomicUserTypeBasicTest userTypeAtomicTest; - - nErrorCount += userTypeAtomicTest.RunTest(); - } - #endif - - #if defined(EASTL_ATOMIC_HAS_128BIT) - { - AtomicUserTypeBasicTest userTypeAtomicTest; - - nErrorCount += userTypeAtomicTest.RunTest(); - } - #endif - - { - AtomicPointerBasicTest ptrAtomicTest; - - nErrorCount += ptrAtomicTest.RunTest(); - } - - { - AtomicVoidPointerBasicTest voidPtrAtomicTest; - - nErrorCount += voidPtrAtomicTest.RunTest(); - } - - { - AtomicFlagBasicTest atomicFlagBasicTest; - - nErrorCount += atomicFlagBasicTest.RunTest(); - } - - { - AtomicStandaloneBasicTest atomicStandaloneBasicTest; - - nErrorCount += atomicStandaloneBasicTest.RunTest(); - } - -#if defined(EASTL_ATOMIC_HAS_128BIT) - - nErrorCount += TestAtomic128Loads(); - -#endif - -#if defined(EASTL_ATOMIC_HAS_8BIT) - - nErrorCount += TestAtomicNonDefaultConstructible(); - -#endif - - return nErrorCount; -} +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#include "EASTLTest.h" + +#include + + +/** + * This is a basic test suite that tests all functionality is implemented + * and that all operations do as expected. + * I.E. fetch_add returns the previous value and add_fetch returns the current value + */ + +static eastl::atomic sAtomicInt{ 4 }; +static eastl::atomic sAtomicPtr{ nullptr }; + +static int TestAtomicConstantInitialization() +{ + int nErrorCount; + + EATEST_VERIFY(sAtomicInt.load() == 4); + EATEST_VERIFY(sAtomicPtr == nullptr); + + return 0; +} + +class AtomicStandaloneBasicTest +{ +public: + + int RunTest() + { + AtomicSignalFence(); + + AtomicThreadFence(); + + AtomicCpuPause(); + + AtomicCompilerBarrier(); + + return nErrorCount; + } + +private: + + void AtomicSignalFence(); + + void AtomicThreadFence(); + + void AtomicCpuPause(); + + void AtomicCompilerBarrier(); + +private: + + int nErrorCount = 0; +}; + +void AtomicStandaloneBasicTest::AtomicSignalFence() +{ + eastl::atomic_signal_fence(eastl::memory_order_relaxed); + + eastl::atomic_signal_fence(eastl::memory_order_acquire); + + eastl::atomic_signal_fence(eastl::memory_order_release); + + eastl::atomic_signal_fence(eastl::memory_order_acq_rel); + + eastl::atomic_signal_fence(eastl::memory_order_seq_cst); +} + +void AtomicStandaloneBasicTest::AtomicThreadFence() +{ + eastl::atomic_thread_fence(eastl::memory_order_relaxed); + + eastl::atomic_thread_fence(eastl::memory_order_acquire); + + eastl::atomic_thread_fence(eastl::memory_order_release); + + eastl::atomic_thread_fence(eastl::memory_order_acq_rel); + + eastl::atomic_thread_fence(eastl::memory_order_seq_cst); +} + +void AtomicStandaloneBasicTest::AtomicCpuPause() +{ + eastl::cpu_pause(); +} + +void AtomicStandaloneBasicTest::AtomicCompilerBarrier() +{ + eastl::compiler_barrier(); + + { + bool ret = false; + eastl::compiler_barrier_data_dependency(ret); + } +} + +class AtomicFlagBasicTest +{ +public: + + using AtomicType = eastl::atomic_flag; + using BoolType = bool; + + int RunTest() + { + TestAtomicFlagCtor(); + + TestAtomicFlagClear(); + + TestAtomicFlagTestAndSet(); + + TestAtomicFlagTest(); + + TestAllMemoryOrders(); + + TestAtomicFlagStandalone(); + + return nErrorCount; + } + +private: + + void TestAtomicFlagCtor(); + + void TestAtomicFlagClear(); + + void TestAtomicFlagTestAndSet(); + + void TestAtomicFlagTest(); + + void TestAllMemoryOrders(); + + void TestAtomicFlagStandalone(); + +private: + + int nErrorCount = 0; +}; + +void AtomicFlagBasicTest::TestAtomicFlagCtor() +{ + { + AtomicType atomic; + + VERIFY(atomic.test(eastl::memory_order_relaxed) == false); + } + + { + AtomicType atomic{ false }; + + VERIFY(atomic.test(eastl::memory_order_relaxed) == false); + } + + { + AtomicType atomic{ true }; + + VERIFY(atomic.test(eastl::memory_order_relaxed) == true); + } +} + +void AtomicFlagBasicTest::TestAtomicFlagClear() +{ + { + AtomicType atomic; + + atomic.clear(eastl::memory_order_relaxed); + + VERIFY(atomic.test(eastl::memory_order_relaxed) == false); + } + + { + AtomicType atomic{ true }; + + atomic.clear(eastl::memory_order_relaxed); + + VERIFY(atomic.test(eastl::memory_order_relaxed) == false); + } +} + +void AtomicFlagBasicTest::TestAtomicFlagTestAndSet() +{ + { + AtomicType atomic; + + BoolType ret = atomic.test_and_set(eastl::memory_order_relaxed); + + VERIFY(ret == false); + + VERIFY(atomic.test(eastl::memory_order_relaxed) == true); + } + + { + AtomicType atomic{ true }; + + BoolType ret = atomic.test_and_set(eastl::memory_order_relaxed); + + VERIFY(ret == true); + + VERIFY(atomic.test(eastl::memory_order_relaxed) == true); + } +} + +void AtomicFlagBasicTest::TestAtomicFlagTest() +{ + { + AtomicType atomic; + + VERIFY(atomic.test(eastl::memory_order_relaxed) == false); + } + + { + AtomicType atomic{ true }; + + VERIFY(atomic.test(eastl::memory_order_relaxed) == true); + } +} + +void AtomicFlagBasicTest::TestAllMemoryOrders() +{ + { + AtomicType atomic; + + atomic.clear(); + + atomic.clear(eastl::memory_order_relaxed); + + atomic.clear(eastl::memory_order_release); + + atomic.clear(eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + atomic.test_and_set(); + + atomic.test_and_set(eastl::memory_order_relaxed); + + atomic.test_and_set(eastl::memory_order_acquire); + + atomic.test_and_set(eastl::memory_order_release); + + atomic.test_and_set(eastl::memory_order_acq_rel); + + atomic.test_and_set(eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + BoolType ret = atomic.test(); + + ret = atomic.test(eastl::memory_order_relaxed); + + ret = atomic.test(eastl::memory_order_acquire); + + ret = atomic.test(eastl::memory_order_seq_cst); + } +} + +void AtomicFlagBasicTest::TestAtomicFlagStandalone() +{ + { + AtomicType atomic; + + BoolType ret = atomic_flag_test_and_set(&atomic); + + ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_relaxed); + + ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_acquire); + + ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_release); + + ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_acq_rel); + + ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + atomic_flag_clear(&atomic); + + atomic_flag_clear_explicit(&atomic, eastl::memory_order_relaxed); + + atomic_flag_clear_explicit(&atomic, eastl::memory_order_release); + + atomic_flag_clear_explicit(&atomic, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + BoolType ret = atomic_flag_test(&atomic); + + ret = atomic_flag_test_explicit(&atomic, eastl::memory_order_relaxed); + + ret = atomic_flag_test_explicit(&atomic, eastl::memory_order_acquire); + + ret = atomic_flag_test_explicit(&atomic, eastl::memory_order_seq_cst); + } +} + +class AtomicVoidPointerBasicTest +{ +public: + + using AtomicType = eastl::atomic; + using PtrType = void*; + + int RunTest() + { + TestAtomicCtor(); + + TestAssignmentOperators(); + + TestIsLockFree(); + + TestStore(); + + TestLoad(); + + TestExchange(); + + TestCompareExchangeWeak(); + + TestCompareExchangeStrong(); + + TestAllMemoryOrders(); + + return nErrorCount; + } + +private: + + void TestAtomicCtor(); + + void TestAssignmentOperators(); + + void TestIsLockFree(); + + void TestStore(); + + void TestLoad(); + + void TestExchange(); + + void TestCompareExchangeWeak(); + + void TestCompareExchangeStrong(); + + void TestAllMemoryOrders(); + +private: + + int nErrorCount = 0; +}; + +void AtomicVoidPointerBasicTest::TestAtomicCtor() +{ + { + AtomicType atomic; + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } + + { + AtomicType atomic{ (PtrType)0x04 }; + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x04); + } +} + +void AtomicVoidPointerBasicTest::TestAssignmentOperators() +{ + { + AtomicType atomic; + + PtrType ret = atomic = (PtrType)0x04; + + VERIFY(ret == (PtrType)0x04); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x04); + } + + { + AtomicType atomic; + + PtrType ret = atomic = (PtrType)0x0; + + VERIFY(ret == (PtrType)0x0); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } +} + +void AtomicVoidPointerBasicTest::TestIsLockFree() +{ + { + AtomicType atomic; + + VERIFY(atomic.is_lock_free() == true); + + VERIFY(atomic.is_always_lock_free == true); + } +} + +void AtomicVoidPointerBasicTest::TestStore() +{ + { + PtrType val = (PtrType)0x0; + AtomicType atomic; + + atomic.store(val, eastl::memory_order_relaxed); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == val); + } + + { + PtrType val = (PtrType)0x4; + AtomicType atomic; + + atomic.store(val, eastl::memory_order_relaxed); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == val); + } +} + +void AtomicVoidPointerBasicTest::TestLoad() +{ + { + AtomicType atomic{ (PtrType)0x4 }; + + PtrType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic == (PtrType)0x4); + } +} + +void AtomicVoidPointerBasicTest::TestExchange() +{ + { + AtomicType atomic; + + PtrType ret = atomic.exchange((PtrType)0x4, eastl::memory_order_release); + + VERIFY(ret == (PtrType)0x0); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } +} + +void AtomicVoidPointerBasicTest::TestCompareExchangeWeak() +{ + { + AtomicType atomic; + + PtrType observed = (PtrType)0x0; + bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + if (ret) + { + VERIFY(ret == true); + VERIFY(observed == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + } + + { + AtomicType atomic; + + PtrType observed = (PtrType)0x4; + bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + VERIFY(ret == false); + VERIFY(observed == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } +} + +void AtomicVoidPointerBasicTest::TestCompareExchangeStrong() +{ + { + AtomicType atomic; + + PtrType observed = (PtrType)0x0; + bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + VERIFY(ret == true); + VERIFY(observed == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + + { + AtomicType atomic; + + PtrType observed = (PtrType)0x4; + bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + VERIFY(ret == false); + VERIFY(observed == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } +} + +void AtomicVoidPointerBasicTest::TestAllMemoryOrders() +{ + { + AtomicType atomic; + PtrType val = (PtrType)0x4; + + atomic.store(val); + + atomic.store(val, eastl::memory_order_relaxed); + + atomic.store(val, eastl::memory_order_release); + + atomic.store(val, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + PtrType ret = atomic.load(); + + ret = atomic.load(eastl::memory_order_relaxed); + + ret = atomic.load(eastl::memory_order_acquire); + + ret = atomic.load(eastl::memory_order_seq_cst); + + ret = atomic.load(eastl::memory_order_read_depends); + } + + { + AtomicType atomic; + + PtrType ret = atomic.exchange((PtrType)0x4); + + ret = atomic.exchange((PtrType)0x4, eastl::memory_order_relaxed); + + ret = atomic.exchange((PtrType)0x4, eastl::memory_order_acquire); + + ret = atomic.exchange((PtrType)0x4, eastl::memory_order_release); + + ret = atomic.exchange((PtrType)0x4, eastl::memory_order_acq_rel); + + ret = atomic.exchange((PtrType)0x4, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + PtrType observed = (PtrType)0x0; + + bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_release); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + PtrType observed = (PtrType)0x0; + + bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_release); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + PtrType observed = (PtrType)0x0; + bool ret; + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_release, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + PtrType observed = (PtrType)0x0; + bool ret; + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_release, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); + } +} + +class AtomicPointerBasicTest +{ +public: + + using AtomicType = eastl::atomic; + using PtrType = uint32_t*; + + int RunTest() + { + TestAtomicCtor(); + + TestAssignmentOperators(); + + TestIsLockFree(); + + TestStore(); + + TestLoad(); + + TestExchange(); + + TestCompareExchangeWeak(); + + TestCompareExchangeStrong(); + + TestAllMemoryOrders(); + + TestFetchAdd(); + TestAddFetch(); + + TestFetchSub(); + TestSubFetch(); + + TestAtomicPointerStandalone(); + + return nErrorCount; + } + +private: + + void TestAtomicCtor(); + + void TestAssignmentOperators(); + + void TestIsLockFree(); + + void TestStore(); + + void TestLoad(); + + void TestExchange(); + + void TestCompareExchangeWeak(); + + void TestCompareExchangeStrong(); + + void TestAllMemoryOrders(); + + void TestFetchAdd(); + void TestAddFetch(); + + void TestFetchSub(); + void TestSubFetch(); + + void TestAtomicPointerStandalone(); + +private: + + int nErrorCount = 0; +}; + +void AtomicPointerBasicTest::TestAtomicCtor() +{ + { + AtomicType atomic{}; + + PtrType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == nullptr); + } + + { + AtomicType atomic{ (PtrType)0x4 }; + + PtrType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x4); + } +} + +void AtomicPointerBasicTest::TestAssignmentOperators() +{ + { + PtrType val = (PtrType)0x4; + AtomicType atomic{val}; + + PtrType expected = (PtrType)0x8; + + PtrType ret = atomic = expected; + + VERIFY(ret == expected); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } + + { + PtrType val = (PtrType)0x0; + AtomicType atomic{val}; + + PtrType ret = atomic = val; + + VERIFY(ret == val); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == val); + } + + { + PtrType val = (PtrType)0x4; + AtomicType atomic{val}; + + PtrType expected = (PtrType)0x8; + PtrType ret = ++atomic; + + VERIFY(ret == expected); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } + + { + PtrType val = (PtrType)0x4; + + AtomicType atomic{val}; + + PtrType expected = (PtrType)0x8; + PtrType ret = atomic++; + + VERIFY(ret == val); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } + + { + PtrType val = (PtrType)0x4; + AtomicType atomic{val}; + + PtrType expected = (PtrType)0x10; + PtrType ret = atomic += 3; + + VERIFY(ret == expected); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } + + { + PtrType val = (PtrType)0x4; + AtomicType atomic{val}; + + PtrType expected = (PtrType)0x4; + PtrType ret = atomic += 0; + + VERIFY(ret == expected); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } + + { + PtrType val = (PtrType)0x4; + AtomicType atomic{val}; + + PtrType expected = (PtrType)0x0; + PtrType ret = atomic -= 1; + + VERIFY(ret == expected); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } + + { + PtrType val = (PtrType)0x4; + AtomicType atomic{val}; + + PtrType expected = (PtrType)0x4; + PtrType ret = atomic -= 0; + + VERIFY(ret == expected); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } +} + +void AtomicPointerBasicTest::TestIsLockFree() +{ + { + AtomicType atomic; + + VERIFY(atomic.is_lock_free() == true); + + VERIFY(atomic.is_always_lock_free == true); + } +} + +void AtomicPointerBasicTest::TestStore() +{ + { + PtrType val = (PtrType)0x0; + AtomicType atomic; + + atomic.store(val, eastl::memory_order_relaxed); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == val); + } + + { + PtrType val = (PtrType)0x4; + AtomicType atomic; + + atomic.store(val, eastl::memory_order_relaxed); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == val); + } +} + +void AtomicPointerBasicTest::TestLoad() +{ + { + AtomicType atomic{ (PtrType)0x4 }; + + PtrType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic == (PtrType)0x4); + } +} + +void AtomicPointerBasicTest::TestCompareExchangeWeak() +{ + { + AtomicType atomic; + + PtrType observed = (PtrType)0x0; + bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + if (ret) + { + VERIFY(ret == true); + VERIFY(observed == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + } + + { + AtomicType atomic; + + PtrType observed = (PtrType)0x4; + bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + VERIFY(ret == false); + VERIFY(observed == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } +} + +void AtomicPointerBasicTest::TestCompareExchangeStrong() +{ + { + AtomicType atomic; + + PtrType observed = (PtrType)0x0; + bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + VERIFY(ret == true); + VERIFY(observed == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + + { + AtomicType atomic; + + PtrType observed = (PtrType)0x4; + bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + VERIFY(ret == false); + VERIFY(observed == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } +} + +void AtomicPointerBasicTest::TestExchange() +{ + { + AtomicType atomic; + + PtrType ret = atomic.exchange((PtrType)0x4, eastl::memory_order_release); + + VERIFY(ret == (PtrType)0x0); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } +} + +void AtomicPointerBasicTest::TestAllMemoryOrders() +{ + { + AtomicType atomic; + PtrType val = (PtrType)0x4; + + atomic.store(val); + + atomic.store(val, eastl::memory_order_relaxed); + + atomic.store(val, eastl::memory_order_release); + + atomic.store(val, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + PtrType ret = atomic.load(); + + ret = atomic.load(eastl::memory_order_relaxed); + + ret = atomic.load(eastl::memory_order_acquire); + + ret = atomic.load(eastl::memory_order_seq_cst); + + ret = atomic.load(eastl::memory_order_read_depends); + } + + { + AtomicType atomic; + + PtrType ret = atomic.fetch_add(0); + + ret = atomic.fetch_add(0, eastl::memory_order_relaxed); + + ret = atomic.fetch_add(0, eastl::memory_order_acquire); + + ret = atomic.fetch_add(0, eastl::memory_order_release); + + ret = atomic.fetch_add(0, eastl::memory_order_acq_rel); + + ret = atomic.fetch_add(0, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + PtrType ret = atomic.fetch_sub(0); + + ret = atomic.fetch_sub(0, eastl::memory_order_relaxed); + + ret = atomic.fetch_sub(0, eastl::memory_order_acquire); + + ret = atomic.fetch_sub(0, eastl::memory_order_release); + + ret = atomic.fetch_sub(0, eastl::memory_order_acq_rel); + + ret = atomic.fetch_sub(0, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + PtrType ret = atomic.add_fetch(0); + + ret = atomic.add_fetch(0, eastl::memory_order_relaxed); + + ret = atomic.add_fetch(0, eastl::memory_order_acquire); + + ret = atomic.add_fetch(0, eastl::memory_order_release); + + ret = atomic.add_fetch(0, eastl::memory_order_acq_rel); + + ret = atomic.add_fetch(0, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + PtrType ret = atomic.sub_fetch(0); + + ret = atomic.sub_fetch(0, eastl::memory_order_relaxed); + + ret = atomic.sub_fetch(0, eastl::memory_order_acquire); + + ret = atomic.sub_fetch(0, eastl::memory_order_release); + + ret = atomic.sub_fetch(0, eastl::memory_order_acq_rel); + + ret = atomic.sub_fetch(0, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + PtrType ret = atomic.exchange((PtrType)0x4); + + ret = atomic.exchange((PtrType)0x4, eastl::memory_order_relaxed); + + ret = atomic.exchange((PtrType)0x4, eastl::memory_order_acquire); + + ret = atomic.exchange((PtrType)0x4, eastl::memory_order_release); + + ret = atomic.exchange((PtrType)0x4, eastl::memory_order_acq_rel); + + ret = atomic.exchange((PtrType)0x4, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + PtrType observed = (PtrType)0x0; + + bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_release); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + PtrType observed = (PtrType)0x0; + + bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_release); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + PtrType observed = (PtrType)0x0; + bool ret; + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_release, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + PtrType observed = (PtrType)0x0; + bool ret; + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_release, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); + } +} + +void AtomicPointerBasicTest::TestFetchAdd() +{ + { + PtrType val = (PtrType)0x4; + AtomicType atomic{ val }; + + PtrType ret = atomic.fetch_add(1, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x8); + } + + { + PtrType val = (PtrType)0x4; + AtomicType atomic{ val }; + + PtrType ret = atomic.fetch_add(0, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } +} + +void AtomicPointerBasicTest::TestAddFetch() +{ + { + PtrType val = (PtrType)0x4; + AtomicType atomic{ val }; + + PtrType ret = atomic.add_fetch(1, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x8); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x8); + } + + { + PtrType val = (PtrType)0x4; + AtomicType atomic{ val }; + + PtrType ret = atomic.add_fetch(0, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } +} + +void AtomicPointerBasicTest::TestFetchSub() +{ + { + PtrType val = (PtrType)0x4; + AtomicType atomic{ val }; + + PtrType ret = atomic.fetch_sub(1, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } + + { + PtrType val = (PtrType)0x4; + AtomicType atomic{ val }; + + PtrType ret = atomic.fetch_sub(0, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } +} + +void AtomicPointerBasicTest::TestSubFetch() +{ + { + PtrType val = (PtrType)0x4; + AtomicType atomic{ val }; + + PtrType ret = atomic.sub_fetch(1, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x0); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } + + { + PtrType val = (PtrType)0x4; + AtomicType atomic{ val }; + + PtrType ret = atomic.sub_fetch(0, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } +} + +void AtomicPointerBasicTest::TestAtomicPointerStandalone() +{ + { + AtomicType atomic; + + VERIFY(atomic_is_lock_free(&atomic) == true); + } + + { + AtomicType atomic; + PtrType val = (PtrType)0x4; + + atomic_store(&atomic, val); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == val); + } + + { + AtomicType atomic; + PtrType val = (PtrType)0x4; + + atomic_store_explicit(&atomic, val, eastl::memory_order_relaxed); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == val); + } + + { + AtomicType atomic; + + PtrType ret = atomic_load(&atomic); + + VERIFY(ret == (PtrType)0x0); + } + + { + AtomicType atomic; + + PtrType ret = atomic_load_explicit(&atomic, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x0); + } + + { + AtomicType atomic; + + PtrType ret = atomic_load_cond(&atomic, [](PtrType val) { return true; }); + + VERIFY(ret == (PtrType)0x0); + } + + { + AtomicType atomic; + + PtrType ret = atomic_load_cond_explicit(&atomic, [](PtrType val) { return true; }, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x0); + } + + { + AtomicType atomic; + + PtrType ret = atomic_exchange(&atomic, (PtrType)0x4); + + VERIFY(ret == (PtrType)0x0); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + + { + AtomicType atomic; + + PtrType ret = atomic_exchange_explicit(&atomic, (PtrType)0x4, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x0); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + + { + AtomicType atomic; + + PtrType ret = atomic_add_fetch(&atomic, 1); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + + { + AtomicType atomic; + + PtrType ret = atomic_add_fetch_explicit(&atomic, 1, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + + { + AtomicType atomic; + + PtrType ret = atomic_fetch_add(&atomic, 1); + + VERIFY(ret == (PtrType)0x0); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + + { + AtomicType atomic; + + PtrType ret = atomic_fetch_add_explicit(&atomic, 1, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x0); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + + { + AtomicType atomic{ (PtrType)0x4 }; + + PtrType ret = atomic_fetch_sub(&atomic, 1); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } + + { + AtomicType atomic{ (PtrType)0x4 }; + + PtrType ret = atomic_fetch_sub_explicit(&atomic, 1, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } + + { + AtomicType atomic{ (PtrType)0x4 }; + + PtrType ret = atomic_sub_fetch(&atomic, 1); + + VERIFY(ret == (PtrType)0x0); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } + + { + AtomicType atomic{ (PtrType)0x4 }; + + PtrType ret = atomic_sub_fetch_explicit(&atomic, 1, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x0); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } + + { + AtomicType atomic; + + PtrType expected = (PtrType)0x0; + bool ret = atomic_compare_exchange_strong(&atomic, &expected, (PtrType)0x4); + + VERIFY(ret == true); + + VERIFY(expected == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + + { + AtomicType atomic; + + PtrType expected = (PtrType)0x0; + bool ret = atomic_compare_exchange_strong_explicit(&atomic, &expected, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + VERIFY(ret == true); + + VERIFY(expected == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + + { + AtomicType atomic; + + PtrType expected = (PtrType)0x0; + bool ret = atomic_compare_exchange_weak(&atomic, &expected, (PtrType)0x4); + + if (ret) + { + VERIFY(ret == true); + + VERIFY(expected == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + } + + { + AtomicType atomic; + + PtrType expected = (PtrType)0x0; + bool ret = atomic_compare_exchange_weak_explicit(&atomic, &expected, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + if (ret) + { + VERIFY(ret == true); + + VERIFY(expected == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + } +} + +struct AtomicNonTriviallyConstructible +{ + AtomicNonTriviallyConstructible() + : a(0) + , b(0) + { + } + + AtomicNonTriviallyConstructible(uint16_t a, uint16_t b) + : a(a) + , b(b) + { + } + + friend bool operator==(const AtomicNonTriviallyConstructible& a, const AtomicNonTriviallyConstructible& b) + { + return a.a == b.a && a.b == b.b; + } + + uint16_t a; + uint16_t b; +}; + +struct AtomicNonTriviallyConstructibleNoExcept +{ + AtomicNonTriviallyConstructibleNoExcept() noexcept + : a(0) + , b(0) + { + } + + AtomicNonTriviallyConstructibleNoExcept(uint16_t a, uint16_t b) noexcept + : a(a) + , b(b) + { + } + + friend bool operator==(const AtomicNonTriviallyConstructibleNoExcept& a, const AtomicNonTriviallyConstructibleNoExcept& b) + { + return a.a == b.a && a.b == b.b; + } + + uint16_t a; + uint16_t b; +}; + +struct AtomicUserType16 +{ + uint8_t a; + uint8_t b; + + friend bool operator==(const AtomicUserType16& a, const AtomicUserType16& b) + { + return (a.a == b.a) && (a.b == b.b); + } +}; + +struct AtomicUserType128 +{ + uint32_t a; + uint32_t b; + uint32_t c; + uint32_t d; + + AtomicUserType128() = default; + + AtomicUserType128(const AtomicUserType128&) = default; + + AtomicUserType128(uint32_t a, uint32_t b) + : a(a) + , b(b) + , c(0) + , d(0) + { + } + + AtomicUserType128& operator=(const AtomicUserType128&) = default; + + friend bool operator==(const AtomicUserType128& a, const AtomicUserType128& b) + { + return (a.a == b.a) && (a.b == b.b) && (a.c == b.c) && (a.d == b.d); + } +}; + +template +class AtomicUserTypeBasicTest +{ +public: + + using AtomicType = eastl::atomic; + using UserType = T; + + int RunTest() + { + TestAtomicCtor(); + + TestAssignmentOperators(); + + TestIsLockFree(); + + TestStore(); + + TestLoad(); + + TestExchange(); + + TestCompareExchangeWeak(); + + TestCompareExchangeStrong(); + + TestAllMemoryOrders(); + + return nErrorCount; + } + +private: + + void TestAtomicCtor(); + + void TestAssignmentOperators(); + + void TestIsLockFree(); + + void TestStore(); + + void TestLoad(); + + void TestExchange(); + + void TestCompareExchangeWeak(); + + void TestCompareExchangeStrong(); + + void TestAllMemoryOrders(); + +private: + + int nErrorCount = 0; +}; + +template +void AtomicUserTypeBasicTest::TestAtomicCtor() +{ + { + AtomicType atomic; + UserType expected{0, 0}; + + UserType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == expected); + } + + { + AtomicType atomic{ {5, 8} }; + UserType expected{5, 8}; + + UserType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == expected); + } +} + +template +void AtomicUserTypeBasicTest::TestAssignmentOperators() +{ + { + AtomicType atomic; + UserType expected{5, 6}; + + atomic = {5, 6}; + + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } + + { + AtomicType atomic; + UserType expected{0, 0}; + + atomic = {0, 0}; + + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } +} + +template +void AtomicUserTypeBasicTest::TestIsLockFree() +{ + { + AtomicType atomic; + + VERIFY(atomic.is_lock_free() == true); + + VERIFY(AtomicType::is_always_lock_free == true); + } +} + +template +void AtomicUserTypeBasicTest::TestStore() +{ + { + AtomicType atomic; + UserType expected{5, 6}; + + atomic.store(expected, eastl::memory_order_relaxed); + + UserType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == expected); + } + + { + AtomicType atomic; + UserType expected{5, 6}; + + atomic.store({5, 6}, eastl::memory_order_relaxed); + + UserType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == expected); + } +} + +template +void AtomicUserTypeBasicTest::TestLoad() +{ + { + AtomicType atomic; + UserType expected{0, 0}; + + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + + VERIFY(atomic == expected); + } + + { + AtomicType atomic{ {5, 6} }; + UserType expected{5, 6}; + + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + + VERIFY(atomic == expected); + } +} + +template +void AtomicUserTypeBasicTest::TestExchange() +{ + { + AtomicType atomic; + UserType expected{0, 0}; + + UserType ret = atomic.exchange({0, 0}, eastl::memory_order_relaxed); + + VERIFY(ret == expected); + } + + { + AtomicType atomic; + UserType expected{0, 0}; + UserType expected2{0, 1}; + + UserType ret = atomic.exchange({0, 1}, eastl::memory_order_relaxed); + + VERIFY(ret == expected); + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected2); + } +} + +template +void AtomicUserTypeBasicTest::TestCompareExchangeWeak() +{ + { + AtomicType atomic; + + UserType observed{0, 0}; + bool ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_relaxed); + + UserType expected{0, 0}; + if (ret) + { + VERIFY(ret == true); + VERIFY(observed == expected); + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } + } + + { + AtomicType atomic; + + UserType observed{0, 0}; + bool ret = atomic.compare_exchange_weak(observed, {0, 1}, eastl::memory_order_relaxed); + + UserType expected{0, 1}; + UserType expected2{0, 0}; + if (ret) + { + VERIFY(ret == true); + VERIFY(observed == expected2); + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } + } + + { + AtomicType atomic; + + UserType observed{0, 1}; + bool ret = atomic.compare_exchange_weak(observed, {0, 1}, eastl::memory_order_relaxed); + + UserType expected{0, 0}; + + VERIFY(ret == false); + VERIFY(observed == expected); + } +} + +template +void AtomicUserTypeBasicTest::TestCompareExchangeStrong() +{ + { + AtomicType atomic; + + UserType observed{0, 0}; + bool ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_relaxed); + + UserType expected{0, 0}; + + VERIFY(ret == true); + VERIFY(observed == expected); + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } + + { + AtomicType atomic; + + UserType observed{0, 0}; + bool ret = atomic.compare_exchange_strong(observed, {0, 1}, eastl::memory_order_relaxed); + + UserType expected{0, 1}; + UserType expected2{0, 0}; + + VERIFY(ret == true); + VERIFY(observed == expected2); + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } + + { + AtomicType atomic; + + UserType observed{0, 1}; + bool ret = atomic.compare_exchange_strong(observed, {0, 1}, eastl::memory_order_relaxed); + + UserType expected{0, 0}; + + VERIFY(ret == false); + VERIFY(observed == expected); + } +} + +template +void AtomicUserTypeBasicTest::TestAllMemoryOrders() +{ + { + AtomicType atomic; + UserType val{0, 1}; + + atomic.store(val); + + atomic.store(val, eastl::memory_order_relaxed); + + atomic.store(val, eastl::memory_order_release); + + atomic.store(val, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + UserType ret = atomic.load(); + + ret = atomic.load(eastl::memory_order_relaxed); + + ret = atomic.load(eastl::memory_order_acquire); + + ret = atomic.load(eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + UserType ret = atomic.exchange({0, 1}); + + ret = atomic.exchange({0, 0}, eastl::memory_order_relaxed); + + ret = atomic.exchange({0, 0}, eastl::memory_order_acquire); + + ret = atomic.exchange({0, 0}, eastl::memory_order_release); + + ret = atomic.exchange({0, 0}, eastl::memory_order_acq_rel); + + ret = atomic.exchange({0, 0}, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + UserType observed{0, 0}; + + bool ret = atomic.compare_exchange_weak(observed, {0, 0}); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_release); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acq_rel); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + UserType observed{0, 0}; + + bool ret = atomic.compare_exchange_strong(observed, {0, 0}); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_release); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acq_rel); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + UserType observed{0, 0}; + bool ret; + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acquire, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acquire, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_release, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acq_rel, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + UserType observed{0, 0}; + bool ret; + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acquire, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acquire, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_release, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acq_rel, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); + } +} + + +class AtomicBoolBasicTest +{ +public: + + using AtomicType = eastl::atomic; + using BoolType = bool; + + int RunTest() + { + TestAtomicCtor(); + + TestAssignmentOperators(); + + TestIsLockFree(); + + TestStore(); + + TestLoad(); + + TestExchange(); + + TestCompareExchangeWeak(); + + TestCompareExchangeStrong(); + + TestAllMemoryOrders(); + + return nErrorCount; + } + +private: + + void TestAtomicCtor(); + + void TestAssignmentOperators(); + + void TestIsLockFree(); + + void TestStore(); + + void TestLoad(); + + void TestExchange(); + + void TestCompareExchangeWeak(); + + void TestCompareExchangeStrong(); + + void TestAllMemoryOrders(); + +private: + + int nErrorCount = 0; +}; + +void AtomicBoolBasicTest::TestAtomicCtor() +{ + { + AtomicType atomic{ false }; + + BoolType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == false); + } + + { + AtomicType atomic{ true }; + + BoolType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == true); + } + + { + AtomicType atomic; + + BoolType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == false); + } + + { + AtomicType atomic{}; + + BoolType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == false); + } +} + +void AtomicBoolBasicTest::TestAssignmentOperators() +{ + { + AtomicType atomic; + + BoolType ret = atomic = true; + + VERIFY(ret == true); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == true); + } +} + +void AtomicBoolBasicTest::TestIsLockFree() +{ + { + AtomicType atomic; + + bool ret = atomic.is_lock_free(); + + VERIFY(ret == true); + + VERIFY(AtomicType::is_always_lock_free == true); + } +} + +void AtomicBoolBasicTest::TestStore() +{ + { + AtomicType atomic; + + atomic.store(true, eastl::memory_order_relaxed); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == true); + } +} + +void AtomicBoolBasicTest::TestLoad() +{ + { + AtomicType atomic; + + VERIFY(atomic.load(eastl::memory_order_relaxed) == false); + + VERIFY(atomic == false); + } + + { + AtomicType atomic{ true }; + + VERIFY(atomic.load(eastl::memory_order_relaxed) == true); + + VERIFY(atomic == true); + } +} + +void AtomicBoolBasicTest::TestExchange() +{ + { + AtomicType atomic; + + BoolType ret = atomic.exchange(false, eastl::memory_order_relaxed); + + VERIFY(ret == false); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == false); + } + + { + AtomicType atomic; + + BoolType ret = atomic.exchange(true, eastl::memory_order_relaxed); + + VERIFY(ret == false); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == true); + } +} + +void AtomicBoolBasicTest::TestCompareExchangeWeak() +{ + { + AtomicType atomic{ false }; + + BoolType observed = false; + bool ret = atomic.compare_exchange_weak(observed, false, eastl::memory_order_relaxed); + + if (ret) + { + VERIFY(ret == true); + VERIFY(observed == false); + VERIFY(atomic.load(eastl::memory_order_relaxed) == false); + } + } + + { + AtomicType atomic{ false }; + + BoolType observed = false; + bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); + + if (ret) + { + VERIFY(ret == true); + VERIFY(observed == false); + VERIFY(atomic.load(eastl::memory_order_relaxed) == true); + } + } + + { + AtomicType atomic{ false }; + + BoolType observed = true; + bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); + + VERIFY(ret == false); + VERIFY(observed == false); + } +} + +void AtomicBoolBasicTest::TestCompareExchangeStrong() +{ + { + AtomicType atomic{ false }; + + BoolType observed = false; + bool ret = atomic.compare_exchange_weak(observed, false, eastl::memory_order_relaxed); + + VERIFY(ret == true); + VERIFY(observed == false); + VERIFY(atomic.load(eastl::memory_order_relaxed) == false); + } + + { + AtomicType atomic{ false }; + + BoolType observed = false; + bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); + + VERIFY(ret == true); + VERIFY(observed == false); + VERIFY(atomic.load(eastl::memory_order_relaxed) == true); + } + + { + AtomicType atomic{ false }; + + BoolType observed = true; + bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); + + VERIFY(ret == false); + VERIFY(observed == false); + } +} + +void AtomicBoolBasicTest::TestAllMemoryOrders() +{ + { + AtomicType atomic; + + atomic.store(true); + + atomic.store(true, eastl::memory_order_relaxed); + + atomic.store(true, eastl::memory_order_release); + + atomic.store(true, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + BoolType ret = atomic.load(); + + ret = atomic.load(eastl::memory_order_relaxed); + + ret = atomic.load(eastl::memory_order_acquire); + + ret = atomic.load(eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + BoolType ret = atomic.exchange(true); + + ret = atomic.exchange(true, eastl::memory_order_relaxed); + + ret = atomic.exchange(true, eastl::memory_order_acquire); + + ret = atomic.exchange(true, eastl::memory_order_release); + + ret = atomic.exchange(true, eastl::memory_order_acq_rel); + + ret = atomic.exchange(true, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + BoolType observed = false; + bool ret = atomic.compare_exchange_weak(observed, true); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_release); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acq_rel); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + BoolType observed = false; + bool ret = atomic.compare_exchange_strong(observed, true); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_release); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acq_rel); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + BoolType observed = false; + bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acquire, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acquire, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_release, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acq_rel, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + BoolType observed = false; + bool ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acquire, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acquire, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_release, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acq_rel, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); + } +} + + +template +class AtomicIntegralBasicTest +{ +public: + + using AtomicType = eastl::atomic; + using IntegralType = T; + + int RunTest() + { + TestAtomicCtor(); + + TestAtomicFetchAdd(); + TestAtomicAddFetch(); + + TestAtomicFetchSub(); + TestAtomicSubFetch(); + + TestAtomicFetchAnd(); + TestAtomicAndFetch(); + + TestAtomicFetchOr(); + TestAtomicOrFetch(); + + TestAtomicFetchXor(); + TestAtomicXorFetch(); + + TestAssignmentOperators(); + + TestIsLockFree(); + + TestStore(); + + TestLoad(); + + TestExchange(); + + TestCompareExchangeWeak(); + + TestCompareExchangeStrong(); + + TestAllMemoryOrders(); + + TestAtomicStandalone(); + + return nErrorCount; + } + +private: + + void TestAtomicCtor(); + + void TestAtomicFetchAdd(); + void TestAtomicAddFetch(); + + void TestAtomicFetchSub(); + void TestAtomicSubFetch(); + + void TestAtomicFetchAnd(); + void TestAtomicAndFetch(); + + void TestAtomicFetchOr(); + void TestAtomicOrFetch(); + + void TestAtomicFetchXor(); + void TestAtomicXorFetch(); + + void TestAssignmentOperators(); + + void TestIsLockFree(); + + void TestStore(); + + void TestLoad(); + + void TestExchange(); + + void TestCompareExchangeWeak(); + + void TestCompareExchangeStrong(); + + void TestAllMemoryOrders(); + + void TestAtomicStandalone(); + +private: + + int nErrorCount = 0; +}; + +template +void AtomicIntegralBasicTest::TestAtomicCtor() +{ + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 1 }; + + IntegralType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 1); + } + + { + AtomicType atomic{ 20 }; + + IntegralType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 20); + } + + { + AtomicType atomic; + + IntegralType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } +} + +template +void AtomicIntegralBasicTest::TestAtomicFetchAdd() +{ + { + AtomicType atomic; + + IntegralType ret = atomic.fetch_add(1, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic.fetch_add(0, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 5 }; + + IntegralType ret = atomic.fetch_add(0, eastl::memory_order_relaxed); + + VERIFY(ret == 5); + + ret = atomic.fetch_add(4, eastl::memory_order_relaxed); + + VERIFY(ret == 5); + + ret = atomic.fetch_add(1, eastl::memory_order_relaxed); + + VERIFY(ret == 9); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 10); + } +} + +template +void AtomicIntegralBasicTest::TestAtomicAddFetch() +{ + { + AtomicType atomic; + + IntegralType ret = atomic.add_fetch(1, eastl::memory_order_relaxed); + + VERIFY(ret == 1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic.add_fetch(0, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 5 }; + + IntegralType ret = atomic.add_fetch(0, eastl::memory_order_relaxed); + + VERIFY(ret == 5); + + ret = atomic.add_fetch(4, eastl::memory_order_relaxed); + + VERIFY(ret == 9); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 9); + } +} + +template +void AtomicIntegralBasicTest::TestAtomicFetchSub() +{ + { + AtomicType atomic{ 1 }; + + IntegralType ret = atomic.fetch_sub(1, eastl::memory_order_relaxed); + + VERIFY(ret == 1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 1 }; + + IntegralType ret = atomic.fetch_sub(0, eastl::memory_order_relaxed); + + VERIFY(ret == 1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 1); + } + + { + AtomicType atomic{ 5 }; + + IntegralType ret = atomic.fetch_sub(2, eastl::memory_order_relaxed); + + VERIFY(ret == 5); + + ret = atomic.fetch_sub(1, eastl::memory_order_relaxed); + + VERIFY(ret == 3); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 2); + } +} + +template +void AtomicIntegralBasicTest::TestAtomicSubFetch() +{ + { + AtomicType atomic{ 1 }; + + IntegralType ret = atomic.sub_fetch(1, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 1 }; + + IntegralType ret = atomic.sub_fetch(0, eastl::memory_order_relaxed); + + VERIFY(ret == 1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 1); + } + + { + AtomicType atomic{ 5 }; + + IntegralType ret = atomic.sub_fetch(2, eastl::memory_order_relaxed); + + VERIFY(ret == 3); + + ret = atomic.sub_fetch(1, eastl::memory_order_relaxed); + + VERIFY(ret == 2); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 2); + } +} + +template +void AtomicIntegralBasicTest::TestAtomicFetchAnd() +{ + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic.fetch_and(0x0, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic.fetch_and(0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 0xF }; + + IntegralType ret = atomic.fetch_and(0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0xF); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0X1); + } + + { + AtomicType atomic{ 0xF }; + + IntegralType ret = atomic.fetch_and(0xF0, eastl::memory_order_relaxed); + + VERIFY(ret == 0xF); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + } +} + +template +void AtomicIntegralBasicTest::TestAtomicAndFetch() +{ + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic.and_fetch(0x0, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic.and_fetch(0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 0xF }; + + IntegralType ret = atomic.and_fetch(0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + } + + { + AtomicType atomic{ 0xF }; + + IntegralType ret = atomic.and_fetch(0xF0, eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + } +} + +template +void AtomicIntegralBasicTest::TestAtomicFetchOr() +{ + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic.fetch_or(0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic.fetch_or(0x0, eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic.fetch_or(0x2, eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x3); + } +} + +template +void AtomicIntegralBasicTest::TestAtomicOrFetch() +{ + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic.or_fetch(0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic.or_fetch(0x0, eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic.or_fetch(0x2, eastl::memory_order_relaxed); + + VERIFY(ret == 0x3); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x3); + } +} + +template +void AtomicIntegralBasicTest::TestAtomicFetchXor() +{ + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic.fetch_xor(0x0, eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic.fetch_xor(0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + } + + { + AtomicType atomic{ 0x0 }; + + IntegralType ret = atomic.fetch_xor(0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + } +} + +template +void AtomicIntegralBasicTest::TestAtomicXorFetch() +{ + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic.xor_fetch(0x0, eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic.xor_fetch(0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + } + + { + AtomicType atomic{ 0x0 }; + + IntegralType ret = atomic.xor_fetch(0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + } +} + +template +void AtomicIntegralBasicTest::TestAssignmentOperators() +{ + { + AtomicType atomic{ 0 }; + + IntegralType ret = (atomic = 5); + + VERIFY(ret == 5); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 5); + } + + { + AtomicType atomic{ 0 }; + + IntegralType ret = ++atomic; + + VERIFY(ret == 1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 1); + } + + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic++; + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 1); + } + + { + AtomicType atomic{ 1 }; + + IntegralType ret = --atomic; + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 1 }; + + IntegralType ret = atomic--; + + VERIFY(ret == 1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic += 5; + + VERIFY(ret == 5); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 5); + } + + { + AtomicType atomic{ 5 }; + + IntegralType ret = atomic -= 3; + + VERIFY(ret == 2); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 2); + } + + { + AtomicType atomic{ 0x0 }; + + IntegralType ret = atomic |= 0x1; + + VERIFY(ret == 0x1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic &= 0x1; + + VERIFY(ret == 0x1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic ^= 0x1; + + VERIFY(ret == 0x0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + } +} + +template +void AtomicIntegralBasicTest::TestIsLockFree() +{ + { + const AtomicType atomic{ 5 }; + + VERIFY(atomic.is_lock_free() == true); + + VERIFY(AtomicType::is_always_lock_free == true); + } +} + +template +void AtomicIntegralBasicTest::TestStore() +{ + { + AtomicType atomic{ 0 }; + + atomic.store(0, eastl::memory_order_relaxed); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); + } + + { + AtomicType atomic{ 0 }; + + atomic.store(1, eastl::memory_order_relaxed); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } +} + +template +void AtomicIntegralBasicTest::TestLoad() +{ + { + AtomicType atomic{ 0 }; + + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); + + bool ret = atomic == 0; + VERIFY(ret == true); + + VERIFY(atomic == 0); + } + + { + AtomicType atomic{ 5 }; + + VERIFY(atomic.load(eastl::memory_order_relaxed) == 5); + + bool ret = atomic == 5; + VERIFY(ret == true); + + VERIFY(atomic == 5); + } +} + +template +void AtomicIntegralBasicTest::TestExchange() +{ + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic.exchange(0, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic.exchange(1, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 1); + } +} + +template +void AtomicIntegralBasicTest::TestCompareExchangeWeak() +{ + { + AtomicType atomic{ 0 }; + + IntegralType observed = 0; + bool ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_relaxed); + + if (ret == true) + { + VERIFY(ret == true); + VERIFY(observed == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + } + + { + AtomicType atomic{ 0 }; + + IntegralType observed = 1; + bool ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_relaxed); + + VERIFY(ret == false); + VERIFY(observed == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); + } +} + +template +void AtomicIntegralBasicTest::TestCompareExchangeStrong() +{ + { + AtomicType atomic{ 0 }; + + IntegralType observed = 0; + bool ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_relaxed); + + VERIFY(ret == true); + VERIFY(observed == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + + { + AtomicType atomic{ 0 }; + + IntegralType observed = 1; + bool ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_relaxed); + + VERIFY(ret == false); + VERIFY(observed == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); + } +} + +template +void AtomicIntegralBasicTest::TestAllMemoryOrders() +{ + { + AtomicType atomic{}; + + atomic.store(1); + + atomic.store(1, eastl::memory_order_relaxed); + + atomic.store(1, eastl::memory_order_release); + + atomic.store(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.load(); + + ret = atomic.load(eastl::memory_order_relaxed); + + ret = atomic.load(eastl::memory_order_acquire); + + ret = atomic.load(eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.exchange(1); + + ret = atomic.exchange(1, eastl::memory_order_relaxed); + + ret = atomic.exchange(1, eastl::memory_order_acquire); + + ret = atomic.exchange(1, eastl::memory_order_release); + + ret = atomic.exchange(1, eastl::memory_order_acq_rel); + + ret = atomic.exchange(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.fetch_add(1); + + ret = atomic.fetch_add(1, eastl::memory_order_relaxed); + + ret = atomic.fetch_add(1, eastl::memory_order_acquire); + + ret = atomic.fetch_add(1, eastl::memory_order_release); + + ret = atomic.fetch_add(1, eastl::memory_order_acq_rel); + + ret = atomic.fetch_add(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.add_fetch(1); + + ret = atomic.add_fetch(1, eastl::memory_order_relaxed); + + ret = atomic.add_fetch(1, eastl::memory_order_acquire); + + ret = atomic.add_fetch(1, eastl::memory_order_release); + + ret = atomic.add_fetch(1, eastl::memory_order_acq_rel); + + ret = atomic.add_fetch(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.fetch_sub(1); + + ret = atomic.fetch_sub(1, eastl::memory_order_relaxed); + + ret = atomic.fetch_sub(1, eastl::memory_order_acquire); + + ret = atomic.fetch_sub(1, eastl::memory_order_release); + + ret = atomic.fetch_sub(1, eastl::memory_order_acq_rel); + + ret = atomic.fetch_sub(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.sub_fetch(1); + + ret = atomic.sub_fetch(1, eastl::memory_order_relaxed); + + ret = atomic.sub_fetch(1, eastl::memory_order_acquire); + + ret = atomic.sub_fetch(1, eastl::memory_order_release); + + ret = atomic.sub_fetch(1, eastl::memory_order_acq_rel); + + ret = atomic.sub_fetch(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.fetch_and(1); + + ret = atomic.fetch_and(1, eastl::memory_order_relaxed); + + ret = atomic.fetch_and(1, eastl::memory_order_acquire); + + ret = atomic.fetch_and(1, eastl::memory_order_release); + + ret = atomic.fetch_and(1, eastl::memory_order_acq_rel); + + ret = atomic.fetch_and(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.and_fetch(1); + + ret = atomic.and_fetch(1, eastl::memory_order_relaxed); + + ret = atomic.and_fetch(1, eastl::memory_order_acquire); + + ret = atomic.and_fetch(1, eastl::memory_order_release); + + ret = atomic.and_fetch(1, eastl::memory_order_acq_rel); + + ret = atomic.and_fetch(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.fetch_or(1); + + ret = atomic.fetch_or(1, eastl::memory_order_relaxed); + + ret = atomic.fetch_or(1, eastl::memory_order_acquire); + + ret = atomic.fetch_or(1, eastl::memory_order_release); + + ret = atomic.fetch_or(1, eastl::memory_order_acq_rel); + + ret = atomic.fetch_or(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.or_fetch(1); + + ret = atomic.or_fetch(1, eastl::memory_order_relaxed); + + ret = atomic.or_fetch(1, eastl::memory_order_acquire); + + ret = atomic.or_fetch(1, eastl::memory_order_release); + + ret = atomic.or_fetch(1, eastl::memory_order_acq_rel); + + ret = atomic.or_fetch(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.fetch_xor(1); + + ret = atomic.fetch_xor(1, eastl::memory_order_relaxed); + + ret = atomic.fetch_xor(1, eastl::memory_order_acquire); + + ret = atomic.fetch_xor(1, eastl::memory_order_release); + + ret = atomic.fetch_xor(1, eastl::memory_order_acq_rel); + + ret = atomic.fetch_xor(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.xor_fetch(1); + + ret = atomic.xor_fetch(1, eastl::memory_order_relaxed); + + ret = atomic.xor_fetch(1, eastl::memory_order_acquire); + + ret = atomic.xor_fetch(1, eastl::memory_order_release); + + ret = atomic.xor_fetch(1, eastl::memory_order_acq_rel); + + ret = atomic.xor_fetch(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType observed = 0; + bool ret; + + ret = atomic.compare_exchange_weak(observed, 1); + + ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_release); + + ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_acq_rel); + + ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType observed = 0; + bool ret; + + ret = atomic.compare_exchange_strong(observed, 1); + + ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_release); + + ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_acq_rel); + + ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType observed = 0; + bool ret; + + ret = atomic.compare_exchange_weak(observed, 1, + eastl::memory_order_relaxed, + eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, 1, + eastl::memory_order_acquire, + eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, 1, + eastl::memory_order_acquire, + eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, 1, + eastl::memory_order_release, + eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, 1, + eastl::memory_order_acq_rel, + eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, 1, + eastl::memory_order_acq_rel, + eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, 1, + eastl::memory_order_seq_cst, + eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, 1, + eastl::memory_order_seq_cst, + eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, 1, + eastl::memory_order_seq_cst, + eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType observed = 0; + bool ret; + + ret = atomic.compare_exchange_strong(observed, 1, + eastl::memory_order_relaxed, + eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, 1, + eastl::memory_order_acquire, + eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, 1, + eastl::memory_order_acquire, + eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, 1, + eastl::memory_order_release, + eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, 1, + eastl::memory_order_acq_rel, + eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, 1, + eastl::memory_order_acq_rel, + eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, 1, + eastl::memory_order_seq_cst, + eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, 1, + eastl::memory_order_seq_cst, + eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, 1, + eastl::memory_order_seq_cst, + eastl::memory_order_seq_cst); + } + +} + +template +void AtomicIntegralBasicTest::TestAtomicStandalone() +{ + { + AtomicType atomic; + + IntegralType expected = 0; + bool ret = atomic_compare_exchange_weak(&atomic, &expected, 1); + + if (ret) + { + VERIFY(ret == true); + + VERIFY(expected == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + } + + { + AtomicType atomic; + + IntegralType expected = 0; + bool ret = atomic_compare_exchange_weak_explicit(&atomic, &expected, 1, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + if (ret) + { + VERIFY(ret == true); + + VERIFY(expected == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + } + + { + AtomicType atomic; + + IntegralType expected = 0; + bool ret = atomic_compare_exchange_strong(&atomic, &expected, 1); + + VERIFY(ret == true); + + VERIFY(expected == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + + { + AtomicType atomic; + + IntegralType expected = 0; + bool ret = atomic_compare_exchange_strong_explicit(&atomic, &expected, 1, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + VERIFY(ret == true); + + VERIFY(expected == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_fetch_xor(&atomic, 0x1); + + VERIFY(ret == 0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_fetch_xor_explicit(&atomic, 0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_xor_fetch(&atomic, 0x1); + + VERIFY(ret == 0x1); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_xor_fetch_explicit(&atomic, 0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_fetch_or(&atomic, 0x1); + + VERIFY(ret == 0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_fetch_or_explicit(&atomic, 0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_or_fetch(&atomic, 0x1); + + VERIFY(ret == 0x1); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_or_fetch_explicit(&atomic, 0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic_fetch_and(&atomic, 0x0); + + VERIFY(ret == 0x1); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x0); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic_fetch_and_explicit(&atomic, 0x0, eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x0); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic_and_fetch(&atomic, 0x0); + + VERIFY(ret == 0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x0); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic_and_fetch_explicit(&atomic, 0x0, eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x0); + } + + { + AtomicType atomic{ 1 }; + + IntegralType ret = atomic_fetch_sub(&atomic, 1); + + VERIFY(ret == 1); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); + } + + { + AtomicType atomic{ 1 }; + + IntegralType ret = atomic_fetch_sub_explicit(&atomic, 1, eastl::memory_order_relaxed); + + VERIFY(ret == 1); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); + } + + { + AtomicType atomic{ 1 }; + + IntegralType ret = atomic_sub_fetch(&atomic, 1); + + VERIFY(ret == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); + } + + { + AtomicType atomic{ 1 }; + + IntegralType ret = atomic_sub_fetch_explicit(&atomic, 1, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_fetch_add(&atomic, 1); + + VERIFY(ret == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_fetch_add_explicit(&atomic, 1, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_add_fetch(&atomic, 1); + + VERIFY(ret == 1); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_add_fetch_explicit(&atomic, 1, eastl::memory_order_relaxed); + + VERIFY(ret == 1); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_exchange(&atomic, 1); + + VERIFY(ret == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_exchange_explicit(&atomic, 1, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_load(&atomic); + + VERIFY(ret == 0); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_load_explicit(&atomic, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_load_cond(&atomic, [](IntegralType val) { return true; }); + + VERIFY(ret == 0); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_load_cond_explicit(&atomic, [](IntegralType val) { return true; }, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic; + + atomic_store(&atomic, 1); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + + { + AtomicType atomic; + + atomic_store_explicit(&atomic, 1, eastl::memory_order_relaxed); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + + { + AtomicType atomic; + + VERIFY(atomic_is_lock_free(&atomic) == true); + } +} + +struct AtomicNonDefaultConstructible +{ + AtomicNonDefaultConstructible(uint8_t a) + : a(a) + { + } + + friend bool operator==(const AtomicNonDefaultConstructible& a, const AtomicNonDefaultConstructible& b) + { + return a.a == b.a; + } + + uint8_t a; +}; + +#if defined(EASTL_ATOMIC_HAS_8BIT) + +int TestAtomicNonDefaultConstructible() +{ + int nErrorCount = 0; + + { + eastl::atomic atomic{AtomicNonDefaultConstructible{(uint8_t)3}}; + + VERIFY(atomic.load() == AtomicNonDefaultConstructible{(uint8_t)3}); + } + + { + eastl::atomic atomic{AtomicNonDefaultConstructible{(uint8_t)3}}; + + atomic.store(AtomicNonDefaultConstructible{(uint8_t)4}); + + VERIFY(atomic.load() == AtomicNonDefaultConstructible{(uint8_t)4}); + } + + { + eastl::atomic atomic{AtomicNonDefaultConstructible{(uint8_t)3}}; + + VERIFY(atomic_load_cond(&atomic, [] (AtomicNonDefaultConstructible) { return true; }) == AtomicNonDefaultConstructible{(uint8_t)3}); + } + + { + eastl::atomic atomic{AtomicNonDefaultConstructible{(uint8_t)3}}; + + VERIFY(atomic_load_cond_explicit(&atomic, [] (AtomicNonDefaultConstructible) { return true; }, eastl::memory_order_seq_cst) == AtomicNonDefaultConstructible{(uint8_t)3}); + } + + return nErrorCount; +} + +#endif + +struct Atomic128LoadType +{ + friend bool operator==(const Atomic128LoadType& a, const Atomic128LoadType& b) + { + return a.a == b.a && a.b == b.b && a.c == b.c && a.d == b.d; + } + + uint32_t a, b, c, d; +}; + +#if defined(EASTL_ATOMIC_HAS_128BIT) + +int TestAtomic128Loads() +{ + int nErrorCount = 0; + + { + eastl::atomic atomic{Atomic128LoadType{1, 1, 0, 0}}; + + VERIFY((atomic.load() == Atomic128LoadType{1, 1, 0, 0})); + } + + { + eastl::atomic atomic{Atomic128LoadType{0, 0, 1, 1}}; + + VERIFY((atomic.load() == Atomic128LoadType{0, 0, 1, 1})); + } + + { + eastl::atomic atomic{Atomic128LoadType{0, 1, 0, 1}}; + + VERIFY((atomic.load() == Atomic128LoadType{0, 1, 0, 1})); + } + + { + eastl::atomic atomic{Atomic128LoadType{1, 0, 1, 0}}; + + VERIFY((atomic.load() == Atomic128LoadType{1, 0, 1, 0})); + } + + { + eastl::atomic atomic{Atomic128LoadType{1, 1, 0, 0}}; + + Atomic128LoadType expected{0, 0, 0, 0}; + atomic.compare_exchange_strong(expected, Atomic128LoadType{1, 1, 0, 0}); + + VERIFY((expected == Atomic128LoadType{1, 1, 0, 0})); + } + + { + eastl::atomic atomic{Atomic128LoadType{0, 0, 1, 1}}; + + Atomic128LoadType expected{0, 0, 0, 0}; + atomic.compare_exchange_strong(expected, Atomic128LoadType{0, 0, 1, 1}); + + VERIFY((expected == Atomic128LoadType{0, 0, 1, 1})); + } + + { + eastl::atomic atomic{Atomic128LoadType{0, 1, 0, 1}}; + + Atomic128LoadType expected{0, 0, 0, 0}; + atomic.compare_exchange_strong(expected, Atomic128LoadType{0, 1, 0, 1}); + + VERIFY((expected == Atomic128LoadType{0, 1, 0, 1})); + } + + { + eastl::atomic atomic{Atomic128LoadType{1, 0, 1, 0}}; + + Atomic128LoadType expected{0, 0, 0, 0}; + atomic.compare_exchange_strong(expected, Atomic128LoadType{1, 0, 1, 0}); + + VERIFY((expected == Atomic128LoadType{1, 0, 1, 0})); + } + + { + eastl::atomic atomic{Atomic128LoadType{0, 0, 0, 0}}; + + Atomic128LoadType expected{0, 0, 0, 0}; + atomic.compare_exchange_strong(expected, Atomic128LoadType{1, 1, 0, 0}); + + VERIFY((atomic.load() == Atomic128LoadType{1, 1, 0, 0})); + } + + { + eastl::atomic atomic{Atomic128LoadType{0, 0, 0, 0}}; + + Atomic128LoadType expected{0, 0, 0, 0}; + atomic.compare_exchange_strong(expected, Atomic128LoadType{0, 0, 1, 1}); + + VERIFY((atomic.load() == Atomic128LoadType{0, 0, 1, 1})); + } + + { + eastl::atomic atomic{Atomic128LoadType{0, 0, 0, 0}}; + + Atomic128LoadType expected{0, 0, 0, 0}; + atomic.compare_exchange_strong(expected, Atomic128LoadType{0, 1, 0, 1}); + + VERIFY((atomic.load() == Atomic128LoadType{0, 1, 0, 1})); + } + + { + eastl::atomic atomic{Atomic128LoadType{0, 0, 0, 0}}; + + Atomic128LoadType expected{0, 0, 0, 0}; + atomic.compare_exchange_strong(expected, Atomic128LoadType{1, 0, 1, 0}); + + VERIFY((atomic.load() == Atomic128LoadType{1, 0, 1, 0})); + } + + return nErrorCount; +} + +#endif + +int TestAtomicBasic() +{ + int nErrorCount = 0; + + #if defined(EASTL_ATOMIC_HAS_8BIT) + { + AtomicIntegralBasicTest u8AtomicTest; + + nErrorCount += u8AtomicTest.RunTest(); + } + #endif + + #if defined(EASTL_ATOMIC_HAS_16BIT) + { + AtomicIntegralBasicTest u16AtomicTest; + + nErrorCount += u16AtomicTest.RunTest(); + } + #endif + + #if defined(EASTL_ATOMIC_HAS_32BIT) + { + AtomicIntegralBasicTest u32AtomicTest; + + nErrorCount += u32AtomicTest.RunTest(); + } + #endif + + #if defined(EASTL_ATOMIC_HAS_64BIT) + { + AtomicIntegralBasicTest u64AtomicTest; + + nErrorCount += u64AtomicTest.RunTest(); + } + #endif + + #if defined(EASTL_ATOMIC_HAS_128BIT) && (defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) + { + AtomicIntegralBasicTest<__uint128_t> u128AtomicTest; + + nErrorCount += u128AtomicTest.RunTest(); + } + + { + AtomicIntegralBasicTest u128AtomicTest; + + nErrorCount += u128AtomicTest.RunTest(); + } + #endif + + { + AtomicBoolBasicTest boolAtomicTest; + + nErrorCount += boolAtomicTest.RunTest(); + } + + #if defined(EASTL_ATOMIC_HAS_16BIT) + { + AtomicUserTypeBasicTest userTypeAtomicTest; + + nErrorCount += userTypeAtomicTest.RunTest(); + } + #endif + + #if defined(EASTL_ATOMIC_HAS_32BIT) + { + AtomicUserTypeBasicTest userTypeAtomicTest; + + nErrorCount += userTypeAtomicTest.RunTest(); + } + + { + AtomicUserTypeBasicTest userTypeAtomicTest; + + nErrorCount += userTypeAtomicTest.RunTest(); + } + #endif + + #if defined(EASTL_ATOMIC_HAS_128BIT) + { + AtomicUserTypeBasicTest userTypeAtomicTest; + + nErrorCount += userTypeAtomicTest.RunTest(); + } + #endif + + { + AtomicPointerBasicTest ptrAtomicTest; + + nErrorCount += ptrAtomicTest.RunTest(); + } + + { + AtomicVoidPointerBasicTest voidPtrAtomicTest; + + nErrorCount += voidPtrAtomicTest.RunTest(); + } + + { + AtomicFlagBasicTest atomicFlagBasicTest; + + nErrorCount += atomicFlagBasicTest.RunTest(); + } + + { + AtomicStandaloneBasicTest atomicStandaloneBasicTest; + + nErrorCount += atomicStandaloneBasicTest.RunTest(); + } + +#if defined(EASTL_ATOMIC_HAS_128BIT) + + nErrorCount += TestAtomic128Loads(); + +#endif + +#if defined(EASTL_ATOMIC_HAS_8BIT) + + nErrorCount += TestAtomicNonDefaultConstructible(); + +#endif + + nErrorCount += TestAtomicConstantInitialization(); + + return nErrorCount; +} diff --git a/library/3rdparty/EASTL/test/source/TestBitcast.cpp b/library/3rdparty/EASTL/test/source/TestBitcast.cpp new file mode 100644 index 0000000..d6f0840 --- /dev/null +++ b/library/3rdparty/EASTL/test/source/TestBitcast.cpp @@ -0,0 +1,52 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#include "EASTLTest.h" +#include + +using namespace eastl; + + +int TestBitcast() +{ + int nErrorCount = 0; + + { + uint32_t int32Value = 0x12345678; + float floatValue = eastl::bit_cast(int32Value); + VERIFY(memcmp(&int32Value, &floatValue, sizeof(float)) == 0); + } + + { + struct IntFloatStruct + { + uint32_t i = 0x87654321; + float f = 10.f; + }; + struct CharIntStruct + { + char c1; + char c2; + char c3; + char c4; + uint32_t i; + }; + + IntFloatStruct ifStruct; + CharIntStruct ciStruct = eastl::bit_cast(ifStruct); + VERIFY(memcmp(&ifStruct, &ciStruct, sizeof(IntFloatStruct)) == 0); + } + +#if EASTL_CONSTEXPR_BIT_CAST_SUPPORTED + { + constexpr uint32_t int32Value = 40; + constexpr float floatValue = eastl::bit_cast(int32Value); + VERIFY(memcmp(&int32Value, &floatValue, sizeof(float)) == 0); + } +#endif + + + return nErrorCount; +} diff --git a/library/3rdparty/EASTL/test/source/TestFunctional.cpp b/library/3rdparty/EASTL/test/source/TestFunctional.cpp index 88f4c2c..63b3516 100644 --- a/library/3rdparty/EASTL/test/source/TestFunctional.cpp +++ b/library/3rdparty/EASTL/test/source/TestFunctional.cpp @@ -68,14 +68,17 @@ namespace bool operator==(const N1& n1, const N1& n1a){ return (n1.mX == n1a.mX); } bool operator==(const N1& n1, const N2& n2) { return (n1.mX == n2.mX); } bool operator==(const N2& n2, const N1& n1) { return (n2.mX == n1.mX); } + bool operator==(const volatile N1& n1, const volatile N1& n1a) { return (n1.mX == n1a.mX); } bool operator!=(const N1& n1, const N1& n1a){ return (n1.mX != n1a.mX); } bool operator!=(const N1& n1, const N2& n2) { return (n1.mX != n2.mX); } bool operator!=(const N2& n2, const N1& n1) { return (n2.mX != n1.mX); } + bool operator!=(const volatile N1& n1, const volatile N1& n1a) { return (n1.mX != n1a.mX); } bool operator< (const N1& n1, const N1& n1a){ return (n1.mX < n1a.mX); } bool operator< (const N1& n1, const N2& n2) { return (n1.mX < n2.mX); } bool operator< (const N2& n2, const N1& n1) { return (n2.mX < n1.mX); } + bool operator< (const volatile N1& n1, const volatile N1& n1a) { return (n1.mX < n1a.mX); } // Used for mem_fun tests below. @@ -260,8 +263,12 @@ int TestFunctional() N1 n13(3); N2 n21(1); N2 n22(2); - //const N1 cn11(1); - //const N1 cn13(3); + const N1 cn11(1); + const N1 cn13(3); + volatile N1 vn11(1); + volatile N1 vn13(3); + const volatile N1 cvn11(1); + const volatile N1 cvn13(3); equal_to_2 e; EATEST_VERIFY(e(n11, n21)); @@ -269,9 +276,40 @@ int TestFunctional() equal_to_2 es; EATEST_VERIFY(es(n11, n11)); + EATEST_VERIFY(!es(n11, n13)); - //equal_to_2 ec; // To do: Make this case work. - //EATEST_VERIFY(e(cn11, n11)); + equal_to_2 ec; + EATEST_VERIFY(ec(cn11, n11)); + EATEST_VERIFY(ec(n11, cn11)); + + equal_to_2 ec2; + EATEST_VERIFY(ec2(n11, cn11)); + EATEST_VERIFY(ec2(cn11, n11)); + + equal_to_2 ecc; + EATEST_VERIFY(ecc(cn11, cn11)); + + equal_to_2 ev; + EATEST_VERIFY(ev(vn11, n11)); + EATEST_VERIFY(ev(n11, vn11)); + + equal_to_2 ev2; + EATEST_VERIFY(ev2(n11, vn11)); + EATEST_VERIFY(ev2(vn11, n11)); + + equal_to_2 evv; + EATEST_VERIFY(evv(vn11, vn11)); + + equal_to_2 ecv; + EATEST_VERIFY(ecv(cvn11, n11)); + EATEST_VERIFY(ecv(n11, cvn11)); + + equal_to_2 ecv2; + EATEST_VERIFY(ecv2(n11, cvn11)); + EATEST_VERIFY(ecv2(cvn11, n11)); + + equal_to_2 ecvcv; + EATEST_VERIFY(ecvcv(cvn11, cvn11)); // not_equal_to_2 not_equal_to_2 n; @@ -280,6 +318,40 @@ int TestFunctional() not_equal_to_2 ns; EATEST_VERIFY(ns(n11, n13)); + EATEST_VERIFY(!ns(n11, n11)); + + not_equal_to_2 nc; + EATEST_VERIFY(nc(cn11, n13)); + EATEST_VERIFY(nc(n13, cn11)); + + not_equal_to_2 nc2; + EATEST_VERIFY(nc2(n13, cn11)); + EATEST_VERIFY(nc2(cn11, n13)); + + not_equal_to_2 ncc; + EATEST_VERIFY(ncc(cn11, cn13)); + + not_equal_to_2 nv; + EATEST_VERIFY(nv(vn11, n13)); + EATEST_VERIFY(nv(n11, vn13)); + + not_equal_to_2 nv2; + EATEST_VERIFY(nv2(n11, vn13)); + EATEST_VERIFY(nv2(vn11, n13)); + + not_equal_to_2 nvv; + EATEST_VERIFY(nvv(vn11, vn13)); + + not_equal_to_2 ncv; + EATEST_VERIFY(ncv(cvn11, n13)); + EATEST_VERIFY(ncv(n11, cvn13)); + + not_equal_to_2 ncv2; + EATEST_VERIFY(ncv2(n11, cvn13)); + EATEST_VERIFY(ncv2(cvn11, n13)); + + not_equal_to_2 ncvcv; + EATEST_VERIFY(ncvcv(cvn11, cvn13)); // less_2 less_2 le; @@ -288,6 +360,39 @@ int TestFunctional() less_2 les; EATEST_VERIFY(les(n11, n13)); + + less_2 lec; + EATEST_VERIFY(lec(cn11, n13)); + EATEST_VERIFY(lec(n11, cn13)); + + less_2 lec2; + EATEST_VERIFY(lec2(n11, cn13)); + EATEST_VERIFY(lec2(cn11, n13)); + + less_2 lecc; + EATEST_VERIFY(lecc(cn11, cn13)); + + less_2 lev; + EATEST_VERIFY(lev(vn11, n13)); + EATEST_VERIFY(lev(n11, vn13)); + + less_2 lev2; + EATEST_VERIFY(lev2(n11, vn13)); + EATEST_VERIFY(lev2(vn11, n13)); + + less_2 levv; + EATEST_VERIFY(levv(vn11, vn13)); + + less_2 lecv; + EATEST_VERIFY(lecv(cvn11, n13)); + EATEST_VERIFY(lecv(n11, cvn13)); + + less_2 lecv2; + EATEST_VERIFY(lecv2(n11, cvn13)); + EATEST_VERIFY(lecv2(cvn11, n13)); + + less_2 lecvcv; + EATEST_VERIFY(lecvcv(cvn11, cvn13)); } @@ -435,6 +540,7 @@ int TestFunctional() void Add(int addAmount) { value += addAmount; } int GetValue() { return value; } int& GetValueReference() { return value; } + void NoThrow(int inValue) EA_NOEXCEPT {} int value; }; @@ -444,6 +550,12 @@ int TestFunctional() bool called = false; }; + struct TestFunctorNoThrow + { + void operator()() EA_NOEXCEPT { called = true; } + bool called = false; + }; + struct TestFunctorArguments { void operator()(int i) { value = i; } @@ -457,6 +569,8 @@ int TestFunctional() static_assert(eastl::is_same::type, void>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); + static_assert(eastl::is_nothrow_invocable::value, "incorrect value for is_nothrow_invocable"); + static_assert(!eastl::is_nothrow_invocable::value, "incorrect value for is_nothrow_invocable"); } { TestStruct a(42); @@ -465,6 +579,8 @@ int TestFunctional() static_assert(eastl::is_same::type, void>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); + static_assert(eastl::is_nothrow_invocable::value, "incorrect value for is_nothrow_invocable"); + static_assert(!eastl::is_nothrow_invocable::value, "incorrect value for is_nothrow_invocable"); } { TestStruct a(42); @@ -474,6 +590,8 @@ int TestFunctional() static_assert(eastl::is_same, int>::type, void>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable, int>::value, "incorrect value for is_invocable"); + static_assert(eastl::is_nothrow_invocable, int>::value, "incorrect value for is_nothrow_invocable"); + static_assert(!eastl::is_nothrow_invocable, int>::value, "incorrect value for is_nothrow_invocable"); } { TestStruct a(42); @@ -535,6 +653,16 @@ int TestFunctional() static_assert(eastl::is_same::type, void>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); + static_assert(!eastl::is_nothrow_invocable::value, "incorrect value for is_nothrow_invocable"); + } + { + TestFunctorNoThrow f; + eastl::invoke(f); + EATEST_VERIFY(f.called); + + static_assert(eastl::is_same::type, void>::value, "incorrect type for invoke_result"); + static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); + static_assert(eastl::is_nothrow_invocable::value, "incorrect value for is_nothrow_invocable"); } { TestFunctorArguments f; @@ -544,6 +672,43 @@ int TestFunctional() static_assert(eastl::is_same::type, void>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); } + { + struct TestInvokeConstAccess + { + void ConstMemberFunc(int i) const {} + void ConstVolatileMemberFunc(int i) const volatile {} + + int mI; + }; + + static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); + static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); + } + { + struct TestReferenceWrapperInvoke + { + int NonConstMemberFunc(int i) { return i; } + int ConstMemberFunc(int i) const { return i; } + + int mI = 1; + const int mIC = 1; + }; + + TestReferenceWrapperInvoke testStruct; + int ret; + + ret = eastl::invoke(&TestReferenceWrapperInvoke::NonConstMemberFunc, eastl::ref(testStruct), 1); + EATEST_VERIFY(ret == 1); + + ret = eastl::invoke(&TestReferenceWrapperInvoke::ConstMemberFunc, eastl::ref(testStruct), 1); + EATEST_VERIFY(ret == 1); + + ret = eastl::invoke(&TestReferenceWrapperInvoke::mI, eastl::ref(testStruct)); + EATEST_VERIFY(ret == 1); + + ret = eastl::invoke(&TestReferenceWrapperInvoke::mIC, eastl::ref(testStruct)); + EATEST_VERIFY(ret == 1); + } { static bool called = false; auto f = [] {called = true;}; @@ -565,16 +730,20 @@ int TestFunctional() { struct A {}; struct B : public A {}; + struct C : public A {}; struct TestStruct { A a() { return A(); }; B b() { return B(); }; + C c() EA_NOEXCEPT { return C(); }; }; static_assert(!eastl::is_invocable_r::value, "incorrect value for is_invocable_r"); static_assert(eastl::is_invocable_r::value, "incorrect value for is_invocable_r"); static_assert(eastl::is_invocable_r::value, "incorrect value for is_invocable_r"); + static_assert(!eastl::is_nothrow_invocable_r::value, "incorrect value for is_nothrow_invocable_r"); + static_assert(eastl::is_nothrow_invocable_r::value, "incorrect value for is_nothrow_invocable_r"); } } diff --git a/library/3rdparty/EASTL/test/source/TestHash.cpp b/library/3rdparty/EASTL/test/source/TestHash.cpp index eff6156..9c9bf9d 100644 --- a/library/3rdparty/EASTL/test/source/TestHash.cpp +++ b/library/3rdparty/EASTL/test/source/TestHash.cpp @@ -994,9 +994,19 @@ int TestHash() EATEST_VERIFY(it != hashSet.end()); else EATEST_VERIFY(it == hashSet.end()); + + string::CtorSprintf cs; + string s(cs, "%d", i); + + it = hashSet.find_as(s); + if (i < kCount) + EATEST_VERIFY(it != hashSet.end()); + else + EATEST_VERIFY(it == hashSet.end()); } } + { // Test const containers. const hash_set constHashSet; diff --git a/library/3rdparty/EASTL/test/source/TestIntrusiveHash.cpp b/library/3rdparty/EASTL/test/source/TestIntrusiveHash.cpp index 4fd8215..f089aab 100644 --- a/library/3rdparty/EASTL/test/source/TestIntrusiveHash.cpp +++ b/library/3rdparty/EASTL/test/source/TestIntrusiveHash.cpp @@ -617,6 +617,12 @@ int TestIntrusiveHash() itfc = ihmMW1Const.find_as(7.f); VERIFY(itfc->mKey == 7); + + itf = ihmMW1.find_as(8); + VERIFY(itf->mKey == 8); + + itfc = ihmMW1Const.find_as(8); + VERIFY(itfc->mKey == 8); // iterator find_as(const U& u, UHash uhash, BinaryPredicate predicate); diff --git a/library/3rdparty/EASTL/test/source/TestIterator.cpp b/library/3rdparty/EASTL/test/source/TestIterator.cpp index 6a7ea95..02aa1d4 100644 --- a/library/3rdparty/EASTL/test/source/TestIterator.cpp +++ b/library/3rdparty/EASTL/test/source/TestIterator.cpp @@ -14,6 +14,7 @@ #include #include #include +#include EA_DISABLE_ALL_VC_WARNINGS() #include @@ -42,15 +43,15 @@ int TestIterator_advance() for(i = 0; i < num_elements; i++) { EATEST_VERIFY(*it == v[i]); - eastl::advance(it, 1); + eastl::advance(it, 1); } // test backwards advancement eastl::vector::iterator it2 = v.end(); i = num_elements - 1; do - { - eastl::advance(it2, -1); + { + eastl::advance(it2, -1); EATEST_VERIFY(*it2 == v[i]); } while(i-- != 0); @@ -114,7 +115,7 @@ int TestIterator_advance() eastl::vector::iterator it = v.end(); EATEST_VERIFY(*eastl::prev(it, 2) == 42); - EATEST_VERIFY(*eastl::prev(it /*testing the iterator distance default value*/) == 2); + EATEST_VERIFY(*eastl::prev(it /*testing the iterator distance default value*/) == 2); } return nErrorCount; @@ -130,15 +131,86 @@ int TestIterator_moveIterator() // operator++(int) auto moveIter = constBeginMoveIter; - moveIter++; // the result of the expression is the incremented value, we need this test to read the existing state of the iterator. + moveIter++; // the result of the expression is the incremented value, we need this test to read the existing state of the iterator. EATEST_VERIFY(*moveIter != *constBeginMoveIter); // operator--(int) moveIter = constBeginMoveIter + 2; // points to '42' - moveIter--; // the result of the expression is the incremented value, we need this test to read the existing state of the iterator. + moveIter--; // the result of the expression is the incremented value, we need this test to read the existing state of the iterator. EATEST_VERIFY(*moveIter != *(constBeginMoveIter + 2)); } + { + // Ensure that move_iterator indeed move yielded value whenever possible. + auto x = eastl::make_unique(42); + auto* pX = &x; + auto moveIter = eastl::make_move_iterator(pX); + + constexpr bool isCorrectReferenceType = eastl::is_same_v&&>; + constexpr bool isCorrectReturnType = eastl::is_same_v&&>; + + static_assert(isCorrectReferenceType, "move_iterator::reference has wrong type."); + static_assert(isCorrectReturnType, "move_iterator::operator*() has wrong return type."); + EATEST_VERIFY(isCorrectReferenceType); + EATEST_VERIFY(isCorrectReturnType); + + auto pMoveX = *moveIter; + EATEST_VERIFY(*pMoveX == 42); + } + + // Bellow are regression tests that ensure we are covering the defect LWG 2106: http://cplusplus.github.io/LWG/lwg-defects.html#2106 + { + // Check that we support iterators yielding const references. + const int x = 42; + const int* pX = &x; + auto moveIter = eastl::make_move_iterator(pX); + + constexpr bool isCorrectReferenceType = eastl::is_same_v; + constexpr bool isCorrectReturnType = eastl::is_same_v; + + static_assert(isCorrectReferenceType, "move_iterator::reference has wrong type."); + static_assert(isCorrectReturnType, "move_iterator::operator*() has wrong return type."); + EATEST_VERIFY(isCorrectReferenceType); + EATEST_VERIFY(isCorrectReturnType); + + auto pCopiedX = *moveIter; + EATEST_VERIFY(pCopiedX == 42); + } + + { + // Check that we support iterators yielding plain value (typically a proxy-iterator). + struct FakeProxyIterator + { + using iterator_category = eastl::forward_iterator_tag; + using difference_type = ptrdiff_t; + using value_type = int; + using pointer = int; // Note that we are yielding by value. + using reference = int; // Note that we are yielding by value. + + reference operator*() const { return 42; } + pointer operator->() { return 42; } + FakeProxyIterator& operator++() { return *this; } + FakeProxyIterator operator++(int) { return {}; } + + bool operator==(const FakeProxyIterator& rhs) { return true; }; + bool operator!=(const FakeProxyIterator& rhs) { return false; }; + }; + + FakeProxyIterator it = {}; + auto moveIter = eastl::make_move_iterator(it); + + constexpr bool isCorrectReferenceType = eastl::is_same_v; + constexpr bool isCorrectReturnType = eastl::is_same_v; + + static_assert(isCorrectReferenceType, "move_iterator::reference has wrong type."); + static_assert(isCorrectReturnType, "move_iterator::operator*() has wrong return type."); + EATEST_VERIFY(isCorrectReferenceType); + EATEST_VERIFY(isCorrectReturnType); + + auto pCopiedX = *moveIter; + EATEST_VERIFY(pCopiedX == 42); + } + return nErrorCount; } @@ -152,7 +224,7 @@ int TestIterator() int nErrorCount = 0; nErrorCount += TestIterator_advance(); nErrorCount += TestIterator_moveIterator(); - + { // reverse_iterator // reverse_iterator make_reverse_iterator(Iterator mi) @@ -227,8 +299,9 @@ int TestIterator() { // difference_type distance(InputIterator first, InputIterator last) - // To do. - } + eastl::vector intVector = {0, 1, 2, 3, 4, 5, 6, 7}; + EATEST_VERIFY(eastl::distance(intVector.begin(), intVector.end()) == 8); + } { @@ -260,7 +333,7 @@ int TestIterator() eastl::string8 str8; eastl::string8::iterator string8Iterator = eastl::begin(str8); EATEST_VERIFY(string8Iterator == eastl::end(str8)); - #endif + #endif } // eastl::data @@ -292,6 +365,7 @@ int TestIterator() int intCArray[34]; EATEST_VERIFY(eastl::size(intCArray) == 34); + static_assert(eastl::size(intCArray) == 34, "eastl::size failure"); } // eastl::ssize @@ -304,6 +378,7 @@ int TestIterator() int intCArray[34]; EATEST_VERIFY(eastl::ssize(intCArray) == (signed)34); + static_assert(eastl::ssize(intCArray) == 34, "eastl::ssize failure"); } // eastl::empty @@ -311,25 +386,22 @@ int TestIterator() eastl::vector intVector; EATEST_VERIFY(eastl::empty(intVector)); intVector.push_back(); - EATEST_VERIFY(!eastl::empty(intVector)); + EATEST_VERIFY(!eastl::empty(intVector)); std::initializer_list intInitListEmpty; EATEST_VERIFY(eastl::empty(intInitListEmpty)); - - #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) - EATEST_VERIFY(!eastl::empty({1, 2, 3, 4, 5, 6})); - #endif + EATEST_VERIFY(!eastl::empty({1, 2, 3, 4, 5, 6})); } // Range-based for loops - #if !defined(EA_COMPILER_NO_RANGE_BASED_FOR_LOOP) + { { eastl::vector v; int I = 0; v.push_back(0); v.push_back(1); - + for(int i : v) EATEST_VERIFY(i == I++); } @@ -340,11 +412,11 @@ int TestIterator() s8.push_back('a'); s8.push_back('b'); - + for(char c : s8) EATEST_VERIFY(c == C++); } - #endif + } { @@ -385,6 +457,17 @@ int TestIterator() static_assert((eastl::is_same::iterator>::value == true), "unwrap_iterator failure"); } + { + // array cbegin - cend + int arr[3]{ 1, 2, 3 }; + auto b = eastl::cbegin(arr); + auto e = eastl::cend(arr); + EATEST_VERIFY(*b == 1); + + auto dist = eastl::distance(b,e); + EATEST_VERIFY(dist == 3); + } + return nErrorCount; } diff --git a/library/3rdparty/EASTL/test/source/TestMap.cpp b/library/3rdparty/EASTL/test/source/TestMap.cpp index df4a195..e2eef2f 100644 --- a/library/3rdparty/EASTL/test/source/TestMap.cpp +++ b/library/3rdparty/EASTL/test/source/TestMap.cpp @@ -119,6 +119,19 @@ int TestMap() m.find_as(EA_CHAR8("some string"), eastl::equal_to_2()); } + { + eastl::map m; + int* ip = (int*)(uintptr_t)0xDEADC0DE; + + m[ip] = 0; + + auto it = m.find_as(ip, eastl::less_2{}); + EATEST_VERIFY(it != m.end()); + + it = m.find_as((int*)(uintptr_t)0xDEADC0DE, eastl::less_2{}); + EATEST_VERIFY(it != m.end()); + } + { // User reports that vector> is crashing after the recent changes to add rvalue move and emplace support to rbtree. typedef eastl::map IntIntMap; diff --git a/library/3rdparty/EASTL/test/source/TestOptional.cpp b/library/3rdparty/EASTL/test/source/TestOptional.cpp index 6c1fa4f..b4934a7 100644 --- a/library/3rdparty/EASTL/test/source/TestOptional.cpp +++ b/library/3rdparty/EASTL/test/source/TestOptional.cpp @@ -536,13 +536,13 @@ int TestOptional() // optional rvalue tests { - VERIFY(*optional(1) == 1); - VERIFY( optional(1).value() == 1); - VERIFY( optional(1).value_or(0xdeadf00d) == 1); - VERIFY( optional().value_or(0xdeadf00d) == 0xdeadf00d); - VERIFY( optional(1).has_value() == true); - VERIFY( optional().has_value() == false); - VERIFY( optional(in_place, 10)->data == 10); + VERIFY(*optional(1u) == 1u); + VERIFY(optional(1u).value() == 1u); + VERIFY(optional(1u).value_or(0xdeadf00d) == 1u); + VERIFY(optional().value_or(0xdeadf00d) == 0xdeadf00d); + VERIFY(optional(1u).has_value() == true); + VERIFY(optional().has_value() == false); + VERIFY( optional(in_place, 10)->data == 10); } @@ -611,7 +611,7 @@ int TestOptional() copyCtorCalledWithUninitializedValue = moveCtorCalledWithUninitializedValue = false; struct local { - int val; + uint32_t val; local() : val(0xabcdabcd) {} diff --git a/library/3rdparty/EASTL/test/source/TestSort.cpp b/library/3rdparty/EASTL/test/source/TestSort.cpp index fffa3b0..2d0116f 100644 --- a/library/3rdparty/EASTL/test/source/TestSort.cpp +++ b/library/3rdparty/EASTL/test/source/TestSort.cpp @@ -305,6 +305,23 @@ int TestSort() } } + // Test tim sort with a specific array size and seed that caused a crash + { + vector intArray; + int i = 1000000; + { + EASTLTest_Rand testRng(232526); + + for (int n = 0; n < i; n++) + { + intArray.push_back(testRng.Rand()); + } + vector buffer(intArray.size() / 2); + tim_sort_buffer(intArray.begin(), intArray.end(), buffer.data()); + EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end())); + } + } + // Test insertion_sort() does not invalidate a BidirectionalIterator by doing --BidirectionalIterator.begin() { // Test Passes if the Test doesn't crash diff --git a/library/3rdparty/EASTL/test/source/TestSpan.cpp b/library/3rdparty/EASTL/test/source/TestSpan.cpp index 060950d..5a0ec07 100644 --- a/library/3rdparty/EASTL/test/source/TestSpan.cpp +++ b/library/3rdparty/EASTL/test/source/TestSpan.cpp @@ -295,7 +295,7 @@ void TestSpanContainerConversion(int& nErrorCount) { vector v = {0, 1, 2, 3, 4, 5}; - span s1(v); + span s1(v); span s2(s1); VERIFY(s2.size() == (span::index_type)v.size()); @@ -391,6 +391,24 @@ void TestSpanSubViews(int& nErrorCount) VERIFY(first_span[3] == 9); } + { // empty range + span s{}; + + auto fixed_span = s.subspan<0, 0>(); + VERIFY(fixed_span.empty()); + fixed_span = s.first<0>(); + VERIFY(fixed_span.empty()); + fixed_span = s.last<0>(); + VERIFY(fixed_span.empty()); + + span dynamic_span; + VERIFY(dynamic_span.empty()); + dynamic_span = s.first(0); + VERIFY(dynamic_span.empty()); + dynamic_span = s.last(0); + VERIFY(dynamic_span.empty()); + } + { // subspan: full range span s = arr1; diff --git a/library/3rdparty/EASTL/test/source/TestTypeTraits.cpp b/library/3rdparty/EASTL/test/source/TestTypeTraits.cpp index 0fb6280..0353be9 100644 --- a/library/3rdparty/EASTL/test/source/TestTypeTraits.cpp +++ b/library/3rdparty/EASTL/test/source/TestTypeTraits.cpp @@ -620,9 +620,15 @@ int TestTypeTraits() static_assert(is_reference::value == true, "is_reference failure"); EATEST_VERIFY(GetType(is_reference()) == true); + static_assert(is_reference::value == true, "is_reference failure"); + EATEST_VERIFY(GetType(is_reference()) == true); + static_assert(is_reference::value == true, "is_reference failure"); EATEST_VERIFY(GetType(is_reference()) == true); + static_assert(is_reference::value == true, "is_reference failure"); + EATEST_VERIFY(GetType(is_reference()) == true); + static_assert(is_reference::value == false, "is_reference failure"); EATEST_VERIFY(GetType(is_reference()) == false); @@ -674,6 +680,14 @@ int TestTypeTraits() static_assert(is_enum_v == false, "is_enum failure "); EATEST_VERIFY(GetType(is_enum()) == false); + static_assert(is_enum::value == false, "is_enum failure "); + static_assert(is_enum_v == false, "is_enum failure "); + EATEST_VERIFY(GetType(is_enum()) == false); + + static_assert(is_enum::value == false, "is_enum failure "); + static_assert(is_enum_v == false, "is_enum failure "); + EATEST_VERIFY(GetType(is_enum()) == false); + // is_union static_assert(is_union::value == true, "is_union failure"); @@ -747,6 +761,9 @@ int TestTypeTraits() static_assert(is_object::value == false, "is_object failure"); EATEST_VERIFY(GetType(is_object()) == false); + static_assert(is_object::value == false, "is_object failure"); + EATEST_VERIFY(GetType(is_object()) == false); + // is_scalar static_assert(is_scalar::value == true, "is_scalar failure"); @@ -827,10 +844,22 @@ int TestTypeTraits() EATEST_VERIFY(GetType(is_volatile()) == false); - // underlying_type + // underlying_type and to_underlying #if EASTL_TYPE_TRAIT_underlying_type_CONFORMANCE && !defined(EA_COMPILER_NO_STRONGLY_TYPED_ENUMS) // If we can execute this test... enum UnderlyingTypeTest : uint16_t { firstVal = 0, secondVal = 1 }; - static_assert(sizeof(underlying_type::type) == sizeof(uint16_t), "underlying_type failure"); + + constexpr bool isUnderlyingTypeCorrect = is_same_v, uint16_t>; + static_assert(isUnderlyingTypeCorrect, "Wrong type for underlying_type_t."); + EATEST_VERIFY(isUnderlyingTypeCorrect); + + auto v1 = to_underlying(UnderlyingTypeTest::firstVal); + auto v2 = to_underlying(UnderlyingTypeTest::secondVal); + + constexpr bool isToUnderlyingReturnTypeCorrect = is_same_v; + static_assert(isToUnderlyingReturnTypeCorrect, "Wrong return type for to_underlying."); + EATEST_VERIFY(isToUnderlyingReturnTypeCorrect); + + EATEST_VERIFY(v1 == 0 && v2 == 1); #endif @@ -1276,6 +1305,7 @@ int TestTypeTraits() static_assert(is_constructible::value == false, "is_constructible failure"); static_assert(is_constructible::value == true, "is_constructible failure"); static_assert(is_constructible::value == false, "is_constructible failure"); + static_assert(is_constructible::value == false, "is_constructible failure"); static_assert(is_constructible::value == true, "is_constructible failure"); static_assert(is_constructible::value == false, "is_constructible failure"); static_assert(is_constructible::value == true, "is_constructible failure"); @@ -1381,6 +1411,8 @@ int TestTypeTraits() // is_trivially_destructible static_assert(is_trivially_destructible::value == true, "is_trivially_destructible failure"); + static_assert(is_trivially_destructible::value == true, "is_trivially_destructible failure"); + static_assert(is_trivially_destructible::value == true, "is_trivially_destructible failure"); static_assert(is_trivially_destructible::value == true, "is_trivially_destructible failure"); static_assert(is_trivially_destructible::value == true, "is_trivially_destructible failure"); static_assert(is_trivially_destructible::value == false, "is_trivially_destructible failure"); @@ -1397,6 +1429,8 @@ int TestTypeTraits() // is_nothrow_destructible static_assert(is_nothrow_destructible::value == true, "is_nothrow_destructible failure"); + static_assert(is_nothrow_destructible::value == true, "is_nothrow_destructible failure"); + static_assert(is_nothrow_destructible::value == true, "is_nothrow_destructible failure"); static_assert(is_nothrow_destructible::value == false, "is_nothrow_destructible failure"); #if EASTL_TYPE_TRAIT_is_nothrow_destructible_CONFORMANCE static_assert(is_nothrow_destructible::value == true, "is_nothrow_destructible failure"); // NonPod2 is nothrow destructible because it has an empty destructor (makes no calls) which has no exception specification. Thus its exception specification defaults to noexcept(true) [C++11 Standard, 15.4 paragraph 14] @@ -1573,6 +1607,120 @@ int TestTypeTraits() EATEST_VERIFY(u64 == UINT64_C(0xffffffffffffffff)); i64 = static_cast::type>(u64); EATEST_VERIFY(i64 == -1); + + + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + static_assert(eastl::is_same_v::type>); + + #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + static_assert(eastl::is_same_v<__uint128_t, eastl::make_unsigned<__int128_t>::type>); + static_assert(eastl::is_same_v<__uint128_t, eastl::make_unsigned<__uint128_t>::type>); + + static_assert(eastl::is_same_v<__int128_t, eastl::make_signed<__int128_t>::type>); + static_assert(eastl::is_same_v<__int128_t, eastl::make_signed<__uint128_t>::type>); + #endif + + // Char tests + static_assert(sizeof(char) == sizeof(eastl::make_signed::type)); + static_assert(sizeof(wchar_t) == sizeof(eastl::make_signed::type)); + static_assert(sizeof(char16_t) == sizeof(eastl::make_signed::type)); + static_assert(sizeof(char32_t) == sizeof(eastl::make_signed::type)); + static_assert(sizeof(char) == sizeof(eastl::make_unsigned::type)); + static_assert(sizeof(wchar_t) == sizeof(eastl::make_unsigned::type)); + static_assert(sizeof(char16_t) == sizeof(eastl::make_unsigned::type)); + static_assert(sizeof(char32_t) == sizeof(eastl::make_unsigned::type)); + + // Enum tests + enum EnumUCharSize : unsigned char {}; + enum EnumUShortSize : unsigned short {}; + enum EnumUIntSize : unsigned int {}; + enum EnumULongSize : unsigned long {}; + enum EnumULongLongSize : unsigned long long {}; + + static_assert(eastl::is_signed_v::type>); + static_assert(eastl::is_signed_v::type>); + static_assert(eastl::is_signed_v::type>); + static_assert(eastl::is_signed_v::type>); + static_assert(eastl::is_signed_v::type>); + static_assert(sizeof(EnumUCharSize) == sizeof(eastl::make_signed::type)); + static_assert(sizeof(EnumUShortSize) == sizeof(eastl::make_signed::type)); + static_assert(sizeof(EnumUIntSize) == sizeof(eastl::make_signed::type)); + static_assert(sizeof(EnumULongSize) == sizeof(eastl::make_signed::type)); + static_assert(sizeof(EnumULongLongSize) == sizeof(eastl::make_signed::type)); + + enum EnumCharSize : signed char {}; + enum EnumShortSize : short {}; + enum EnumIntSize : int {}; + enum EnumLongSize : long {}; + enum EnumLongLongSize : long long {}; + + static_assert(eastl::is_unsigned_v::type>); + static_assert(eastl::is_unsigned_v::type>); + static_assert(eastl::is_unsigned_v::type>); + static_assert(eastl::is_unsigned_v::type>); + static_assert(eastl::is_unsigned_v::type>); + static_assert(sizeof(EnumCharSize) == sizeof(eastl::make_unsigned::type)); + static_assert(sizeof(EnumShortSize) == sizeof(eastl::make_unsigned::type)); + static_assert(sizeof(EnumIntSize) == sizeof(eastl::make_unsigned::type)); + static_assert(sizeof(EnumLongSize) == sizeof(eastl::make_unsigned::type)); + static_assert(sizeof(EnumLongLongSize) == sizeof(eastl::make_unsigned::type)); } // remove_const @@ -2027,12 +2175,31 @@ int TestTypeTraits() } #endif - return nErrorCount; -} - + // is_complete_type + { + struct Foo + { + int x; + }; + struct FooEmpty + { + }; + struct Bar; + void FooFunc(); + static_assert(eastl::internal::is_complete_type_v, "is_complete_type failure"); + static_assert(eastl::internal::is_complete_type_v, "is_complete_type failure"); + static_assert(!eastl::internal::is_complete_type_v, "is_complete_type failure"); + static_assert(!eastl::internal::is_complete_type_v, "is_complete_type failure"); + static_assert(!eastl::internal::is_complete_type_v, "is_complete_type failure"); + static_assert(!eastl::internal::is_complete_type_v, "is_complete_type failure"); + static_assert(!eastl::internal::is_complete_type_v, "is_complete_type failure"); + static_assert(eastl::internal::is_complete_type_v, "is_complete_type failure"); + } + return nErrorCount; +} diff --git a/library/3rdparty/EASTL/test/source/TestVariant.cpp b/library/3rdparty/EASTL/test/source/TestVariant.cpp index b5a2eab..a8197e5 100644 --- a/library/3rdparty/EASTL/test/source/TestVariant.cpp +++ b/library/3rdparty/EASTL/test/source/TestVariant.cpp @@ -13,6 +13,27 @@ #include +#if EASTL_EXCEPTIONS_ENABLED + +// Intentionally Non-Trivial. +// There are optimizations we can make in variant if the types are trivial that we don't currently do but can do. +template +struct valueless_struct +{ + valueless_struct() {} + + valueless_struct(const valueless_struct&) {} + + ~valueless_struct() {} + + struct exception_tag {}; + + operator T() const { throw exception_tag{}; } +}; + +#endif + + int TestVariantAlternative() { using namespace eastl; @@ -212,6 +233,7 @@ int TestVariantGet() VERIFY(get(v) == strValue); VERIFY(!holds_alternative(v)); VERIFY(holds_alternative(v)); + VERIFY(get(move(v)) == strValue); } { v_t v; @@ -624,6 +646,89 @@ int TestVariantInplaceCtors() return nErrorCount; } +// Many Compilers are smart and will fully inline the visitor in our unittests, +// Thereby not actually testing the recursive call. +EA_NO_INLINE int TestVariantVisitNoInline(const eastl::variant& v) +{ + int nErrorCount = 0; + + bool bVisited = false; + + struct MyVisitor + { + MyVisitor() = delete; + MyVisitor(bool& b) : mVisited(b) {} + + void operator()(int) { mVisited = true; } + void operator()(bool) { mVisited = true; } + void operator()(unsigned) { mVisited = true; } + + bool& mVisited; + }; + + eastl::visit(MyVisitor{bVisited}, v); + + EATEST_VERIFY(bVisited); + + return nErrorCount; +} + +EA_NO_INLINE int TestVariantVisit2NoInline(const eastl::variant& v0, const eastl::variant& v1) +{ + int nErrorCount = 0; + + bool bVisited = false; + + struct MyVisitor + { + MyVisitor() = delete; + MyVisitor(bool& b) : mVisited(b) {} + + void operator()(int, int) { mVisited = true; } + void operator()(bool, int) { mVisited = true; } + void operator()(int, bool) { mVisited = true; } + void operator()(bool, bool) { mVisited = true; } + + bool& mVisited; + }; + + eastl::visit(MyVisitor{bVisited}, v0, v1); + + EATEST_VERIFY(bVisited); + + return nErrorCount; +} + +EA_NO_INLINE int TestVariantVisit3tNoInline(const eastl::variant& v0, const eastl::variant& v1, const eastl::variant& v2) +{ + int nErrorCount = 0; + + bool bVisited = false; + + struct MyVisitor + { + MyVisitor() = delete; + MyVisitor(bool& b) : mVisited(b) {} + + void operator()(int, int, int) { mVisited = true; } + void operator()(bool, int, int) { mVisited = true; } + void operator()(int, bool, int) { mVisited = true; } + void operator()(bool, bool, int) { mVisited = true; } + + void operator()(int, int, bool) { mVisited = true; } + void operator()(bool, int, bool) { mVisited = true; } + void operator()(int, bool, bool) { mVisited = true; } + void operator()(bool, bool, bool) { mVisited = true; } + + bool& mVisited; + }; + + eastl::visit(MyVisitor{bVisited}, v0, v1, v2); + + EATEST_VERIFY(bVisited); + + return nErrorCount; +} int TestVariantVisitor() { @@ -661,6 +766,14 @@ int TestVariantVisitor() } VERIFY(count == EAArrayCount(arr)); + + count = 0; + for (auto& e : arr) + { + eastl::visit([&](auto){ count++; }, e); + } + + VERIFY(count == EAArrayCount(arr)); } { @@ -670,14 +783,171 @@ int TestVariantVisitor() struct MyVisitor { - MyVisitor& operator()(int) { bVisited = true; return *this; }; - MyVisitor& operator()(long) { return *this; }; - MyVisitor& operator()(string) { return *this; }; - MyVisitor& operator()(unsigned) { return *this; }; // not in variant + void operator()(int) { bVisited = true; }; + void operator()(long) { }; + void operator()(string) { }; + void operator()(unsigned) { }; // not in variant }; visit(MyVisitor{}, v); VERIFY(bVisited); + + bVisited = false; + + visit(MyVisitor{}, v); + VERIFY(bVisited); + } + + { + static bool bVisited = false; + + variant v = (int)1; + + struct MyVisitor + { + bool& operator()(int) { return bVisited; } + bool& operator()(bool) { return bVisited; } + bool& operator()(unsigned) { return bVisited; } + }; + + bool& ret = visit(MyVisitor{}, v); + ret = true; + VERIFY(bVisited); + + bVisited = false; + bool& ret2 = visit(MyVisitor{}, v); + ret2 = true; + VERIFY(bVisited); + } + + { + variant v = (int)1; + + struct MyVisitor + { + void operator()(int& i) { i = 2; } + void operator()(bool&) {} + void operator()(unsigned&) {} + }; + + visit(MyVisitor{}, v); + EATEST_VERIFY(get<0>(v) == (int)2); + + v = (int)1; + visit(MyVisitor{}, v); + EATEST_VERIFY(get<0>(v) == (int)2); + } + + { + static bool bVisited = false; + + variant v =(int)1; + + struct MyVisitor + { + void operator()(const int&) { bVisited = true; } + void operator()(const bool&) {} + void operator()(const unsigned&) {} + }; + + visit(MyVisitor{}, v); + EATEST_VERIFY(bVisited); + + bVisited = false; + visit(MyVisitor{}, v); + EATEST_VERIFY(bVisited); + } + + { + static bool bVisited = false; + + const variant v =(int)1; + + struct MyVisitor + { + void operator()(const int&) { bVisited = true; } + void operator()(const bool&) {} + void operator()(const unsigned&) {} + }; + + visit(MyVisitor{}, v); + EATEST_VERIFY(bVisited); + + bVisited = false; + visit(MyVisitor{}, v); + EATEST_VERIFY(bVisited); + } + + { + static bool bVisited = false; + + struct MyVisitor + { + void operator()(int&&) { bVisited = true; } + void operator()(bool&&) {} + void operator()(unsigned&&) {} + }; + + visit(MyVisitor{}, variant{(int)1}); + EATEST_VERIFY(bVisited); + + visit(MyVisitor{}, variant{(int)1}); + EATEST_VERIFY(bVisited); + } + + { + static bool bVisited = false; + + variant v = (int)1; + + struct MyVisitor + { + bool&& operator()(int) { return eastl::move(bVisited); } + bool&& operator()(bool) { return eastl::move(bVisited); } + bool&& operator()(unsigned) { return eastl::move(bVisited); } + }; + + bool&& ret = visit(MyVisitor{}, v); + ret = true; + VERIFY(bVisited); + + bVisited = false; + bool&& ret2 = visit(MyVisitor{}, v); + ret2 = true; + VERIFY(bVisited); + } + + { + variant v = (int)1; + + TestVariantVisitNoInline(v); + v = (bool)true; + TestVariantVisitNoInline(v); + v = (int)3; + TestVariantVisitNoInline(v); + } + + { + variant v0 = (int)1; + variant v1 = (bool)true; + + TestVariantVisit2NoInline(v0, v1); + v0 = (bool)false; + TestVariantVisit2NoInline(v0, v1); + v1 = (int)2; + TestVariantVisit2NoInline(v0, v1); + } + + { + variant v0 = (int)1; + variant v1 = (int)2; + variant v2 = (int)3; + + TestVariantVisit3tNoInline(v0, v1, v2); + v2 = (bool)false; + TestVariantVisit3tNoInline(v0, v1, v2); + v0 = (bool)true; + TestVariantVisit3tNoInline(v0, v1, v2); } { @@ -694,10 +964,42 @@ int TestVariantVisitor() MultipleVisitor& operator()(string, string) { return *this; } }; - visit(MultipleVisitor{}, i, s); + MultipleVisitor& ret = visit(MultipleVisitor{}, i, s); + EA_UNUSED(ret); + VERIFY(bVisited); + + MultipleVisitor& ret2 = visit(MultipleVisitor{}, i, s); + EA_UNUSED(ret2); VERIFY(bVisited); } + { + bool bVisited = false; + + variant v0 = 0; + variant v1 = 1; + + struct MultipleVisitor + { + MultipleVisitor() = delete; + MultipleVisitor(bool& b) : mVisited(b) {} + + void operator()(int, int) { mVisited = true; } + void operator()(int, bool) {} + void operator()(bool, int) {} + void operator()(bool, bool) {} + + bool& mVisited; + }; + + visit(MultipleVisitor{bVisited}, v0, v1); + EATEST_VERIFY(bVisited); + + bVisited = false; + visit(MultipleVisitor{bVisited}, v0, v1); + EATEST_VERIFY(bVisited); + } + { variant v = 42; @@ -723,24 +1025,128 @@ int TestVariantVisitor() VERIFY(visit(ReturningVisitor{}, v) == 42); } -#if !defined(EA_COMPILER_MSVC) + return nErrorCount; +} + +int TestVariantVisitorReturn() +{ + int nErrorCount = 0; + { - variant v = 42; + static bool bVisited = false; + + eastl::variant v = (int)1; - struct ReturningDifferentTypesVisitor + struct MyVisitor { - int operator()(int i) {return i;} - size_t operator()(string s) {return s.size();} + bool operator()(int) { bVisited = true; return true; } + bool operator()(bool) { return false; } }; - VERIFY(visit(ReturningDifferentTypesVisitor{}, v) == 42); + eastl::visit(MyVisitor{}, v); + EATEST_VERIFY(bVisited); + } + + { + static bool bVisited = false; + + eastl::variant v = (int)1; + + struct MyVisitor + { + bool operator()(int) { bVisited = true; return true; } + bool operator()(bool) { return false; } + }; + + eastl::visit(MyVisitor{}, v); + EATEST_VERIFY(bVisited); + } + + { + static bool bVisited = false; + + eastl::variant v = (int)1; + + struct MyVisitor + { + bool operator()(int) { bVisited = true; return true; } + bool operator()(bool) { return false; } + }; + + eastl::visit(MyVisitor{}, v); + EATEST_VERIFY(bVisited); + } + + { + static bool bVisited = false; + + eastl::variant v = (int)1; + + struct MyVisitor + { + bool operator()(int) { bVisited = true; return true; } + bool operator()(bool) { return false; } + }; + + eastl::visit(MyVisitor{}, v); + EATEST_VERIFY(bVisited); + } + + { + static bool bVisited = false; + + eastl::variant v = (int)1; + + struct MyVisitor + { + bool operator()(int) { bVisited = true; return true; } + bool operator()(bool) { return false; } + }; + + int ret = eastl::visit(MyVisitor{}, v); + EATEST_VERIFY(bVisited); + EATEST_VERIFY(ret); + } + + { + static bool bVisited = false; + + struct A {}; + struct B : public A {}; + struct C : public A {}; + + eastl::variant v = (int)1; + + struct MyVisitor + { + B operator()(int) { bVisited = true; return B{}; } + C operator()(bool) { return C{}; } + }; + + A ret = eastl::visit(MyVisitor{}, v); + EA_UNUSED(ret); + EATEST_VERIFY(bVisited); + } + + { + static bool bVisited = false; + + eastl::variant v = (int)1; + + struct MyVisitor + { + MyVisitor operator()(int) { bVisited = true; return MyVisitor{}; } + MyVisitor operator()(bool) { return MyVisitor{}; } + }; + + MyVisitor ret = eastl::visit(MyVisitor{}, v); + EA_UNUSED(ret); + EATEST_VERIFY(bVisited); } -#endif return nErrorCount; } - int TestVariantAssignment() { using namespace eastl; @@ -824,6 +1230,328 @@ int TestVariantUserRegressionCopyMoveAssignmentOperatorLeak() return nErrorCount; } +int TestVariantRelationalOperators() +{ + int nErrorCount = 0; + + using VariantNoThrow = eastl::variant; + + // Equality + { + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ true }; + + EATEST_VERIFY((v1 == v2) == false); + } + + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 == v2) == true); + } + + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ (int)0 }; + + EATEST_VERIFY((v1 == v2) == false); + } + } + + // Inequality + { + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ true }; + + EATEST_VERIFY((v1 != v2) == true); + } + + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 != v2) == false); + } + + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ (int)0 }; + + EATEST_VERIFY((v1 != v2) == true); + } + } + + // Less Than + { + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ true }; + + EATEST_VERIFY((v1 < v2) == true); + } + + { + VariantNoThrow v1{ true }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 < v2) == false); + } + + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 < v2) == false); + } + + { + VariantNoThrow v1{ (int)0 }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 < v2) == true); + } + } + + // Greater Than + { + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ true }; + + EATEST_VERIFY((v1 > v2) == false); + } + + { + VariantNoThrow v1{ true }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 > v2) == true); + } + + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 > v2) == false); + } + + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ (int)0 }; + + EATEST_VERIFY((v1 > v2) == true); + } + } + + // Less Equal + { + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ true }; + + EATEST_VERIFY((v1 <= v2) == true); + } + + { + VariantNoThrow v1{ true }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 <= v2) == false); + } + + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 <= v2) == true); + } + + { + VariantNoThrow v1{ (int)0 }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 <= v2) == true); + } + + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ (int)0 }; + + EATEST_VERIFY((v1 <= v2) == false); + } + } + + // Greater Equal + { + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ true }; + + EATEST_VERIFY((v1 >= v2) == false); + } + + { + VariantNoThrow v1{ true }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 >= v2) == true); + } + + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 >= v2) == true); + } + + { + VariantNoThrow v1{ (int)0 }; + VariantNoThrow v2{ (int)1 }; + + EATEST_VERIFY((v1 >= v2) == false); + } + + { + VariantNoThrow v1{ (int)1 }; + VariantNoThrow v2{ (int)0 }; + + EATEST_VERIFY((v1 >= v2) == true); + } + } + +#if EASTL_EXCEPTIONS_ENABLED + + using VariantThrow = eastl::variant; + + auto make_variant_valueless = [](VariantThrow& v) + { + try + { + v.emplace<0>(valueless_struct{}); + } + catch(const typename valueless_struct::exception_tag &) + { + } + }; + + // Equality + { + { + VariantThrow v0{ (int)0 }; + VariantThrow v1{ (int)1 }; + + make_variant_valueless(v0); + make_variant_valueless(v1); + + EATEST_VERIFY((v0 == v1) == true); + } + } + + // Inequality + { + { + VariantThrow v0{ (int)0 }; + VariantThrow v1{ (int)1 }; + + make_variant_valueless(v0); + make_variant_valueless(v1); + + EATEST_VERIFY((v0 != v1) == false); + } + } + + // Less Than + { + { + VariantThrow v0{ (int)0 }; + VariantThrow v1{ (int)1 }; + + make_variant_valueless(v0); + + EATEST_VERIFY((v0 < v1) == true); + } + + { + VariantThrow v0{ (int)0 }; + VariantThrow v1{ (int)1 }; + + make_variant_valueless(v1); + + EATEST_VERIFY((v0 < v1) == false); + } + } + + // Greater Than + { + { + VariantThrow v0{ (int)1 }; + VariantThrow v1{ (int)0 }; + + make_variant_valueless(v0); + + EATEST_VERIFY((v0 > v1) == false); + } + + { + VariantThrow v0{ (int)1 }; + VariantThrow v1{ (int)0 }; + + make_variant_valueless(v1); + + EATEST_VERIFY((v0 > v1) == true); + } + } + + // Less Equal + { + { + VariantThrow v0{ (int)1 }; + VariantThrow v1{ (int)1 }; + + make_variant_valueless(v0); + + EATEST_VERIFY((v0 <= v1) == true); + } + + { + VariantThrow v0{ (int)1 }; + VariantThrow v1{ (int)0 }; + + make_variant_valueless(v1); + + EATEST_VERIFY((v0 <= v1) == false); + } + } + + // Greater Equal + { + { + VariantThrow v0{ (int)1 }; + VariantThrow v1{ (int)1 }; + + make_variant_valueless(v0); + + EATEST_VERIFY((v0 >= v1) == false); + } + + { + VariantThrow v0{ (int)1 }; + VariantThrow v1{ (int)0 }; + + make_variant_valueless(v1); + + EATEST_VERIFY((v0 >= v1) == true); + } + } + +#endif + + return nErrorCount; +} + int TestVariantUserRegressionIncompleteType() { @@ -847,6 +1575,155 @@ int TestVariantUserRegressionIncompleteType() return nErrorCount; } +#define EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(Type, VarName) \ + bool operator==(const Type & rhs) const { return VarName == rhs.VarName; } \ + bool operator!=(const Type & rhs) const { return VarName != rhs.VarName; } \ + bool operator<(const Type & rhs) const { return VarName < rhs.VarName; } \ + bool operator>(const Type & rhs) const { return VarName > rhs.VarName; } \ + bool operator<=(const Type & rhs) const { return VarName <= rhs.VarName; } \ + bool operator>=(const Type & rhs) const { return VarName >= rhs.VarName; } + +int TestBigVariantComparison() +{ + int nErrorCount = 0; + + struct A; + struct B; + struct C; + struct D; + struct E; + struct F; + struct G; + struct H; + struct I; + struct J; + struct K; + struct L; + struct M; + struct N; + struct O; + struct P; + struct Q; + struct R; + struct S; + struct T; + struct U; + struct V; + struct W; + struct X; + struct Y; + struct Z; + + using BigVariant = eastl::variant; + + struct A { int a; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(A, a) }; + struct B { int b; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(B, b) }; + struct C { int c; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(C, c) }; + struct D { int d; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(D, d) }; + struct E { int e; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(E, e) }; + struct F { int f; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(F, f) }; + struct G { int g; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(G, g) }; + struct H { int h; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(H, h) }; + struct I { int i; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(I, i) }; + struct J { int j; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(J, j) }; + struct K { int k; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(K, k) }; + struct L { int l; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(L, l) }; + struct M { int m; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(M, m) }; + struct N { int n; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(N, n) }; + struct O { int o; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(O, o) }; + struct P { int p; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(P, p) }; + struct Q { int q; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(Q, q) }; + struct R { int r; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(R, r) }; + struct S { int s; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(S, s) }; + struct T { int t; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(T, t) }; + struct U { int u; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(U, u) }; + struct V { int v; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(V, v) }; + struct W { int w; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(W, w) }; + struct X { int x; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(X, x) }; + struct Y { int y; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(Y, y) }; + struct Z { int z; EASTL_TEST_BIG_VARIANT_RELATIONAL_OPS(Z, z) }; + + { + BigVariant v0{ A{0} }; + BigVariant v1{ A{1} }; + + VERIFY(v0 != v1); + } + + { + BigVariant v0{ A{0} }; + BigVariant v1{ A{1} }; + + VERIFY(v0 < v1); + } + + { + BigVariant v0{ A{0} }; + BigVariant v1{ A{0} }; + + VERIFY(v0 == v1); + } + + { + BigVariant v0{ A{1} }; + BigVariant v1{ A{0} }; + + VERIFY(v0 > v1); + } + + { + BigVariant v0{ A{0} }; + BigVariant v1{ A{1} }; + + VERIFY(v0 <= v1); + } + + { + BigVariant v0{ A{0} }; + BigVariant v1{ A{0} }; + + VERIFY(v0 <= v1); + } + + { + BigVariant v0{ A{0} }; + BigVariant v1{ A{0} }; + + VERIFY(v0 >= v1); + } + + { + BigVariant v0{ A{1} }; + BigVariant v1{ A{0} }; + + VERIFY(v0 >= v1); + } + + { + BigVariant v0{ A{0} }; + BigVariant v1{ B{0} }; + + VERIFY(v0 != v1); + } + + { + BigVariant v0{ A{0} }; + BigVariant v1{ B{0} }; + + VERIFY(v0 < v1); + } + + { + BigVariant v0{ A{0} }; + BigVariant v1{ B{0} }; + + VERIFY(v1 > v0); + } + + return nErrorCount; +} + int TestVariantGeneratingComparisonOverloads(); int TestVariant() @@ -871,6 +1748,8 @@ int TestVariant() nErrorCount += TestVariantUserRegressionCopyMoveAssignmentOperatorLeak(); nErrorCount += TestVariantUserRegressionIncompleteType(); nErrorCount += TestVariantGeneratingComparisonOverloads(); + nErrorCount += TestBigVariantComparison(); + nErrorCount += TestVariantRelationalOperators(); return nErrorCount; } diff --git a/library/3rdparty/EASTL/test/source/main.cpp b/library/3rdparty/EASTL/test/source/main.cpp index 962d2c4..8ce7c1b 100644 --- a/library/3rdparty/EASTL/test/source/main.cpp +++ b/library/3rdparty/EASTL/test/source/main.cpp @@ -145,6 +145,7 @@ int EAMain(int argc, char* argv[]) testSuite.AddTest("VectorSet", TestVectorSet); testSuite.AddTest("AtomicBasic", TestAtomicBasic); testSuite.AddTest("AtomicAsm", TestAtomicAsm); + testSuite.AddTest("TestBitcast", TestBitcast); nErrorCount += testSuite.Run(); From e1088151c583deda35e299e9f46b9148b8907a8c Mon Sep 17 00:00:00 2001 From: Marcos Bracco Date: Wed, 22 Feb 2023 15:46:49 -0300 Subject: [PATCH 23/31] Diff for EASTL-3.19.05 --- library/3rdparty/EASTL-3.19.05.diff | 3096 +++++++++++++++++++++++ library/3rdparty/clone-EABase-EASTL.bat | 4 +- library/3rdparty/clone-EABase-EASTL.sh | 4 +- 3 files changed, 3100 insertions(+), 4 deletions(-) create mode 100644 library/3rdparty/EASTL-3.19.05.diff diff --git a/library/3rdparty/EASTL-3.19.05.diff b/library/3rdparty/EASTL-3.19.05.diff new file mode 100644 index 0000000..38a8d10 --- /dev/null +++ b/library/3rdparty/EASTL-3.19.05.diff @@ -0,0 +1,3096 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index e8700dc..bba15ff 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -20,7 +20,7 @@ include(CommonCppFlags) + # Library definition + #------------------------------------------------------------------------------------------- + file(GLOB EASTL_SOURCES "source/*.cpp") +-add_library(EASTL ${EASTL_SOURCES}) ++add_library(EASTL STATIC ${EASTL_SOURCES}) + + if(EASTL_BUILD_BENCHMARK) + add_subdirectory(benchmark) +diff --git a/include/EASTL/allocator.h b/include/EASTL/allocator.h +index d645466..3c66a4e 100644 +--- a/include/EASTL/allocator.h ++++ b/include/EASTL/allocator.h +@@ -64,6 +64,78 @@ namespace eastl + const char* get_name() const; + void set_name(const char* pName); + ++ //////// safememory methods and aliases below //////// ++ ++ template ++ using pointer = T*; ++ ++ template ++ using array_pointer = T*; ++ ++ template ++ T* allocate_array(eastl_size_t count, int flags = 0) { ++ //TODO use aligned allocate ++ return (T*)allocate(count * sizeof(T), flags); ++ } ++ ++ template ++ T* allocate_array_zeroed(eastl_size_t count, int flags = 0) { ++ //TODO use aligned allocate ++ auto arr = (T*)allocate(count * sizeof(T), flags); ++ memset(arr, 0, count * sizeof(T)); ++ return arr; ++ } ++ ++ template ++ void deallocate_array(T* p, eastl_size_t count) { ++ deallocate(p, count * sizeof(T)); ++ } ++ ++ template ++ T* allocate_node() { ++ return (T*)allocate(sizeof(T), 0); ++ } ++ ++ template ++ void deallocate_node(T* p) { ++ deallocate(p, sizeof(T)); ++ } ++ ++ template ++ static T* to_raw(T* p) { ++ return p; ++ } ++ ++ template ++ static int make_raii(T* p) { ++ return 0; ++ } ++ ++ static void force_changes_in_dtor(const void*) {} ++ ++ //////// hashtable special values //////// ++ template ++ static T* get_hashtable_sentinel() { ++ return reinterpret_cast((void*)uintptr_t(~0)); ++ } ++ ++ template ++ static T* get_empty_hashtable() { ++ extern EASTL_API void* gpEmptyBucketArray[2]; ++ return reinterpret_cast(&gpEmptyBucketArray[0]); ++ } ++ ++ template ++ static bool is_hashtable_sentinel(const T* p) { ++ return p == get_hashtable_sentinel(); ++ } ++ ++ template ++ static bool is_empty_hashtable(const T* a) { ++ return a == get_empty_hashtable(); ++ } ++ ++ + protected: + #if EASTL_NAME_ENABLED + const char* mpName; // Debug name, used to track memory. +@@ -75,7 +147,6 @@ namespace eastl + bool operator!=(const allocator& a, const allocator& b); + #endif + +- + /// dummy_allocator + /// + /// Defines an allocator which does nothing. It returns NULL from allocate calls. +diff --git a/include/EASTL/internal/atomic/atomic_integral.h b/include/EASTL/internal/atomic/atomic_integral.h +index a9c96c7..674e051 100644 +--- a/include/EASTL/internal/atomic/atomic_integral.h ++++ b/include/EASTL/internal/atomic/atomic_integral.h +@@ -326,9 +326,9 @@ namespace internal + EASTL_ATOMIC_INTEGRAL_WIDTH_SPECIALIZE(8, 64) + #endif + +-#if defined(EASTL_ATOMIC_HAS_128BIT) +- EASTL_ATOMIC_INTEGRAL_WIDTH_SPECIALIZE(16, 128) +-#endif ++// #if defined(EASTL_ATOMIC_HAS_128BIT) ++// EASTL_ATOMIC_INTEGRAL_WIDTH_SPECIALIZE(16, 128) ++// #endif + + + } // namespace internal +diff --git a/include/EASTL/internal/hashtable.h b/include/EASTL/internal/hashtable.h +index 077f5b4..d4cdfd1 100644 +--- a/include/EASTL/internal/hashtable.h ++++ b/include/EASTL/internal/hashtable.h +@@ -103,34 +103,34 @@ namespace eastl + /// store a hash code in the node to speed up hash calculations + /// and comparisons in some cases. + /// +- template ++ template + struct hash_node; + + EA_DISABLE_VC_WARNING(4625 4626) // "copy constructor / assignment operator could not be generated because a base class copy constructor is inaccessible or deleted" + #ifdef EA_COMPILER_MSVC_2015 + EA_DISABLE_VC_WARNING(5026) // disable warning: "move constructor was implicitly defined as deleted" + #endif +- template +- struct hash_node ++ template ++ struct hash_node + { + hash_node() = default; + hash_node(const hash_node&) = default; + hash_node(hash_node&&) = default; + + Value mValue; +- hash_node* mpNext; ++ typename Allocator::template pointer mpNext; + eastl_size_t mnHashCode; // See config.h for the definition of eastl_size_t, which defaults to size_t. + } EASTL_MAY_ALIAS; + +- template +- struct hash_node ++ template ++ struct hash_node + { + hash_node() = default; + hash_node(const hash_node&) = default; + hash_node(hash_node&&) = default; + + Value mValue; +- hash_node* mpNext; ++ typename Allocator::template pointer mpNext; + } EASTL_MAY_ALIAS; + + #ifdef EA_COMPILER_MSVC_2015 +@@ -161,8 +161,8 @@ namespace eastl + }; + } + +- static_assert(Internal::has_hashcode_member>::value, "contains a mnHashCode member"); +- static_assert(!Internal::has_hashcode_member>::value, "doesn't contain a mnHashCode member"); ++ // static_assert(Internal::has_hashcode_member>::value, "contains a mnHashCode member"); ++ // static_assert(!Internal::has_hashcode_member>::value, "doesn't contain a mnHashCode member"); + + // convenience macros to increase the readability of the code paths that must SFINAE on if the 'hash_node' + // contains the cached hashed value or not. +@@ -179,16 +179,22 @@ namespace eastl + /// We define a base class here because it is shared by both const and + /// non-const iterators. + /// +- template ++ template + struct node_iterator_base + { +- typedef hash_node node_type; ++ typedef hash_node node_type; ++ typedef typename Allocator::template pointer pointer_type; + +- node_type* mpNode; ++ pointer_type mpNode; + +- node_iterator_base(node_type* pNode) ++ node_iterator_base(pointer_type pNode) + : mpNode(pNode) { } + ++ ~node_iterator_base() { ++ mpNode = nullptr; ++ Allocator::force_changes_in_dtor(this); ++ } ++ + void increment() + { mpNode = mpNode->mpNext; } + }; +@@ -202,12 +208,12 @@ namespace eastl + /// The bConst parameter defines if the iterator is a const_iterator + /// or an iterator. + /// +- template +- struct node_iterator : public node_iterator_base ++ template ++ struct node_iterator : public node_iterator_base + { + public: +- typedef node_iterator_base base_type; +- typedef node_iterator this_type; ++ typedef node_iterator_base base_type; ++ typedef node_iterator this_type; + typedef typename base_type::node_type node_type; + typedef Value value_type; + typedef typename type_select::type pointer; +@@ -216,10 +222,10 @@ namespace eastl + typedef EASTL_ITC_NS::forward_iterator_tag iterator_category; + + public: +- explicit node_iterator(node_type* pNode = NULL) ++ explicit node_iterator(typename base_type::pointer_type pNode = NULL) + : base_type(pNode) { } + +- node_iterator(const node_iterator& x) ++ node_iterator(const node_iterator& x) + : base_type(x.mpNode) { } + + reference operator*() const +@@ -248,33 +254,41 @@ namespace eastl + /// We define a base class here because it is shared by both const and + /// non-const iterators. + /// +- template ++ template + struct hashtable_iterator_base + { + public: +- typedef hashtable_iterator_base this_type; +- typedef hash_node node_type; ++ typedef hashtable_iterator_base this_type; ++ typedef hash_node node_type; ++ typedef typename Allocator::template pointer pointer_type; + + protected: ++ + template + friend class hashtable; + +- template ++ template + friend struct hashtable_iterator; + +- template +- friend bool operator==(const hashtable_iterator_base&, const hashtable_iterator_base&); ++ template ++ friend bool operator==(const hashtable_iterator_base&, const hashtable_iterator_base&); + +- template +- friend bool operator!=(const hashtable_iterator_base&, const hashtable_iterator_base&); ++ template ++ friend bool operator!=(const hashtable_iterator_base&, const hashtable_iterator_base&); + +- node_type* mpNode; // Current node within current bucket. +- node_type** mpBucket; // Current bucket. ++ pointer_type mpNode; // Current node within current bucket. ++ pointer_type* mpBucket; // Current bucket. + + public: +- hashtable_iterator_base(node_type* pNode, node_type** pBucket) ++ hashtable_iterator_base(const pointer_type& pNode, pointer_type* pBucket) + : mpNode(pNode), mpBucket(pBucket) { } + ++ ~hashtable_iterator_base() { ++ mpNode = nullptr; ++ mpBucket = nullptr; ++ Allocator::force_changes_in_dtor(this); ++ } ++ + void increment_bucket() + { + ++mpBucket; +@@ -306,13 +320,13 @@ namespace eastl + /// The bConst parameter defines if the iterator is a const_iterator + /// or an iterator. + /// +- template +- struct hashtable_iterator : public hashtable_iterator_base ++ template ++ struct hashtable_iterator : public hashtable_iterator_base + { + public: +- typedef hashtable_iterator_base base_type; +- typedef hashtable_iterator this_type; +- typedef hashtable_iterator this_type_non_const; ++ typedef hashtable_iterator_base base_type; ++ typedef hashtable_iterator this_type; ++ typedef hashtable_iterator this_type_non_const; + typedef typename base_type::node_type node_type; + typedef Value value_type; + typedef typename type_select::type pointer; +@@ -320,16 +334,29 @@ namespace eastl + typedef ptrdiff_t difference_type; + typedef EASTL_ITC_NS::forward_iterator_tag iterator_category; + ++ typedef typename base_type::pointer_type pointer_type; ++ + public: +- hashtable_iterator(node_type* pNode = NULL, node_type** pBucket = NULL) ++ hashtable_iterator(const pointer_type& pNode = NULL, pointer_type* pBucket = NULL) + : base_type(pNode, pBucket) { } + +- hashtable_iterator(node_type** pBucket) ++ hashtable_iterator(pointer_type* pBucket) + : base_type(*pBucket, pBucket) { } + + hashtable_iterator(const this_type_non_const& x) + : base_type(x.mpNode, x.mpBucket) { } + ++ hashtable_iterator& operator=(const this_type_non_const& x) ++ { ++ if(this != static_cast(&x)) ++ { ++ base_type::mpNode = x.mpNode; ++ base_type::mpBucket = x.mpBucket; ++ } ++ ++ return *this; ++ } ++ + reference operator*() const + { return base_type::mpNode->mValue; } + +@@ -342,9 +369,11 @@ namespace eastl + hashtable_iterator operator++(int) + { hashtable_iterator temp(*this); base_type::increment(); return temp; } + +- const node_type* get_node() const ++ const pointer_type& get_node() const + { return base_type::mpNode; } + ++ pointer_type* get_bucket() const ++ { return base_type::mpBucket; } + }; // hashtable_iterator + + +@@ -511,7 +540,7 @@ namespace eastl + /// objects here, for convenience. + /// + template ++ typename H1, typename H2, typename H, bool bCacheHashCode, typename Allocator> + struct hash_code_base; + + +@@ -520,8 +549,8 @@ namespace eastl + /// Specialization: ranged hash function, no caching hash codes. + /// H1 and H2 are provided but ignored. We define a dummy hash code type. + /// +- template +- struct hash_code_base ++ template ++ struct hash_code_base + { + protected: + ExtractKey mExtractKey; // To do: Make this member go away entirely, as it never has any data. +@@ -560,16 +589,16 @@ namespace eastl + bucket_index_t bucket_index(const Key& key, hash_code_t, uint32_t nBucketCount) const + { return (bucket_index_t)mRangedHash(key, nBucketCount); } + +- bucket_index_t bucket_index(const hash_node* pNode, uint32_t nBucketCount) const ++ bucket_index_t bucket_index(const hash_node* pNode, uint32_t nBucketCount) const + { return (bucket_index_t)mRangedHash(mExtractKey(pNode->mValue), nBucketCount); } + +- bool compare(const Key& key, hash_code_t, hash_node* pNode) const ++ bool compare(const Key& key, hash_code_t, hash_node* pNode) const + { return mEqual(key, mExtractKey(pNode->mValue)); } + +- void copy_code(hash_node*, const hash_node*) const ++ void copy_code(hash_node*, const hash_node*) const + { } // Nothing to do. + +- void set_code(hash_node* pDest, hash_code_t c) const ++ void set_code(hash_node* pDest, hash_code_t c) const + { + EA_UNUSED(pDest); + EA_UNUSED(c); +@@ -596,8 +625,8 @@ namespace eastl + /// This combination is meaningless, so we provide only a declaration + /// and no definition. + /// +- template +- struct hash_code_base; ++ template ++ struct hash_code_base; + + + +@@ -607,8 +636,8 @@ namespace eastl + /// no caching of hash codes. H is provided but ignored. + /// Provides typedef and accessor required by TR1. + /// +- template +- struct hash_code_base ++ template ++ struct hash_code_base + { + protected: + ExtractKey mExtractKey; +@@ -634,7 +663,7 @@ namespace eastl + protected: + typedef size_t hash_code_t; + typedef uint32_t bucket_index_t; +- typedef hash_node node_type; ++ typedef hash_node node_type; + + hash_code_base(const ExtractKey& ex, const Equal& eq, const H1& h1, const H2& h2, const default_ranged_hash&) + : mExtractKey(ex), mEqual(eq), m_h1(h1), m_h2(h2) { } +@@ -678,8 +707,8 @@ namespace eastl + /// caching hash codes. H is provided but ignored. + /// Provides typedef and accessor required by TR1. + /// +- template +- struct hash_code_base ++ template ++ struct hash_code_base + { + protected: + ExtractKey mExtractKey; +@@ -705,7 +734,7 @@ namespace eastl + protected: + typedef uint32_t hash_code_t; + typedef uint32_t bucket_index_t; +- typedef hash_node node_type; ++ typedef hash_node node_type; + + hash_code_base(const ExtractKey& ex, const Equal& eq, const H1& h1, const H2& h2, const default_ranged_hash&) + : mExtractKey(ex), mEqual(eq), m_h1(h1), m_h2(h2) { } +@@ -826,13 +855,13 @@ namespace eastl + typename RehashPolicy, bool bCacheHashCode, bool bMutableIterators, bool bUniqueKeys> + class hashtable + : public rehash_base >, +- public hash_code_base ++ public hash_code_base + { + public: + typedef Key key_type; + typedef Value value_type; + typedef typename ExtractKey::result_type mapped_type; +- typedef hash_code_base hash_code_base_type; ++ typedef hash_code_base hash_code_base_type; + typedef typename hash_code_base_type::hash_code_t hash_code_t; + typedef Allocator allocator_type; + typedef Equal key_equal; +@@ -840,11 +869,13 @@ namespace eastl + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to size_t. + typedef value_type& reference; + typedef const value_type& const_reference; +- typedef node_iterator local_iterator; +- typedef node_iterator const_local_iterator; +- typedef hashtable_iterator iterator; +- typedef hashtable_iterator const_iterator; +- typedef hash_node node_type; ++ typedef node_iterator local_iterator; ++ typedef node_iterator const_local_iterator; ++ typedef hashtable_iterator iterator; ++ typedef hashtable_iterator const_iterator; ++ typedef hash_node node_type; ++ typedef typename allocator_type::template pointer node_pointer; ++ typedef typename allocator_type::template array_pointer bucket_array_type; + typedef typename type_select, iterator>::type insert_return_type; + typedef hashtable this_type; +@@ -873,7 +904,7 @@ namespace eastl + }; + + protected: +- node_type** mpBucketArray; ++ bucket_array_type mpBucketArray; + size_type mnBucketCount; + size_type mnElementCount; + RehashPolicy mRehashPolicy; // To do: Use base class optimization to make this go away. +@@ -916,7 +947,7 @@ namespace eastl + + iterator begin() EA_NOEXCEPT + { +- iterator i(mpBucketArray); ++ iterator i(allocator_type::to_raw(mpBucketArray)); + if(!i.mpNode) + i.increment_bucket(); + return i; +@@ -924,7 +955,7 @@ namespace eastl + + const_iterator begin() const EA_NOEXCEPT + { +- const_iterator i(mpBucketArray); ++ const_iterator i(allocator_type::to_raw(mpBucketArray)); + if(!i.mpNode) + i.increment_bucket(); + return i; +@@ -1035,7 +1066,7 @@ namespace eastl + + // Non-standard extension + template // See comments below for the const value_type& equivalent to this function. +- insert_return_type insert(hash_code_t c, node_type* pNodeNew, P&& otherValue); ++ insert_return_type insert(hash_code_t c, node_pointer pNodeNew, P&& otherValue); + + // We provide a version of insert which lets the caller directly specify the hash value and + // a potential node to insert if needed. This allows for less thread contention in the case +@@ -1046,7 +1077,7 @@ namespace eastl + // to another call to insert. pNodeNew need not be assigned the value by the caller, as the insert + // function will assign value to pNodeNew upon insertion into the hash table. pNodeNew may be + // created by the user with the allocate_uninitialized_node function, and freed by the free_uninitialized_node function. +- insert_return_type insert(hash_code_t c, node_type* pNodeNew, const value_type& value); ++ insert_return_type insert(hash_code_t c, node_pointer pNodeNew, const value_type& value); + + template eastl::pair insert_or_assign(const key_type& k, M&& obj); + template eastl::pair insert_or_assign(key_type&& k, M&& obj); +@@ -1054,8 +1085,8 @@ namespace eastl + template iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); + + // Used to allocate and free memory used by insert(const value_type& value, hash_code_t c, node_type* pNodeNew). +- node_type* allocate_uninitialized_node(); +- void free_uninitialized_node(node_type* pNode); ++ node_pointer allocate_uninitialized_node(); ++ void free_uninitialized_node(node_pointer pNode); + + iterator erase(const_iterator position); + iterator erase(const_iterator first, const_iterator last); +@@ -1115,7 +1146,7 @@ namespace eastl + + const size_type n = (size_type)bucket_index(c, (uint32_t)mnBucketCount); + +- node_type* const pNode = DoFindNode(mpBucketArray[n], c); ++ node_pointer const pNode = DoFindNode(mpBucketArray[n], c); + + return pNode ? iterator(pNode, mpBucketArray + n) : + iterator(mpBucketArray + mnBucketCount); // iterator(mpBucketArray + mnBucketCount) == end() +@@ -1131,7 +1162,7 @@ namespace eastl + + const size_type n = (size_type)bucket_index(c, (uint32_t)mnBucketCount); + +- node_type* const pNode = DoFindNode(mpBucketArray[n], c); ++ node_pointer const pNode = DoFindNode(mpBucketArray[n], c); + + return pNode ? + const_iterator(pNode, mpBucketArray + n) : +@@ -1142,7 +1173,7 @@ namespace eastl + { + const size_type n = (size_type)bucket_index(c, (uint32_t)mnBucketCount); + +- node_type* const pNode = DoFindNode(mpBucketArray[n], k, c); ++ node_pointer const pNode = DoFindNode(mpBucketArray[n], k, c); + return pNode ? iterator(pNode, mpBucketArray + n) : iterator(mpBucketArray + mnBucketCount); // iterator(mpBucketArray + mnBucketCount) == end() + } + +@@ -1150,7 +1181,7 @@ namespace eastl + { + const size_type n = (size_type)bucket_index(c, (uint32_t)mnBucketCount); + +- node_type* const pNode = DoFindNode(mpBucketArray[n], k, c); ++ node_pointer const pNode = DoFindNode(mpBucketArray[n], k, c); + return pNode ? const_iterator(pNode, mpBucketArray + n) : const_iterator(mpBucketArray + mnBucketCount); // iterator(mpBucketArray + mnBucketCount) == end() + } + +@@ -1193,16 +1224,16 @@ namespace eastl + return irt; + } + +- node_type* DoAllocateNodeFromKey(const key_type& key); +- node_type* DoAllocateNodeFromKey(key_type&& key); +- void DoFreeNode(node_type* pNode); +- void DoFreeNodes(node_type** pBucketArray, size_type); ++ node_pointer DoAllocateNodeFromKey(const key_type& key); ++ node_pointer DoAllocateNodeFromKey(key_type&& key); ++ void DoFreeNode(node_pointer pNode); ++ void DoFreeNodes(bucket_array_type pBucketArray, size_type); + +- node_type** DoAllocateBuckets(size_type n); +- void DoFreeBuckets(node_type** pBucketArray, size_type n); ++ bucket_array_type DoAllocateBuckets(size_type n); ++ void DoFreeBuckets(bucket_array_type pBucketArray, size_type n); + + template , ENABLE_IF_TRUETYPE(Enabled) = nullptr> // only enabled when keys are unique +- eastl::pair DoInsertUniqueNode(const key_type& k, hash_code_t c, size_type n, node_type* pNodeNew); ++ eastl::pair DoInsertUniqueNode(const key_type& k, hash_code_t c, size_type n, node_pointer pNodeNew); + + template + eastl::pair DoInsertValue(BoolConstantT, Args&&... args); +@@ -1215,7 +1246,7 @@ namespace eastl + eastl::pair DoInsertValueExtra(BoolConstantT, + const key_type& k, + hash_code_t c, +- node_type* pNodeNew, ++ node_pointer pNodeNew, + value_type&& value, + ENABLE_IF_TRUETYPE(BoolConstantT) = nullptr); + +@@ -1228,7 +1259,7 @@ namespace eastl + iterator DoInsertValueExtra(BoolConstantT, + const key_type& k, + hash_code_t c, +- node_type* pNodeNew, ++ node_pointer pNodeNew, + value_type&& value, + DISABLE_IF_TRUETYPE(BoolConstantT) = nullptr); + +@@ -1240,7 +1271,7 @@ namespace eastl + eastl::pair DoInsertValueExtra(BoolConstantT, + const key_type& k, + hash_code_t c, +- node_type* pNodeNew, ++ node_pointer pNodeNew, + const value_type& value, + ENABLE_IF_TRUETYPE(BoolConstantT) = nullptr); + +@@ -1253,7 +1284,7 @@ namespace eastl + iterator DoInsertValueExtra(BoolConstantT, + const key_type& k, + hash_code_t c, +- node_type* pNodeNew, ++ node_pointer pNodeNew, + const value_type& value, + DISABLE_IF_TRUETYPE(BoolConstantT) = nullptr); + +@@ -1261,9 +1292,9 @@ namespace eastl + iterator DoInsertValue(BoolConstantT, const value_type& value, DISABLE_IF_TRUETYPE(BoolConstantT) = nullptr); + + template +- node_type* DoAllocateNode(Args&&... args); +- node_type* DoAllocateNode(value_type&& value); +- node_type* DoAllocateNode(const value_type& value); ++ node_pointer DoAllocateNode(Args&&... args); ++ node_pointer DoAllocateNode(value_type&& value); ++ node_pointer DoAllocateNode(const value_type& value); + + // DoInsertKey is supposed to get hash_code_t c = get_hash_code(key). + // it is done in case application has it's own hashset/hashmap-like containter, where hash code is for some reason known prior the insert +@@ -1281,7 +1312,7 @@ namespace eastl + iterator DoInsertKey(false_type, key_type&& key) { return DoInsertKey(false_type(), eastl::move(key), get_hash_code(key)); } + + void DoRehash(size_type nBucketCount); +- node_type* DoFindNode(node_type* pNode, const key_type& k, hash_code_t c) const; ++ node_pointer DoFindNode(node_pointer pNode, const key_type& k, hash_code_t c) const; + NodeFindKeyData DoFindKeyData(const key_type& k) const; + + template +@@ -1296,13 +1327,13 @@ namespace eastl + } + + template +- node_type* DoFindNodeT(node_type* pNode, const U& u, BinaryPredicate predicate) const; ++ node_pointer DoFindNodeT(node_pointer pNode, const U& u, BinaryPredicate predicate) const; + + private: + template , ENABLE_IF_TRUETYPE(Enabled) = nullptr> + eastl::pair DoInsertValueExtraForwarding(const key_type& k, + hash_code_t c, +- node_type* pNodeNew, ++ node_pointer pNodeNew, + V&& value); + + +@@ -1316,12 +1347,12 @@ namespace eastl + // node_iterator_base + /////////////////////////////////////////////////////////////////////// + +- template +- inline bool operator==(const node_iterator_base& a, const node_iterator_base& b) ++ template ++ inline bool operator==(const node_iterator_base& a, const node_iterator_base& b) + { return a.mpNode == b.mpNode; } + +- template +- inline bool operator!=(const node_iterator_base& a, const node_iterator_base& b) ++ template ++ inline bool operator!=(const node_iterator_base& a, const node_iterator_base& b) + { return a.mpNode != b.mpNode; } + + +@@ -1331,12 +1362,12 @@ namespace eastl + // hashtable_iterator_base + /////////////////////////////////////////////////////////////////////// + +- template +- inline bool operator==(const hashtable_iterator_base& a, const hashtable_iterator_base& b) ++ template ++ inline bool operator==(const hashtable_iterator_base& a, const hashtable_iterator_base& b) + { return a.mpNode == b.mpNode; } + +- template +- inline bool operator!=(const hashtable_iterator_base& a, const hashtable_iterator_base& b) ++ template ++ inline bool operator!=(const hashtable_iterator_base& a, const hashtable_iterator_base& b) + { return a.mpNode != b.mpNode; } + + +@@ -1352,7 +1383,7 @@ namespace eastl + ::hashtable(size_type nBucketCount, const H1& h1, const H2& h2, const H& h, + const Eq& eq, const EK& ek, const allocator_type& allocator) + : rehash_base(), +- hash_code_base(ek, eq, h1, h2, h), ++ hash_code_base(ek, eq, h1, h2, h), + mnBucketCount(0), + mnElementCount(0), + mRehashPolicy(), +@@ -1377,7 +1408,7 @@ namespace eastl + const H1& h1, const H2& h2, const H& h, + const Eq& eq, const EK& ek, const allocator_type& allocator) + : rehash_base(), +- hash_code_base(ek, eq, h1, h2, h), ++ hash_code_base(ek, eq, h1, h2, h), + //mnBucketCount(0), // This gets re-assigned below. + mnElementCount(0), + mRehashPolicy(), +@@ -1419,7 +1450,7 @@ namespace eastl + typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU> + hashtable::hashtable(const this_type& x) + : rehash_base(x), +- hash_code_base(x), ++ hash_code_base(x), + mnBucketCount(x.mnBucketCount), + mnElementCount(x.mnElementCount), + mRehashPolicy(x.mRehashPolicy), +@@ -1435,13 +1466,13 @@ namespace eastl + #endif + for(size_type i = 0; i < x.mnBucketCount; ++i) + { +- node_type* pNodeSource = x.mpBucketArray[i]; +- node_type** ppNodeDest = mpBucketArray + i; ++ node_pointer pNodeSource = x.mpBucketArray[i]; ++ node_pointer* ppNodeDest = mpBucketArray + i; + + while(pNodeSource) + { + *ppNodeDest = DoAllocateNode(pNodeSource->mValue); +- copy_code(*ppNodeDest, pNodeSource); ++ copy_code(allocator_type::to_raw(*ppNodeDest), allocator_type::to_raw(pNodeSource)); + ppNodeDest = &(*ppNodeDest)->mpNext; + pNodeSource = pNodeSource->mpNext; + } +@@ -1469,7 +1500,7 @@ namespace eastl + typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU> + hashtable::hashtable(this_type&& x) + : rehash_base(x), +- hash_code_base(x), ++ hash_code_base(x), + mnBucketCount(0), + mnElementCount(0), + mRehashPolicy(x.mRehashPolicy), +@@ -1484,7 +1515,7 @@ namespace eastl + typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU> + hashtable::hashtable(this_type&& x, const allocator_type& allocator) + : rehash_base(x), +- hash_code_base(x), ++ hash_code_base(x), + mnBucketCount(0), + mnElementCount(0), + mRehashPolicy(x.mRehashPolicy), +@@ -1577,21 +1608,25 @@ namespace eastl + { + clear(); + DoFreeBuckets(mpBucketArray, mnBucketCount); ++ reset_lose_memory(); ++ allocator_type::force_changes_in_dtor(this); + } + + + template +- typename hashtable::node_type* ++ typename hashtable::node_pointer + hashtable::DoAllocateNodeFromKey(const key_type& key) + { +- node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++ node_pointer const pNode = mAllocator.template allocate_node(); + EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif ++ auto raii = allocator_type::make_raii(pNode); + ::new(eastl::addressof(pNode->mValue)) value_type(pair_first_construct, key); + pNode->mpNext = NULL; + return pNode; +@@ -1599,7 +1634,8 @@ namespace eastl + } + catch(...) + { +- EASTLFree(mAllocator, pNode, sizeof(node_type)); ++// EASTLFree(mAllocator, pNode, sizeof(node_type)); ++ mAllocator.deallocate_node(pNode); + throw; + } + #endif +@@ -1608,16 +1644,18 @@ namespace eastl + + template +- typename hashtable::node_type* ++ typename hashtable::node_pointer + hashtable::DoAllocateNodeFromKey(key_type&& key) + { +- node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++ node_pointer const pNode = mAllocator.template allocate_node(); + EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif ++ auto raii = allocator_type::make_raii(pNode); + ::new(eastl::addressof(pNode->mValue)) value_type(pair_first_construct, eastl::move(key)); + pNode->mpNext = NULL; + return pNode; +@@ -1625,7 +1663,8 @@ namespace eastl + } + catch(...) + { +- EASTLFree(mAllocator, pNode, sizeof(node_type)); ++ // EASTLFree(mAllocator, pNode, sizeof(node_type)); ++ mAllocator.deallocate_node(pNode); + throw; + } + #endif +@@ -1634,24 +1673,25 @@ namespace eastl + + template +- inline void hashtable::DoFreeNode(node_type* pNode) ++ inline void hashtable::DoFreeNode(node_pointer pNode) + { + pNode->~node_type(); +- EASTLFree(mAllocator, pNode, sizeof(node_type)); ++ // EASTLFree(mAllocator, pNode, sizeof(node_type)); ++ mAllocator.deallocate_node(pNode); + } + + + + template +- void hashtable::DoFreeNodes(node_type** pNodeArray, size_type n) ++ void hashtable::DoFreeNodes(bucket_array_type pNodeArray, size_type n) + { + for(size_type i = 0; i < n; ++i) + { +- node_type* pNode = pNodeArray[i]; ++ node_pointer pNode = pNodeArray[i]; + while(pNode) + { +- node_type* const pTempNode = pNode; ++ node_pointer const pTempNode = pNode; + pNode = pNode->mpNext; + DoFreeNode(pTempNode); + } +@@ -1663,17 +1703,18 @@ namespace eastl + + template +- typename hashtable::node_type** ++ typename hashtable::bucket_array_type + hashtable::DoAllocateBuckets(size_type n) + { + // We allocate one extra bucket to hold a sentinel, an arbitrary + // non-null pointer. Iterator increment relies on this. + EASTL_ASSERT(n > 1); // We reserve an mnBucketCount of 1 for the shared gpEmptyBucketArray. + EASTL_CT_ASSERT(kHashtableAllocFlagBuckets == 0x00400000); // Currently we expect this to be so, because the allocator has a copy of this enum. +- node_type** const pBucketArray = (node_type**)EASTLAllocAlignedFlags(mAllocator, (n + 1) * sizeof(node_type*), EASTL_ALIGN_OF(node_type*), 0, kHashtableAllocFlagBuckets); ++// node_type** const pBucketArray = (node_type**)EASTLAllocAlignedFlags(mAllocator, (n + 1) * sizeof(node_type*), EASTL_ALIGN_OF(node_type*), 0, kHashtableAllocFlagBuckets); ++ bucket_array_type const pBucketArray = mAllocator.template allocate_array_zeroed(n + 1, kHashtableAllocFlagBuckets); + //eastl::fill(pBucketArray, pBucketArray + n, (node_type*)NULL); +- memset(pBucketArray, 0, n * sizeof(node_type*)); +- pBucketArray[n] = reinterpret_cast((uintptr_t)~0); ++ //memset(pBucketArray, 0, n * sizeof(node_pointer)); ++ pBucketArray[n] = allocator_type::template get_hashtable_sentinel(); + return pBucketArray; + } + +@@ -1681,13 +1722,14 @@ namespace eastl + + template +- inline void hashtable::DoFreeBuckets(node_type** pBucketArray, size_type n) ++ inline void hashtable::DoFreeBuckets(bucket_array_type pBucketArray, size_type n) + { + // If n <= 1, then pBucketArray is from the shared gpEmptyBucketArray. We don't test + // for pBucketArray == &gpEmptyBucketArray because one library have a different gpEmptyBucketArray + // than another but pass a hashtable to another. So we go by the size. + if(n > 1) +- EASTLFree(mAllocator, pBucketArray, (n + 1) * sizeof(node_type*)); // '+1' because DoAllocateBuckets allocates nBucketCount + 1 buckets in order to have a NULL sentinel at the end. ++ // EASTLFree(mAllocator, pBucketArray, (n + 1) * sizeof(node_type*)); // '+1' because DoAllocateBuckets allocates nBucketCount + 1 buckets in order to have a NULL sentinel at the end. ++ mAllocator.deallocate_array(pBucketArray, n + 1); + } + + +@@ -1695,9 +1737,9 @@ namespace eastl + typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU> + void hashtable::swap(this_type& x) + { +- hash_code_base::base_swap(x); // hash_code_base has multiple implementations, so we let them handle the swap. ++ hash_code_base::base_swap(x); // hash_code_base has multiple implementations, so we let them handle the swap. + eastl::swap(mRehashPolicy, x.mRehashPolicy); +- EASTL_MACRO_SWAP(node_type**, mpBucketArray, x.mpBucketArray); ++ EASTL_MACRO_SWAP(bucket_array_type, mpBucketArray, x.mpBucketArray); + eastl::swap(mnBucketCount, x.mnBucketCount); + eastl::swap(mnElementCount, x.mnElementCount); + +@@ -1730,7 +1772,7 @@ namespace eastl + const hash_code_t c = get_hash_code(k); + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + +- node_type* const pNode = DoFindNode(mpBucketArray[n], k, c); ++ node_pointer const pNode = DoFindNode(mpBucketArray[n], k, c); + return pNode ? iterator(pNode, mpBucketArray + n) : iterator(mpBucketArray + mnBucketCount); // iterator(mpBucketArray + mnBucketCount) == end() + } + +@@ -1744,7 +1786,7 @@ namespace eastl + const hash_code_t c = get_hash_code(k); + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + +- node_type* const pNode = DoFindNode(mpBucketArray[n], k, c); ++ node_pointer const pNode = DoFindNode(mpBucketArray[n], k, c); + return pNode ? const_iterator(pNode, mpBucketArray + n) : const_iterator(mpBucketArray + mnBucketCount); // iterator(mpBucketArray + mnBucketCount) == end() + } + +@@ -1759,7 +1801,7 @@ namespace eastl + const hash_code_t c = (hash_code_t)uhash(other); + const size_type n = (size_type)(c % mnBucketCount); // This assumes we are using the mod range policy. + +- node_type* const pNode = DoFindNodeT(mpBucketArray[n], other, predicate); ++ node_pointer const pNode = DoFindNodeT(mpBucketArray[n], other, predicate); + return pNode ? iterator(pNode, mpBucketArray + n) : iterator(mpBucketArray + mnBucketCount); // iterator(mpBucketArray + mnBucketCount) == end() + } + +@@ -1774,7 +1816,7 @@ namespace eastl + const hash_code_t c = (hash_code_t)uhash(other); + const size_type n = (size_type)(c % mnBucketCount); // This assumes we are using the mod range policy. + +- node_type* const pNode = DoFindNodeT(mpBucketArray[n], other, predicate); ++ node_pointer const pNode = DoFindNodeT(mpBucketArray[n], other, predicate); + return pNode ? const_iterator(pNode, mpBucketArray + n) : const_iterator(mpBucketArray + mnBucketCount); // iterator(mpBucketArray + mnBucketCount) == end() + } + +@@ -1833,7 +1875,7 @@ namespace eastl + hashtable::find_range_by_hash(hash_code_t c) const + { + const size_type start = (size_type)bucket_index(c, (uint32_t)mnBucketCount); +- node_type* const pNodeStart = mpBucketArray[start]; ++ node_pointer const pNodeStart = mpBucketArray[start]; + + if (pNodeStart) + { +@@ -1856,7 +1898,7 @@ namespace eastl + hashtable::find_range_by_hash(hash_code_t c) + { + const size_type start = (size_type)bucket_index(c, (uint32_t)mnBucketCount); +- node_type* const pNodeStart = mpBucketArray[start]; ++ node_pointer const pNodeStart = mpBucketArray[start]; + + if (pNodeStart) + { +@@ -1884,9 +1926,9 @@ namespace eastl + + // To do: Make a specialization for bU (unique keys) == true and take + // advantage of the fact that the count will always be zero or one in that case. +- for(node_type* pNode = mpBucketArray[n]; pNode; pNode = pNode->mpNext) ++ for(node_pointer pNode = mpBucketArray[n]; pNode; pNode = pNode->mpNext) + { +- if(compare(k, c, pNode)) ++ if(compare(k, c, allocator_type::to_raw(pNode))) + ++result; + } + return result; +@@ -1902,16 +1944,16 @@ namespace eastl + { + const hash_code_t c = get_hash_code(k); + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); +- node_type** head = mpBucketArray + n; +- node_type* pNode = DoFindNode(*head, k, c); ++ node_pointer* head = mpBucketArray + n; ++ node_pointer pNode = DoFindNode(*head, k, c); + + if(pNode) + { +- node_type* p1 = pNode->mpNext; ++ node_pointer p1 = pNode->mpNext; + + for(; p1; p1 = p1->mpNext) + { +- if(!compare(k, c, p1)) ++ if(!compare(k, c, allocator_type::to_raw(p1))) + break; + } + +@@ -1939,16 +1981,16 @@ namespace eastl + { + const hash_code_t c = get_hash_code(k); + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); +- node_type** head = mpBucketArray + n; +- node_type* pNode = DoFindNode(*head, k, c); ++ node_pointer* head = mpBucketArray + n; ++ node_pointer pNode = DoFindNode(*head, k, c); + + if(pNode) + { +- node_type* p1 = pNode->mpNext; ++ node_pointer p1 = pNode->mpNext; + + for(; p1; p1 = p1->mpNext) + { +- if(!compare(k, c, p1)) ++ if(!compare(k, c, allocator_type::to_raw(p1))) + break; + } + +@@ -1979,12 +2021,12 @@ namespace eastl + + template +- inline typename hashtable::node_type* +- hashtable::DoFindNode(node_type* pNode, const key_type& k, hash_code_t c) const ++ inline typename hashtable::node_pointer ++ hashtable::DoFindNode(node_pointer pNode, const key_type& k, hash_code_t c) const + { + for(; pNode; pNode = pNode->mpNext) + { +- if(compare(k, c, pNode)) ++ if(compare(k, c, allocator_type::to_raw(pNode))) + return pNode; + } + return NULL; +@@ -1995,8 +2037,8 @@ namespace eastl + template + template +- inline typename hashtable::node_type* +- hashtable::DoFindNodeT(node_type* pNode, const U& other, BinaryPredicate predicate) const ++ inline typename hashtable::node_pointer ++ hashtable::DoFindNodeT(node_pointer pNode, const U& other, BinaryPredicate predicate) const + { + for(; pNode; pNode = pNode->mpNext) + { +@@ -2011,7 +2053,7 @@ namespace eastl + typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU> + template // only enabled when keys are unique + eastl::pair::iterator, bool> +- hashtable::DoInsertUniqueNode(const key_type& k, hash_code_t c, size_type n, node_type* pNodeNew) ++ hashtable::DoInsertUniqueNode(const key_type& k, hash_code_t c, size_type n, node_pointer pNodeNew) + { + const eastl::pair bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1); + +@@ -2060,11 +2102,11 @@ namespace eastl + // specializations of the insert function for const value_type& and value_type&&, and so the only time this function + // should get called is when args refers to arguments to construct a value_type. + +- node_type* const pNodeNew = DoAllocateNode(eastl::forward(args)...); ++ node_pointer const pNodeNew = DoAllocateNode(eastl::forward(args)...); + const key_type& k = mExtractKey(pNodeNew->mValue); + const hash_code_t c = get_hash_code(k); + size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); +- node_type* const pNode = DoFindNode(mpBucketArray[n], k, c); ++ node_pointer const pNode = DoFindNode(mpBucketArray[n], k, c); + + if(pNode == NULL) // If value is not present... add it. + { +@@ -2097,12 +2139,12 @@ namespace eastl + if(bRehash.first) + DoRehash(bRehash.second); + +- node_type* pNodeNew = DoAllocateNode(eastl::forward(args)...); ++ node_pointer pNodeNew = DoAllocateNode(eastl::forward(args)...); + const key_type& k = mExtractKey(pNodeNew->mValue); + const hash_code_t c = get_hash_code(k); + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + +- set_code(pNodeNew, c); // This is a no-op for most hashtables. ++ set_code(allocator_type::to_raw(pNodeNew), c); // This is a no-op for most hashtables. + + // To consider: Possibly make this insertion not make equal elements contiguous. + // As it stands now, we insert equal values contiguously in the hashtable. +@@ -2110,11 +2152,11 @@ namespace eastl + // erase(value) can more quickly find equal values. The downside is that + // this insertion operation taking some extra time. How important is it to + // us that equal_range span all equal items? +- node_type* const pNodePrev = DoFindNode(mpBucketArray[n], k, c); ++ node_pointer const pNodePrev = DoFindNode(mpBucketArray[n], k, c); + + if(pNodePrev == NULL) + { +- EASTL_ASSERT((void**)mpBucketArray != &gpEmptyBucketArray[0]); ++ EASTL_ASSERT(!allocator_type::is_empty_hashtable(mpBucketArray)); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + } +@@ -2133,16 +2175,18 @@ namespace eastl + template + template +- typename hashtable::node_type* ++ typename hashtable::node_pointer + hashtable::DoAllocateNode(Args&&... args) + { +- node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++ node_pointer const pNode = mAllocator.template allocate_node(); + EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif ++ auto raii = allocator_type::make_raii(pNode); + ::new(eastl::addressof(pNode->mValue)) value_type(eastl::forward(args)...); + pNode->mpNext = NULL; + return pNode; +@@ -2150,7 +2194,8 @@ namespace eastl + } + catch(...) + { +- EASTLFree(mAllocator, pNode, sizeof(node_type)); ++// EASTLFree(mAllocator, pNode, sizeof(node_type)); ++ mAllocator.deallocate_node(pNode); + throw; + } + #endif +@@ -2169,7 +2214,7 @@ namespace eastl + template + inline eastl::pair::iterator, bool> + hashtable::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. ++ hash_code_t c, node_pointer pNodeNew, value_type&& value, ENABLE_IF_TRUETYPE(BoolConstantT)) // true_type means bUniqueKeys is true. + { + return DoInsertValueExtraForwarding(k, c, pNodeNew, eastl::move(value)); + } +@@ -2179,7 +2224,7 @@ namespace eastl + template + inline eastl::pair::iterator, bool> + hashtable::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. ++ hash_code_t c, node_pointer pNodeNew, const value_type& value, ENABLE_IF_TRUETYPE(BoolConstantT)) // true_type means bUniqueKeys is true. + { + return DoInsertValueExtraForwarding(k, c, pNodeNew, value); + } +@@ -2189,12 +2234,12 @@ namespace eastl + template // true_type means bUniqueKeys is true. + eastl::pair::iterator, bool> + hashtable::DoInsertValueExtraForwarding(const key_type& k, +- hash_code_t c, node_type* pNodeNew, VFwd&& value) ++ hash_code_t c, node_pointer 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); +- node_type* const pNode = DoFindNode(mpBucketArray[n], k, c); ++ node_pointer const pNode = DoFindNode(mpBucketArray[n], k, c); + + if(pNode == NULL) // If value is not present... add it. + { +@@ -2202,6 +2247,7 @@ namespace eastl + // do a rehash if the allocation throws. + if(pNodeNew) + { ++ auto raii = allocator_type::make_raii(pNodeNew); + ::new(eastl::addressof(pNodeNew->mValue)) value_type(eastl::forward(value)); // It's expected that pNodeNew was allocated with allocate_uninitialized_node. + return DoInsertUniqueNode(k, c, n, pNodeNew); + } +@@ -2234,7 +2280,7 @@ namespace eastl + typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU> + template + typename hashtable::iterator +- hashtable::DoInsertValueExtra(BoolConstantT, const key_type& k, hash_code_t c, node_type* pNodeNew, value_type&& value, ++ hashtable::DoInsertValueExtra(BoolConstantT, const key_type& k, hash_code_t c, node_pointer pNodeNew, value_type&& value, + DISABLE_IF_TRUETYPE(BoolConstantT)) // false_type means bUniqueKeys is false. + { + const eastl::pair bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1); +@@ -2244,12 +2290,14 @@ namespace eastl + + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + +- if(pNodeNew) ++ if(pNodeNew) { ++ auto raii = allocator_type::make_raii(pNodeNew); + ::new(eastl::addressof(pNodeNew->mValue)) value_type(eastl::move(value)); // It's expected that pNodeNew was allocated with allocate_uninitialized_node. ++ } + else + pNodeNew = DoAllocateNode(eastl::move(value)); + +- set_code(pNodeNew, c); // This is a no-op for most hashtables. ++ set_code(allocator_type::to_raw(pNodeNew), c); // This is a no-op for most hashtables. + + // To consider: Possibly make this insertion not make equal elements contiguous. + // As it stands now, we insert equal values contiguously in the hashtable. +@@ -2257,11 +2305,11 @@ namespace eastl + // erase(value) can more quickly find equal values. The downside is that + // this insertion operation taking some extra time. How important is it to + // us that equal_range span all equal items? +- node_type* const pNodePrev = DoFindNode(mpBucketArray[n], k, c); ++ node_pointer const pNodePrev = DoFindNode(mpBucketArray[n], k, c); + + if(pNodePrev == NULL) + { +- EASTL_ASSERT((void**)mpBucketArray != &gpEmptyBucketArray[0]); ++ EASTL_ASSERT(!allocator_type::is_empty_hashtable(mpBucketArray)); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + } +@@ -2292,16 +2340,18 @@ namespace eastl + + template +- typename hashtable::node_type* ++ typename hashtable::node_pointer + hashtable::DoAllocateNode(value_type&& value) + { +- node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++ node_pointer const pNode = mAllocator.template allocate_node(); + EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif ++ auto raii = allocator_type::make_raii(pNode); + ::new(eastl::addressof(pNode->mValue)) value_type(eastl::move(value)); + pNode->mpNext = NULL; + return pNode; +@@ -2309,7 +2359,8 @@ namespace eastl + } + catch(...) + { +- EASTLFree(mAllocator, pNode, sizeof(node_type)); ++// EASTLFree(mAllocator, pNode, sizeof(node_type)); ++ mAllocator.deallocate_node(pNode); + throw; + } + #endif +@@ -2332,7 +2383,7 @@ namespace eastl + typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU> + template + typename hashtable::iterator +- hashtable::DoInsertValueExtra(BoolConstantT, const key_type& k, hash_code_t c, node_type* pNodeNew, const value_type& value, ++ hashtable::DoInsertValueExtra(BoolConstantT, const key_type& k, hash_code_t c, node_pointer pNodeNew, const value_type& value, + DISABLE_IF_TRUETYPE(BoolConstantT)) // false_type means bUniqueKeys is false. + { + const eastl::pair bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1); +@@ -2342,12 +2393,14 @@ namespace eastl + + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + +- if(pNodeNew) ++ if(pNodeNew) { ++ auto raii = allocator_type::make_raii(pNodeNew); + ::new(eastl::addressof(pNodeNew->mValue)) value_type(value); // It's expected that pNodeNew was allocated with allocate_uninitialized_node. ++ } + else + pNodeNew = DoAllocateNode(value); + +- set_code(pNodeNew, c); // This is a no-op for most hashtables. ++ set_code(allocator_type::to_raw(pNodeNew), c); // This is a no-op for most hashtables. + + // To consider: Possibly make this insertion not make equal elements contiguous. + // As it stands now, we insert equal values contiguously in the hashtable. +@@ -2355,11 +2408,11 @@ namespace eastl + // erase(value) can more quickly find equal values. The downside is that + // this insertion operation taking some extra time. How important is it to + // us that equal_range span all equal items? +- node_type* const pNodePrev = DoFindNode(mpBucketArray[n], k, c); ++ node_pointer const pNodePrev = DoFindNode(mpBucketArray[n], k, c); + + if(pNodePrev == NULL) + { +- EASTL_ASSERT((void**)mpBucketArray != &gpEmptyBucketArray[0]); ++ EASTL_ASSERT(!allocator_type::is_empty_hashtable(mpBucketArray)); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + } +@@ -2390,16 +2443,18 @@ namespace eastl + + template +- typename hashtable::node_type* ++ typename hashtable::node_pointer + hashtable::DoAllocateNode(const value_type& value) + { +- node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++ node_pointer const pNode = mAllocator.template allocate_node(); + EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif ++ auto raii = allocator_type::make_raii(pNode); + ::new(eastl::addressof(pNode->mValue)) value_type(value); + pNode->mpNext = NULL; + return pNode; +@@ -2407,7 +2462,8 @@ namespace eastl + } + catch(...) + { +- EASTLFree(mAllocator, pNode, sizeof(node_type)); ++ // EASTLFree(mAllocator, pNode, sizeof(node_type)); ++ mAllocator.deallocate_node(pNode); + throw; + } + #endif +@@ -2416,11 +2472,12 @@ namespace eastl + + template +- typename hashtable::node_type* ++ typename hashtable::node_pointer + hashtable::allocate_uninitialized_node() + { + // We don't wrap this in try/catch because users of this function are expected to do that themselves as needed. +- node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++// node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); ++ node_pointer const pNode = mAllocator.template allocate_node(); + EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + // Leave pNode->mValue uninitialized. + pNode->mpNext = NULL; +@@ -2430,10 +2487,11 @@ namespace eastl + + template +- void hashtable::free_uninitialized_node(node_type* pNode) ++ void hashtable::free_uninitialized_node(node_pointer pNode) + { + // pNode->mValue is expected to be uninitialized. +- EASTLFree(mAllocator, pNode, sizeof(node_type)); ++// EASTLFree(mAllocator, pNode, sizeof(node_type)); ++ mAllocator.deallocate_node(pNode); + } + + +@@ -2443,7 +2501,7 @@ namespace eastl + hashtable::DoInsertKey(true_type, const key_type& key, const hash_code_t c) // true_type means bUniqueKeys is true. + { + size_type n = (size_type)bucket_index(key, c, (uint32_t)mnBucketCount); +- node_type* const pNode = DoFindNode(mpBucketArray[n], key, c); ++ node_pointer const pNode = DoFindNode(mpBucketArray[n], key, c); + + if(pNode == NULL) + { +@@ -2451,8 +2509,8 @@ namespace eastl + + // Allocate the new node before doing the rehash so that we don't + // do a rehash if the allocation throws. +- node_type* const pNodeNew = DoAllocateNodeFromKey(key); +- set_code(pNodeNew, c); // This is a no-op for most hashtables. ++ node_pointer const pNodeNew = DoAllocateNodeFromKey(key); ++ set_code(allocator_type::to_raw(pNodeNew), c); // This is a no-op for most hashtables. + + #if EASTL_EXCEPTIONS_ENABLED + try +@@ -2464,7 +2522,7 @@ namespace eastl + DoRehash(bRehash.second); + } + +- EASTL_ASSERT((void**)mpBucketArray != &gpEmptyBucketArray[0]); ++ EASTL_ASSERT(!allocator_type::is_empty_hashtable(mpBucketArray)); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + ++mnElementCount; +@@ -2497,8 +2555,8 @@ namespace eastl + + const size_type n = (size_type)bucket_index(key, c, (uint32_t)mnBucketCount); + +- node_type* const pNodeNew = DoAllocateNodeFromKey(key); +- set_code(pNodeNew, c); // This is a no-op for most hashtables. ++ node_pointer const pNodeNew = DoAllocateNodeFromKey(key); ++ set_code(allocator_type::to_raw(pNodeNew), c); // This is a no-op for most hashtables. + + // To consider: Possibly make this insertion not make equal elements contiguous. + // As it stands now, we insert equal values contiguously in the hashtable. +@@ -2506,11 +2564,11 @@ namespace eastl + // erase(value) can more quickly find equal values. The downside is that + // this insertion operation taking some extra time. How important is it to + // us that equal_range span all equal items? +- node_type* const pNodePrev = DoFindNode(mpBucketArray[n], key, c); ++ node_pointer const pNodePrev = DoFindNode(mpBucketArray[n], key, c); + + if(pNodePrev == NULL) + { +- EASTL_ASSERT((void**)mpBucketArray != &gpEmptyBucketArray[0]); ++ EASTL_ASSERT(!allocator_type::is_empty_hashtable(mpBucketArray)); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + } +@@ -2532,7 +2590,7 @@ namespace eastl + hashtable::DoInsertKey(true_type, key_type&& key, const hash_code_t c) // true_type means bUniqueKeys is true. + { + size_type n = (size_type)bucket_index(key, c, (uint32_t)mnBucketCount); +- node_type* const pNode = DoFindNode(mpBucketArray[n], key, c); ++ node_pointer const pNode = DoFindNode(mpBucketArray[n], key, c); + + if(pNode == NULL) + { +@@ -2540,8 +2598,8 @@ namespace eastl + + // Allocate the new node before doing the rehash so that we don't + // do a rehash if the allocation throws. +- node_type* const pNodeNew = DoAllocateNodeFromKey(eastl::move(key)); +- set_code(pNodeNew, c); // This is a no-op for most hashtables. ++ node_pointer const pNodeNew = DoAllocateNodeFromKey(eastl::move(key)); ++ set_code(allocator_type::to_raw(pNodeNew), c); // This is a no-op for most hashtables. + + #if EASTL_EXCEPTIONS_ENABLED + try +@@ -2553,7 +2611,7 @@ namespace eastl + DoRehash(bRehash.second); + } + +- EASTL_ASSERT((void**)mpBucketArray != &gpEmptyBucketArray[0]); ++ EASTL_ASSERT(!allocator_type::is_empty_hashtable(mpBucketArray)); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + ++mnElementCount; +@@ -2585,8 +2643,8 @@ namespace eastl + + const size_type n = (size_type)bucket_index(key, c, (uint32_t)mnBucketCount); + +- node_type* const pNodeNew = DoAllocateNodeFromKey(eastl::move(key)); +- set_code(pNodeNew, c); // This is a no-op for most hashtables. ++ node_pointer const pNodeNew = DoAllocateNodeFromKey(eastl::move(key)); ++ set_code(allocator_type::to_raw(pNodeNew), c); // This is a no-op for most hashtables. + + // To consider: Possibly make this insertion not make equal elements contiguous. + // As it stands now, we insert equal values contiguously in the hashtable. +@@ -2594,11 +2652,11 @@ namespace eastl + // erase(value) can more quickly find equal values. The downside is that + // this insertion operation taking some extra time. How important is it to + // us that equal_range span all equal items? +- node_type* const pNodePrev = DoFindNode(mpBucketArray[n], key, c); ++ node_pointer const pNodePrev = DoFindNode(mpBucketArray[n], key, c); + + if(pNodePrev == NULL) + { +- EASTL_ASSERT((void**)mpBucketArray != &gpEmptyBucketArray[0]); ++ EASTL_ASSERT(!allocator_type::is_empty_hashtable(mpBucketArray)); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + } +@@ -2647,7 +2705,7 @@ namespace eastl + typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU> + template + typename hashtable::insert_return_type +- hashtable::insert(hash_code_t c, node_type* pNodeNew, P&& otherValue) ++ hashtable::insert(hash_code_t c, node_pointer pNodeNew, P&& otherValue) + { + // pNodeNew->mValue is expected to be uninitialized. + value_type value(eastl::forward