diff --git a/.gitignore b/.gitignore index c024df33..8d148cdc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ tags +cscope.out **/*.swp **/*.swo .swp diff --git a/benchmark/source/BenchmarkVector.cpp b/benchmark/source/BenchmarkVector.cpp index 80cfbce8..93315309 100644 --- a/benchmark/source/BenchmarkVector.cpp +++ b/benchmark/source/BenchmarkVector.cpp @@ -56,16 +56,14 @@ namespace return *this; } - #if EASTL_MOVE_SEMANTICS_ENABLED - MovableType(MovableType&& x) EA_NOEXCEPT : mpData(x.mpData) - { x.mpData = NULL; } + MovableType(MovableType&& x) EA_NOEXCEPT : mpData(x.mpData) + { x.mpData = NULL; } - MovableType& operator=(MovableType&& x) - { - eastl::swap(mpData, x.mpData); // In practice it may not be right to do a swap, depending on the case. - return *this; - } - #endif + MovableType& operator=(MovableType&& x) + { + eastl::swap(mpData, x.mpData); // In practice it may not be right to do a swap, depending on the case. + return *this; + } ~MovableType() { delete[] mpData; } @@ -123,21 +121,19 @@ namespace return *this; } - #if EASTL_MOVE_SEMANTICS_ENABLED - AutoRefCount(AutoRefCount&& x) EA_NOEXCEPT : mpObject(x.mpObject) - { - x.mpObject = NULL; - } + AutoRefCount(AutoRefCount&& x) EA_NOEXCEPT : mpObject(x.mpObject) + { + x.mpObject = NULL; + } - AutoRefCount& operator=(AutoRefCount&& x) - { - if(mpObject) - mpObject->Release(); - mpObject = x.mpObject; - x.mpObject = NULL; - return *this; - } - #endif + AutoRefCount& operator=(AutoRefCount&& x) + { + if(mpObject) + mpObject->Release(); + mpObject = x.mpObject; + x.mpObject = NULL; + return *this; + } ~AutoRefCount() { diff --git a/build.sh b/build.sh new file mode 100755 index 00000000..20dd7c17 --- /dev/null +++ b/build.sh @@ -0,0 +1,15 @@ +build_folder=build +mkdir $build_folder +pushd $build_folder +cmake .. -DEASTL_BUILD_TESTS:BOOL=ON -DEASTL_BUILD_BENCHMARK:BOOL=OFF +cmake --build . --config Release +# cmake --build . --config Debug +# cmake --build . --config RelWithDebInfo +# cmake --build . --config MinSizeRel +pushd test +ctest -C Release +# ctest -C Debug +# ctest -C RelWithDebInfo +# ctest -C MinSizeRel +popd +popd diff --git a/doc/EASTL.natvis b/doc/EASTL.natvis index 836878b1..5b78aa80 100644 --- a/doc/EASTL.natvis +++ b/doc/EASTL.natvis @@ -454,5 +454,13 @@ ({mFirst}, {mSecond}) + + + nullopt + {value()} + + value() + + diff --git a/include/EASTL/algorithm.h b/include/EASTL/algorithm.h index 7710ddbd..dc5202a0 100644 --- a/include/EASTL/algorithm.h +++ b/include/EASTL/algorithm.h @@ -1158,27 +1158,25 @@ namespace eastl /// Rand randInstance; /// shuffle(pArrayBegin, pArrayEnd, randInstance); /// - #if EASTL_MOVE_SEMANTICS_ENABLED - // See the C++11 Standard, 26.5.1.3, Uniform random number generator requirements. - // Also http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution + // See the C++11 Standard, 26.5.1.3, Uniform random number generator requirements. + // Also http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution - template - void shuffle(RandomAccessIterator first, RandomAccessIterator last, UniformRandomNumberGenerator&& urng) + template + void shuffle(RandomAccessIterator first, RandomAccessIterator last, UniformRandomNumberGenerator&& urng) + { + if(first != last) { - if(first != last) - { - typedef typename eastl::iterator_traits::difference_type difference_type; - typedef typename eastl::make_unsigned::type unsigned_difference_type; - typedef typename eastl::uniform_int_distribution uniform_int_distribution; - typedef typename uniform_int_distribution::param_type uniform_int_distribution_param_type; + typedef typename eastl::iterator_traits::difference_type difference_type; + typedef typename eastl::make_unsigned::type unsigned_difference_type; + typedef typename eastl::uniform_int_distribution uniform_int_distribution; + typedef typename uniform_int_distribution::param_type uniform_int_distribution_param_type; - uniform_int_distribution uid; + uniform_int_distribution uid; - for(RandomAccessIterator i = first + 1; i != last; ++i) - iter_swap(i, first + uid(urng, uniform_int_distribution_param_type(0, i - first))); - } + for(RandomAccessIterator i = first + 1; i != last; ++i) + iter_swap(i, first + uid(urng, uniform_int_distribution_param_type(0, i - first))); } - #endif + } /// random_shuffle @@ -1199,23 +1197,18 @@ namespace eastl /// Rand randInstance; /// random_shuffle(pArrayBegin, pArrayEnd, randInstance); /// - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline void random_shuffle(RandomAccessIterator first, RandomAccessIterator last, RandomNumberGenerator&& rng) - #else - template - inline void random_shuffle(RandomAccessIterator first, RandomAccessIterator last, RandomNumberGenerator& rng) - #endif - { - typedef typename eastl::iterator_traits::difference_type difference_type; + template + inline void random_shuffle(RandomAccessIterator first, RandomAccessIterator last, RandomNumberGenerator&& rng) + { + typedef typename eastl::iterator_traits::difference_type difference_type; - // We must do 'rand((i - first) + 1)' here and cannot do 'rand(last - first)', - // as it turns out that the latter results in unequal distribution probabilities. - // http://www.cigital.com/papers/download/developer_gambling.php + // We must do 'rand((i - first) + 1)' here and cannot do 'rand(last - first)', + // 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) - iter_swap(i, first + (difference_type)rng((eastl_size_t)((i - first) + 1))); - } + for(RandomAccessIterator i = first + 1; i < last; ++i) + iter_swap(i, first + (difference_type)rng((eastl_size_t)((i - first) + 1))); + } /// random_shuffle @@ -1997,8 +1990,7 @@ namespace eastl /// We should verify that such a thing results in an improvement. /// template - inline bool - equal(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2) + EA_CPP14_CONSTEXPR inline bool equal(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2) { for(; first1 != last1; ++first1, ++first2) { diff --git a/include/EASTL/allocator.h b/include/EASTL/allocator.h index a52948d5..ad20e4d8 100644 --- a/include/EASTL/allocator.h +++ b/include/EASTL/allocator.h @@ -12,11 +12,6 @@ #include -#ifdef _MSC_VER - #pragma warning(push) - #pragma warning(disable: 4189) // local variable is initialized but not referenced -#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. #endif @@ -167,14 +162,9 @@ namespace eastl #ifndef EASTL_USER_DEFINED_ALLOCATOR // If the user hasn't declared that he has defined a different allocator implementation elsewhere... - #ifdef _MSC_VER - #pragma warning(push, 0) - #pragma warning(disable: 4265 4365 4836 4548) - #include - #pragma warning(pop) - #else - #include - #endif + EA_DISABLE_ALL_VC_WARNINGS() + #include + EA_RESTORE_ALL_VC_WARNINGS() #if !EASTL_DLL // If building a regular library and not building EASTL as a DLL... // It is expected that the application define the following @@ -376,17 +366,15 @@ namespace eastl { result = EASTLAllocAligned(a, n, alignment, alignmentOffset); // Ensure the result is correctly aligned. An assertion here may indicate a bug in the allocator. - EASTL_ASSERT((reinterpret_cast(result)& ~(alignment - 1)) == reinterpret_cast(result)); + auto resultMinusOffset = (char*)result - alignmentOffset; + EA_UNUSED(resultMinusOffset); + EASTL_ASSERT((reinterpret_cast(resultMinusOffset)& ~(alignment - 1)) == reinterpret_cast(resultMinusOffset)); } return result; } } -#ifdef _MSC_VER - #pragma warning(pop) -#endif - #endif // Header include guard diff --git a/include/EASTL/array.h b/include/EASTL/array.h index bc07948d..4158d90e 100644 --- a/include/EASTL/array.h +++ b/include/EASTL/array.h @@ -23,13 +23,9 @@ #include #if EASTL_EXCEPTIONS_ENABLED - #ifdef _MSC_VER - #pragma warning(push, 0) - #endif + EA_DISABLE_ALL_VC_WARNINGS() #include // std::out_of_range, std::length_error. - #ifdef _MSC_VER - #pragma warning(pop) - #endif + EA_RESTORE_ALL_VC_WARNINGS() #endif #if defined(EA_PRAGMA_ONCE_SUPPORTED) @@ -93,39 +89,39 @@ namespace eastl // may exit via an exception, and does not cause iterators to become associated with the other container. void swap(this_type& x) EA_NOEXCEPT_IF(eastl::is_nothrow_swappable::value); - iterator begin() EA_NOEXCEPT; - const_iterator begin() const EA_NOEXCEPT; - const_iterator cbegin() const EA_NOEXCEPT; + EA_CPP14_CONSTEXPR iterator begin() EA_NOEXCEPT; + EA_CPP14_CONSTEXPR const_iterator begin() const EA_NOEXCEPT; + EA_CPP14_CONSTEXPR const_iterator cbegin() const EA_NOEXCEPT; - iterator end() EA_NOEXCEPT; - const_iterator end() const EA_NOEXCEPT; - const_iterator cend() const EA_NOEXCEPT; + EA_CPP14_CONSTEXPR iterator end() EA_NOEXCEPT; + EA_CPP14_CONSTEXPR const_iterator end() const EA_NOEXCEPT; + EA_CPP14_CONSTEXPR const_iterator cend() const EA_NOEXCEPT; - reverse_iterator rbegin() EA_NOEXCEPT; - const_reverse_iterator rbegin() const EA_NOEXCEPT; - const_reverse_iterator crbegin() const EA_NOEXCEPT; + EA_CPP14_CONSTEXPR reverse_iterator rbegin() EA_NOEXCEPT; + EA_CPP14_CONSTEXPR const_reverse_iterator rbegin() const EA_NOEXCEPT; + EA_CPP14_CONSTEXPR const_reverse_iterator crbegin() const EA_NOEXCEPT; - reverse_iterator rend() EA_NOEXCEPT; - const_reverse_iterator rend() const EA_NOEXCEPT; - const_reverse_iterator crend() const EA_NOEXCEPT; + EA_CPP14_CONSTEXPR reverse_iterator rend() EA_NOEXCEPT; + EA_CPP14_CONSTEXPR const_reverse_iterator rend() const EA_NOEXCEPT; + EA_CPP14_CONSTEXPR const_reverse_iterator crend() const EA_NOEXCEPT; - bool empty() const EA_NOEXCEPT; - size_type size() const EA_NOEXCEPT; - size_type max_size() const EA_NOEXCEPT; + EA_CPP14_CONSTEXPR bool empty() const EA_NOEXCEPT; + EA_CPP14_CONSTEXPR size_type size() const EA_NOEXCEPT; + EA_CPP14_CONSTEXPR size_type max_size() const EA_NOEXCEPT; - T* data() EA_NOEXCEPT; - const T* data() const EA_NOEXCEPT; + EA_CPP14_CONSTEXPR T* data() EA_NOEXCEPT; + EA_CPP14_CONSTEXPR const T* data() const EA_NOEXCEPT; - reference operator[](size_type i); - const_reference operator[](size_type i) const; - const_reference at(size_type i) const; - reference at(size_type i); + EA_CPP14_CONSTEXPR reference operator[](size_type i); + EA_CPP14_CONSTEXPR const_reference operator[](size_type i) const; + EA_CPP14_CONSTEXPR const_reference at(size_type i) const; + EA_CPP14_CONSTEXPR reference at(size_type i); - reference front(); - const_reference front() const; + EA_CPP14_CONSTEXPR reference front(); + EA_CPP14_CONSTEXPR const_reference front() const; - reference back(); - const_reference back() const; + EA_CPP14_CONSTEXPR reference back(); + EA_CPP14_CONSTEXPR const_reference back() const; bool validate() const; int validate_iterator(const_iterator i) const; @@ -155,7 +151,7 @@ namespace eastl template - inline typename array::iterator + EA_CPP14_CONSTEXPR inline typename array::iterator array::begin() EA_NOEXCEPT { return &mValue[0]; @@ -163,7 +159,7 @@ namespace eastl template - inline typename array::const_iterator + EA_CPP14_CONSTEXPR inline typename array::const_iterator array::begin() const EA_NOEXCEPT { return &mValue[0]; @@ -171,7 +167,7 @@ namespace eastl template - inline typename array::const_iterator + EA_CPP14_CONSTEXPR inline typename array::const_iterator array::cbegin() const EA_NOEXCEPT { return &mValue[0]; @@ -179,7 +175,7 @@ namespace eastl template - inline typename array::iterator + EA_CPP14_CONSTEXPR inline typename array::iterator array::end() EA_NOEXCEPT { return &mValue[N]; @@ -187,7 +183,7 @@ namespace eastl template - inline typename array::const_iterator + EA_CPP14_CONSTEXPR inline typename array::const_iterator array::end() const EA_NOEXCEPT { return &mValue[N]; @@ -195,7 +191,7 @@ namespace eastl template - inline typename array::const_iterator + EA_CPP14_CONSTEXPR inline typename array::const_iterator array::cend() const EA_NOEXCEPT { return &mValue[N]; @@ -203,7 +199,7 @@ namespace eastl template - inline typename array::reverse_iterator + EA_CPP14_CONSTEXPR inline typename array::reverse_iterator array::rbegin() EA_NOEXCEPT { return reverse_iterator(&mValue[N]); @@ -211,7 +207,7 @@ namespace eastl template - inline typename array::const_reverse_iterator + EA_CPP14_CONSTEXPR inline typename array::const_reverse_iterator array::rbegin() const EA_NOEXCEPT { return const_reverse_iterator(&mValue[N]); @@ -219,7 +215,7 @@ namespace eastl template - inline typename array::const_reverse_iterator + EA_CPP14_CONSTEXPR inline typename array::const_reverse_iterator array::crbegin() const EA_NOEXCEPT { return const_reverse_iterator(&mValue[N]); @@ -227,7 +223,7 @@ namespace eastl template - inline typename array::reverse_iterator + EA_CPP14_CONSTEXPR inline typename array::reverse_iterator array::rend() EA_NOEXCEPT { return reverse_iterator(&mValue[0]); @@ -235,23 +231,23 @@ namespace eastl template - inline typename array::const_reverse_iterator + EA_CPP14_CONSTEXPR inline typename array::const_reverse_iterator array::rend() const EA_NOEXCEPT { - return const_reverse_iterator(reinterpret_cast(&mValue[0])); + return const_reverse_iterator(static_cast(&mValue[0])); } template - inline typename array::const_reverse_iterator + EA_CPP14_CONSTEXPR inline typename array::const_reverse_iterator array::crend() const EA_NOEXCEPT { - return const_reverse_iterator(reinterpret_cast(&mValue[0])); + return const_reverse_iterator(static_cast(&mValue[0])); } template - inline typename array::size_type + EA_CPP14_CONSTEXPR inline typename array::size_type array::size() const EA_NOEXCEPT { return (size_type)N; @@ -259,7 +255,7 @@ namespace eastl template - inline typename array::size_type + EA_CPP14_CONSTEXPR inline typename array::size_type array::max_size() const EA_NOEXCEPT { return (size_type)N; @@ -267,14 +263,14 @@ namespace eastl template - inline bool array::empty() const EA_NOEXCEPT + EA_CPP14_CONSTEXPR inline bool array::empty() const EA_NOEXCEPT { return (N == 0); } template - inline typename array::reference + EA_CPP14_CONSTEXPR inline typename array::reference array::operator[](size_type i) { #if EASTL_ASSERT_ENABLED @@ -288,7 +284,7 @@ namespace eastl template - inline typename array::const_reference + EA_CPP14_CONSTEXPR inline typename array::const_reference array::operator[](size_type i) const { #if EASTL_ASSERT_ENABLED @@ -303,7 +299,7 @@ namespace eastl template - inline typename array::reference + EA_CPP14_CONSTEXPR inline typename array::reference array::front() { #if EASTL_ASSERT_ENABLED @@ -316,7 +312,7 @@ namespace eastl template - inline typename array::const_reference + EA_CPP14_CONSTEXPR inline typename array::const_reference array::front() const { #if EASTL_ASSERT_ENABLED @@ -329,7 +325,7 @@ namespace eastl template - inline typename array::reference + EA_CPP14_CONSTEXPR inline typename array::reference array::back() { #if EASTL_ASSERT_ENABLED @@ -342,7 +338,7 @@ namespace eastl template - inline typename array::const_reference + EA_CPP14_CONSTEXPR inline typename array::const_reference array::back() const { #if EASTL_ASSERT_ENABLED @@ -355,23 +351,21 @@ namespace eastl template - inline T* array::data() EA_NOEXCEPT + EA_CPP14_CONSTEXPR inline T* array::data() EA_NOEXCEPT { return mValue; } template - inline const T* - array::data() const EA_NOEXCEPT + EA_CPP14_CONSTEXPR inline const T* array::data() const EA_NOEXCEPT { return mValue; } template - inline typename array::const_reference - array::at(size_type i) const + EA_CPP14_CONSTEXPR inline typename array::const_reference array::at(size_type i) const { #if EASTL_EXCEPTIONS_ENABLED if(EASTL_UNLIKELY(i >= N)) @@ -382,13 +376,12 @@ namespace eastl #endif EA_ANALYSIS_ASSUME(i < N); - return reinterpret_cast(mValue[i]); + return static_cast(mValue[i]); } template - inline typename array::reference - array::at(size_type i) + EA_CPP14_CONSTEXPR inline typename array::reference array::at(size_type i) { #if EASTL_EXCEPTIONS_ENABLED if(EASTL_UNLIKELY(i >= N)) @@ -399,7 +392,7 @@ namespace eastl #endif EA_ANALYSIS_ASSUME(i < N); - return reinterpret_cast(mValue[i]); + return static_cast(mValue[i]); } @@ -432,42 +425,42 @@ namespace eastl /////////////////////////////////////////////////////////////////////// template - inline bool operator==(const array& a, const array& b) + EA_CPP14_CONSTEXPR inline bool operator==(const array& a, const array& b) { return eastl::equal(&a.mValue[0], &a.mValue[N], &b.mValue[0]); } template - inline bool operator<(const array& a, const array& b) + EA_CPP14_CONSTEXPR inline bool operator<(const array& a, const array& b) { return eastl::lexicographical_compare(&a.mValue[0], &a.mValue[N], &b.mValue[0], &b.mValue[N]); } template - inline bool operator!=(const array& a, const array& b) + EA_CPP14_CONSTEXPR inline bool operator!=(const array& a, const array& b) { return !eastl::equal(&a.mValue[0], &a.mValue[N], &b.mValue[0]); } template - inline bool operator>(const array& a, const array& b) + EA_CPP14_CONSTEXPR inline bool operator>(const array& a, const array& b) { return eastl::lexicographical_compare(&b.mValue[0], &b.mValue[N], &a.mValue[0], &a.mValue[N]); } template - inline bool operator<=(const array& a, const array& b) + EA_CPP14_CONSTEXPR inline bool operator<=(const array& a, const array& b) { return !eastl::lexicographical_compare(&b.mValue[0], &b.mValue[N], &a.mValue[0], &a.mValue[N]); } template - inline bool operator>=(const array& a, const array& b) + EA_CPP14_CONSTEXPR inline bool operator>=(const array& a, const array& b) { return !eastl::lexicographical_compare(&a.mValue[0], &a.mValue[N], &b.mValue[0], &b.mValue[N]); } diff --git a/include/EASTL/bonus/list_map.h b/include/EASTL/bonus/list_map.h index 1a07a603..0c05678f 100644 --- a/include/EASTL/bonus/list_map.h +++ b/include/EASTL/bonus/list_map.h @@ -212,10 +212,8 @@ namespace eastl // To do: Implement the following: //list_map(const this_type& x); - //#if EASTL_MOVE_SEMANTICS_ENABLED - // list_map(this_type&& x); - // list_map(this_type&& x, const allocator_type& allocator); - //#endif + //list_map(this_type&& x); + //list_map(this_type&& x, const allocator_type& allocator); //list_map(std::initializer_list ilist, const Compare& compare = Compare(), const allocator_type& allocator = EASTL_LIST_MAP_DEFAULT_ALLOCATOR); //template @@ -223,10 +221,7 @@ namespace eastl //this_type& operator=(const this_type& x); //this_type& operator=(std::initializer_list ilist); - - //#if EASTL_MOVE_SEMANTICS_ENABLED - // this_type& operator=(this_type&& x); - //#endif + //this_type& operator=(this_type&& x); //void swap(this_type& x); diff --git a/include/EASTL/bonus/ring_buffer.h b/include/EASTL/bonus/ring_buffer.h index 4f022510..fcd8fd2c 100644 --- a/include/EASTL/bonus/ring_buffer.h +++ b/include/EASTL/bonus/ring_buffer.h @@ -940,37 +940,73 @@ namespace eastl } */ - template= EASTL_MAX_STACK_USAGE)> - struct ContainerTemporary + + namespace Internal { - ContainerTemporary(Container& parentContainer); - Container& get(); - }; + /////////////////////////////////////////////////////////////// + // has_overflow_allocator + // + // returns true_type when the specified container type is an + // eastl::fixed_* container and therefore has an overflow + // allocator type. + // + template + struct has_overflow_allocator : false_type {}; + + template + struct has_overflow_allocator().get_overflow_allocator())>> : true_type {}; - template - struct ContainerTemporary + /////////////////////////////////////////////////////////////// + // GetFixedContainerCtorAllocator + // + // eastl::fixed_* containers are only constructible via their + // overflow allocator type. This helper select the appropriate + // allocator from the specified container. + // + template ()()> + struct GetFixedContainerCtorAllocator + { + auto& operator()(Container& c) { return c.get_overflow_allocator(); } + }; + + template + struct GetFixedContainerCtorAllocator + { + auto& operator()(Container& c) { return c.get_allocator(); } + }; + } // namespace Internal + + + /////////////////////////////////////////////////////////////// + // ContainerTemporary + // + // Helper type which prevents utilizing excessive stack space + // when creating temporaries when swapping/copying the underlying + // ring_buffer container type. + // + template = EASTL_MAX_STACK_USAGE)> + struct ContainerTemporary { Container mContainer; ContainerTemporary(Container& parentContainer) - : mContainer(parentContainer.get_allocator()) + : mContainer(Internal::GetFixedContainerCtorAllocator{}(parentContainer)) { } Container& get() { return mContainer; } }; - - template + template struct ContainerTemporary { typename Container::allocator_type* mAllocator; Container* mContainer; ContainerTemporary(Container& parentContainer) - : mAllocator(&parentContainer.get_allocator()) - , mContainer(new(mAllocator->allocate(sizeof(Container))) Container) + : mAllocator(&parentContainer.get_allocator()) + , mContainer(new (mAllocator->allocate(sizeof(Container))) Container) { } diff --git a/include/EASTL/bonus/tuple_vector.h b/include/EASTL/bonus/tuple_vector.h index d9463037..1573f287 100644 --- a/include/EASTL/bonus/tuple_vector.h +++ b/include/EASTL/bonus/tuple_vector.h @@ -34,6 +34,10 @@ #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 +EA_DISABLE_VC_WARNING(4623) // warning C4623: default constructor was implicitly defined as deleted +EA_DISABLE_VC_WARNING(4625) // warning C4625: copy constructor was implicitly defined as deleted +EA_DISABLE_VC_WARNING(4510) // warning C4510: default constructor could not be generated + namespace eastl { /// EASTL_TUPLE_VECTOR_DEFAULT_NAME @@ -162,6 +166,14 @@ struct TupleRecurser<> // This is fine, as our default ctor initializes with NULL pointers. size_type alignment = TupleRecurser::GetTotalAlignment(); void* ptr = capacity ? allocate_memory(vec.internalAllocator(), offset, alignment, 0) : nullptr; + + #if EASTL_ASSERT_ENABLED + if (EASTL_UNLIKELY((size_type)ptr & (alignment - 1)) != 0) + { + EASTL_FAIL_MSG("tuple_vector::DoAllocate -- memory not alignment at requested alignment"); + } + #endif + return make_pair(ptr, offset); } @@ -1375,9 +1387,9 @@ class TupleVecImpl, Ts...> : public TupleV } // namespace TupleVecInternal - // Move_iterator specialization for TupleVecIter. - // An rvalue reference of a move_iterator would normaly be "tuple &&" whereas - // what we actually want is "tuple". This specialization gives us that. +// Move_iterator specialization for TupleVecIter. +// An rvalue reference of a move_iterator would normaly be "tuple &&" whereas +// what we actually want is "tuple". This specialization gives us that. template class move_iterator, Ts...>> { @@ -1557,4 +1569,8 @@ class tuple_vector_alloc } // namespace eastl +EA_RESTORE_VC_WARNING() +EA_RESTORE_VC_WARNING() +EA_RESTORE_VC_WARNING() + #endif // EASTL_TUPLEVECTOR_H diff --git a/include/EASTL/core_allocator_adapter.h b/include/EASTL/core_allocator_adapter.h index 30c431df..e0e8adc8 100644 --- a/include/EASTL/core_allocator_adapter.h +++ b/include/EASTL/core_allocator_adapter.h @@ -165,7 +165,6 @@ namespace EA CoreDeleterAdapter(const CoreDeleterAdapter& in) { mpCoreAllocator = in.mpCoreAllocator; } - #if EASTL_MOVE_SEMANTICS_ENABLED CoreDeleterAdapter(CoreDeleterAdapter&& in) { mpCoreAllocator = in.mpCoreAllocator; @@ -184,8 +183,6 @@ namespace EA in.mpCoreAllocator = nullptr; return *this; } - #endif - }; diff --git a/include/EASTL/deque.h b/include/EASTL/deque.h index 69a3af4a..88fe5750 100644 --- a/include/EASTL/deque.h +++ b/include/EASTL/deque.h @@ -227,19 +227,19 @@ namespace eastl T* mpEnd; // The end of the current subarray. To consider: remove this member, as it is always equal to 'mpBegin + kDequeSubarraySize'. Given that deque subarrays usually consist of hundreds of bytes, this isn't a massive win. Also, now that we are implementing a zero-allocation new deque policy, mpEnd may in fact not be equal to 'mpBegin + kDequeSubarraySize'. T** mpCurrentArrayPtr; // Pointer to current subarray. We could alternatively implement this as a list node iterator if the deque used a linked list. - struct Increment{ }; - struct Decrement{ }; - struct FromConst{}; + struct Increment {}; + struct Decrement {}; + struct FromConst {}; DequeIterator(T** pCurrentArrayPtr, T* pCurrent); DequeIterator(const const_iterator& x, FromConst) : mpCurrent(x.mpCurrent), mpBegin(x.mpBegin), mpEnd(x.mpEnd), mpCurrentArrayPtr(x.mpCurrentArrayPtr){} DequeIterator(const iterator& x, Increment); DequeIterator(const iterator& x, Decrement); - this_type copy(const iterator& first, const iterator& last, true_type); // true means that value_type has the type_trait has_trivial_relocate, + this_type copy(const iterator& first, const iterator& last, true_type); // true means that value_type has the type_trait is_move_assignable, this_type copy(const iterator& first, const iterator& last, false_type); // false means it does not. - void copy_backward(const iterator& first, const iterator& last, true_type); // true means that value_type has the type_trait has_trivial_relocate, + void copy_backward(const iterator& first, const iterator& last, true_type); // true means that value_type has the type_trait is_move_assignable, void copy_backward(const iterator& first, const iterator& last, false_type); // false means it does not. void SetSubarray(T** pCurrentArrayPtr); @@ -298,17 +298,17 @@ namespace eastl void set_allocator(const allocator_type& allocator); protected: - T* DoAllocateSubarray(); - void DoFreeSubarray(T* p); - void DoFreeSubarrays(T** pBegin, T** pEnd); + T* DoAllocateSubarray(); + void DoFreeSubarray(T* p); + void DoFreeSubarrays(T** pBegin, T** pEnd); - T** DoAllocatePtrArray(size_type n); - void DoFreePtrArray(T** p, size_t n); + T** DoAllocatePtrArray(size_type n); + void DoFreePtrArray(T** p, size_t n); iterator DoReallocSubarray(size_type nAdditionalCapacity, Side allocationSide); void DoReallocPtrArray(size_type nAdditionalCapacity, Side allocationSide); - void DoInit(size_type n); + void DoInit(size_type n); }; // DequeBase @@ -1053,7 +1053,7 @@ namespace eastl memmove(mpCurrent, first.mpCurrent, (size_t)((uintptr_t)last.mpCurrent - (uintptr_t)first.mpCurrent)); return *this + (last.mpCurrent - first.mpCurrent); } - return eastl::copy(first, last, *this); + return eastl::copy(eastl::make_move_iterator(first), eastl::make_move_iterator(last), eastl::make_move_iterator(*this)).base(); } @@ -1073,7 +1073,7 @@ namespace eastl if((first.mpBegin == last.mpBegin) && (first.mpBegin == mpBegin)) // If all operations are within the same subarray, implement the operation as a memcpy. memmove(mpCurrent - (last.mpCurrent - first.mpCurrent), first.mpCurrent, (size_t)((uintptr_t)last.mpCurrent - (uintptr_t)first.mpCurrent)); else - eastl::copy_backward(first, last, *this); + eastl::copy_backward(eastl::make_move_iterator(first), eastl::make_move_iterator(last), eastl::make_move_iterator(*this)); } @@ -1780,7 +1780,7 @@ namespace eastl if(i < (difference_type)(size() / 2)) // Should we insert at the front or at the back? We divide the range in half. { - emplace_front(*mItBegin); // This operation potentially invalidates all existing iterators and so we need to assign them anew relative to mItBegin below. + emplace_front(eastl::move(*mItBegin)); // This operation potentially invalidates all existing iterators and so we need to assign them anew relative to mItBegin below. itPosition = mItBegin + i; @@ -1788,18 +1788,18 @@ namespace eastl iterator oldBegin (mItBegin, typename iterator::Increment()); const iterator oldBeginPlus1(oldBegin, typename iterator::Increment()); - oldBegin.copy(oldBeginPlus1, newPosition, eastl::has_trivial_relocate()); + oldBegin.copy(oldBeginPlus1, newPosition, eastl::is_move_assignable()); } else { - emplace_back(*iterator(mItEnd, typename iterator::Decrement())); + emplace_back(eastl::move(*iterator(mItEnd, typename iterator::Decrement()))); itPosition = mItBegin + i; iterator oldBack (mItEnd, typename iterator::Decrement()); const iterator oldBackMinus1(oldBack, typename iterator::Decrement()); - oldBack.copy_backward(itPosition, oldBackMinus1, eastl::has_trivial_relocate()); + oldBack.copy_backward(itPosition, oldBackMinus1, eastl::is_move_assignable()); } *itPosition = eastl::move(valueSaved); @@ -1925,6 +1925,9 @@ namespace eastl #if EASTL_ASSERT_ENABLED if(EASTL_UNLIKELY(!(validate_iterator(position) & isf_valid))) EASTL_FAIL_MSG("deque::erase -- invalid iterator"); + + if(EASTL_UNLIKELY(position == end())) + EASTL_FAIL_MSG("deque::erase -- end() iterator is an invalid iterator for erase"); #endif iterator itPosition(position, typename iterator::FromConst()); @@ -1933,12 +1936,12 @@ namespace eastl if(i < (difference_type)(size() / 2)) // Should we move the front entries forward or the back entries backward? We divide the range in half. { - itNext.copy_backward(mItBegin, itPosition, eastl::has_trivial_relocate()); + itNext.copy_backward(mItBegin, itPosition, eastl::is_move_assignable()); pop_front(); } else { - itPosition.copy(itNext, mItEnd, eastl::has_trivial_relocate()); + itPosition.copy(itNext, mItEnd, eastl::is_move_assignable()); pop_back(); } @@ -1970,7 +1973,7 @@ namespace eastl const iterator itNewBegin(mItBegin + n); value_type** const pPtrArrayBegin = mItBegin.mpCurrentArrayPtr; - itLast.copy_backward(mItBegin, itFirst, eastl::has_trivial_relocate()); + itLast.copy_backward(mItBegin, itFirst, eastl::is_move_assignable()); for(; mItBegin != itNewBegin; ++mItBegin) // Question: If value_type is a POD type, will the compiler generate this loop at all? mItBegin.mpCurrent->~value_type(); // If so, then we need to make a specialization for destructing PODs. @@ -1984,7 +1987,7 @@ namespace eastl iterator itNewEnd(mItEnd - n); value_type** const pPtrArrayEnd = itNewEnd.mpCurrentArrayPtr + 1; - itFirst.copy(itLast, mItEnd, eastl::has_trivial_relocate()); + itFirst.copy(itLast, mItEnd, eastl::is_move_assignable()); for(iterator itTemp(itNewEnd); itTemp != mItEnd; ++itTemp) itTemp.mpCurrent->~value_type(); @@ -2077,6 +2080,7 @@ namespace eastl template void deque::swap(deque& x) { + #if defined(EASTL_DEQUE_LEGACY_SWAP_BEHAVIOUR_REQUIRES_COPY_CTOR) && EASTL_DEQUE_LEGACY_SWAP_BEHAVIOUR_REQUIRES_COPY_CTOR if(mAllocator == x.mAllocator) // If allocators are equivalent... DoSwap(x); else // else swap the contents. @@ -2085,6 +2089,19 @@ namespace eastl *this = x; // itself call this member swap function. x = temp; } + #else + // NOTE(rparolin): The previous implementation required T to be copy-constructible in the fall-back case where + // allocators with unique instances copied elements. This was an unnecessary restriction and prevented the common + // usage of deque with non-copyable types (eg. eastl::deque or eastl::deque). + // + // The previous implementation violated the following requirements of deque::swap so the fall-back code has + // been removed. EASTL implicitly defines 'propagate_on_container_swap = false' therefore the fall-back case is + // undefined behaviour. We simply swap the contents and the allocator as that is the common expectation of + // users and does not put the container into an invalid state since it can not free its memory via its current + // allocator instance. + // + DoSwap(x); + #endif } diff --git a/include/EASTL/fixed_hash_set.h b/include/EASTL/fixed_hash_set.h index f5f56d71..0db9f49f 100644 --- a/include/EASTL/fixed_hash_set.h +++ b/include/EASTL/fixed_hash_set.h @@ -116,18 +116,14 @@ namespace eastl const Predicate& predicate = Predicate()); fixed_hash_set(const this_type& x); - #if EASTL_MOVE_SEMANTICS_ENABLED - fixed_hash_set(this_type&& x); - fixed_hash_set(this_type&& x, const overflow_allocator_type& overflowAllocator); - #endif + fixed_hash_set(this_type&& x); + fixed_hash_set(this_type&& x, const overflow_allocator_type& overflowAllocator); fixed_hash_set(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_HASH_SET_DEFAULT_ALLOCATOR); this_type& operator=(const this_type& x); this_type& operator=(std::initializer_list ilist); - #if EASTL_MOVE_SEMANTICS_ENABLED - this_type& operator=(this_type&& x); - #endif + this_type& operator=(this_type&& x); void swap(this_type& x); @@ -207,17 +203,13 @@ namespace eastl const Predicate& predicate = Predicate()); fixed_hash_multiset(const this_type& x); - #if EASTL_MOVE_SEMANTICS_ENABLED - fixed_hash_multiset(this_type&& x); - fixed_hash_multiset(this_type&& x, const overflow_allocator_type& overflowAllocator); - #endif + fixed_hash_multiset(this_type&& x); + fixed_hash_multiset(this_type&& x, const overflow_allocator_type& overflowAllocator); fixed_hash_multiset(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_HASH_MULTISET_DEFAULT_ALLOCATOR); this_type& operator=(const this_type& x); this_type& operator=(std::initializer_list ilist); - #if EASTL_MOVE_SEMANTICS_ENABLED - this_type& operator=(this_type&& x); - #endif + this_type& operator=(this_type&& x); void swap(this_type& x); @@ -343,50 +335,48 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline fixed_hash_set::fixed_hash_set(this_type&& x) - : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), - x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer)) - { - // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. - mAllocator.copy_overflow_allocator(x.mAllocator); + template + inline fixed_hash_set::fixed_hash_set(this_type&& x) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), + x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer)) + { + // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. + mAllocator.copy_overflow_allocator(x.mAllocator); - #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); - #endif + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif - EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + 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(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. - mAllocator.reset(mNodeBuffer); - base_type::insert(x.begin(), x.end()); - } + mAllocator.reset(mNodeBuffer); + base_type::insert(x.begin(), x.end()); + } - template - inline fixed_hash_set::fixed_hash_set(this_type&& x, const overflow_allocator_type& overflowAllocator) - : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), - x.hash_function(), x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) - { - // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. - mAllocator.copy_overflow_allocator(x.mAllocator); + template + inline fixed_hash_set::fixed_hash_set(this_type&& x, const overflow_allocator_type& overflowAllocator) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), + x.hash_function(), x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) + { + // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. + mAllocator.copy_overflow_allocator(x.mAllocator); - #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); - #endif + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif - EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + 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(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. - mAllocator.reset(mNodeBuffer); - base_type::insert(x.begin(), x.end()); - } - #endif + mAllocator.reset(mNodeBuffer); + base_type::insert(x.begin(), x.end()); + } template @@ -418,15 +408,13 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline typename fixed_hash_set::this_type& - fixed_hash_set::operator=(this_type&& x) - { - operator=(x); - return *this; - } - #endif + template + inline typename fixed_hash_set::this_type& + fixed_hash_set::operator=(this_type&& x) + { + operator=(x); + return *this; + } template @@ -620,50 +608,48 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline fixed_hash_multiset::fixed_hash_multiset(this_type&& x) - : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), - x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer)) - { - // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. - mAllocator.copy_overflow_allocator(x.mAllocator); + template + inline fixed_hash_multiset::fixed_hash_multiset(this_type&& x) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), + x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer)) + { + // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. + mAllocator.copy_overflow_allocator(x.mAllocator); - #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); - #endif + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif - EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + 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(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. - mAllocator.reset(mNodeBuffer); - base_type::insert(x.begin(), x.end()); - } + mAllocator.reset(mNodeBuffer); + base_type::insert(x.begin(), x.end()); + } - template - inline fixed_hash_multiset::fixed_hash_multiset(this_type&& x, const overflow_allocator_type& overflowAllocator) - : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), - x.hash_function(), x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) - { - // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. - mAllocator.copy_overflow_allocator(x.mAllocator); + template + inline fixed_hash_multiset::fixed_hash_multiset(this_type&& x, const overflow_allocator_type& overflowAllocator) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), + x.hash_function(), x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) + { + // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. + mAllocator.copy_overflow_allocator(x.mAllocator); - #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); - #endif + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif - EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + 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(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. - mAllocator.reset(mNodeBuffer); - base_type::insert(x.begin(), x.end()); - } - #endif + mAllocator.reset(mNodeBuffer); + base_type::insert(x.begin(), x.end()); + } template @@ -695,15 +681,13 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline typename fixed_hash_multiset::this_type& - fixed_hash_multiset::operator=(this_type&& x) - { - base_type::operator=(x); - return *this; - } - #endif + template + inline typename fixed_hash_multiset::this_type& + fixed_hash_multiset::operator=(this_type&& x) + { + base_type::operator=(x); + return *this; + } template diff --git a/include/EASTL/fixed_list.h b/include/EASTL/fixed_list.h index dbac1ae0..88c70317 100644 --- a/include/EASTL/fixed_list.h +++ b/include/EASTL/fixed_list.h @@ -96,10 +96,8 @@ namespace eastl explicit fixed_list(size_type n); // Currently we don't support overflowAllocator specification for other constructors, for simplicity. fixed_list(size_type n, const value_type& value); fixed_list(const this_type& x); - #if EASTL_MOVE_SEMANTICS_ENABLED - fixed_list(this_type&& x); - fixed_list(this_type&&, const overflow_allocator_type& overflowAllocator); - #endif + fixed_list(this_type&& x); + fixed_list(this_type&&, const overflow_allocator_type& overflowAllocator); fixed_list(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_LIST_DEFAULT_ALLOCATOR); template @@ -107,9 +105,7 @@ namespace eastl this_type& operator=(const this_type& x); this_type& operator=(std::initializer_list ilist); - #if EASTL_MOVE_SEMANTICS_ENABLED - this_type& operator=(this_type&& x); - #endif + this_type& operator=(this_type&& x); void swap(this_type& x); void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. @@ -188,44 +184,42 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline fixed_list::fixed_list(this_type&& x) - : base_type(fixed_allocator_type(mBuffer)) - { - // Since we are a fixed_list, we can't normally swap pointers unless both this and - // x are using using overflow and the overflow allocators are equal. To do: - //if(has_overflowed() && x.has_overflowed() && (get_overflow_allocator() == x.get_overflow_allocator())) - //{ - // We can swap contents and may need to swap the allocators as well. - //} - - // The following is currently identical to the fixed_vector(const this_type& x) code above. If it stays that - // way then we may want to make a shared implementation. - mAllocator.copy_overflow_allocator(x.mAllocator); - - #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); - #endif + template + inline fixed_list::fixed_list(this_type&& x) + : base_type(fixed_allocator_type(mBuffer)) + { + // Since we are a fixed_list, we can't normally swap pointers unless both this and + // x are using using overflow and the overflow allocators are equal. To do: + //if(has_overflowed() && x.has_overflowed() && (get_overflow_allocator() == x.get_overflow_allocator())) + //{ + // We can swap contents and may need to swap the allocators as well. + //} + + // The following is currently identical to the fixed_vector(const this_type& x) code above. If it stays that + // way then we may want to make a shared implementation. + mAllocator.copy_overflow_allocator(x.mAllocator); - assign(x.begin(), x.end()); - } + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + assign(x.begin(), x.end()); + } - template - inline fixed_list::fixed_list(this_type&& x, const overflow_allocator_type& overflowAllocator) - : base_type(fixed_allocator_type(mBuffer, overflowAllocator)) - { - // See comments above. - mAllocator.copy_overflow_allocator(x.mAllocator); - #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); - #endif + template + inline fixed_list::fixed_list(this_type&& x, const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer, overflowAllocator)) + { + // See comments above. + mAllocator.copy_overflow_allocator(x.mAllocator); - assign(x.begin(), x.end()); - } - #endif + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + assign(x.begin(), x.end()); + } template @@ -267,14 +261,12 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline typename fixed_list::this_type& - fixed_list::operator=(this_type&& x) - { - return operator=(x); - } - #endif + template + inline typename fixed_list::this_type& + fixed_list::operator=(this_type&& x) + { + return operator=(x); + } template diff --git a/include/EASTL/fixed_slist.h b/include/EASTL/fixed_slist.h index 25b49b3a..c2bceccb 100644 --- a/include/EASTL/fixed_slist.h +++ b/include/EASTL/fixed_slist.h @@ -93,10 +93,8 @@ namespace eastl explicit fixed_slist(size_type n); // Currently we don't support overflowAllocator specification for other constructors, for simplicity. fixed_slist(size_type n, const value_type& value); fixed_slist(const this_type& x); - #if EASTL_MOVE_SEMANTICS_ENABLED - fixed_slist(this_type&& x); - fixed_slist(this_type&&, const overflow_allocator_type&); - #endif + fixed_slist(this_type&& x); + fixed_slist(this_type&&, const overflow_allocator_type&); fixed_slist(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_SLIST_DEFAULT_ALLOCATOR); template @@ -104,9 +102,7 @@ namespace eastl this_type& operator=(const this_type& x); this_type& operator=(std::initializer_list ilist); - #if EASTL_MOVE_SEMANTICS_ENABLED - this_type& operator=(this_type&& x); - #endif + this_type& operator=(this_type&& x); void swap(this_type& x); void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. @@ -186,44 +182,41 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline fixed_slist::fixed_slist(this_type&& x) - : base_type(fixed_allocator_type(mBuffer)) - { - // Since we are a fixed_list, we can't normally swap pointers unless both this and - // x are using using overflow and the overflow allocators are equal. To do: - //if(has_overflowed() && x.has_overflowed() && (get_overflow_allocator() == x.get_overflow_allocator())) - //{ - // We can swap contents and may need to swap the allocators as well. - //} - - // The following is currently identical to the fixed_vector(const this_type& x) code above. If it stays that - // way then we may want to make a shared implementation. - mAllocator.copy_overflow_allocator(x.mAllocator); - - #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); - #endif + template + inline fixed_slist::fixed_slist(this_type&& x) + : base_type(fixed_allocator_type(mBuffer)) + { + // Since we are a fixed_list, we can't normally swap pointers unless both this and + // x are using using overflow and the overflow allocators are equal. To do: + //if(has_overflowed() && x.has_overflowed() && (get_overflow_allocator() == x.get_overflow_allocator())) + //{ + // We can swap contents and may need to swap the allocators as well. + //} + + // The following is currently identical to the fixed_vector(const this_type& x) code above. If it stays that + // way then we may want to make a shared implementation. + mAllocator.copy_overflow_allocator(x.mAllocator); - assign(x.begin(), x.end()); - } + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif - template - inline fixed_slist::fixed_slist(this_type&& x, const overflow_allocator_type& overflowAllocator) - : base_type(fixed_allocator_type(mBuffer, overflowAllocator)) - { - // See comments above. - mAllocator.copy_overflow_allocator(x.mAllocator); + assign(x.begin(), x.end()); + } - #if EASTL_NAME_ENABLED - mAllocator.set_name(x.mAllocator.get_name()); - #endif + template + inline fixed_slist::fixed_slist(this_type&& x, const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer, overflowAllocator)) + { + // See comments above. + mAllocator.copy_overflow_allocator(x.mAllocator); - assign(x.begin(), x.end()); - } + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif - #endif + assign(x.begin(), x.end()); + } template @@ -269,14 +262,12 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline typename fixed_slist::this_type& - fixed_slist::operator=(this_type&& x) - { - return operator=(x); - } - #endif + template + inline typename fixed_slist::this_type& + fixed_slist::operator=(this_type&& x) + { + return operator=(x); + } template diff --git a/include/EASTL/fixed_string.h b/include/EASTL/fixed_string.h index 3e06a8d2..33906722 100644 --- a/include/EASTL/fixed_string.h +++ b/include/EASTL/fixed_string.h @@ -121,21 +121,15 @@ namespace eastl fixed_string(CtorDoNotInitialize, size_type n); fixed_string(CtorSprintf, const value_type* pFormat, ...); fixed_string(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator); - - #if EASTL_MOVE_SEMANTICS_ENABLED fixed_string(this_type&& x); fixed_string(this_type&& x, const overflow_allocator_type& overflowAllocator); - #endif this_type& operator=(const this_type& x); this_type& operator=(const base_type& x); this_type& operator=(const value_type* p); this_type& operator=(const value_type c); this_type& operator=(std::initializer_list ilist); - - #if EASTL_MOVE_SEMANTICS_ENABLED this_type& operator=(this_type&& x); - #endif void swap(this_type& x); @@ -410,43 +404,41 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline fixed_string::fixed_string(this_type&& x) - : base_type(fixed_allocator_type(mBuffer.buffer)) - { - // We copy from x instead of trade with it. We need to do so because fixed_ containers use local memory buffers. - #if EASTL_NAME_ENABLED - get_allocator().set_name(x.get_allocator().get_name()); - #endif + template + inline fixed_string::fixed_string(this_type&& x) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + // We copy from x instead of trade with it. We need to do so because fixed_ containers use local memory buffers. + #if EASTL_NAME_ENABLED + get_allocator().set_name(x.get_allocator().get_name()); + #endif - internalLayout().SetHeapBeginPtr(mArray); - internalLayout().SetHeapCapacity(nodeCount - 1); - internalLayout().SetHeapSize(0); + internalLayout().SetHeapBeginPtr(mArray); + internalLayout().SetHeapCapacity(nodeCount - 1); + internalLayout().SetHeapSize(0); - *internalLayout().HeapBeginPtr() = 0; + *internalLayout().HeapBeginPtr() = 0; - append(x); // Let x destruct its own items. - } + append(x); // Let x destruct its own items. + } - template - inline fixed_string::fixed_string(this_type&& x, const overflow_allocator_type& overflowAllocator) - : base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator)) - { - // We copy from x instead of trade with it. We need to do so because fixed_ containers use local memory buffers. - #if EASTL_NAME_ENABLED - get_allocator().set_name(x.get_allocator().get_name()); - #endif + template + inline fixed_string::fixed_string(this_type&& x, const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator)) + { + // We copy from x instead of trade with it. We need to do so because fixed_ containers use local memory buffers. + #if EASTL_NAME_ENABLED + get_allocator().set_name(x.get_allocator().get_name()); + #endif - internalLayout().SetHeapBeginPtr(mArray); - internalLayout().SetHeapCapacity(nodeCount - 1); - internalLayout().SetHeapSize(0); + internalLayout().SetHeapBeginPtr(mArray); + internalLayout().SetHeapCapacity(nodeCount - 1); + internalLayout().SetHeapSize(0); - *internalLayout().HeapBeginPtr() = 0; + *internalLayout().HeapBeginPtr() = 0; - append(x); // Let x destruct its own items. - } - #endif + append(x); // Let x destruct its own items. + } template @@ -518,26 +510,24 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline typename fixed_string:: - this_type& fixed_string::operator=(this_type&& x) - { - // We copy from x instead of trade with it. We need to do so because fixed_ containers use local memory buffers. + template + inline typename fixed_string:: + this_type& fixed_string::operator=(this_type&& x) + { + // We copy from x instead of trade with it. We need to do so because fixed_ containers use local memory buffers. - // if(static_cast(this) != &x) This should be impossible, so we disable it until proven otherwise. - { - clear(); + // if(static_cast(this) != &x) This should be impossible, so we disable it until proven otherwise. + { + clear(); - #if EASTL_ALLOCATOR_COPY_ENABLED - get_allocator() = x.get_allocator(); - #endif + #if EASTL_ALLOCATOR_COPY_ENABLED + get_allocator() = x.get_allocator(); + #endif - append(x); // Let x destruct its own items. - } - return *this; + append(x); // Let x destruct its own items. } - #endif + return *this; + } template @@ -758,47 +748,45 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - fixed_string operator+(fixed_string&& a, - fixed_string&& b) - { - a.append(b); // Using an rvalue by name results in it becoming an lvalue. - return a; - } + template + fixed_string operator+(fixed_string&& a, + fixed_string&& b) + { + a.append(b); // Using an rvalue by name results in it becoming an lvalue. + return a; + } - template - fixed_string operator+(fixed_string&& a, - const fixed_string& b) - { - a.append(b); - return a; - } + template + fixed_string operator+(fixed_string&& a, + const fixed_string& b) + { + a.append(b); + return a; + } - template - fixed_string operator+(const typename fixed_string::value_type* p, - fixed_string&& b) - { - b.insert(0, p); - return b; - } + template + fixed_string operator+(const typename fixed_string::value_type* p, + fixed_string&& b) + { + b.insert(0, p); + return b; + } - template - fixed_string operator+(fixed_string&& a, - const typename fixed_string::value_type* p) - { - a.append(p); - return a; - } + template + fixed_string operator+(fixed_string&& a, + const typename fixed_string::value_type* p) + { + a.append(p); + return a; + } - template - fixed_string operator+(fixed_string&& a, - typename fixed_string::value_type c) - { - a.push_back(c); - return a; - } - #endif + template + fixed_string operator+(fixed_string&& a, + typename fixed_string::value_type c) + { + a.push_back(c); + return a; + } // operator ==, !=, <, >, <=, >= come from the string implementations. diff --git a/include/EASTL/functional.h b/include/EASTL/functional.h index 83253aeb..574f70b1 100644 --- a/include/EASTL/functional.h +++ b/include/EASTL/functional.h @@ -1006,9 +1006,31 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // hash /////////////////////////////////////////////////////////////////////// + namespace Internal + { + // utility to disable the generic template specialization that is + // used for enum types only. + template + struct EnableHashIf + { + }; + + template + struct EnableHashIf + { + size_t operator()(const T& p) const { return size_t(p); } + }; + } // namespace Internal + template struct hash; + template + struct hash : Internal::EnableHashIf> + { + size_t operator()(T p) const { return size_t(p); } + }; + template struct hash // Note that we use the pointer as-is and don't divide by sizeof(T*). This is because the table is of a prime size and this division doesn't benefit distribution. { size_t operator()(T* p) const { return size_t(uintptr_t(p)); } }; diff --git a/include/EASTL/hash_set.h b/include/EASTL/hash_set.h index f776de4c..0dd7435e 100644 --- a/include/EASTL/hash_set.h +++ b/include/EASTL/hash_set.h @@ -145,18 +145,16 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - hash_set(this_type&& x) - : base_type(eastl::move(x)) - { - } + hash_set(this_type&& x) + : base_type(eastl::move(x)) + { + } - hash_set(this_type&& x, const allocator_type& allocator) - : base_type(eastl::move(x), allocator) - { - } - #endif + hash_set(this_type&& x, const allocator_type& allocator) + : base_type(eastl::move(x), allocator) + { + } /// hash_set @@ -198,12 +196,10 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - this_type& operator=(this_type&& x) - { - return static_cast(base_type::operator=(eastl::move(x))); - } - #endif + this_type& operator=(this_type&& x) + { + return static_cast(base_type::operator=(eastl::move(x))); + } }; // hash_set @@ -267,18 +263,16 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - hash_multiset(this_type&& x) - : base_type(eastl::move(x)) - { - } + hash_multiset(this_type&& x) + : base_type(eastl::move(x)) + { + } - hash_multiset(this_type&& x, const allocator_type& allocator) - : base_type(eastl::move(x), allocator) - { - } - #endif + hash_multiset(this_type&& x, const allocator_type& allocator) + : base_type(eastl::move(x), allocator) + { + } /// hash_multiset @@ -320,12 +314,10 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - this_type& operator=(this_type&& x) - { - return static_cast(base_type::operator=(eastl::move(x))); - } - #endif + this_type& operator=(this_type&& x) + { + return static_cast(base_type::operator=(eastl::move(x))); + } }; // hash_multiset diff --git a/include/EASTL/initializer_list.h b/include/EASTL/initializer_list.h index 250dc828..028fb4f8 100644 --- a/include/EASTL/initializer_list.h +++ b/include/EASTL/initializer_list.h @@ -18,42 +18,14 @@ #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 -// Older EABase versions have a bug in EA_HAVE_CPP11_INITIALIZER_LIST for the -// combination of clang/libstdc++, so we implement a fix for that here. -#if (EABASE_VERSION_N < 20042) // If using a version of EABase that has a bug or doesn't have support at all... - #if defined(EA_HAVE_CPP11_INITIALIZER_LIST) - #undef EA_HAVE_CPP11_INITIALIZER_LIST - #endif - #if defined(EA_NO_HAVE_CPP11_INITIALIZER_LIST) - #undef EA_NO_HAVE_CPP11_INITIALIZER_LIST - #endif - - #if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 520) && !defined(EA_COMPILER_NO_INITIALIZER_LISTS) // Dinkumware. VS2010+ - #define EA_HAVE_CPP11_INITIALIZER_LIST 1 - #elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_CLANG) && (EA_COMPILER_VERSION >= 301) && !defined(EA_COMPILER_NO_INITIALIZER_LISTS) && !defined(EA_PLATFORM_APPLE) - #define EA_HAVE_CPP11_INITIALIZER_LIST 1 - #elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4004) && !defined(EA_COMPILER_NO_INITIALIZER_LISTS) && !defined(EA_PLATFORM_APPLE) - #define EA_HAVE_CPP11_INITIALIZER_LIST 1 - #elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1) && !defined(EA_COMPILER_NO_INITIALIZER_LISTS) - #define EA_HAVE_CPP11_INITIALIZER_LIST 1 - #else - #define EA_NO_HAVE_CPP11_INITIALIZER_LIST 1 - #endif - -#endif - #if defined(EA_HAVE_CPP11_INITIALIZER_LIST) // If the compiler can generate calls to std::initializer_list... // The initializer_list type must be declared in the std namespace, as that's the // namespace the compiler uses when generating code to use it. - #ifdef _MSC_VER - #pragma warning(push, 0) - #endif + EA_DISABLE_ALL_VC_WARNINGS() #include - #ifdef _MSC_VER - #pragma warning(pop) - #endif + EA_RESTORE_ALL_VC_WARNINGS() #else diff --git a/include/EASTL/internal/config.h b/include/EASTL/internal/config.h index 908f1edf..ba1ed9b5 100644 --- a/include/EASTL/internal/config.h +++ b/include/EASTL/internal/config.h @@ -89,8 +89,8 @@ /////////////////////////////////////////////////////////////////////////////// #ifndef EASTL_VERSION - #define EASTL_VERSION "3.12.01" - #define EASTL_VERSION_N 31201 + #define EASTL_VERSION "3.12.04" + #define EASTL_VERSION_N 31204 #endif @@ -146,10 +146,12 @@ #if defined(EA_COMPILER_MSVC_2015) #define EA_CPP14_CONSTEXPR // not supported + #define EA_NO_CPP14_CONSTEXPR #elif defined(EA_COMPILER_CPP14_ENABLED) #define EA_CPP14_CONSTEXPR constexpr #else #define EA_CPP14_CONSTEXPR // not supported + #define EA_NO_CPP14_CONSTEXPR #endif #endif diff --git a/include/EASTL/internal/function_detail.h b/include/EASTL/internal/function_detail.h index 208e93b7..d8d6c1e0 100644 --- a/include/EASTL/internal/function_detail.h +++ b/include/EASTL/internal/function_detail.h @@ -36,7 +36,6 @@ namespace eastl { - #if EASTL_EXCEPTIONS_ENABLED class bad_function_call : public std::exception { @@ -52,7 +51,6 @@ namespace eastl namespace internal { - class unused_class {}; union functor_storage_alignment @@ -98,8 +96,9 @@ namespace eastl template struct is_functor_inplace_allocatable { - static constexpr bool value = sizeof(Functor) <= sizeof(functor_storage) - && (eastl::alignment_of>::value % eastl::alignment_of::value) == 0; + static constexpr bool value = + sizeof(Functor) <= sizeof(functor_storage) && + (eastl::alignment_of_v> % eastl::alignment_of_v) == 0; }; template @@ -200,6 +199,7 @@ namespace eastl { auto& allocator = *EASTLAllocatorDefault(); Functor* func = static_cast(allocator.allocate(sizeof(Functor), alignof(Functor), 0)); + #if EASTL_EXCEPTIONS_ENABLED if (!func) { @@ -208,6 +208,7 @@ namespace eastl #else EASTL_ASSERT_MSG(func != nullptr, "Allocation failed!"); #endif + ::new (static_cast(func)) Functor(eastl::forward(functor)); GetFunctorPtrRef(storage) = func; } @@ -343,18 +344,22 @@ namespace eastl public: function_detail() EA_NOEXCEPT = default; - function_detail(std::nullptr_t) EA_NOEXCEPT - { - } + function_detail(std::nullptr_t) EA_NOEXCEPT {} function_detail(const function_detail& other) { - Copy(other); + if (this != &other) + { + Copy(other); + } } function_detail(function_detail&& other) { - Move(eastl::move(other)); + if (this != &other) + { + Move(eastl::move(other)); + } } template @@ -370,16 +375,22 @@ namespace eastl function_detail& operator=(const function_detail& other) { - Destroy(); - Copy(other); + if (this != &other) + { + Destroy(); + Copy(other); + } return *this; } function_detail& operator=(function_detail&& other) { - Destroy(); - Move(eastl::move(other)); + if(this != &other) + { + Destroy(); + Move(eastl::move(other)); + } return *this; } @@ -397,7 +408,6 @@ namespace eastl function_detail& operator=(Functor&& functor) { CreateForwardFunctor(eastl::forward(functor)); - return *this; } @@ -405,23 +415,27 @@ namespace eastl function_detail& operator=(eastl::reference_wrapper f) EA_NOEXCEPT { CreateForwardFunctor(f); - return *this; } void swap(function_detail& other) EA_NOEXCEPT { + if(this == &other) + return; + FunctorStorageType tempStorage; if (other.HaveManager()) { (void)(*other.mMgrFuncPtr)(static_cast(&tempStorage), static_cast(&other.mStorage), Base::ManagerOperations::MGROPS_MOVE_FUNCTOR); } + if (HaveManager()) { (void)(*mMgrFuncPtr)(static_cast(&other.mStorage), static_cast(&mStorage), Base::ManagerOperations::MGROPS_MOVE_FUNCTOR); } + if (other.HaveManager()) { (void)(*other.mMgrFuncPtr)(static_cast(&mStorage), static_cast(&tempStorage), @@ -497,7 +511,7 @@ namespace eastl if (HaveManager()) { (void)(*mMgrFuncPtr)(static_cast(&mStorage), nullptr, - Base::ManagerOperations::MGROPS_DESTRUCT_FUNCTOR); + Base::ManagerOperations::MGROPS_DESTRUCT_FUNCTOR); } } @@ -505,9 +519,11 @@ namespace eastl { if (other.HaveManager()) { - (void)(*other.mMgrFuncPtr)(static_cast(&mStorage), const_cast(static_cast(&other.mStorage)), - Base::ManagerOperations::MGROPS_COPY_FUNCTOR); + (void)(*other.mMgrFuncPtr)(static_cast(&mStorage), + const_cast(static_cast(&other.mStorage)), + Base::ManagerOperations::MGROPS_COPY_FUNCTOR); } + mMgrFuncPtr = other.mMgrFuncPtr; mInvokeFuncPtr = other.mInvokeFuncPtr; } @@ -517,8 +533,9 @@ namespace eastl if (other.HaveManager()) { (void)(*other.mMgrFuncPtr)(static_cast(&mStorage), static_cast(&other.mStorage), - Base::ManagerOperations::MGROPS_MOVE_FUNCTOR); + Base::ManagerOperations::MGROPS_MOVE_FUNCTOR); } + mMgrFuncPtr = other.mMgrFuncPtr; mInvokeFuncPtr = other.mInvokeFuncPtr; other.mMgrFuncPtr = nullptr; diff --git a/include/EASTL/internal/move_help.h b/include/EASTL/internal/move_help.h index 20bab670..3b879318 100644 --- a/include/EASTL/internal/move_help.h +++ b/include/EASTL/internal/move_help.h @@ -39,26 +39,18 @@ /// Acts like eastl::forward but is implemented inline instead of a function call. /// This allows code to be faster in debug builds in particular. /// -#if EASTL_MOVE_SEMANTICS_ENABLED - #define EASTL_MOVE(x) eastl::move(x) - #if !defined(EA_COMPILER_NO_DECLTYPE) - #define EASTL_MOVE_INLINE(x) static_cast::type&&>(x) - #elif defined(__GNUC__) - #define EASTL_MOVE_INLINE(x) static_cast::type&&>(x) - #else - #define EASTL_MOVE_INLINE(x) eastl::move(x) - #endif - - #define EASTL_FORWARD(T, x) eastl::forward(x) - #define EASTL_FORWARD_INLINE(T, x) eastl::forward(x) // Need to investigate how to properly make a macro for this. (eastl::is_reference::value ? static_cast(static_cast(x)) : static_cast(x)) +#define EASTL_MOVE(x) eastl::move(x) +#if !defined(EA_COMPILER_NO_DECLTYPE) + #define EASTL_MOVE_INLINE(x) static_cast::type&&>(x) +#elif defined(__GNUC__) + #define EASTL_MOVE_INLINE(x) static_cast::type&&>(x) #else - #define EASTL_MOVE(x) (x) - #define EASTL_MOVE_INLINE(x) (x) - - #define EASTL_FORWARD(T, x) (x) - #define EASTL_FORWARD_INLINE(T, x) (x) + #define EASTL_MOVE_INLINE(x) eastl::move(x) #endif +#define EASTL_FORWARD(T, x) eastl::forward(x) +#define EASTL_FORWARD_INLINE(T, x) eastl::forward(x) // Need to investigate how to properly make a macro for this. (eastl::is_reference::value ? static_cast(static_cast(x)) : static_cast(x)) + @@ -68,113 +60,87 @@ /// http://en.cppreference.com/w/cpp/algorithm/move /// http://en.cppreference.com/w/cpp/algorithm/move_backward /// -#if EASTL_MOVE_SEMANTICS_ENABLED - #define EASTL_MOVE_RANGE(first, last, result) eastl::move(first, last, result) - #define EASTL_MOVE_BACKWARD_RANGE(first, last, resultEnd) eastl::move_backward(first, last, resultEnd) -#else - #define EASTL_MOVE_RANGE(first, last, result) eastl::copy(first, last, result) - #define EASTL_MOVE_BACKWARD_RANGE(first, last, result) eastl::copy_backward(first, last, result) -#endif +#define EASTL_MOVE_RANGE(first, last, result) eastl::move(first, last, result) +#define EASTL_MOVE_BACKWARD_RANGE(first, last, resultEnd) eastl::move_backward(first, last, resultEnd) namespace eastl { - #if EASTL_MOVE_SEMANTICS_ENABLED - // forward - // - // forwards the argument to another function exactly as it was passed to the calling function. - // Not to be confused with move, this is specifically for echoing templated argument types - // to another function. move is specifically about making a type be an rvalue reference (i.e. movable) type. - // - // Example usage: - // template - // void WrapperFunction(T&& arg) - // { foo(eastl::forward(arg)); } - // - // template - // void WrapperFunction(Args&&... args) - // { foo(eastl::forward(args)...); } - // - // See the C++ Standard, section 20.2.3 - // http://en.cppreference.com/w/cpp/utility/forward - // - template - EA_CPP14_CONSTEXPR T&& forward(typename eastl::remove_reference::type& x) EA_NOEXCEPT - { - return static_cast(x); - } - - - template - EA_CPP14_CONSTEXPR T&& forward(typename eastl::remove_reference::type&& x) EA_NOEXCEPT - { - //static_assert(!is_lvalue_reference::value, "forward T isn't lvalue reference"); - return static_cast(x); - } - - - // move - // - // move obtains an rvalue reference to its argument and converts it to an xvalue. - // Returns, by definition: static_cast::type&&>(t). - // The primary use of this is to pass a move'd type to a function which takes T&&, - // and thus select that function instead of (e.g.) a function which takes T or T&. - // See the C++ Standard, section 20.2.3 - // http://en.cppreference.com/w/cpp/utility/move - // - template - EA_CPP14_CONSTEXPR typename eastl::remove_reference::type&& - move(T&& x) EA_NOEXCEPT + // forward + // + // forwards the argument to another function exactly as it was passed to the calling function. + // Not to be confused with move, this is specifically for echoing templated argument types + // to another function. move is specifically about making a type be an rvalue reference (i.e. movable) type. + // + // Example usage: + // template + // void WrapperFunction(T&& arg) + // { foo(eastl::forward(arg)); } + // + // template + // void WrapperFunction(Args&&... args) + // { foo(eastl::forward(args)...); } + // + // See the C++ Standard, section 20.2.3 + // http://en.cppreference.com/w/cpp/utility/forward + // + template + EA_CPP14_CONSTEXPR T&& forward(typename eastl::remove_reference::type& x) EA_NOEXCEPT + { + return static_cast(x); + } + + + template + EA_CPP14_CONSTEXPR T&& forward(typename eastl::remove_reference::type&& x) EA_NOEXCEPT + { + //static_assert(!is_lvalue_reference::value, "forward T isn't lvalue reference"); + return static_cast(x); + } + + + // move + // + // move obtains an rvalue reference to its argument and converts it to an xvalue. + // Returns, by definition: static_cast::type&&>(t). + // The primary use of this is to pass a move'd type to a function which takes T&&, + // and thus select that function instead of (e.g.) a function which takes T or T&. + // See the C++ Standard, section 20.2.3 + // http://en.cppreference.com/w/cpp/utility/move + // + template + EA_CPP14_CONSTEXPR typename eastl::remove_reference::type&& + move(T&& x) EA_NOEXCEPT + { + return ((typename eastl::remove_reference::type&&)x); + } + + + // move_if_noexcept + // + // Returns T&& if move-constructing T throws no exceptions. Instead returns const T& if + // move-constructing T throws exceptions or has no accessible copy constructor. + // The purpose of this is to use automatically use copy construction instead of move + // construction when the move may possible throw an exception. + // See the C++ Standard, section 20.2.3 + // http://en.cppreference.com/w/cpp/utility/move_if_noexcept + // + #if EASTL_EXCEPTIONS_ENABLED + template + EA_CPP14_CONSTEXPR typename eastl::conditional::value && + eastl::is_copy_constructible::value, const T&, T&&>::type + move_if_noexcept(T& x) EA_NOEXCEPT { - return ((typename eastl::remove_reference::type&&)x); + return eastl::move(x); } - - - // move_if_noexcept - // - // Returns T&& if move-constructing T throws no exceptions. Instead returns const T& if - // move-constructing T throws exceptions or has no accessible copy constructor. - // The purpose of this is to use automatically use copy construction instead of move - // construction when the move may possible throw an exception. - // See the C++ Standard, section 20.2.3 - // http://en.cppreference.com/w/cpp/utility/move_if_noexcept - // - #if EASTL_EXCEPTIONS_ENABLED - template - EA_CPP14_CONSTEXPR typename eastl::conditional::value && - eastl::is_copy_constructible::value, const T&, T&&>::type - move_if_noexcept(T& x) EA_NOEXCEPT - { - return eastl::move(x); - } - #else - template - EA_CPP14_CONSTEXPR T&& - move_if_noexcept(T& x) EA_NOEXCEPT - { - return eastl::move(x); - } - #endif #else - template - T& forward(T& x) EA_NOEXCEPT - { - return x; - } - - template - T& move(T& x) EA_NOEXCEPT - { - return x; - } - template - T& move_if_noexcept(T& x) EA_NOEXCEPT + EA_CPP14_CONSTEXPR T&& + move_if_noexcept(T& x) EA_NOEXCEPT { - return x; + return eastl::move(x); } - - #endif // EASTL_MOVE_SEMANTICS_ENABLED + #endif } // namespace eastl diff --git a/include/EASTL/internal/thread_support.h b/include/EASTL/internal/thread_support.h index 84c05384..747d9946 100644 --- a/include/EASTL/internal/thread_support.h +++ b/include/EASTL/internal/thread_support.h @@ -13,14 +13,22 @@ #endif #include -#if defined(EA_HAVE_CPP11_MUTEX) && !defined(EA_PLATFORM_MICROSOFT) && !defined(EA_PLATFORM_UNIX) // We stick with platform-specific mutex support to the extent possible, as it's currently more reliably available. +///////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE(rparolin): We need a fallback mutex implementation because the Microsoft implementation +// of std::mutex can not be included in managed-cpp code. +// +// 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 #endif #if EASTL_CPP11_MUTEX_ENABLED + EA_DISABLE_ALL_VC_WARNINGS() #include + EA_RESTORE_ALL_VC_WARNINGS() #endif #if defined(EA_PLATFORM_MICROSOFT) @@ -212,13 +220,8 @@ namespace eastl protected: mutex* pMutex; - #if defined(EA_COMPILER_NO_DELETED_FUNCTIONS) - auto_mutex(const auto_mutex&) : pMutex(NULL) {} - void operator=(const auto_mutex&) {} - #else - auto_mutex(const auto_mutex&) = delete; - void operator=(const auto_mutex&) = delete; - #endif + auto_mutex(const auto_mutex&) = delete; + void operator=(const auto_mutex&) = delete; }; @@ -228,10 +231,8 @@ namespace eastl public: shared_ptr_auto_mutex(const void* pSharedPtr); - #if !defined(EA_COMPILER_NO_DELETED_FUNCTIONS) - shared_ptr_auto_mutex(const shared_ptr_auto_mutex&) = delete; - void operator=(shared_ptr_auto_mutex&&) = delete; - #endif + shared_ptr_auto_mutex(const shared_ptr_auto_mutex&) = delete; + void operator=(shared_ptr_auto_mutex&&) = delete; }; diff --git a/include/EASTL/internal/type_compound.h b/include/EASTL/internal/type_compound.h index ebe78be7..d0cb6d8d 100644 --- a/include/EASTL/internal/type_compound.h +++ b/include/EASTL/internal/type_compound.h @@ -445,11 +445,17 @@ namespace eastl template <> struct is_enum : public false_type {}; #endif + #if !defined(EA_COMPILER_NO_TEMPLATE_ALIASES) + 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 // diff --git a/include/EASTL/internal/type_pod.h b/include/EASTL/internal/type_pod.h index 1d8eca80..4e11bb55 100644 --- a/include/EASTL/internal/type_pod.h +++ b/include/EASTL/internal/type_pod.h @@ -388,11 +388,10 @@ namespace eastl #define EASTL_TYPE_TRAIT_has_trivial_relocate_CONFORMANCE 0 // is_pod is not fully conforming. Can return false negatives. - // With current compilers, this is all we can do. - template - struct has_trivial_relocate : public eastl::integral_constant::value && !eastl::is_volatile::value>{}; + template + struct has_trivial_relocate : public eastl::bool_constant && !eastl::is_volatile_v> {}; - #define EASTL_DECLARE_TRIVIAL_RELOCATE(T) namespace eastl{ template <> struct has_trivial_relocate : public true_type{}; template <> struct has_trivial_relocate : public true_type{}; } + #define EASTL_DECLARE_TRIVIAL_RELOCATE(T) namespace eastl{ template <> struct has_trivial_relocate : public true_type{}; template <> struct has_trivial_relocate : public true_type{}; } @@ -1450,6 +1449,11 @@ namespace eastl #endif + #if EASTL_VARIABLE_TEMPLATES_ENABLED + template + EA_CONSTEXPR bool is_trivially_assignable_v = is_trivially_assignable::value; + #endif + // The main purpose of this function is to help the non-conforming case above. // Note: We don't handle const/volatile variations here, as we expect the user to // manually specify any such variations via this macro. diff --git a/include/EASTL/iterator.h b/include/EASTL/iterator.h index 6a4f3159..ade610f5 100644 --- a/include/EASTL/iterator.h +++ b/include/EASTL/iterator.h @@ -242,68 +242,68 @@ namespace eastl Iterator mIterator; public: - 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. - explicit reverse_iterator(iterator_type i) + EA_CPP14_CONSTEXPR explicit reverse_iterator(iterator_type i) : mIterator(i) { } - reverse_iterator(const reverse_iterator& ri) + EA_CPP14_CONSTEXPR reverse_iterator(const reverse_iterator& ri) : mIterator(ri.mIterator) { } template - reverse_iterator(const reverse_iterator& ri) + EA_CPP14_CONSTEXPR reverse_iterator(const reverse_iterator& ri) : mIterator(ri.base()) { } // 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 - reverse_iterator& operator=(const reverse_iterator& ri) + EA_CPP14_CONSTEXPR reverse_iterator& operator=(const reverse_iterator& ri) { mIterator = ri.base(); return *this; } - iterator_type base() const + EA_CPP14_CONSTEXPR iterator_type base() const { return mIterator; } - reference operator*() const + EA_CPP14_CONSTEXPR reference operator*() const { iterator_type i(mIterator); return *--i; } - pointer operator->() const + EA_CPP14_CONSTEXPR pointer operator->() const { return &(operator*()); } - reverse_iterator& operator++() + EA_CPP14_CONSTEXPR reverse_iterator& operator++() { --mIterator; return *this; } - reverse_iterator operator++(int) + EA_CPP14_CONSTEXPR reverse_iterator operator++(int) { reverse_iterator ri(*this); --mIterator; return ri; } - reverse_iterator& operator--() + EA_CPP14_CONSTEXPR reverse_iterator& operator--() { ++mIterator; return *this; } - reverse_iterator operator--(int) + EA_CPP14_CONSTEXPR reverse_iterator operator--(int) { reverse_iterator ri(*this); ++mIterator; return ri; } - reverse_iterator operator+(difference_type n) const + EA_CPP14_CONSTEXPR reverse_iterator operator+(difference_type n) const { return reverse_iterator(mIterator - n); } - reverse_iterator& operator+=(difference_type n) + EA_CPP14_CONSTEXPR reverse_iterator& operator+=(difference_type n) { mIterator -= n; return *this; } - reverse_iterator operator-(difference_type n) const + EA_CPP14_CONSTEXPR reverse_iterator operator-(difference_type n) const { return reverse_iterator(mIterator + n); } - reverse_iterator& operator-=(difference_type n) + EA_CPP14_CONSTEXPR reverse_iterator& operator-=(difference_type n) { mIterator += n; return *this; } // http://cplusplus.github.io/LWG/lwg-defects.html#386, @@ -314,7 +314,7 @@ namespace eastl // reference operator[](difference_type n) const // { return mIterator[-n - 1]; } - reference operator[](difference_type n) const + EA_CPP14_CONSTEXPR reference operator[](difference_type n) const { return *(*this + n); } }; @@ -329,49 +329,49 @@ namespace eastl // 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 - inline bool + EA_CPP14_CONSTEXPR inline bool operator==(const reverse_iterator& a, const reverse_iterator& b) { return a.base() == b.base(); } template - inline bool + EA_CPP14_CONSTEXPR inline bool operator<(const reverse_iterator& a, const reverse_iterator& b) { return a.base() > b.base(); } template - inline bool + EA_CPP14_CONSTEXPR inline bool operator!=(const reverse_iterator& a, const reverse_iterator& b) { return a.base() != b.base(); } template - inline bool + EA_CPP14_CONSTEXPR inline bool operator>(const reverse_iterator& a, const reverse_iterator& b) { return a.base() < b.base(); } template - inline bool + EA_CPP14_CONSTEXPR inline bool operator<=(const reverse_iterator& a, const reverse_iterator& b) { return a.base() >= b.base(); } template - inline bool + EA_CPP14_CONSTEXPR inline bool operator>=(const reverse_iterator& a, const reverse_iterator& b) { return a.base() <= b.base(); } template - inline typename reverse_iterator::difference_type + EA_CPP14_CONSTEXPR inline typename reverse_iterator::difference_type operator-(const reverse_iterator& a, const reverse_iterator& b) { return b.base() - a.base(); } template - inline reverse_iterator + EA_CPP14_CONSTEXPR inline reverse_iterator operator+(typename reverse_iterator::difference_type n, const reverse_iterator& a) { return reverse_iterator(a.base() - n); } @@ -410,212 +410,171 @@ namespace eastl - #if EASTL_MOVE_SEMANTICS_ENABLED - /// move_iterator - /// - /// From the C++11 Standard, section 24.5.3.1: - /// Class template move_iterator is an iterator adaptor with the same behavior as the underlying iterator - /// except that its dereference operator implicitly converts the value returned by the underlying iterator's - /// dereference operator to an rvalue reference. Some generic algorithms can be called with move iterators to - /// replace copying with moving. + /// move_iterator + /// + /// From the C++11 Standard, section 24.5.3.1: + /// Class template move_iterator is an iterator adaptor with the same behavior as the underlying iterator + /// except that its dereference operator implicitly converts the value returned by the underlying iterator's + /// dereference operator to an rvalue reference. Some generic algorithms can be called with move iterators to + /// replace copying with moving. - template - class move_iterator // Don't inherit from iterator. + template + class move_iterator // Don't inherit from iterator. + { + public: + typedef Iterator iterator_type; + typedef iterator_type wrapped_iterator_type; // This is not in the C++ Standard; it's used by use to identify it as a wrapping iterator type. + typedef iterator_traits traits_type; + typedef typename traits_type::iterator_category iterator_category; + typedef typename traits_type::value_type value_type; + typedef typename traits_type::difference_type difference_type; + typedef Iterator pointer; + typedef value_type&& reference; + + protected: + iterator_type mIterator; + + public: + move_iterator() + : mIterator() { - public: - typedef Iterator iterator_type; - typedef iterator_type wrapped_iterator_type; // This is not in the C++ Standard; it's used by use to identify it as a wrapping iterator type. - typedef iterator_traits traits_type; - typedef typename traits_type::iterator_category iterator_category; - typedef typename traits_type::value_type value_type; - typedef typename traits_type::difference_type difference_type; - typedef Iterator pointer; - typedef value_type&& reference; - - protected: - iterator_type mIterator; - - public: - move_iterator() - : mIterator() - { - } + } - explicit move_iterator(iterator_type mi) - : mIterator(mi) { } + explicit move_iterator(iterator_type mi) + : mIterator(mi) { } - template - move_iterator(const move_iterator& mi) - : mIterator(mi.base()) - { - } + template + move_iterator(const move_iterator& mi) + : mIterator(mi.base()) + { + } - iterator_type base() const - { return mIterator; } + iterator_type base() const + { return mIterator; } - reference operator*() const - { return eastl::move(*mIterator); } + reference operator*() const + { return eastl::move(*mIterator); } - pointer operator->() const - { return mIterator; } + pointer operator->() const + { return mIterator; } - move_iterator& operator++() - { - ++mIterator; - return *this; - } + move_iterator& operator++() + { + ++mIterator; + return *this; + } - move_iterator operator++(int) - { - move_iterator tempMoveIterator = *this; - ++mIterator; - return tempMoveIterator; - } + move_iterator operator++(int) + { + move_iterator tempMoveIterator = *this; + ++mIterator; + return tempMoveIterator; + } - move_iterator& operator--() - { - --mIterator; - return *this; - } + move_iterator& operator--() + { + --mIterator; + return *this; + } - move_iterator operator--(int) - { - move_iterator tempMoveIterator = *this; - --mIterator; - return tempMoveIterator; - } + move_iterator operator--(int) + { + move_iterator tempMoveIterator = *this; + --mIterator; + return tempMoveIterator; + } - move_iterator operator+(difference_type n) const - { return move_iterator(mIterator + n); } + move_iterator operator+(difference_type n) const + { return move_iterator(mIterator + n); } - move_iterator& operator+=(difference_type n) - { - mIterator += n; - return *this; - } + move_iterator& operator+=(difference_type n) + { + mIterator += n; + return *this; + } - move_iterator operator-(difference_type n) const - { return move_iterator(mIterator - n); } - - move_iterator& operator-=(difference_type n) - { - mIterator -= n; - return *this; - } + move_iterator operator-(difference_type n) const + { return move_iterator(mIterator - n); } + + move_iterator& operator-=(difference_type n) + { + mIterator -= n; + return *this; + } + + reference operator[](difference_type n) const + { return eastl::move(mIterator[n]); } + }; + + template + inline bool + operator==(const move_iterator& a, const move_iterator& b) + { return a.base() == b.base(); } + + + template + inline bool + operator!=(const move_iterator& a, const move_iterator& b) + { return !(a == b); } - reference operator[](difference_type n) const - { return eastl::move(mIterator[n]); } - }; - - template - inline bool - operator==(const move_iterator& a, const move_iterator& b) - { return a.base() == b.base(); } - - - template - inline bool - operator!=(const move_iterator& a, const move_iterator& b) - { return !(a == b); } - - - template - inline bool - operator<(const move_iterator& a, const move_iterator& b) - { return a.base() < b.base(); } - - - template - inline bool - operator<=(const move_iterator& a, const move_iterator& b) - { return !(b < a); } - - - template - inline bool - operator>(const move_iterator& a, const move_iterator& b) - { return b < a; } - - - template - inline bool - operator>=(const move_iterator& a, const move_iterator& b) - { return !(a < b); } - - - template - inline auto - operator-(const move_iterator& a, const move_iterator& b) -> decltype(a.base() - b.base()) - { return a.base() - b.base(); } - - - template - inline move_iterator - operator+(typename move_iterator::difference_type n, const move_iterator& a) - { return a + n; } - - - template - inline move_iterator make_move_iterator(Iterator i) - { return move_iterator(i); } - - - // 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 - // 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 - #if defined(EA_COMPILER_NO_FUNCTION_TEMPLATE_DEFAULT_ARGS) - namespace Internal - { - template - struct mminei_helper_1 - { - typedef eastl::move_iterator ReturnType; - static inline ReturnType mminei(Iterator i) - { return eastl::move_iterator(i); } - }; - template - struct mminei_helper_1 - { - typedef Iterator ReturnType; - static inline ReturnType mminei(Iterator i) - { return eastl::move_iterator(i); } - }; - - template - struct mminei_helper - { - static const bool is_noexcept = eastl::is_nothrow_move_constructible::value_type>::value || !eastl::is_copy_constructible::value_type>::value; - typedef typename mminei_helper_1::ReturnType ReturnType; - }; - } - - template - inline typename Internal::mminei_helper::ReturnType - make_move_if_noexcept_iterator(Iterator i) - { - return Internal::mminei_helper_1::is_noexcept>::mminei(i); - } - #else - 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); } - #endif - #else - // Else there are no exceptions and thus we always return a move_iterator. - template - inline eastl::move_iterator make_move_if_noexcept_iterator(Iterator i) - { return eastl::move_iterator(i); } - #endif - #else - // To consider: Should we make a dummy move_iterator that does nothing new? - // It could be a subclass of generic_iterator. + template + inline bool + operator<(const move_iterator& a, const move_iterator& b) + { return a.base() < b.base(); } + + + template + inline bool + operator<=(const move_iterator& a, const move_iterator& b) + { return !(b < a); } + + + template + inline bool + operator>(const move_iterator& a, const move_iterator& b) + { return b < a; } + + + template + inline bool + operator>=(const move_iterator& a, const move_iterator& b) + { return !(a < b); } + - #endif // #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline auto + operator-(const move_iterator& a, const move_iterator& b) -> decltype(a.base() - b.base()) + { return a.base() - b.base(); } + + + template + inline move_iterator + operator+(typename move_iterator::difference_type n, const move_iterator& a) + { return a + n; } + + + template + inline move_iterator make_move_iterator(Iterator i) + { return move_iterator(i); } + + + // 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 + // 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, + eastl::move_iterator, Iterator>::type> + inline IteratorType make_move_if_noexcept_iterator(Iterator i) + { return IteratorType(i); } + #else + // Else there are no exceptions and thus we always return a move_iterator. + template + inline eastl::move_iterator make_move_if_noexcept_iterator(Iterator i) + { return eastl::move_iterator(i); } + #endif @@ -631,11 +590,9 @@ namespace eastl struct is_move_iterator : public eastl::false_type {}; - #if EASTL_MOVE_SEMANTICS_ENABLED - template - struct is_move_iterator< eastl::move_iterator > - : public eastl::true_type {}; - #endif + template + struct is_move_iterator< eastl::move_iterator > + : public eastl::true_type {}; /// unwrap_move_iterator @@ -1021,19 +978,19 @@ namespace eastl // http://en.cppreference.com/w/cpp/iterator/data // template - EA_CONSTEXPR auto data(Container& c) -> decltype(c.data()) + EA_CPP14_CONSTEXPR auto data(Container& c) -> decltype(c.data()) { return c.data(); } template - EA_CONSTEXPR auto data(const Container& c) -> decltype(c.data()) + EA_CPP14_CONSTEXPR auto data(const Container& c) -> decltype(c.data()) { return c.data(); } template - EA_CONSTEXPR T* data(T(&array)[N]) EA_NOEXCEPT + EA_CPP14_CONSTEXPR T* data(T(&array)[N]) EA_NOEXCEPT { return array; } template - EA_CONSTEXPR const E* data(std::initializer_list il) EA_NOEXCEPT + EA_CPP14_CONSTEXPR const E* data(std::initializer_list il) EA_NOEXCEPT { return il.begin(); } @@ -1042,11 +999,11 @@ namespace eastl // http://en.cppreference.com/w/cpp/iterator/size // template - EA_CONSTEXPR auto size(const C& c) -> decltype(c.size()) + EA_CPP14_CONSTEXPR auto size(const C& c) -> decltype(c.size()) { return c.size(); } template - EA_CONSTEXPR std::size_t size(const T (&)[N]) EA_NOEXCEPT + EA_CPP14_CONSTEXPR std::size_t size(const T (&)[N]) EA_NOEXCEPT { return N; } @@ -1055,15 +1012,15 @@ namespace eastl // http://en.cppreference.com/w/cpp/iterator/empty // template - EA_CONSTEXPR auto empty(const Container& c) -> decltype(c.empty()) + EA_CPP14_CONSTEXPR auto empty(const Container& c) -> decltype(c.empty()) { return c.empty(); } template - EA_CONSTEXPR bool empty(const T (&)[N]) EA_NOEXCEPT + EA_CPP14_CONSTEXPR bool empty(const T (&)[N]) EA_NOEXCEPT { return false; } template - EA_CONSTEXPR bool empty(std::initializer_list il) EA_NOEXCEPT + EA_CPP14_CONSTEXPR bool empty(std::initializer_list il) EA_NOEXCEPT { return il.size() == 0; } #endif // defined(EA_COMPILER_CPP11_ENABLED) && EA_COMPILER_CPP11_ENABLED @@ -1091,115 +1048,115 @@ namespace eastl #if EASTL_BEGIN_END_ENABLED template - inline auto begin(Container& container) -> decltype(container.begin()) + EA_CPP14_CONSTEXPR inline auto begin(Container& container) -> decltype(container.begin()) { return container.begin(); } template - inline auto begin(const Container& container) -> decltype(container.begin()) + EA_CPP14_CONSTEXPR inline auto begin(const Container& container) -> decltype(container.begin()) { return container.begin(); } template - inline auto cbegin(const Container& container) -> decltype(container.begin()) + EA_CPP14_CONSTEXPR inline auto cbegin(const Container& container) -> decltype(container.begin()) { return container.begin(); } template - inline auto end(Container& container) -> decltype(container.end()) + EA_CPP14_CONSTEXPR inline auto end(Container& container) -> decltype(container.end()) { return container.end(); } template - inline auto end(const Container& container) -> decltype(container.end()) + EA_CPP14_CONSTEXPR inline auto end(const Container& container) -> decltype(container.end()) { return container.end(); } template - inline auto cend(const Container& container) -> decltype(container.end()) + EA_CPP14_CONSTEXPR inline auto cend(const Container& container) -> decltype(container.end()) { return container.end(); } template - inline auto rbegin(Container& container) -> decltype(container.rbegin()) + EA_CPP14_CONSTEXPR inline auto rbegin(Container& container) -> decltype(container.rbegin()) { return container.rbegin(); } template - inline auto rbegin(const Container& container) -> decltype(container.rbegin()) + EA_CPP14_CONSTEXPR inline auto rbegin(const Container& container) -> decltype(container.rbegin()) { return container.rbegin(); } template - inline auto rend(Container& container) -> decltype(container.rend()) + EA_CPP14_CONSTEXPR inline auto rend(Container& container) -> decltype(container.rend()) { return container.rend(); } template - inline auto rend(const Container& container) -> decltype(container.rend()) + EA_CPP14_CONSTEXPR inline auto rend(const Container& container) -> decltype(container.rend()) { return container.rend(); } template - inline auto crbegin(const Container& container) -> decltype(eastl::rbegin(container)) + EA_CPP14_CONSTEXPR inline auto crbegin(const Container& container) -> decltype(eastl::rbegin(container)) { return container.rbegin(); } template - inline auto crend(const Container& container) -> decltype(eastl::rend(container)) + EA_CPP14_CONSTEXPR inline auto crend(const Container& container) -> decltype(eastl::rend(container)) { return container.rend(); } template - inline T* begin(T (&arrayObject)[arraySize]) + EA_CPP14_CONSTEXPR inline T* begin(T (&arrayObject)[arraySize]) { return arrayObject; } template - inline T* end(T (&arrayObject)[arraySize]) + EA_CPP14_CONSTEXPR inline T* end(T (&arrayObject)[arraySize]) { return (arrayObject + arraySize); } template - inline reverse_iterator rbegin(T (&arrayObject)[arraySize]) + EA_CPP14_CONSTEXPR inline reverse_iterator rbegin(T (&arrayObject)[arraySize]) { return reverse_iterator(arrayObject + arraySize); } template - inline reverse_iterator rend(T (&arrayObject)[arraySize]) + EA_CPP14_CONSTEXPR inline reverse_iterator rend(T (&arrayObject)[arraySize]) { return reverse_iterator(arrayObject); } template - inline reverse_iterator rbegin(std::initializer_list ilist) + EA_CPP14_CONSTEXPR inline reverse_iterator rbegin(std::initializer_list ilist) { return eastl::reverse_iterator(ilist.end()); } template - inline reverse_iterator rend(std::initializer_list ilist) + EA_CPP14_CONSTEXPR inline reverse_iterator rend(std::initializer_list ilist) { return eastl::reverse_iterator(ilist.begin()); } template - reverse_iterator make_reverse_iterator(Iterator i) + EA_CPP14_CONSTEXPR reverse_iterator make_reverse_iterator(Iterator i) { return reverse_iterator(i); } #endif // EASTL_BEGIN_END_ENABLED diff --git a/include/EASTL/list.h b/include/EASTL/list.h index dc787466..cbd558d2 100644 --- a/include/EASTL/list.h +++ b/include/EASTL/list.h @@ -141,11 +141,13 @@ namespace eastl #else + EA_DISABLE_VC_WARNING(4625 4626) template struct ListNode : public ListNodeBase { T mValue; }; + EA_RESTORE_VC_WARNING() #endif @@ -306,10 +308,8 @@ namespace eastl list(size_type n, const value_type& value, const allocator_type& allocator = EASTL_LIST_DEFAULT_ALLOCATOR); list(const this_type& x); list(const this_type& x, const allocator_type& allocator); - #if EASTL_MOVE_SEMANTICS_ENABLED - list(this_type&& x); - list(this_type&&, const allocator_type&); - #endif + list(this_type&& x); + list(this_type&&, const allocator_type&); list(std::initializer_list ilist, const allocator_type& allocator = EASTL_LIST_DEFAULT_ALLOCATOR); template @@ -317,9 +317,7 @@ namespace eastl this_type& operator=(const this_type& x); this_type& operator=(std::initializer_list ilist); - #if EASTL_MOVE_SEMANTICS_ENABLED - this_type& operator=(this_type&& x); - #endif + this_type& operator=(this_type&& x); // In the case that the two containers' allocators are unequal, swap copies elements instead // of replacing them in place. In this case swap is an O(n) operation instead of O(1). @@ -360,60 +358,36 @@ namespace eastl reference back(); const_reference back() const; - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - template - void emplace_front(Args&&... args); + template + void emplace_front(Args&&... args); - template - void emplace_back(Args&&... args); - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - void emplace_front(value_type&& value); - void emplace_back(value_type&& value); - #endif - void emplace_front(const value_type& value); - void emplace_back(const value_type& value); - #endif + template + void emplace_back(Args&&... args); void push_front(const value_type& value); - #if EASTL_MOVE_SEMANTICS_ENABLED - void push_front(value_type&& x); - #endif + void push_front(value_type&& x); reference push_front(); void* push_front_uninitialized(); void push_back(const value_type& value); - #if EASTL_MOVE_SEMANTICS_ENABLED - void push_back(value_type&& x); - #endif + void push_back(value_type&& x); reference push_back(); void* push_back_uninitialized(); void pop_front(); void pop_back(); - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - template - iterator emplace(const_iterator position, Args&&... args); - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - iterator emplace(const_iterator position, value_type&& value); - #endif - iterator emplace(const_iterator position, const value_type& value); - #endif + template + iterator emplace(const_iterator position, Args&&... args); iterator insert(const_iterator position); iterator insert(const_iterator position, const value_type& value); - #if EASTL_MOVE_SEMANTICS_ENABLED - iterator insert(const_iterator position, value_type&& x); - #endif - - void insert(const_iterator position, size_type n, const value_type& value); + iterator insert(const_iterator position, value_type&& x); + iterator insert(const_iterator position, std::initializer_list ilist); + void insert(const_iterator position, size_type n, const value_type& value); // TODO(rparolin): return iterator C++11 support template - void insert(const_iterator position, InputIterator first, InputIterator last); - - iterator insert(const_iterator position, std::initializer_list ilist); + void insert(const_iterator position, InputIterator first, InputIterator last); // TODO(rparolin): return iterator C++11 support iterator erase(const_iterator position); iterator erase(const_iterator first, const_iterator last); @@ -438,28 +412,20 @@ namespace eastl void splice(const_iterator position, this_type& x); void splice(const_iterator position, this_type& x, const_iterator i); void splice(const_iterator position, this_type& x, const_iterator first, const_iterator last); - - #if EASTL_MOVE_SEMANTICS_ENABLED - void splice(const_iterator position, this_type&& x); - void splice(const_iterator position, this_type&& x, const_iterator i); - void splice(const_iterator position, this_type&& x, const_iterator first, const_iterator last); - #endif + void splice(const_iterator position, this_type&& x); + void splice(const_iterator position, this_type&& x, const_iterator i); + void splice(const_iterator position, this_type&& x, const_iterator first, const_iterator last); public: // For merge, see notes for splice regarding the handling of unequal allocators. void merge(this_type& x); - - #if EASTL_MOVE_SEMANTICS_ENABLED - void merge(this_type&& x); - #endif + void merge(this_type&& x); template void merge(this_type& x, Compare compare); - #if EASTL_MOVE_SEMANTICS_ENABLED - template - void merge(this_type&& x, Compare compare); - #endif + template + void merge(this_type&& x, Compare compare); void unique(); @@ -482,15 +448,8 @@ namespace eastl protected: node_type* DoCreateNode(); - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED // If we can do variadic arguments... - template - node_type* DoCreateNode(Args&&... args); - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - node_type* DoCreateNode(value_type&& value); - #endif - node_type* DoCreateNode(const value_type& value); - #endif + template + node_type* DoCreateNode(Args&&... args); template void DoAssign(Integer n, Integer value, true_type); @@ -508,15 +467,8 @@ namespace eastl void DoInsertValues(ListNodeBase* pNode, size_type n, const value_type& value); - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED // If we can do variadic arguments... - template - void DoInsertValue(ListNodeBase* pNode, Args&&... args); - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - void DoInsertValue(ListNodeBase* pNode, value_type&& value); - #endif - void DoInsertValue(ListNodeBase* pNode, const value_type& value); - #endif + template + void DoInsertValue(ListNodeBase* pNode, Args&&... args); void DoErase(ListNodeBase* pNode); @@ -905,22 +857,20 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline list::list(this_type&& x) - : base_type(eastl::move(x.mAllocator)) - { - swap(x); - } + template + inline list::list(this_type&& x) + : base_type(eastl::move(x.mAllocator)) + { + swap(x); + } - template - inline list::list(this_type&& x, const allocator_type& allocator) - : base_type(allocator) - { - swap(x); // member swap handles the case that x has a different allocator than our allocator by doing a copy. - } - #endif + template + inline list::list(this_type&& x, const allocator_type& allocator) + : base_type(allocator) + { + swap(x); // member swap handles the case that x has a different allocator than our allocator by doing a copy. + } template @@ -1166,19 +1116,17 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - typename list::this_type& - list::operator=(this_type&& x) + template + typename list::this_type& + list::operator=(this_type&& x) + { + if(this != &x) { - if(this != &x) - { - clear(); // To consider: Are we really required to clear here? x is going away soon and will clear itself in its dtor. - swap(x); // member swap handles the case that x has a different allocator than our allocator by doing a copy. - } - return *this; + clear(); // To consider: Are we really required to clear here? x is going away soon and will clear itself in its dtor. + swap(x); // member swap handles the case that x has a different allocator than our allocator by doing a copy. } - #endif + return *this; + } template @@ -1265,47 +1213,19 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - template - template - void list::emplace_front(Args&&... args) - { - DoInsertValue((ListNodeBase*)mNode.mpNext, eastl::forward(args)...); - } - - template - template - void list::emplace_back(Args&&... args) - { - DoInsertValue((ListNodeBase*)&mNode, eastl::forward(args)...); - } - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - template - void list::emplace_front(value_type&& value) - { - DoInsertValue((ListNodeBase*)mNode.mpNext, eastl::move(value)); - } - - template - void list::emplace_back(value_type&& value) - { - DoInsertValue((ListNodeBase*)&mNode, eastl::move(value)); - } - #endif - - template - void list::emplace_front(const value_type& value) - { - DoInsertValue((ListNodeBase*)mNode.mpNext, value); - } + template + template + void list::emplace_front(Args&&... args) + { + DoInsertValue((ListNodeBase*)mNode.mpNext, eastl::forward(args)...); + } - template - void list::emplace_back(const value_type& value) - { - DoInsertValue((ListNodeBase*)&mNode, value); - } - #endif + template + template + void list::emplace_back(Args&&... args) + { + DoInsertValue((ListNodeBase*)&mNode, eastl::forward(args)...); + } template @@ -1315,13 +1235,11 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline void list::push_front(value_type&& value) - { - emplace(begin(), eastl::move(value)); - } - #endif + template + inline void list::push_front(value_type&& value) + { + emplace(begin(), eastl::move(value)); + } template @@ -1368,13 +1286,11 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline void list::push_back(value_type&& value) - { - emplace(end(), eastl::move(value)); - } - #endif + template + inline void list::push_back(value_type&& value) + { + emplace(end(), eastl::move(value)); + } template @@ -1414,34 +1330,14 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - template - template - inline typename list::iterator - list::emplace(const_iterator position, Args&&... args) - { - DoInsertValue(position.mpNode, eastl::forward(args)...); - return iterator(position.mpNode->mpPrev); - } - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline typename list::iterator - list::emplace(const_iterator position, value_type&& value) - { - DoInsertValue(position.mpNode, eastl::move(value)); - return iterator(position.mpNode->mpPrev); - } - #endif - - template - inline typename list::iterator - list::emplace(const_iterator position, const value_type& value) - { - DoInsertValue(position.mpNode, value); - return iterator(position.mpNode->mpPrev); - } - #endif + template + template + inline typename list::iterator + list::emplace(const_iterator position, Args&&... args) + { + DoInsertValue(position.mpNode, eastl::forward(args)...); + return iterator(position.mpNode->mpPrev); + } template @@ -1470,15 +1366,12 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline typename list::iterator - list::insert(const_iterator position, value_type&& value) - { - return emplace(position, eastl::move(value)); - } - #endif - + template + inline typename list::iterator + list::insert(const_iterator position, value_type&& value) + { + return emplace(position, eastl::move(value)); + } template inline void list::insert(const_iterator position, size_type n, const value_type& value) @@ -1624,13 +1517,11 @@ namespace eastl } } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline void list::splice(const_iterator position, this_type&& x) - { - return splice(position, x); // This will call splice(const_iterator, const this_type&); - } - #endif + template + inline void list::splice(const_iterator position, this_type&& x) + { + return splice(position, x); // This will call splice(const_iterator, const this_type&); + } template @@ -1658,13 +1549,11 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline void list::splice(const_iterator position, list&& x, const_iterator i) - { - return splice(position, x, i); // This will call splice(const_iterator, const this_type&, const_iterator); - } - #endif + template + inline void list::splice(const_iterator position, list&& x, const_iterator i) + { + return splice(position, x, i); // This will call splice(const_iterator, const this_type&, const_iterator); + } template @@ -1694,13 +1583,11 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline void list::splice(const_iterator position, list&& x, const_iterator first, const_iterator last) - { - return splice(position, x, first, last); // This will call splice(const_iterator, const this_type&, const_iterator, const_iterator); - } - #endif + template + inline void list::splice(const_iterator position, list&& x, const_iterator first, const_iterator last) + { + return splice(position, x, first, last); // This will call splice(const_iterator, const this_type&, const_iterator, const_iterator); + } template @@ -1746,13 +1633,11 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - void list::merge(this_type&& x) - { - return merge(x); // This will call merge(this_type&) - } - #endif + template + void list::merge(this_type&& x) + { + return merge(x); // This will call merge(this_type&) + } template @@ -1785,14 +1670,12 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - template - void list::merge(this_type&& x, Compare compare) - { - return merge(x, compare); // This will call merge(this_type&, Compare) - } - #endif + template + template + void list::merge(this_type&& x, Compare compare) + { + return merge(x, compare); // This will call merge(this_type&, Compare) + } template @@ -1967,79 +1850,29 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED // If we can do variadic arguments... - template - template - inline typename list::node_type* - list::DoCreateNode(Args&&... args) - { - node_type* const pNode = DoAllocateNode(); // pNode is of type node_type, but it's uninitialized memory. + template + template + inline typename list::node_type* + list::DoCreateNode(Args&&... args) + { + node_type* const pNode = DoAllocateNode(); // pNode is of type node_type, but it's uninitialized memory. - #if EASTL_EXCEPTIONS_ENABLED - try - { - ::new((void*)&pNode->mValue) value_type(eastl::forward(args)...); - } - catch(...) - { - DoFreeNode(pNode); - throw; - } - #else + #if EASTL_EXCEPTIONS_ENABLED + try + { ::new((void*)&pNode->mValue) value_type(eastl::forward(args)...); - #endif - - return pNode; - } - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline typename list::node_type* - list::DoCreateNode(value_type&& value) + } + catch(...) { - node_type* const pNode = DoAllocateNode(); - - #if EASTL_EXCEPTIONS_ENABLED - try - { - ::new((void*)&pNode->mValue) value_type(eastl::move(value)); - } - catch(...) - { - DoFreeNode(pNode); - throw; - } - #else - ::new((void*)&pNode->mValue) value_type(eastl::move(value)); - #endif - - return pNode; + DoFreeNode(pNode); + throw; } + #else + ::new((void*)&pNode->mValue) value_type(eastl::forward(args)...); #endif - template - inline typename list::node_type* - list::DoCreateNode(const value_type& value) - { - node_type* const pNode = DoAllocateNode(); - - #if EASTL_EXCEPTIONS_ENABLED - try - { - ::new((void*)&pNode->mValue) value_type(value); - } - catch(...) - { - DoFreeNode(pNode); - throw; - } - #else - ::new((void*)&pNode->mValue) value_type(value); - #endif - - return pNode; - } - #endif + return pNode; + } template @@ -2136,40 +1969,16 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED // If we can do variadic arguments... - template - template - inline void list::DoInsertValue(ListNodeBase* pNode, Args&&... args) - { - node_type* const pNodeNew = DoCreateNode(eastl::forward(args)...); - ((ListNodeBase*)pNodeNew)->insert(pNode); - #if EASTL_LIST_SIZE_CACHE - ++mSize; - #endif - } - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline void list::DoInsertValue(ListNodeBase* pNode, value_type&& value) - { - node_type* const pNodeNew = DoCreateNode(eastl::move(value)); - ((ListNodeBase*)pNodeNew)->insert(pNode); - #if EASTL_LIST_SIZE_CACHE - ++mSize; - #endif - } + template + template + inline void list::DoInsertValue(ListNodeBase* pNode, Args&&... args) + { + node_type* const pNodeNew = DoCreateNode(eastl::forward(args)...); + ((ListNodeBase*)pNodeNew)->insert(pNode); + #if EASTL_LIST_SIZE_CACHE + ++mSize; #endif - - template - inline void list::DoInsertValue(ListNodeBase* pNode, const value_type& value) - { - node_type* const pNodeNew = DoCreateNode(value); - ((ListNodeBase*)pNodeNew)->insert(pNode); - #if EASTL_LIST_SIZE_CACHE - ++mSize; - #endif - } - #endif + } template diff --git a/include/EASTL/memory.h b/include/EASTL/memory.h index 4c0db0c1..ca244c9b 100644 --- a/include/EASTL/memory.h +++ b/include/EASTL/memory.h @@ -653,66 +653,58 @@ namespace eastl /// This is a specialization of uninitialized_move for iterators that are pointers. We use it because /// internally it uses generic_iterator to make pointers act like regular eastl::iterator. /// - #if EASTL_MOVE_SEMANTICS_ENABLED - namespace Internal + namespace Internal + { + template + inline ForwardIterator uninitialized_move_impl(InputIterator first, InputIterator last, ForwardIterator dest, true_type) { - template - inline ForwardIterator uninitialized_move_impl(InputIterator first, InputIterator last, ForwardIterator dest, true_type) - { - return eastl::copy(first, last, dest); // The copy() in turn will use memcpy for is_trivially_copy_assignable (e.g. POD) types. - } + return eastl::copy(first, last, dest); // The copy() in turn will use memcpy for is_trivially_copy_assignable (e.g. POD) types. + } - template - inline ForwardIterator uninitialized_move_impl(InputIterator first, InputIterator last, ForwardIterator dest, false_type) - { - typedef typename eastl::iterator_traits::value_type value_type; - ForwardIterator currentDest(dest); + template + inline ForwardIterator uninitialized_move_impl(InputIterator first, InputIterator last, ForwardIterator dest, false_type) + { + typedef typename eastl::iterator_traits::value_type value_type; + ForwardIterator currentDest(dest); - // We must run a loop over every element and move-construct it at the new location. - #if EASTL_EXCEPTIONS_ENABLED - try - { - #endif - for(; first != last; ++first, ++currentDest) - ::new((void*)eastl::addressof(*currentDest)) value_type(eastl::move(*first)); // If value_type has a move constructor then it will be used here. - #if EASTL_EXCEPTIONS_ENABLED - } - catch(...) - { - // We have a problem here: If an exception occurs while doing the loop below then we will - // have values that were moved from the source to the dest that may need to be moved back - // in the catch. What does the C++11 Standard say about this? And what happens if there's an - // exception while moving them back? We may want to trace through a conforming C++11 Standard - // Library to see what it does and do something similar. Given that rvalue references are - // objects that are going away, we may not need to move the values back, though that has the - // side effect of a certain kind of lost elements problem. - for(; dest < currentDest; ++dest) - (*dest).~value_type(); - throw; - } - #endif + // We must run a loop over every element and move-construct it at the new location. + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + for(; first != last; ++first, ++currentDest) + ::new((void*)eastl::addressof(*currentDest)) value_type(eastl::move(*first)); // If value_type has a move constructor then it will be used here. + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + // We have a problem here: If an exception occurs while doing the loop below then we will + // have values that were moved from the source to the dest that may need to be moved back + // in the catch. What does the C++11 Standard say about this? And what happens if there's an + // exception while moving them back? We may want to trace through a conforming C++11 Standard + // Library to see what it does and do something similar. Given that rvalue references are + // objects that are going away, we may not need to move the values back, though that has the + // side effect of a certain kind of lost elements problem. + for(; dest < currentDest; ++dest) + (*dest).~value_type(); + throw; + } + #endif - return currentDest; - } + return currentDest; } + } - template - inline Result uninitialized_move_ptr(First first, Last last, Result dest) - { - typedef typename eastl::iterator_traits >::value_type value_type; - const generic_iterator i(Internal::uninitialized_move_impl(eastl::generic_iterator(first), // generic_iterator makes a pointer act like an iterator. - eastl::generic_iterator(last), - eastl::generic_iterator(dest), - eastl::is_trivially_copy_assignable())); // is_trivially_copy_assignable identifies if copy assignment would be as valid as move assignment, which means we have the opportunity to memcpy/memmove optimization. - return i.base(); - } - #else - template - inline Result uninitialized_move_ptr(First first, Last last, Result dest) - { - return uninitialized_copy_ptr(first, last, dest); - } - #endif + template + inline Result uninitialized_move_ptr(First first, Last last, Result dest) + { + typedef typename eastl::iterator_traits >::value_type value_type; + const generic_iterator i(Internal::uninitialized_move_impl(eastl::generic_iterator(first), // generic_iterator makes a pointer act like an iterator. + eastl::generic_iterator(last), + eastl::generic_iterator(dest), + eastl::is_trivially_copy_assignable())); // is_trivially_copy_assignable identifies if copy assignment would be as valid as move assignment, which means we have the opportunity to memcpy/memmove optimization. + return i.base(); + } @@ -736,11 +728,7 @@ namespace eastl template inline ForwardIterator uninitialized_move(InputIterator first, InputIterator last, ForwardIterator dest) { - #if EASTL_MOVE_SEMANTICS_ENABLED - return eastl::uninitialized_copy(eastl::make_move_iterator(first), eastl::make_move_iterator(last), dest); - #else - return eastl::uninitialized_copy(first, last, dest); - #endif + return eastl::uninitialized_copy(eastl::make_move_iterator(first), eastl::make_move_iterator(last), dest); } @@ -752,11 +740,7 @@ namespace eastl template inline ForwardIterator uninitialized_move_if_noexcept(InputIterator first, InputIterator last, ForwardIterator dest) { - #if EASTL_MOVE_SEMANTICS_ENABLED - return eastl::uninitialized_copy(eastl::make_move_if_noexcept_iterator(first), eastl::make_move_if_noexcept_iterator(last), dest); - #else - return eastl::uninitialized_copy(first, last, dest); - #endif + return eastl::uninitialized_copy(eastl::make_move_if_noexcept_iterator(first), eastl::make_move_if_noexcept_iterator(last), dest); } @@ -786,11 +770,7 @@ namespace eastl template inline ForwardIterator uninitialized_move_n(InputIterator first, Count n, ForwardIterator dest) { - #if EASTL_MOVE_SEMANTICS_ENABLED - return eastl::uninitialized_copy_n(eastl::make_move_iterator(first), n, dest); - #else - return eastl::uninitialized_copy_n(first, n, dest); - #endif + return eastl::uninitialized_copy_n(eastl::make_move_iterator(first), n, dest); } // Disable warning C4345 - behavior change: an object of POD type constructed with an initializer of the form () diff --git a/include/EASTL/priority_queue.h b/include/EASTL/priority_queue.h index 55219348..0853be17 100644 --- a/include/EASTL/priority_queue.h +++ b/include/EASTL/priority_queue.h @@ -132,23 +132,17 @@ namespace eastl eastl::make_heap(c.begin(), c.end(), comp); } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - priority_queue(this_type&& x, const Allocator& allocator, typename eastl::enable_if::value>::type* = NULL) - : c(eastl::move(x.c), allocator), comp(x.comp) - { - eastl::make_heap(c.begin(), c.end(), comp); - } - #endif + template + priority_queue(this_type&& x, const Allocator& allocator, typename eastl::enable_if::value>::type* = NULL) + : c(eastl::move(x.c), allocator), comp(x.comp) + { + eastl::make_heap(c.begin(), c.end(), comp); + } explicit priority_queue(const compare_type& compare); + explicit priority_queue(const compare_type& compare, container_type&& x); priority_queue(const compare_type& compare, const container_type& x); - - #if EASTL_MOVE_SEMANTICS_ENABLED - explicit priority_queue(const compare_type& compare, container_type&& x); - #endif - priority_queue(std::initializer_list ilist, const compare_type& compare = compare_type()); // C++11 doesn't specify that std::priority_queue has initializer list support. template @@ -160,10 +154,8 @@ namespace eastl template priority_queue(InputIterator first, InputIterator last, const compare_type& compare, const container_type& x); - #if EASTL_MOVE_SEMANTICS_ENABLED - template - priority_queue(InputIterator first, InputIterator last, const compare_type& compare, container_type&& x); - #endif + template + priority_queue(InputIterator first, InputIterator last, const compare_type& compare, container_type&& x); // Additional C++11 support to consider: // @@ -183,20 +175,10 @@ namespace eastl void push(const value_type& value); - #if EASTL_MOVE_SEMANTICS_ENABLED - void push(value_type&& x); - #endif - - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - template - void emplace(Args&&... args); - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - void emplace(value_type&& x); - #endif + void push(value_type&& x); - void emplace(const value_type& x); - #endif + template + void emplace(Args&&... args); void pop(); @@ -246,14 +228,12 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline priority_queue::priority_queue(const compare_type& compare, container_type&& x) - : c(eastl::move(x)), comp(compare) - { - eastl::make_heap(c.begin(), c.end(), comp); - } - #endif + template + inline priority_queue::priority_queue(const compare_type& compare, container_type&& x) + : c(eastl::move(x)), comp(compare) + { + eastl::make_heap(c.begin(), c.end(), comp); + } template @@ -294,16 +274,14 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - template - inline priority_queue::priority_queue(InputIterator first, InputIterator last, const compare_type& compare, container_type&& x) - : c(eastl::move(x)), comp(compare) - { - c.insert(c.end(), first, last); - eastl::make_heap(c.begin(), c.end(), comp); - } - #endif + template + template + inline priority_queue::priority_queue(InputIterator first, InputIterator last, const compare_type& compare, container_type&& x) + : c(eastl::move(x)), comp(compare) + { + c.insert(c.end(), first, last); + eastl::make_heap(c.begin(), c.end(), comp); + } template @@ -350,51 +328,33 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline void priority_queue::push(value_type&& value) - { - #if EASTL_EXCEPTIONS_ENABLED - try - { - c.push_back(eastl::move(value)); - eastl::push_heap(c.begin(), c.end(), comp); - } - catch(...) - { - c.clear(); - throw; - } - #else + template + inline void priority_queue::push(value_type&& value) + { + #if EASTL_EXCEPTIONS_ENABLED + try + { c.push_back(eastl::move(value)); eastl::push_heap(c.begin(), c.end(), comp); - #endif - } - #endif - - - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - template - template - inline void priority_queue::emplace(Args&&... args) - { - push(value_type(eastl::forward(args)...)); // The C++11 Standard 23.6.4/1 states that c.emplace is used, but also declares that c doesn't need to have an emplace function. - } - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline void priority_queue::emplace(value_type&& value) + } + catch(...) { - push(eastl::move(value)); // The C++11 Standard 23.6.4/1 states that c.emplace is used, but also declares that c doesn't need to have an emplace function. + c.clear(); + throw; } + #else + c.push_back(eastl::move(value)); + eastl::push_heap(c.begin(), c.end(), comp); #endif + } - template - inline void priority_queue::emplace(const value_type& value) - { - push(value); // The C++11 Standard 23.6.4/1 states that c.emplace is used, but also declares that c doesn't need to have an emplace function. - } - #endif + + template + template + inline void priority_queue::emplace(Args&&... args) + { + push(value_type(eastl::forward(args)...)); // The C++11 Standard 23.6.4/1 states that c.emplace is used, but also declares that c doesn't need to have an emplace function. + } template diff --git a/include/EASTL/queue.h b/include/EASTL/queue.h index 94a6aca6..fa6950f4 100644 --- a/include/EASTL/queue.h +++ b/include/EASTL/queue.h @@ -90,19 +90,14 @@ namespace eastl { } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - queue(this_type&& x, const Allocator& allocator, typename eastl::enable_if::value>::type* = NULL) - : c(eastl::move(x.c), allocator) - { - } - #endif + template + queue(this_type&& x, const Allocator& allocator, typename eastl::enable_if::value>::type* = NULL) + : c(eastl::move(x.c), allocator) + { + } explicit queue(const container_type& x); - - #if EASTL_MOVE_SEMANTICS_ENABLED - explicit queue(container_type&& x); - #endif + explicit queue(container_type&& x); // Additional C++11 support to consider: // @@ -124,21 +119,10 @@ namespace eastl const_reference back() const; void push(const value_type& value); + void push(value_type&& x); - #if EASTL_MOVE_SEMANTICS_ENABLED - void push(value_type&& x); - #endif - - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - template - void emplace_back(Args&&... args); - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - void emplace_back(value_type&& x); - #endif - - void emplace_back(const value_type& x); - #endif + template + void emplace_back(Args&&... args); void pop(); @@ -174,14 +158,12 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline queue::queue(Container&& x) - : c(eastl::move(x)) - { - // Empty - } - #endif + template + inline queue::queue(Container&& x) + : c(eastl::move(x)) + { + // Empty + } template @@ -254,37 +236,19 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline void queue::push(value_type&& x) - { - c.push_back(eastl::move(x)); - } - #endif + template + inline void queue::push(value_type&& x) + { + c.push_back(eastl::move(x)); + } - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - template - template - inline void queue::emplace_back(Args&&... args) - { - c.emplace_back(eastl::forward(args)...); - } - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline void queue::emplace_back(value_type&& x) - { - c.emplace_back(eastl::move(x)); - } - #endif - - template - inline void queue::emplace_back(const value_type& x) - { - c.emplace_back(x); - } - #endif + template + template + inline void queue::emplace_back(Args&&... args) + { + c.emplace_back(eastl::forward(args)...); + } template diff --git a/include/EASTL/slist.h b/include/EASTL/slist.h index 8580bdf3..213333a3 100644 --- a/include/EASTL/slist.h +++ b/include/EASTL/slist.h @@ -269,19 +269,15 @@ namespace eastl slist(size_type n, const value_type& value, const allocator_type& allocator = EASTL_SLIST_DEFAULT_ALLOCATOR); slist(const this_type& x); slist(std::initializer_list ilist, const allocator_type& allocator = EASTL_SLIST_DEFAULT_ALLOCATOR); - #if EASTL_MOVE_SEMANTICS_ENABLED - slist(this_type&& x); - slist(this_type&& x, const allocator_type& allocator); - #endif + slist(this_type&& x); + slist(this_type&& x, const allocator_type& allocator); template slist(InputIterator first, InputIterator last); // allocator arg removed because VC7.1 fails on the default arg. To do: Make a second version of this function without a default arg. this_type& operator=(const this_type& x); this_type& operator=(std::initializer_list); - #if EASTL_MOVE_SEMANTICS_ENABLED - this_type& operator=(this_type&& x); - #endif + this_type& operator=(this_type&& x); void swap(this_type& x); @@ -309,21 +305,12 @@ namespace eastl reference front(); const_reference front() const; - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - template - void emplace_front(Args&&... args); - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - void emplace_front(value_type&& value); - #endif - void emplace_front(const value_type& value); - #endif + template + void emplace_front(Args&&... args); void push_front(const value_type& value); reference push_front(); - #if EASTL_MOVE_SEMANTICS_ENABLED - void push_front(value_type&& value); - #endif + void push_front(value_type&& value); void pop_front(); @@ -345,21 +332,10 @@ namespace eastl iterator insert_after(const_iterator position, const value_type& value); iterator insert_after(const_iterator position, size_type n, const value_type& value); iterator insert_after(const_iterator position, std::initializer_list ilist); + iterator insert_after(const_iterator position, value_type&& value); - #if EASTL_MOVE_SEMANTICS_ENABLED - iterator insert_after(const_iterator position, value_type&& value); - #endif - - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - template - iterator emplace_after(const_iterator position, Args&&... args); - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - iterator emplace_after(const_iterator position, value_type&& value); - #endif - - iterator emplace_after(const_iterator position, const value_type& value); - #endif + template + iterator emplace_after(const_iterator position, Args&&... args); template iterator insert_after(const_iterator position, InputIterator first, InputIterator last); @@ -386,22 +362,16 @@ namespace eastl void splice(const_iterator position, this_type& x); void splice(const_iterator position, this_type& x, const_iterator i); void splice(const_iterator position, this_type& x, const_iterator first, const_iterator last); - - #if EASTL_MOVE_SEMANTICS_ENABLED - void splice(const_iterator position, this_type&& x); - void splice(const_iterator position, this_type&& x, const_iterator i); - void splice(const_iterator position, this_type&& x, const_iterator first, const_iterator last); - #endif + void splice(const_iterator position, this_type&& x); + void splice(const_iterator position, this_type&& x, const_iterator i); + void splice(const_iterator position, this_type&& x, const_iterator first, const_iterator last); void splice_after(const_iterator position, this_type& x); void splice_after(const_iterator position, this_type& x, const_iterator i); void splice_after(const_iterator position, this_type& x, const_iterator first, const_iterator last); - - #if EASTL_MOVE_SEMANTICS_ENABLED - void splice_after(const_iterator position, this_type&& x); - void splice_after(const_iterator position, this_type&& x, const_iterator i); - void splice_after(const_iterator position, this_type&& x, const_iterator first, const_iterator last); - #endif + void splice_after(const_iterator position, this_type&& x); + void splice_after(const_iterator position, this_type&& x, const_iterator i); + void splice_after(const_iterator position, this_type&& x, const_iterator first, const_iterator last); // The following splice_after funcions are deprecated, as they don't allow for recognizing // the allocator, cannot maintain the source mSize, and are not in the C++11 Standard definition @@ -433,15 +403,8 @@ namespace eastl protected: node_type* DoCreateNode(); - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED // If we can do variadic arguments... - template - node_type* DoCreateNode(Args&&... args); - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - node_type* DoCreateNode(value_type&& value); - #endif - node_type* DoCreateNode(const value_type& value); - #endif + template + node_type* DoCreateNode(Args&&... args); template void DoAssign(Integer n, Integer value, true_type); @@ -463,15 +426,8 @@ namespace eastl node_type* DoInsertValueAfter(SListNodeBase* pNode); node_type* DoInsertValuesAfter(SListNodeBase* pNode, size_type n, const value_type& value); - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED // If we can do variadic arguments... - template - node_type* DoInsertValueAfter(SListNodeBase* pNode, Args&&... args); - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - node_type* DoInsertValueAfter(SListNodeBase* pNode, value_type&& value); - #endif - node_type* DoInsertValueAfter(SListNodeBase* pNode, const value_type& value); - #endif + template + node_type* DoInsertValueAfter(SListNodeBase* pNode, Args&&... args); void DoSwap(this_type& x); @@ -814,21 +770,19 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - slist::slist(this_type&& x) - : base_type(x.mAllocator) - { - swap(x); - } + template + slist::slist(this_type&& x) + : base_type(x.mAllocator) + { + swap(x); + } - template - slist::slist(this_type&& x, const allocator_type& allocator) - : base_type(allocator) - { - swap(x); // member swap handles the case that x has a different allocator than our allocator by doing a copy. - } - #endif + template + slist::slist(this_type&& x, const allocator_type& allocator) + : base_type(allocator) + { + swap(x); // member swap handles the case that x has a different allocator than our allocator by doing a copy. + } template @@ -966,28 +920,12 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - template - template - void slist::emplace_front(Args&&... args) - { - DoInsertValueAfter((SListNodeBase*)&mNode, eastl::forward(args)...); - } - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - template - void slist::emplace_front(value_type&& value) - { - DoInsertValueAfter((SListNodeBase*)&mNode, eastl::move(value)); - } - #endif - - template - void slist::emplace_front(const value_type& value) - { - DoInsertValueAfter((SListNodeBase*)&mNode, value); - } - #endif + template + template + void slist::emplace_front(Args&&... args) + { + DoInsertValueAfter((SListNodeBase*)&mNode, eastl::forward(args)...); + } template @@ -1011,13 +949,11 @@ namespace eastl return ((node_type*)mNode.mpNext)->mValue; // Same as return front(); } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - void slist::push_front(value_type&& value) - { - emplace_after(before_begin(), eastl::move(value)); - } - #endif + template + void slist::push_front(value_type&& value) + { + emplace_after(before_begin(), eastl::move(value)); + } template @@ -1073,18 +1009,16 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - typename slist::this_type& slist::operator=(this_type&& x) + template + typename slist::this_type& slist::operator=(this_type&& x) + { + if(this != &x) { - if(this != &x) - { - clear(); // To consider: Are we really required to clear here? x is going away soon and will clear itself in its dtor. - swap(x); // member swap handles the case that x has a different allocator than our allocator by doing a copy. - } - return *this; + clear(); // To consider: Are we really required to clear here? x is going away soon and will clear itself in its dtor. + swap(x); // member swap handles the case that x has a different allocator than our allocator by doing a copy. } - #endif + return *this; + } template @@ -1263,41 +1197,21 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline typename slist::iterator - slist::insert_after(const_iterator position, value_type&& value) - { - return emplace_after(position, eastl::move(value)); - } - #endif - + template + inline typename slist::iterator + slist::insert_after(const_iterator position, value_type&& value) + { + return emplace_after(position, eastl::move(value)); + } - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - template - template - inline typename slist::iterator - slist::emplace_after(const_iterator position, Args&&... args) - { - return iterator((SListNodeBase*)DoInsertValueAfter(position.mpNode, eastl::forward(args)...)); - } - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline typename slist::iterator - slist::emplace_after(const_iterator position, value_type&& value) - { - return iterator((SListNodeBase*)DoInsertValueAfter(position.mpNode, eastl::move(value))); - } - #endif - template - inline typename slist::iterator - slist::emplace_after(const_iterator position, const value_type& value) - { - return iterator((SListNodeBase*)DoInsertValueAfter(position.mpNode, value)); - } - #endif + template + template + inline typename slist::iterator + slist::emplace_after(const_iterator position, Args&&... args) + { + return iterator((SListNodeBase*)DoInsertValueAfter(position.mpNode, eastl::forward(args)...)); + } template @@ -1443,25 +1357,23 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - void slist::splice(const_iterator position, this_type&& x) - { - return splice(position, x); // This will splice(const_iterator, this_type&) - } + template + void slist::splice(const_iterator position, this_type&& x) + { + return splice(position, x); // This will splice(const_iterator, this_type&) + } - template - void slist::splice(const_iterator position, this_type&& x, const_iterator i) - { - return splice(position, x, i); // This will splice_after(const_iterator, this_type&, const_iterator) - } + template + void slist::splice(const_iterator position, this_type&& x, const_iterator i) + { + return splice(position, x, i); // This will splice_after(const_iterator, this_type&, const_iterator) + } - template - void slist::splice(const_iterator position, this_type&& x, const_iterator first, const_iterator last) - { - return splice(position, x, first, last); // This will splice(const_iterator, this_type&, const_iterator, const_iterator) - } - #endif + template + void slist::splice(const_iterator position, this_type&& x, const_iterator first, const_iterator last) + { + return splice(position, x, first, last); // This will splice(const_iterator, this_type&, const_iterator, const_iterator) + } template @@ -1532,25 +1444,23 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline void slist::splice_after(const_iterator position, this_type&& x) - { - return splice_after(position, x); // This will call splice_after(const_iterator, this_type&) - } + template + inline void slist::splice_after(const_iterator position, this_type&& x) + { + return splice_after(position, x); // This will call splice_after(const_iterator, this_type&) + } - template - inline void slist::splice_after(const_iterator position, this_type&& x, const_iterator i) - { - return splice_after(position, x, i); // This will call splice_after(const_iterator, this_type&, const_iterator) - } + template + inline void slist::splice_after(const_iterator position, this_type&& x, const_iterator i) + { + return splice_after(position, x, i); // This will call splice_after(const_iterator, this_type&, const_iterator) + } - template - inline void slist::splice_after(const_iterator position, this_type&& x, const_iterator first, const_iterator last) - { - return splice_after(position, x, first, last); // This will call splice_after(const_iterator, this_type&, const_iterator, const_iterator) - } - #endif + template + inline void slist::splice_after(const_iterator position, this_type&& x, const_iterator first, const_iterator last) + { + return splice_after(position, x, first, last); // This will call splice_after(const_iterator, this_type&, const_iterator, const_iterator) + } // This function is deprecated. @@ -1644,81 +1554,29 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED // If we can do variadic arguments... - template - template - inline typename slist::node_type* - slist::DoCreateNode(Args&&... args) - { - node_type* const pNode = DoAllocateNode(); // pNode is of type node_type, but it's uninitialized memory. + template + template + inline typename slist::node_type* + slist::DoCreateNode(Args&&... args) + { + node_type* const pNode = DoAllocateNode(); // pNode is of type node_type, but it's uninitialized memory. - #if EASTL_EXCEPTIONS_ENABLED - try - { - ::new((void*)&pNode->mValue) value_type(eastl::forward(args)...); - } - catch(...) - { - DoFreeNode(pNode); - throw; - } - #else + #if EASTL_EXCEPTIONS_ENABLED + try + { ::new((void*)&pNode->mValue) value_type(eastl::forward(args)...); - #endif - - return pNode; - } - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline typename slist::node_type* - slist::DoCreateNode(value_type&& value) + } + catch(...) { - node_type* const pNode = DoAllocateNode(); - - #if EASTL_EXCEPTIONS_ENABLED - try - { - ::new((void*)&pNode->mValue) value_type(eastl::move(value)); - } - catch(...) - { - DoFreeNode(pNode); - throw; - } - #else - ::new((void*)&pNode->mValue) value_type(eastl::move(value)); - #endif - - return pNode; + DoFreeNode(pNode); + throw; } + #else + ::new((void*)&pNode->mValue) value_type(eastl::forward(args)...); #endif - template - inline typename slist::node_type* - slist::DoCreateNode(const value_type& value) - { - node_type* const pNode = DoAllocateNode(); - - #if EASTL_EXCEPTIONS_ENABLED - try - { - ::new((void*)&pNode->mValue) value_type(value); - } - catch(...) - { - DoFreeNode(pNode); - throw; - } - #else - ::new((void*)&pNode->mValue) value_type(value); - #endif - - return pNode; - } - #endif - - + return pNode; + } template @@ -1841,48 +1699,18 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED // If we can do variadic arguments... - template - template - inline typename slist::node_type* - slist::DoInsertValueAfter(SListNodeBase* pNode, Args&&... args) - { - SListNodeBase* pNodeNew = (SListNodeBase*)DoCreateNode(eastl::forward(args)...); - pNode = SListNodeInsertAfter(pNode, pNodeNew); - #if EASTL_LIST_SIZE_CACHE - ++mSize; // Increment the size after the node creation because we need to assume an exception can occur in the creation. - #endif - return static_cast((base_node_type*)pNode); - } - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline typename slist::node_type* - slist::DoInsertValueAfter(SListNodeBase* pNode, value_type&& value) - { - SListNodeBase* pNodeNew = (SListNodeBase*)DoCreateNode(eastl::move(value)); - pNode = SListNodeInsertAfter(pNode, pNodeNew); - #if EASTL_LIST_SIZE_CACHE - ++mSize; // Increment the size after the node creation because we need to assume an exception can occur in the creation. - #endif - return static_cast((base_node_type*)pNode); - } + template + template + inline typename slist::node_type* + slist::DoInsertValueAfter(SListNodeBase* pNode, Args&&... args) + { + SListNodeBase* pNodeNew = (SListNodeBase*)DoCreateNode(eastl::forward(args)...); + pNode = SListNodeInsertAfter(pNode, pNodeNew); + #if EASTL_LIST_SIZE_CACHE + ++mSize; // Increment the size after the node creation because we need to assume an exception can occur in the creation. #endif - - template - inline typename slist::node_type* - slist::DoInsertValueAfter(SListNodeBase* pNode, const value_type& value) - { - SListNodeBase* pNodeNew = (SListNodeBase*)DoCreateNode(value); - pNode = SListNodeInsertAfter(pNode, pNodeNew); - #if EASTL_LIST_SIZE_CACHE - ++mSize; // Increment the size after the node creation because we need to assume an exception can occur in the creation. - #endif - return static_cast((base_node_type*)pNode); - } - - #endif - + return static_cast((base_node_type*)pNode); + } template diff --git a/include/EASTL/sort.h b/include/EASTL/sort.h index 5ecdb1ad..400553ce 100644 --- a/include/EASTL/sort.h +++ b/include/EASTL/sort.h @@ -553,6 +553,7 @@ namespace eastl { firstHalfLocation = sort_impl(first, first + nMid, pBuffer, lastSortedEnd, compare); } + ResultLocation secondHalfLocation = sort_impl(first + nMid, last, pBuffer + nMid, lastSortedEnd - nMid, compare); return merge_halves(first, last, nMid, pBuffer, firstHalfLocation, secondHalfLocation, compare); @@ -571,7 +572,7 @@ namespace eastl // The inputs to this method effectively define two large buffers. The variables 'firstHalfLocation' and 'secondHalfLocation' define where the data to be // merged is located within the two buffers. It is entirely possible that the two areas to be merged could be entirely located in either of the larger buffers. // Upon returning the merged results will be in one of the two buffers (indicated by the return result). - static ResultLocation merge_halves(RandomAccessIterator first, RandomAccessIterator last, difference_type nMid, T* pBuffer, bool firstHalfLocation, bool secondHalfLocation, StrictWeakOrdering compare) + static ResultLocation merge_halves(RandomAccessIterator first, RandomAccessIterator last, difference_type nMid, T* pBuffer, ResultLocation firstHalfLocation, ResultLocation secondHalfLocation, StrictWeakOrdering compare) { const difference_type nCount = last - first; if (firstHalfLocation == RL_SourceRange) diff --git a/include/EASTL/stack.h b/include/EASTL/stack.h index 7868c31e..95750e70 100644 --- a/include/EASTL/stack.h +++ b/include/EASTL/stack.h @@ -86,19 +86,14 @@ namespace eastl { } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - stack(this_type&& x, const Allocator& allocator, typename eastl::enable_if::value>::type* = NULL) - : c(eastl::move(x.c), allocator) - { - } - #endif + template + stack(this_type&& x, const Allocator& allocator, typename eastl::enable_if::value>::type* = NULL) + : c(eastl::move(x.c), allocator) + { + } explicit stack(const container_type& x); - - #if EASTL_MOVE_SEMANTICS_ENABLED - explicit stack(container_type&& x); - #endif + explicit stack(container_type&& x); // Additional C++11 support to consider: // @@ -117,21 +112,10 @@ namespace eastl const_reference top() const; void push(const value_type& value); + void push(value_type&& x); - #if EASTL_MOVE_SEMANTICS_ENABLED - void push(value_type&& x); - #endif - - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - template - void emplace_back(Args&&... args); - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - void emplace_back(value_type&& x); - #endif - - void emplace_back(const value_type& x); - #endif + template + void emplace_back(Args&&... args); void pop(); @@ -168,14 +152,12 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline stack::stack(Container&& x) - : c(eastl::move(x)) - { - // Empty - } - #endif + template + inline stack::stack(Container&& x) + : c(eastl::move(x)) + { + // Empty + } template @@ -231,38 +213,19 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline void stack::push(value_type&& x) - { - c.push_back(eastl::move(x)); - } - #endif + template + inline void stack::push(value_type&& x) + { + c.push_back(eastl::move(x)); + } - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - template - template - inline void stack::emplace_back(Args&&... args) - { - c.emplace_back(eastl::forward(args)...); - } - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline void stack::emplace_back(value_type&& x) - { - c.emplace_back(eastl::move(x)); - } - #endif - - - template - inline void stack::emplace_back(const value_type& x) - { - c.emplace_back(x); - } - #endif + template + template + inline void stack::emplace_back(Args&&... args) + { + c.emplace_back(eastl::forward(args)...); + } template diff --git a/include/EASTL/string_view.h b/include/EASTL/string_view.h index 2b68be95..23dd133d 100644 --- a/include/EASTL/string_view.h +++ b/include/EASTL/string_view.h @@ -150,7 +150,7 @@ namespace eastl count = eastl::min(count, mnCount - pos); auto* pResult = CharStringUninitializedCopy(mpBegin + pos, mpBegin + pos + count, pDestination); - *pResult = 0; // write null-terminator + // *pResult = 0; // don't write the null-terminator return pResult - pDestination; } diff --git a/include/EASTL/tuple.h b/include/EASTL/tuple.h index 20020826..f42b8eb9 100644 --- a/include/EASTL/tuple.h +++ b/include/EASTL/tuple.h @@ -917,7 +917,6 @@ inline typename Internal::TupleCat::ResultType tuple_cat(Tuples&&... return Internal::TupleCat::DoCat(forward(ts)...); } - // apply // // Invoke a callable object using a tuple to supply the arguments. @@ -943,6 +942,35 @@ EA_CONSTEXPR decltype(auto) apply(F&& f, Tuple&& t) } // namespace eastl + +/////////////////////////////////////////////////////////////// +// C++17 structured bindings support for eastl::tuple +// +#ifndef EA_COMPILER_NO_STRUCTURED_BINDING + #include + namespace std + { + // NOTE(rparolin): Some platform implementations didn't check the standard specification and implemented the + // "tuple_size" and "tuple_element" primary template with as a struct. The standard specifies they are + // implemented with the class keyword so we provide the template specializations as a class and disable the + // generated warning. + EA_DISABLE_CLANG_WARNING(-Wmismatched-tags) + + template + class tuple_size<::eastl::tuple> : ::eastl::integral_constant + { + }; + + template + class tuple_element> : public ::eastl::tuple_element> + { + }; + + EA_RESTORE_CLANG_WARNING() + } +#endif + + #endif // EASTL_TUPLE_ENABLED EA_RESTORE_VC_WARNING() EA_RESTORE_VC_WARNING() diff --git a/include/EASTL/type_traits.h b/include/EASTL/type_traits.h index 97798837..94df70a4 100644 --- a/include/EASTL/type_traits.h +++ b/include/EASTL/type_traits.h @@ -345,6 +345,8 @@ namespace eastl // // Example usage: // typedef ChosenType = typename type_select::value, ChoiceAType, ChoiceBType>::type; + // or + // using ChosenType = type_select_t, ChoiceAType, ChoiceBType>; // template struct type_select { typedef ConditionIsTrueType type; }; @@ -352,6 +354,12 @@ namespace eastl template struct type_select { typedef ConditionIsFalseType type; }; + #if EASTL_VARIABLE_TEMPLATES_ENABLED + template + using type_select_t = typename type_select::type; + #endif + + /////////////////////////////////////////////////////////////////////// // first_type_select @@ -643,6 +651,10 @@ namespace eastl template struct is_volatile : public eastl::is_volatile_value{}; template struct is_volatile : public eastl::false_type{}; // Note here that T is volatile, not the reference to T. So is_const is false. See section 8.3.2p1 of the C++ standard. + #if EASTL_VARIABLE_TEMPLATES_ENABLED + template + EA_CONSTEXPR bool is_volatile_v = is_volatile::value; + #endif /////////////////////////////////////////////////////////////////////// @@ -1076,6 +1088,7 @@ namespace eastl /// or big endian. Mixed or middle endian is not modeled here as described /// by the C++20 spec. /////////////////////////////////////////////////////////////////////// + EA_DISABLE_VC_WARNING(4472) // 'endian' is a native enum: add an access specifier (private/public) to declare a managed enum enum class endian { #ifdef EA_SYSTEM_LITTLE_ENDIAN @@ -1088,6 +1101,7 @@ namespace eastl native = big #endif }; + EA_RESTORE_VC_WARNING(); } // namespace eastl diff --git a/include/EASTL/vector_multiset.h b/include/EASTL/vector_multiset.h index ca4c1c4c..620ccbbf 100644 --- a/include/EASTL/vector_multiset.h +++ b/include/EASTL/vector_multiset.h @@ -124,10 +124,8 @@ namespace eastl explicit vector_multiset(const allocator_type& allocator); explicit vector_multiset(const key_compare& comp, const allocator_type& allocator = EASTL_VECTOR_MULTISET_DEFAULT_ALLOCATOR); vector_multiset(const this_type& x); - #if EASTL_MOVE_SEMANTICS_ENABLED vector_multiset(this_type&& x); vector_multiset(this_type&& x, const allocator_type& allocator); - #endif vector_multiset(std::initializer_list ilist, const key_compare& compare = key_compare(), const allocator_type& allocator = EASTL_VECTOR_MULTISET_DEFAULT_ALLOCATOR); template @@ -138,9 +136,7 @@ namespace eastl this_type& operator=(const this_type& x); this_type& operator=(std::initializer_list ilist); - #if EASTL_MOVE_SEMANTICS_ENABLED this_type& operator=(this_type&& x); - #endif void swap(this_type& x); @@ -175,44 +171,28 @@ namespace eastl // bool empty() const; // void clear(); - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - template - iterator emplace(Args&&... args); - - template - iterator emplace_hint(const_iterator position, Args&&... args); - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - iterator emplace(value_type&& value); - iterator emplace_hint(const_iterator position, value_type&& value); - #endif + template + iterator emplace(Args&&... args); - iterator emplace(const value_type& value); - iterator emplace_hint(const_iterator position, const value_type& value); - #endif + template + iterator emplace_hint(const_iterator position, Args&&... args); iterator insert(const value_type& value); // The signature of this function was change in EASTL v2.05.00 from (the mistaken) pair to (the correct) iterator. - #if EASTL_MOVE_SEMANTICS_ENABLED - template - iterator insert(P&& otherValue); - #endif - iterator insert(const_iterator position, const value_type& value); - #if EASTL_MOVE_SEMANTICS_ENABLED iterator insert(const_iterator position, value_type&& value); - #endif + void insert(std::initializer_list ilist); - void insert(std::initializer_list ilist); + template + iterator insert(P&& otherValue); template void insert(InputIterator first, InputIterator last); - iterator erase(const_iterator position); - iterator erase(const_iterator first, const_iterator last); - size_type erase(const key_type& k); - - reverse_iterator erase(const_reverse_iterator position); - reverse_iterator erase(const_reverse_iterator first, const_reverse_iterator last); + iterator erase(const_iterator position); + iterator erase(const_iterator first, const_iterator last); + size_type erase(const key_type& k); + reverse_iterator erase(const_reverse_iterator position); + reverse_iterator erase(const_reverse_iterator first, const_reverse_iterator last); iterator find(const key_type& k); const_iterator find(const key_type& k) const; @@ -317,21 +297,19 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline vector_multiset::vector_multiset(this_type&& x) - : base_type(eastl::move(x)), mCompare(x.mCompare) - { - // Empty. Note: x is left with empty contents but its original mValueCompare instead of the default one. - } + template + inline vector_multiset::vector_multiset(this_type&& x) + : base_type(eastl::move(x)), mCompare(x.mCompare) + { + // Empty. Note: x is left with empty contents but its original mValueCompare instead of the default one. + } - template - inline vector_multiset::vector_multiset(this_type&& x, const allocator_type& allocator) - : base_type(eastl::move(x), allocator), mCompare(x.mCompare) - { - // Empty. Note: x is left with empty contents but its original mValueCompare instead of the default one. - } - #endif + template + inline vector_multiset::vector_multiset(this_type&& x, const allocator_type& allocator) + : base_type(eastl::move(x), allocator), mCompare(x.mCompare) + { + // Empty. Note: x is left with empty contents but its original mValueCompare instead of the default one. + } template @@ -352,16 +330,14 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline vector_multiset& - vector_multiset::operator=(this_type&& x) - { - base_type::operator=(eastl::move(x)); - eastl::swap(mCompare, x.mCompare); - return *this; - } - #endif + template + inline vector_multiset& + vector_multiset::operator=(this_type&& x) + { + base_type::operator=(eastl::move(x)); + eastl::swap(mCompare, x.mCompare); + return *this; + } template @@ -414,63 +390,31 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - template - template - typename vector_multiset::iterator - vector_multiset::emplace(Args&&... args) - { - #if EASTL_USE_FORWARD_WORKAROUND - auto value = value_type(eastl::forward(args)...); // Workaround for compiler bug in VS2013 which results in a compiler internal crash while compiling this code. - #else - value_type value(eastl::forward(args)...); - #endif - return insert(eastl::move(value)); - } - - template - template - typename vector_multiset::iterator - vector_multiset::emplace_hint(const_iterator position, Args&&... args) - { - #if EASTL_USE_FORWARD_WORKAROUND - auto value = value_type(eastl::forward(args)...); // Workaround for compiler bug in VS2013 which results in a compiler internal crash while compiling this code. - #else - value_type value(eastl::forward(args)...); - #endif - return insert(position, eastl::move(value)); - } - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - template - typename vector_multiset::iterator - vector_multiset::emplace(value_type&& value) - { - return insert(eastl::move(value)); - } - - template - typename vector_multiset::iterator - vector_multiset::emplace_hint(const_iterator position, value_type&& value) - { - return insert(position, eastl::move(value)); - } + template + template + typename vector_multiset::iterator + vector_multiset::emplace(Args&&... args) + { + #if EASTL_USE_FORWARD_WORKAROUND + auto value = value_type(eastl::forward(args)...); // Workaround for compiler bug in VS2013 which results in a compiler internal crash while compiling this code. + #else + value_type value(eastl::forward(args)...); #endif + return insert(eastl::move(value)); + } - template - typename vector_multiset::iterator - vector_multiset::emplace(const value_type& value) - { - return insert(value); - } - - template - typename vector_multiset::iterator - vector_multiset::emplace_hint(const_iterator position, const value_type& value) - { - return insert(position, value); - } - #endif + template + template + typename vector_multiset::iterator + vector_multiset::emplace_hint(const_iterator position, Args&&... args) + { + #if EASTL_USE_FORWARD_WORKAROUND + auto value = value_type(eastl::forward(args)...); // Workaround for compiler bug in VS2013 which results in a compiler internal crash while compiling this code. + #else + value_type value(eastl::forward(args)...); + #endif + return insert(position, eastl::move(value)); + } template @@ -482,17 +426,15 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - template - typename vector_multiset::iterator - vector_multiset::insert(P&& otherValue) - { - value_type value(eastl::forward

(otherValue)); - const iterator itLB(lower_bound(value)); - return base_type::insert(itLB, eastl::move(value)); - } - #endif + template + template + typename vector_multiset::iterator + vector_multiset::insert(P&& otherValue) + { + value_type value(eastl::forward

(otherValue)); + const iterator itLB(lower_bound(value)); + return base_type::insert(itLB, eastl::move(value)); + } template @@ -522,21 +464,19 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - typename vector_multiset::iterator - vector_multiset::insert(const_iterator position, value_type&& value) + template + typename vector_multiset::iterator + vector_multiset::insert(const_iterator position, value_type&& value) + { + if((position == end()) || !mCompare(*position, value)) // If value is <= the element at position... { - if((position == end()) || !mCompare(*position, value)) // If value is <= the element at position... - { - if((position == begin()) || !mCompare(value, *(position - 1))) // If value is >= the element before position... - return base_type::insert(position, eastl::move(value)); - } - - // In this case we have an incorrect position. We fall back to the regular insert function. - return insert(eastl::move(value)); + if((position == begin()) || !mCompare(value, *(position - 1))) // If value is >= the element before position... + return base_type::insert(position, eastl::move(value)); } - #endif + + // In this case we have an incorrect position. We fall back to the regular insert function. + return insert(eastl::move(value)); + } template diff --git a/include/EASTL/vector_set.h b/include/EASTL/vector_set.h index ec37c75b..ed844bc8 100644 --- a/include/EASTL/vector_set.h +++ b/include/EASTL/vector_set.h @@ -126,10 +126,8 @@ namespace eastl explicit vector_set(const allocator_type& allocator); explicit vector_set(const key_compare& compare, const allocator_type& allocator = EASTL_VECTOR_SET_DEFAULT_ALLOCATOR); vector_set(const this_type& x); - #if EASTL_MOVE_SEMANTICS_ENABLED vector_set(this_type&& x); vector_set(this_type&& x, const allocator_type& allocator); - #endif vector_set(std::initializer_list ilist, const key_compare& compare = key_compare(), const allocator_type& allocator = EASTL_VECTOR_SET_DEFAULT_ALLOCATOR); template @@ -140,9 +138,7 @@ namespace eastl this_type& operator=(const this_type& x); this_type& operator=(std::initializer_list ilist); - #if EASTL_MOVE_SEMANTICS_ENABLED this_type& operator=(this_type&& x); - #endif void swap(this_type& x); @@ -177,32 +173,18 @@ namespace eastl // bool empty() const; // void clear(); - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - template - eastl::pair emplace(Args&&... args); - - template - iterator emplace_hint(const_iterator position, Args&&... args); - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - eastl::pair emplace(value_type&& value); - iterator emplace_hint(const_iterator position, value_type&& value); - #endif + template + eastl::pair emplace(Args&&... args); - eastl::pair emplace(const value_type& value); - iterator emplace_hint(const_iterator position, const value_type& value); - #endif + template + iterator emplace_hint(const_iterator position, Args&&... args); eastl::pair insert(const value_type& value); - #if EASTL_MOVE_SEMANTICS_ENABLED template pair insert(P&& otherValue); - #endif iterator insert(const_iterator position, const value_type& value); - #if EASTL_MOVE_SEMANTICS_ENABLED iterator insert(const_iterator position, value_type&& value); - #endif void insert(std::initializer_list ilist); @@ -242,12 +224,10 @@ namespace eastl template eastl::pair equal_range(const U& u, BinaryPredicate) const; - // Functions which are disallowed due to being unsafe. We are looking for a way to disable these at - // compile-time. Declaring but not defining them doesn't work due to explicit template instantiations. - // - // void push_back(const value_type& value); - // reference push_back(); - // void* push_back_uninitialized(); + // Functions which are disallowed due to being unsafe. + void push_back(const value_type& value) = delete; + reference push_back() = delete; + void* push_back_uninitialized() = delete; }; // vector_set @@ -291,22 +271,20 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline vector_set::vector_set(this_type&& x) - : base_type(eastl::move(x)), mCompare(x.mCompare) - { - // Empty. Note: x is left with empty contents but its original mValueCompare instead of the default one. - } + template + inline vector_set::vector_set(this_type&& x) + : base_type(eastl::move(x)), mCompare(x.mCompare) + { + // Empty. Note: x is left with empty contents but its original mValueCompare instead of the default one. + } - template - inline vector_set::vector_set(this_type&& x, const allocator_type& allocator) - : base_type(eastl::move(x), allocator), mCompare(x.mCompare) - { - // Empty. Note: x is left with empty contents but its original mValueCompare instead of the default one. - } - #endif + template + inline vector_set::vector_set(this_type&& x, const allocator_type& allocator) + : base_type(eastl::move(x), allocator), mCompare(x.mCompare) + { + // Empty. Note: x is left with empty contents but its original mValueCompare instead of the default one. + } template @@ -345,16 +323,14 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline vector_set& - vector_set::operator=(this_type&& x) - { - base_type::operator=(eastl::move(x)); - eastl::swap(mCompare, x.mCompare); - return *this; - } - #endif + template + inline vector_set& + vector_set::operator=(this_type&& x) + { + base_type::operator=(eastl::move(x)); + eastl::swap(mCompare, x.mCompare); + return *this; + } template @@ -407,65 +383,33 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - template - template - inline eastl::pair::iterator, bool> - vector_set::emplace(Args&&... args) - { - #if EASTL_USE_FORWARD_WORKAROUND - auto value = value_type(eastl::forward(args)...); // Workaround for compiler bug in VS2013 which results in a compiler internal crash while compiling this code. - #else - value_type value(eastl::forward(args)...); - #endif - - return insert(eastl::move(value)); - } + template + template + inline eastl::pair::iterator, bool> + vector_set::emplace(Args&&... args) + { + #if EASTL_USE_FORWARD_WORKAROUND + auto value = value_type(eastl::forward(args)...); // Workaround for compiler bug in VS2013 which results in a compiler internal crash while compiling this code. + #else + value_type value(eastl::forward(args)...); + #endif - template - template - inline typename vector_set::iterator - vector_set::emplace_hint(const_iterator position, Args&&... args) - { - #if EASTL_USE_FORWARD_WORKAROUND - auto value = value_type(eastl::forward(args)...); // Workaround for compiler bug in VS2013 which results in a compiler internal crash while compiling this code. - #else - value_type value(eastl::forward(args)...); - #endif + return insert(eastl::move(value)); + } - return insert(position, eastl::move(value)); - } - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline eastl::pair::iterator, bool> - vector_set::emplace(value_type&& value) - { - return insert(eastl::move(value)); - } - - template - inline typename vector_set::iterator - vector_set::emplace_hint(const_iterator position, value_type&& value) - { - return insert(position, eastl::move(value)); - } + template + template + inline typename vector_set::iterator + vector_set::emplace_hint(const_iterator position, Args&&... args) + { + #if EASTL_USE_FORWARD_WORKAROUND + auto value = value_type(eastl::forward(args)...); // Workaround for compiler bug in VS2013 which results in a compiler internal crash while compiling this code. + #else + value_type value(eastl::forward(args)...); #endif - template - inline eastl::pair::iterator, bool> - vector_set::emplace(const value_type& value) - { - return insert(value); - } - - template - inline typename vector_set::iterator - vector_set::emplace_hint(const_iterator position, const value_type& value) - { - return insert(position, value); - } - #endif + return insert(position, eastl::move(value)); + } template @@ -480,20 +424,18 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - template - inline eastl::pair::iterator, bool> - vector_set::insert(P&& otherValue) - { - value_type value(eastl::forward

(otherValue)); - const iterator itLB(lower_bound(value)); + template + template + inline eastl::pair::iterator, bool> + vector_set::insert(P&& otherValue) + { + value_type value(eastl::forward

(otherValue)); + const iterator itLB(lower_bound(value)); - if((itLB != end()) && !mCompare(value, *itLB)) - return eastl::pair(itLB, false); - return eastl::pair(base_type::insert(itLB, eastl::move(value)), true); - } - #endif + if((itLB != end()) && !mCompare(value, *itLB)) + return eastl::pair(itLB, false); + return eastl::pair(base_type::insert(itLB, eastl::move(value)), true); + } template @@ -521,23 +463,21 @@ namespace eastl } - #if EASTL_MOVE_SEMANTICS_ENABLED - template - inline typename vector_set::iterator - vector_set::insert(const_iterator position, value_type&& value) + template + inline typename vector_set::iterator + vector_set::insert(const_iterator position, value_type&& value) + { + // See the other version of this function for documentation. + if((position == end()) || mCompare(value, *position)) // If the element at position is greater than value... { - // See the other version of this function for documentation. - if((position == end()) || mCompare(value, *position)) // If the element at position is greater than value... - { - if((position == begin()) || mCompare(*(position - 1), value)) // If the element before position is less than value... - return base_type::insert(position, eastl::move(value)); - } + if((position == begin()) || mCompare(*(position - 1), value)) // If the element before position is less than value... + return base_type::insert(position, eastl::move(value)); + } - const eastl::pair result = insert(eastl::move(value)); + const eastl::pair result = insert(eastl::move(value)); - return result.first; - } - #endif + return result.first; + } template diff --git a/source/assert.cpp b/source/assert.cpp index bb4724cd..63be0483 100644 --- a/source/assert.cpp +++ b/source/assert.cpp @@ -63,15 +63,15 @@ namespace eastl { #if EASTL_ASSERT_ENABLED #if defined(EA_PLATFORM_MICROSOFT) - printf("%s", pExpression); // Write the message to stdout + printf("%s\n", pExpression); // Write the message to stdout if( ::IsDebuggerPresent()) { OutputDebugStringA(pExpression); } #elif defined(EA_PLATFORM_ANDROID) - __android_log_print(ANDROID_LOG_INFO, "PRINTF", "%s", pExpression); + __android_log_print(ANDROID_LOG_INFO, "PRINTF", "%s\n", pExpression); #else - printf("%s", pExpression); // Write the message to stdout, which happens to be the trace view for many console debug machines. + printf("%s\n", pExpression); // Write the message to stdout, which happens to be the trace view for many console debug machines. #endif #else EA_UNUSED(pExpression); diff --git a/test/packages/EABase/.gitignore b/test/packages/EABase/.gitignore new file mode 100644 index 00000000..1b19a79f --- /dev/null +++ b/test/packages/EABase/.gitignore @@ -0,0 +1,2 @@ +tags + diff --git a/test/packages/EABase/.p4ignore b/test/packages/EABase/.p4ignore index 803d119f..d5ea8837 100644 --- a/test/packages/EABase/.p4ignore +++ b/test/packages/EABase/.p4ignore @@ -1,2 +1,4 @@ tags .p4ignore + +/.git/ diff --git a/test/packages/EABase/include/Common/EABase/config/eacompiler.h b/test/packages/EABase/include/Common/EABase/config/eacompiler.h index d18a269d..ed5da76b 100644 --- a/test/packages/EABase/include/Common/EABase/config/eacompiler.h +++ b/test/packages/EABase/include/Common/EABase/config/eacompiler.h @@ -600,7 +600,7 @@ #if defined(_MSC_VER) #define EA_DISABLE_ALL_VC_WARNINGS() \ __pragma(warning(push, 0)) \ - __pragma(warning(disable: 4244 4265 4267 4350 4472 4509 4548 4710 4985 6320 4755 4625 4626 4702)) // Some warnings need to be explicitly called out. + __pragma(warning(disable: 4244 4265 4267 4350 4472 4509 4548 4623 4710 4985 6320 4755 4625 4626 4702)) // Some warnings need to be explicitly called out. #else #define EA_DISABLE_ALL_VC_WARNINGS() #endif @@ -1258,6 +1258,23 @@ #endif + // EA_COMPILER_NO_STRUCTURED_BINDING + // + // Indicates if target compiler supports the C++17 "structured binding" language feature. + // https://en.cppreference.com/w/cpp/language/structured_binding + // + // + #if !defined(EA_COMPILER_NO_STRUCTURED_BINDING) + #if defined(EA_COMPILER_CPP17_ENABLED) + // supported. + #elif defined(EA_COMPILER_MSVC) && (EA_COMPILER_VERSION >= 1912) // VS2017 15.3+ + // supported. + #else + #define EA_COMPILER_NO_STRUCTURED_BINDING 1 + #endif + #endif + + // EA_COMPILER_NO_NONSTATIC_MEMBER_INITIALIZERS // // Refers to C++11 declaration attribute: carries_dependency. diff --git a/test/packages/EABase/include/Common/EABase/config/eacompilertraits.h b/test/packages/EABase/include/Common/EABase/config/eacompilertraits.h index 8042eb1f..944c9eae 100644 --- a/test/packages/EABase/include/Common/EABase/config/eacompilertraits.h +++ b/test/packages/EABase/include/Common/EABase/config/eacompilertraits.h @@ -352,7 +352,7 @@ // using postfix alignment attributes. Prefix works for alignment, but does not align // the size like postfix does. Prefix also fails on templates. So gcc style post fix // is still used, but the user will need to use EA_POSTFIX_ALIGN before the constructor parameters. - #if defined(__GNUC__) && (__GNUC__ < 3) + #if defined(__GNUC__) && (__GNUC__ < 3) #define EA_ALIGN_OF(type) ((size_t)__alignof__(type)) #define EA_ALIGN(n) #define EA_PREFIX_ALIGN(n) @@ -481,8 +481,10 @@ // Defines if the GCC attribute init_priority is supported by the compiler. // #if !defined(EA_INIT_PRIORITY_AVAILABLE) - #if defined(__GNUC__) && !defined(__EDG__) // EDG typically #defines __GNUC__ but doesn't implement init_priority. + #if defined(__GNUC__) && !defined(__EDG__) // EDG typically #defines __GNUC__ but doesn't implement init_priority. #define EA_INIT_PRIORITY_AVAILABLE 1 + #elif defined(__clang__) + #define EA_INIT_PRIORITY_AVAILABLE 1 // Clang implements init_priority #endif #endif @@ -1608,8 +1610,9 @@ // ------------------------------------------------------------------------ // EA_ABM // EA_ABM may be used to determine if Advanced Bit Manipulation sets are available for the target architecture (POPCNT, LZCNT) + // #ifndef EA_ABM - #if defined(__ABM__) || defined(EA_PLATFORM_CAPILANO) + #if defined(__ABM__) || defined(EA_PLATFORM_XBOXONE) || defined(EA_PLATFORM_PS4) #define EA_ABM 1 #else #define EA_ABM 0 diff --git a/test/packages/EABase/include/Common/EABase/eabase.h b/test/packages/EABase/include/Common/EABase/eabase.h index 870d9f0f..98476fe1 100644 --- a/test/packages/EABase/include/Common/EABase/eabase.h +++ b/test/packages/EABase/include/Common/EABase/eabase.h @@ -28,6 +28,7 @@ // Define common SI unit macros #include + // ------------------------------------------------------------------------ // The C++ standard defines size_t as a built-in type. Some compilers are // not standards-compliant in this respect, so we need an additional include. @@ -975,6 +976,14 @@ // NOTE: Numeric values for x will produce a parse error while empty values produce a divide by zero, and the test is a bool for proper negation behavior #define EA_IS_ENABLED(x) (333 == 333 * 111 / ((x 0) * (((x 0) == 333 ? 1 : 0) + ((x 0) == 111 ? 1 : 0)))) + + +// Define int128_t / uint128_t types. +// NOTE(rparolin): include file at the end because we want all the signed integral types defined. +#ifdef __cplusplus + #include +#endif + #endif // Header include guard diff --git a/test/packages/EABase/include/Common/EABase/int128.h b/test/packages/EABase/include/Common/EABase/int128.h new file mode 100644 index 00000000..01e3d4a0 --- /dev/null +++ b/test/packages/EABase/include/Common/EABase/int128.h @@ -0,0 +1,1275 @@ +/*----------------------------------------------------------------------------- + * eaint128_t.h + * + * Copyright (c) Electronic Arts Inc. All rights reserved. + *---------------------------------------------------------------------------*/ + + +#ifndef INCLUDED_int128_h +#define INCLUDED_int128_h + + +/////////////////////////////////////////////////////////////////////////////////////////////////////// +// EA_INT128_INTRINSIC_AVAILABLE +// +#if (EA_COMPILER_INTMAX_SIZE >= 16) && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + // __int128_t/__uint128_t is supported + #define EA_INT128_INTRINSIC_AVAILABLE 1 +#else + #define EA_INT128_INTRINSIC_AVAILABLE 0 +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////// +// EA_INT128_ALIGNAS +// +#if EA_INT128_INTRINSIC_AVAILABLE + #define EA_INT128_ALIGNAS alignas(unsigned __int128) +#else + #define EA_INT128_ALIGNAS +#endif + + +/////////////////////////////////////////////////////////////////////////////////////////////////////// +// EA_HAVE_INT128 +// +// Indicates that EABase implements 128-bit integer types +// +#define EA_HAVE_INT128 1 + + +/////////////////////////////////////////////////////////////////////////////////////////////////////// +// uint128_t_base +// +struct EA_INT128_ALIGNAS int128_t_base +{ + // Constructors / destructors + int128_t_base() = default; + int128_t_base(uint32_t nPart0, uint32_t nPart1, uint32_t nPart2, uint32_t nPart3); + int128_t_base(uint64_t nPart0, uint64_t nPart1); + int128_t_base(uint8_t value); + int128_t_base(uint16_t value); + int128_t_base(uint32_t value); + int128_t_base(uint64_t value); + int128_t_base(const int128_t_base& value) = default; + + // Assignment operator + int128_t_base& operator=(const int128_t_base& value) = default; + + // Explicit operators to convert back to basic types + EA_CONSTEXPR explicit operator bool() const; + EA_CONSTEXPR explicit operator char() const; + EA_CONSTEXPR explicit operator int() const; + EA_CONSTEXPR explicit operator long() const; + EA_CONSTEXPR explicit operator long long() const; + EA_CONSTEXPR explicit operator short() const; + EA_CONSTEXPR explicit operator signed char() const; + EA_CONSTEXPR explicit operator unsigned char() const; + EA_CONSTEXPR explicit operator unsigned int() const; + EA_CONSTEXPR explicit operator unsigned long long() const; + EA_CONSTEXPR explicit operator unsigned long() const; + EA_CONSTEXPR explicit operator unsigned short() const; +#if EA_WCHAR_UNIQUE + // EA_CONSTEXPR explicit operator char16_t() const; + // EA_CONSTEXPR explicit operator char32_t() const; + // EA_CONSTEXPR explicit operator wchar_t() const; +#endif + EA_CONSTEXPR explicit operator float() const; + EA_CONSTEXPR explicit operator double() const; + EA_CONSTEXPR explicit operator long double() const; +#if EA_INT128_INTRINSIC_AVAILABLE + EA_CONSTEXPR explicit operator __int128() const; + EA_CONSTEXPR explicit operator unsigned __int128() const; +#endif + + // Math operators + static void OperatorPlus (const int128_t_base& value1, const int128_t_base& value2, int128_t_base& result); + static void OperatorMinus(const int128_t_base& value1, const int128_t_base& value2, int128_t_base& result); + static void OperatorMul (const int128_t_base& value1, const int128_t_base& value2, int128_t_base& result); + + // Shift operators + static void OperatorShiftRight(const int128_t_base& value, int nShift, int128_t_base& result); + static void OperatorShiftLeft (const int128_t_base& value, int nShift, int128_t_base& result); + + // Unary arithmetic/logic operators + bool operator!() const; + + // Logical operators + static void OperatorXOR(const int128_t_base& value1, const int128_t_base& value2, int128_t_base& result); + static void OperatorOR (const int128_t_base& value1, const int128_t_base& value2, int128_t_base& result); + static void OperatorAND(const int128_t_base& value1, const int128_t_base& value2, int128_t_base& result); + + bool IsZero() const; + void SetZero(); + void TwosComplement(); + void InverseTwosComplement(); + + int GetBit(int nIndex) const; + void SetBit(int nIndex, int value); + +protected: + void DoubleToUint128(double value); + + EA_CONSTEXPR uint64_t Low() const + { + #ifdef EA_SYSTEM_BIG_ENDIAN + return mPart0; + #else + return mPart1; + #endif + } + + EA_CONSTEXPR uint64_t High() const + { + #ifdef EA_SYSTEM_BIG_ENDIAN + return mPart1; + #else + return mPart0; + #endif + } + +protected: + #ifdef EA_SYSTEM_BIG_ENDIAN + uint64_t mPart1; // Most significant byte. + uint64_t mPart0; // Least significant byte. + #else + uint64_t mPart0; // Most significant byte. + uint64_t mPart1; // Least significant byte. + #endif +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////////// +// int128_t +// +// Implements signed 128 bit integer. +// +struct int128_t : public int128_t_base +{ + // Constructors / destructors + using int128_t_base::int128_t_base; + + // Assignment operator + using int128_t_base::operator=; + + // Unary arithmetic/logic operators + int128_t operator-() const; + int128_t& operator++(); + int128_t& operator--(); + int128_t operator++(int); + int128_t operator--(int); + int128_t operator~() const; + int128_t operator+() const; + + // Math operators + int128_t operator+ (const int128_t& other); + int128_t operator- (const int128_t& other); + int128_t operator* (const int128_t& other); + int128_t operator/ (const int128_t& other); + int128_t operator% (const int128_t& other); + int128_t& operator+=(const int128_t& other); + int128_t& operator-=(const int128_t& other); + int128_t& operator*=(const int128_t& other); + int128_t& operator/=(const int128_t& other); + int128_t& operator%=(const int128_t& other); + + // Shift operators + int128_t operator>> (int nShift) const; + int128_t operator<< (int nShift) const; + int128_t& operator>>=(int nShift); + int128_t& operator<<=(int nShift); + + // Logical operators + int128_t operator^ (const int128_t& other) const; + int128_t operator| (const int128_t& other) const; + int128_t operator& (const int128_t& other) const; + int128_t& operator^=(const int128_t& other); + int128_t& operator|=(const int128_t& other); + int128_t& operator&=(const int128_t& other); + + // Equality operators + bool operator==(const int128_t& other) const; + bool operator!=(const int128_t& other) const; + bool operator> (const int128_t& other) const; + bool operator>=(const int128_t& other) const; + bool operator< (const int128_t& other) const; + bool operator<=(const int128_t& other) const; + +protected: + int compare(const int128_t& other) const; + void Negate(); + void Modulus(const int128_t& divisor, int128_t& quotient, int128_t& remainder) const; + bool IsNegative() const; // Returns true for value < 0 + bool IsPositive() const; // Returns true for value >= 0 +}; + + +/////////////////////////////////////////////////////////////////////////////////////////////////////// +// uint128_t +// +// Implements unsigned 128 bit integer. +// +struct uint128_t : public int128_t_base +{ + // Constructors / destructors + using int128_t_base::int128_t_base; + + // Assignment operator + using int128_t_base::operator=; + + // Unary arithmetic/logic operators + uint128_t operator-() const; + uint128_t& operator++(); + uint128_t& operator--(); + uint128_t operator++(int); + uint128_t operator--(int); + uint128_t operator~() const; + uint128_t operator+() const; + + // Math operators + uint128_t operator+ (const uint128_t& other); + uint128_t operator- (const uint128_t& other); + uint128_t operator* (const uint128_t& other); + uint128_t operator/ (const uint128_t& other); + uint128_t operator% (const uint128_t& other); + uint128_t& operator+=(const uint128_t& other); + uint128_t& operator-=(const uint128_t& other); + uint128_t& operator*=(const uint128_t& other); + uint128_t& operator/=(const uint128_t& other); + uint128_t& operator%=(const uint128_t& other); + + // Shift operators + uint128_t operator>> (int nShift) const; + uint128_t operator<< (int nShift) const; + uint128_t& operator>>=(int nShift); + uint128_t& operator<<=(int nShift); + + // Logical operators + uint128_t operator^ (const uint128_t& other) const; + uint128_t operator| (const uint128_t& other) const; + uint128_t operator& (const uint128_t& other) const; + uint128_t& operator^=(const uint128_t& other); + uint128_t& operator|=(const uint128_t& other); + uint128_t& operator&=(const uint128_t& other); + + // Equality operators + bool operator==(const uint128_t& other) const; + bool operator!=(const uint128_t& other) const; + bool operator> (const uint128_t& other) const; + bool operator>=(const uint128_t& other) const; + bool operator< (const uint128_t& other) const; + bool operator<=(const uint128_t& other) const; + +protected: + int compare(const uint128_t& other) const; + void Negate(); + void Modulus(const uint128_t& divisor, uint128_t& quotient, uint128_t& remainder) const; + bool IsNegative() const; // Returns true for value < 0 + bool IsPositive() const; // Returns true for value >= 0 +}; + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////// +// uint128_t_base implementation +/////////////////////////////////////////////////////////////////////////////////////////////////////// +EA_CONSTEXPR inline int128_t_base::operator bool() const { return mPart0 || mPart1; } +EA_CONSTEXPR inline int128_t_base::operator char() const { return static_cast(Low()); } +#if EA_WCHAR_UNIQUE +// EA_CONSTEXPR inline int128_t_base::operator char16_t() const { return static_cast(Low()); } +// EA_CONSTEXPR inline int128_t_base::operator char32_t() const { return static_cast(Low()); } +// EA_CONSTEXPR inline int128_t_base::operator wchar_t() const { return static_cast(Low()); } +#endif +EA_CONSTEXPR inline int128_t_base::operator int() const { return static_cast(Low()); } +EA_CONSTEXPR inline int128_t_base::operator long() const { return static_cast(Low()); } +EA_CONSTEXPR inline int128_t_base::operator long long() const { return static_cast(Low()); } +EA_CONSTEXPR inline int128_t_base::operator short() const { return static_cast(Low()); } +EA_CONSTEXPR inline int128_t_base::operator signed char() const { return static_cast(Low()); } +EA_CONSTEXPR inline int128_t_base::operator unsigned char() const { return static_cast(Low()); } +EA_CONSTEXPR inline int128_t_base::operator unsigned int() const { return static_cast(Low()); } +EA_CONSTEXPR inline int128_t_base::operator unsigned long long() const { return static_cast(Low()); } +EA_CONSTEXPR inline int128_t_base::operator unsigned short() const { return static_cast(Low()); } +EA_CONSTEXPR inline int128_t_base::operator float() const { return static_cast(Low()); } +EA_CONSTEXPR inline int128_t_base::operator double() const { return static_cast(Low()); } +EA_CONSTEXPR inline int128_t_base::operator long double() const { return static_cast(Low()); } +#if EA_INT128_INTRINSIC_AVAILABLE +EA_CONSTEXPR inline int128_t_base::operator __int128() const { return static_cast<__int128>(Low()); } +EA_CONSTEXPR inline int128_t_base::operator unsigned __int128() const { return static_cast(Low()); } +#endif + +inline void int128_t_base::SetBit(int nIndex, int value) +{ + // EA_ASSERT((nIndex >= 0) && (nIndex < 128)); + + const uint64_t nBitMask = ((uint64_t)1 << (nIndex % 64)); + + if(nIndex < 64) + { + if(value) + mPart0 = mPart0 | nBitMask; + else + mPart0 = mPart0 & ~nBitMask; + } + else if(nIndex < 128) + { + if(value) + mPart1 = mPart1 | nBitMask; + else + mPart1 = mPart1 & ~nBitMask; + } +} + +inline int int128_t_base::GetBit(int nIndex) const +{ + // EA_ASSERT((nIndex >= 0) && (nIndex < 128)); + + const uint64_t nBitMask = ((uint64_t)1 << (nIndex % 64)); + + if(nIndex < 64) + return ((mPart0 & nBitMask) ? 1 : 0); + else if(nIndex < 128) + return ((mPart1 & nBitMask) ? 1 : 0); + return 0; +} + +inline int128_t_base::int128_t_base(uint32_t nPart0, uint32_t nPart1, uint32_t nPart2, uint32_t nPart3) +{ + mPart1 = ((uint64_t)nPart3 << 32) + nPart2; + mPart0 = ((uint64_t)nPart1 << 32) + nPart0; +} + +inline int128_t_base::int128_t_base(uint64_t nPart0, uint64_t nPart1) +{ + mPart1 = nPart1; + mPart0 = nPart0; +} + +inline int128_t_base::int128_t_base(uint8_t value) +{ + mPart1 = 0; + mPart0 = value; +} + +inline int128_t_base::int128_t_base(uint16_t value) +{ + mPart1 = 0; + mPart0 = value; +} + +inline int128_t_base::int128_t_base(uint32_t value) +{ + mPart1 = 0; + mPart0 = value; +} + +inline int128_t_base::int128_t_base(uint64_t value) +{ + mPart1 = 0; + mPart0 = value; +} + +/////////////////////////////////////////////////////////////////////////////// +// OperatorPlus +// +// Returns: (value1 + value2) into result. +// The output 'result' *is* allowed to point to the same memory as one of the inputs. +// To consider: Fix 'defect' of this function whereby it doesn't implement overflow wraparound. +// +inline void int128_t_base::OperatorPlus(const int128_t_base& value1, const int128_t_base& value2, int128_t_base& result) +{ + uint64_t t = value1.mPart0 + value2.mPart0; + uint64_t nCarry = (t < value1.mPart0) && (t < value2.mPart0); + result.mPart0 = t; + result.mPart1 = value1.mPart1 + value2.mPart1 + nCarry; +} + +/////////////////////////////////////////////////////////////////////////////// +// OperatorMinus +// +// Returns: (value1 - value2) into result. +// The output 'result' *is* allowed to point to the same memory as one of the inputs. +// To consider: Fix 'defect' of this function whereby it doesn't implement overflow wraparound. +// +inline void int128_t_base::OperatorMinus(const int128_t_base& value1, const int128_t_base& value2, int128_t_base& result) +{ + uint64_t t = (value1.mPart0 - value2.mPart0); + uint64_t nCarry = (value1.mPart0 < value2.mPart0) ? 1 : 0; + result.mPart0 = t; + result.mPart1 = (value1.mPart1 - value2.mPart1) - nCarry; +} + +/////////////////////////////////////////////////////////////////////////////// +// OperatorMul +// +// 64 bit systems: +// This is how it would be able to work if we could get a 128 bit result from +// two 64 bit values. None of the 64 bit systems that we are currently working +// with have C language support for multiplying two 64 bit numbers and retrieving +// the 128 bit result. However, many 64 bit platforms have support at the asm +// level for doing such a thing. +// Part 1 Part 0 +// 0000000000000002 0000000000000001 +// x 0000000000000002 0000000000000001 +// ------------------------------------------- +// | 0000000000000002 0000000000000001 +// + 0000000000000004 | 0000000000000002 (0000000000000000) +// ------------------------------------------------------------------------- +// +inline void int128_t_base::OperatorMul(const int128_t_base& a, const int128_t_base& b, int128_t_base& result) +{ + // To consider: Use compiler or OS-provided custom functionality here, such as + // Windows UnsignedMultiply128 and GCC's built-in int128_t. + + #if defined(DISABLED_PLATFORM_WIN64) + // To do: Implement x86-64 asm here. + + #else + // Else we are stuck doing something less efficient. In this case we + // fall back to doing 32 bit multiplies as with 32 bit platforms. + result = (a.mPart0 & 0xffffffff) * (b.mPart0 & 0xffffffff); + int128_t v01 = (a.mPart0 & 0xffffffff) * ((b.mPart0 >> 32) & 0xffffffff); + int128_t v02 = (a.mPart0 & 0xffffffff) * (b.mPart1 & 0xffffffff); + int128_t v03 = (a.mPart0 & 0xffffffff) * ((b.mPart1 >> 32) & 0xffffffff); + + int128_t v10 = ((a.mPart0 >> 32) & 0xffffffff) * (b.mPart0 & 0xffffffff); + int128_t v11 = ((a.mPart0 >> 32) & 0xffffffff) * ((b.mPart0 >> 32) & 0xffffffff); + int128_t v12 = ((a.mPart0 >> 32) & 0xffffffff) * (b.mPart1 & 0xffffffff); + + int128_t v20 = (a.mPart1 & 0xffffffff) * (b.mPart0 & 0xffffffff); + int128_t v21 = (a.mPart1 & 0xffffffff) * ((b.mPart0 >> 32) & 0xffffffff); + + int128_t v30 = ((a.mPart1 >> 32) & 0xffffffff) * (b.mPart0 & 0xffffffff); + + // Do row addition, shifting as needed. + OperatorPlus(result, v01 << 32, result); + OperatorPlus(result, v02 << 64, result); + OperatorPlus(result, v03 << 96, result); + + OperatorPlus(result, v10 << 32, result); + OperatorPlus(result, v11 << 64, result); + OperatorPlus(result, v12 << 96, result); + + OperatorPlus(result, v20 << 64, result); + OperatorPlus(result, v21 << 96, result); + + OperatorPlus(result, v30 << 96, result); + #endif +} + +/////////////////////////////////////////////////////////////////////////////// +// OperatorShiftRight +// +// Returns: value >> nShift into result +// The output 'result' may *not* be the same as one the input. +// With rightward shifts of negative numbers, shift in zero from the left side. +// +inline void int128_t_base::OperatorShiftRight(const int128_t_base& value, int nShift, int128_t_base& result) +{ + if(nShift >= 0) + { + if(nShift < 64) + { // 0 - 63 + result.mPart1 = (value.mPart1 >> nShift); + + if(nShift == 0) + result.mPart0 = (value.mPart0 >> nShift); + else + result.mPart0 = (value.mPart0 >> nShift) | (value.mPart1 << (64 - nShift)); + } + else + { // 64+ + result.mPart1 = 0; + result.mPart0 = (value.mPart1 >> (nShift - 64)); + } + } + else // (nShift < 0) + OperatorShiftLeft(value, -nShift, result); +} + + +/////////////////////////////////////////////////////////////////////////////// +// OperatorShiftRight +// +// Returns: value << nShift into result +// The output 'result' may *not* be the same as one the input. +// With rightward shifts of negative numbers, shift in zero from the left side. +// +inline void int128_t_base::OperatorShiftLeft(const int128_t_base& value, int nShift, int128_t_base& result) +{ + if(nShift >= 0) + { + if(nShift < 64) + { + if(nShift) // We need to have a special case because CPUs convert a shift by 64 to a no-op. + { + // 1 - 63 + result.mPart0 = (value.mPart0 << nShift); + result.mPart1 = (value.mPart1 << nShift) | (value.mPart0 >> (64 - nShift)); + } + else + { + result.mPart0 = value.mPart0; + result.mPart1 = value.mPart1; + } + } + else + { // 64+ + result.mPart0 = 0; + result.mPart1 = (value.mPart0 << (nShift - 64)); + } + } + else // (nShift < 0) + OperatorShiftRight(value, -nShift, result); +} + + +inline bool int128_t_base::operator!() const +{ + return (mPart0 == 0) && (mPart1 == 0); +} + + +/////////////////////////////////////////////////////////////////////////////// +// OperatorXOR +// +// Returns: value1 ^ value2 into result +// The output 'result' may be the same as one the input. +// +inline void int128_t_base::OperatorXOR(const int128_t_base& value1, const int128_t_base& value2, int128_t_base& result) +{ + result.mPart0 = (value1.mPart0 ^ value2.mPart0); + result.mPart1 = (value1.mPart1 ^ value2.mPart1); +} + + +/////////////////////////////////////////////////////////////////////////////// +// OperatorOR +// +// Returns: value1 | value2 into result +// The output 'result' may be the same as one the input. +// +inline void int128_t_base::OperatorOR(const int128_t_base& value1, const int128_t_base& value2, int128_t_base& result) +{ + result.mPart0 = (value1.mPart0 | value2.mPart0); + result.mPart1 = (value1.mPart1 | value2.mPart1); +} + + +/////////////////////////////////////////////////////////////////////////////// +// OperatorAND +// +// Returns: value1 & value2 into result +// The output 'result' may be the same as one the input. +// +inline void int128_t_base::OperatorAND(const int128_t_base& value1, const int128_t_base& value2, int128_t_base& result) +{ + result.mPart0 = (value1.mPart0 & value2.mPart0); + result.mPart1 = (value1.mPart1 & value2.mPart1); +} + + +inline bool int128_t_base::IsZero() const +{ + return (mPart0 == 0) && // Check mPart0 first as this will likely yield faster execution. + (mPart1 == 0); +} + + +inline void int128_t_base::SetZero() +{ + mPart1 = 0; + mPart0 = 0; +} + + +inline void int128_t_base::TwosComplement() +{ + mPart1 = ~mPart1; + mPart0 = ~mPart0; + + // What we want to do, but isn't available at this level: + // operator++(); + // Alternative: + int128_t_base one((uint32_t)1); + OperatorPlus(*this, one, *this); +} + + +inline void int128_t_base::InverseTwosComplement() +{ + // What we want to do, but isn't available at this level: + // operator--(); + // Alternative: + int128_t_base one((uint32_t)1); + OperatorMinus(*this, one, *this); + + mPart1 = ~mPart1; + mPart0 = ~mPart0; +} + + +inline void int128_t_base::DoubleToUint128(double value) +{ + // Currently this function is limited to 64 bits of integer input. + // We need to make a better version of this function. Perhaps we should implement + // it via dissecting the IEEE floating point format (sign, exponent, matissa). + // EA_ASSERT(fabs(value) < 18446744073709551616.0); // Assert that the input is <= 64 bits of integer. + + mPart1 = 0; + mPart0 = (value >= 0 ? (uint64_t)value : (uint64_t)-value); +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////// +// uint128_t implementation +/////////////////////////////////////////////////////////////////////////////////////////////////////// + +inline uint128_t uint128_t::operator^(const uint128_t& other) const +{ + uint128_t temp; + uint128_t::OperatorXOR(*this, other, temp); + return temp; +} + +inline uint128_t uint128_t::operator|(const uint128_t& other) const +{ + uint128_t temp; + uint128_t::OperatorOR(*this, other, temp); + return temp; +} + +inline uint128_t uint128_t::operator&(const uint128_t& other) const +{ + uint128_t temp; + uint128_t::OperatorAND(*this, other, temp); + return temp; +} + +inline uint128_t& uint128_t::operator^=(const uint128_t& value) +{ + OperatorXOR(*this, value, *this); + return *this; +} + +inline uint128_t& uint128_t::operator|=(const uint128_t& value) +{ + OperatorOR(*this, value, *this); + return *this; +} + +inline uint128_t& uint128_t::operator&=(const uint128_t& value) +{ + OperatorAND(*this, value, *this); + return *this; +} + +// With rightward shifts of negative numbers, shift in zero from the left side. +inline uint128_t uint128_t::operator>>(int nShift) const +{ + uint128_t temp; + OperatorShiftRight(*this, nShift, temp); + return temp; +} + +// With rightward shifts of negative numbers, shift in zero from the left side. +inline uint128_t uint128_t::operator<<(int nShift) const +{ + uint128_t temp; + OperatorShiftLeft(*this, nShift, temp); + return temp; +} + +inline uint128_t& uint128_t::operator>>=(int nShift) +{ + uint128_t temp; + OperatorShiftRight(*this, nShift, temp); + *this = temp; + return *this; +} + +inline uint128_t& uint128_t::operator<<=(int nShift) +{ + uint128_t temp; + OperatorShiftLeft(*this, nShift, temp); + *this = temp; + return *this; +} + +inline uint128_t& uint128_t::operator+=(const uint128_t& value) +{ + OperatorPlus(*this, value, *this); + return *this; +} + +inline uint128_t& uint128_t::operator-=(const uint128_t& value) +{ + OperatorMinus(*this, value, *this); + return *this; +} + +inline uint128_t& uint128_t::operator*=(const uint128_t& value) +{ + *this = *this * value; + return *this; +} + +inline uint128_t& uint128_t::operator/=(const uint128_t& value) +{ + *this = *this / value; + return *this; +} + +inline uint128_t& uint128_t::operator%=(const uint128_t& value) +{ + *this = *this % value; + return *this; +} + +inline uint128_t uint128_t::operator+(const uint128_t& other) +{ + uint128_t temp; + uint128_t::OperatorPlus(*this, other, temp); + return temp; +} + +inline uint128_t uint128_t::operator-(const uint128_t& other) +{ + uint128_t temp; + uint128_t::OperatorMinus(*this, other, temp); + return temp; +} + +inline uint128_t uint128_t::operator*(const uint128_t& other) +{ + uint128_t returnValue; + int128_t_base::OperatorMul(*this, other, returnValue); + return returnValue; +} + +inline uint128_t uint128_t::operator/(const uint128_t& other) +{ + uint128_t remainder; + uint128_t quotient; + this->Modulus(other, quotient, remainder); + return quotient; +} + +inline uint128_t uint128_t::operator%(const uint128_t& other) +{ + uint128_t remainder; + uint128_t quotient; + this->Modulus(other, quotient, remainder); + return remainder; +} + +inline uint128_t uint128_t::operator+() const +{ + return *this; +} + +inline uint128_t uint128_t::operator~() const +{ + return uint128_t(~mPart0, ~mPart1); +} + +inline uint128_t& uint128_t::operator--() +{ + int128_t_base one((uint32_t)1); + OperatorMinus(*this, one, *this); + return *this; +} + +inline uint128_t uint128_t::operator--(int) +{ + uint128_t temp((uint32_t)1); + OperatorMinus(*this, temp, temp); + return temp; +} + +inline uint128_t uint128_t::operator++(int) +{ + uint128_t prev = *this; + uint128_t temp((uint32_t)1); + OperatorPlus(*this, temp, *this); + return prev; +} + +inline uint128_t& uint128_t::operator++() +{ + int128_t_base one((uint32_t)1); + OperatorPlus(*this, one, *this); + return *this; +} + +inline void uint128_t::Negate() +{ + TwosComplement(); +} + +inline uint128_t uint128_t::operator-() const +{ + uint128_t returnValue(*this); + returnValue.Negate(); + return returnValue; +} + +// This function forms the basis of all logical comparison functions. +// If value1 < value2, the return value is -1. +// If value1 == value2, the return value is 0. +// If value1 > value2, the return value is 1. +inline int uint128_t::compare(const uint128_t& other) const +{ + // Compare individual parts. At this point, the two numbers have the same sign. + if(mPart1 == other.mPart1) + { + if(mPart0 == other.mPart0) + return 0; + else if(mPart0 > other.mPart0) + return 1; + // return -1; //Just fall through to the end. + } + else if(mPart1 > other.mPart1) + return 1; + return -1; +} + +EA_DISABLE_VC_WARNING(4723) // warning C4723: potential divide by 0 +inline void uint128_t::Modulus(const uint128_t& divisor, uint128_t& quotient, uint128_t& remainder) const +{ + uint128_t tempDividend(*this); + uint128_t tempDivisor(divisor); + + if(tempDivisor.IsZero()) + { + // Force a divide by zero exception. + // We know that tempDivisor.mPart0 is zero. + quotient.mPart0 /= tempDivisor.mPart0; + } + else if(tempDividend.IsZero()) + { + quotient = uint128_t((uint32_t)0); + remainder = uint128_t((uint32_t)0); + } + else + { + remainder.SetZero(); + + for(int i(0); i < 128; i++) + { + remainder += (uint32_t)tempDividend.GetBit(127 - i); + const bool bBit(remainder >= tempDivisor); + quotient.SetBit(127 - i, bBit); + + if(bBit) + remainder -= tempDivisor; + + if((i != 127) && !remainder.IsZero()) + remainder <<= 1; + } + } +} +EA_RESTORE_VC_WARNING() + +inline bool uint128_t::operator==(const uint128_t& other) const +{ + return (mPart0 == other.mPart0) && // Check mPart0 first as this will likely yield faster execution. + (mPart1 == other.mPart1); +} + +inline bool uint128_t::operator< (const uint128_t& other) const { return (compare(other) < 0); } +inline bool uint128_t::operator!=(const uint128_t& other) const { return !(*this == other); } +inline bool uint128_t::operator> (const uint128_t& other) const { return other < *this; } +inline bool uint128_t::operator>=(const uint128_t& other) const { return !(*this < other); } +inline bool uint128_t::operator<=(const uint128_t& other) const { return !(other < *this); } + +inline bool uint128_t::IsNegative() const +{ // True if value < 0 + return false; +} + +inline bool uint128_t::IsPositive() const +{ + // True of value >= 0 + return true; +} + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////// +// int128_t implementation +/////////////////////////////////////////////////////////////////////////////////////////////////////// + +inline void int128_t::Negate() +{ + if (IsPositive()) + TwosComplement(); + else + InverseTwosComplement(); +} + +inline int128_t int128_t::operator-() const +{ + int128_t returnValue(*this); + returnValue.Negate(); + return returnValue; +} + +inline int128_t& int128_t::operator++() +{ + int128_t_base one((uint32_t)1); + OperatorPlus(*this, one, *this); + return *this; +} + +inline int128_t& int128_t::operator--() +{ + int128_t_base one((uint32_t)1); + OperatorMinus(*this, one, *this); + return *this; +} + +inline int128_t int128_t::operator++(int) +{ + int128_t prev = *this; + int128_t temp((uint32_t)1); + OperatorPlus(*this, temp, *this); + return prev; +} + +inline int128_t int128_t::operator--(int) +{ + int128_t temp((uint32_t)1); + OperatorMinus(*this, temp, temp); + return temp; +} + +inline int128_t int128_t::operator+() const +{ + return *this; +} + +inline int128_t int128_t::operator~() const +{ + return int128_t(~mPart0, ~mPart1); +} + +inline int128_t int128_t::operator+(const int128_t& other) +{ + int128_t temp; + int128_t::OperatorPlus(*this, other, temp); + return temp; +} + +inline int128_t int128_t::operator-(const int128_t& other) +{ + int128_t temp; + int128_t::OperatorMinus(*this, other, temp); + return temp; +} + +// This function forms the basis of all logical comparison functions. +// If value1 < value2, the return value is -1. +// If value1 == value2, the return value is 0. +// If value1 > value2, the return value is 1. +inline int int128_t::compare(const int128_t& other) const +{ + // Cache some values. Positive means >= 0. Negative means < 0 and thus means '!positive'. + const bool bValue1IsPositive( IsPositive()); + const bool bValue2IsPositive(other.IsPositive()); + + // Do positive/negative tests. + if(bValue1IsPositive != bValue2IsPositive) + return bValue1IsPositive ? 1 : -1; + + // Compare individual parts. At this point, the two numbers have the same sign. + if(mPart1 == other.mPart1) + { + if(mPart0 == other.mPart0) + return 0; + else if(mPart0 > other.mPart0) + return 1; + // return -1; //Just fall through to the end. + } + else if(mPart1 > other.mPart1) + return 1; + return -1; +} + +inline bool int128_t::operator==(const int128_t& other) const +{ + return (mPart0 == other.mPart0) && // Check mPart0 first as this will likely yield faster execution. + (mPart1 == other.mPart1); +} + +inline bool int128_t::operator!=(const int128_t& other) const +{ + return (mPart0 != other.mPart0) || // Check mPart0 first as this will likely yield faster execution. + (mPart1 != other.mPart1); +} + +inline bool int128_t::operator>(const int128_t& other) const +{ + return (compare(other) > 0); +} + +inline bool int128_t::operator>=(const int128_t& other) const +{ + return (compare(other) >= 0); +} + +inline bool int128_t::operator<(const int128_t& other) const +{ + return (compare(other) < 0); +} + +inline bool int128_t::operator<=(const int128_t& other) const +{ + return (compare(other) <= 0); +} + +inline bool int128_t::IsNegative() const +{ // True if value < 0 + return ((mPart1 & UINT64_C(0x8000000000000000)) != 0); +} + +inline bool int128_t::IsPositive() const +{ // True of value >= 0 + return ((mPart1 & UINT64_C(0x8000000000000000)) == 0); +} + +inline int128_t int128_t::operator*(const int128_t& other) +{ + int128_t a(*this); + int128_t b(other); + int128_t returnValue; + + // Correctly handle negative values + bool bANegative(false); + bool bBNegative(false); + + if(a.IsNegative()) + { + bANegative = true; + a.Negate(); + } + + if(b.IsNegative()) + { + bBNegative = true; + b.Negate(); + } + + int128_t_base::OperatorMul(a, b, returnValue); + + // Do negation as needed. + if(bANegative != bBNegative) + returnValue.Negate(); + + return returnValue; +} + +inline int128_t int128_t::operator/(const int128_t& other) +{ + int128_t remainder; + int128_t quotient; + this->Modulus(other, quotient, remainder); + return quotient; +} + +inline int128_t int128_t::operator<<(int nShift) const +{ + int128_t temp; + OperatorShiftLeft(*this, nShift, temp); + return temp; +} + +inline int128_t& int128_t::operator+=(const int128_t& value) +{ + OperatorPlus(*this, value, *this); + return *this; +} + +inline int128_t& int128_t::operator-=(const int128_t& value) +{ + OperatorMinus(*this, value, *this); + return *this; +} + +inline int128_t& int128_t::operator<<=(int nShift) +{ + int128_t temp; + OperatorShiftLeft(*this, nShift, temp); + *this = temp; + return *this; +} + +inline int128_t& int128_t::operator*=(const int128_t& value) +{ + *this = *this * value; + return *this; +} + +inline int128_t& int128_t::operator%=(const int128_t& value) +{ + *this = *this % value; + return *this; +} + +inline int128_t int128_t::operator%(const int128_t& other) +{ + int128_t remainder; + int128_t quotient; + this->Modulus(other, quotient, remainder); + return remainder; +} + +inline int128_t& int128_t::operator/=(const int128_t& value) +{ + *this = *this / value; + return *this; +} + +// With rightward shifts of negative numbers, shift in zero from the left side. +inline int128_t int128_t::operator>>(int nShift) const +{ + int128_t temp; + OperatorShiftRight(*this, nShift, temp); + return temp; +} + +inline int128_t& int128_t::operator>>=(int nShift) +{ + int128_t temp; + OperatorShiftRight(*this, nShift, temp); + *this = temp; + return *this; +} + +inline int128_t int128_t::operator^(const int128_t& other) const +{ + int128_t temp; + int128_t::OperatorXOR(*this, other, temp); + return temp; +} + +inline int128_t int128_t::operator|(const int128_t& other) const +{ + int128_t temp; + int128_t::OperatorOR(*this, other, temp); + return temp; +} + + +inline int128_t int128_t::operator&(const int128_t& other) const +{ + int128_t temp; + int128_t::OperatorAND(*this, other, temp); + return temp; +} + +inline int128_t& int128_t::operator^=(const int128_t& value) +{ + OperatorXOR(*this, value, *this); + return *this; +} + +inline int128_t& int128_t::operator|=(const int128_t& value) +{ + OperatorOR(*this, value, *this); + return *this; +} + +inline int128_t& int128_t::operator&=(const int128_t& value) +{ + OperatorAND(*this, value, *this); + return *this; +} + +EA_DISABLE_VC_WARNING(4723) // warning C4723: potential divide by 0 +inline void int128_t::Modulus(const int128_t& divisor, int128_t& quotient, int128_t& remainder) const +{ + int128_t tempDividend(*this); + int128_t tempDivisor(divisor); + + bool bDividendNegative = false; + bool bDivisorNegative = false; + + if(tempDividend.IsNegative()) + { + bDividendNegative = true; + tempDividend.Negate(); + } + if(tempDivisor.IsNegative()) + { + bDivisorNegative = true; + tempDivisor.Negate(); + } + + // Handle the special cases + if(tempDivisor.IsZero()) + { + // Force a divide by zero exception. + // We know that tempDivisor.mPart0 is zero. + quotient.mPart0 /= tempDivisor.mPart0; + } + else if(tempDividend.IsZero()) + { + quotient = int128_t((uint32_t)0); + remainder = int128_t((uint32_t)0); + } + else + { + remainder.SetZero(); + + for(int i(0); i < 128; i++) + { + remainder += (uint32_t)tempDividend.GetBit(127 - i); + const bool bBit(remainder >= tempDivisor); + quotient.SetBit(127 - i, bBit); + + if(bBit) + remainder -= tempDivisor; + + if((i != 127) && !remainder.IsZero()) + remainder <<= 1; + } + } + + if((bDividendNegative && !bDivisorNegative) || (!bDividendNegative && bDivisorNegative)) + { + // Ensure the following formula applies for negative dividends + // dividend = divisor * quotient + remainder + quotient.Negate(); + } +} +EA_RESTORE_VC_WARNING() + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////// +// INT128_C / UINT128_C +// +// The C99 language defines macros for portably defining constants of +// sized numeric types. For example, there might be: +// #define UINT64_C(x) x##ULL +// Since our int128 data type is not a built-in type, we can't define a +// UINT128_C macro as something that pastes ULLL at the end of the digits. +// Instead we define it to create a temporary that is constructed from a +// string of the digits. This will work in most cases that suffix pasting +// would work. +// +/* EA_CONSTEXPR */ inline uint128_t UINT128_C(uint64_t nPart1, uint64_t nPart0) { return uint128_t(nPart0, nPart1); } +/* EA_CONSTEXPR */ inline int128_t INT128_C(int64_t nPart1, int64_t nPart0) { return int128_t(nPart0, nPart1); } + + + + +#endif // INCLUDED_int128_h + diff --git a/test/packages/EABase/include/Common/EABase/version.h b/test/packages/EABase/include/Common/EABase/version.h index a9965930..e920307f 100644 --- a/test/packages/EABase/include/Common/EABase/version.h +++ b/test/packages/EABase/include/Common/EABase/version.h @@ -29,8 +29,8 @@ /////////////////////////////////////////////////////////////////////////////// #ifndef EABASE_VERSION - #define EABASE_VERSION "2.08.04" - #define EABASE_VERSION_N 20804 + #define EABASE_VERSION "2.09.01" + #define EABASE_VERSION_N 20901 #endif #endif diff --git a/test/source/ConceptImpls.h b/test/source/ConceptImpls.h index 06c69be2..a3b7a294 100644 --- a/test/source/ConceptImpls.h +++ b/test/source/ConceptImpls.h @@ -149,9 +149,8 @@ class MoveAssignable MoveAssignable() : value(defaultValue) {} }; -class MoveAndDefaultConstructible +struct MoveAndDefaultConstructible { -public: static const int defaultValue = 42; MoveAndDefaultConstructible() : value(defaultValue) {} @@ -163,59 +162,29 @@ class MoveAndDefaultConstructible MoveAndDefaultConstructible& operator=(MoveAndDefaultConstructible&&) = delete; const int value; - -private: }; struct MissingMoveConstructor { - MissingMoveConstructor() - { - } - - MissingMoveConstructor(const MissingMoveConstructor & other) - { - } - - MissingMoveConstructor & operator= (MissingMoveConstructor && other) - { - return *this; - } - - MissingMoveConstructor & operator= (const MissingMoveConstructor & other) - { - return *this; - } - - bool operator< (const MissingMoveConstructor & other) const - { - return true; - } + MissingMoveConstructor() {} + MissingMoveConstructor(const MissingMoveConstructor& other) {} + MissingMoveConstructor& operator=(MissingMoveConstructor&& other) { return *this; } + MissingMoveConstructor& operator=(const MissingMoveConstructor& other) { return *this; } + bool operator<(const MissingMoveConstructor& other) const { return true; } }; struct MissingMoveAssignable { - MissingMoveAssignable() - { - } - - MissingMoveAssignable(const MissingMoveAssignable & other) - { - } - - MissingMoveAssignable(MissingMoveAssignable && other) - { - } - - MissingMoveAssignable & operator= (const MissingMoveAssignable& other) - { - return *this; - } + MissingMoveAssignable() {} + MissingMoveAssignable(const MissingMoveAssignable& other) {} + MissingMoveAssignable(MissingMoveAssignable&& other) {} + MissingMoveAssignable& operator=(const MissingMoveAssignable& other) { return *this; } + bool operator<(const MissingMoveAssignable& other) const { return true; } +}; - bool operator< (const MissingMoveAssignable & other) const - { - return true; - } +struct MissingEquality +{ + MissingEquality& operator==(const MissingEquality&) = delete; }; #endif // !defined(EA_COMPILER_NO_DEFAULTED_FUNCTIONS) && !defined(EA_COMPILER_NO_DELETED_FUNCTIONS) diff --git a/test/source/TestAlgorithm.cpp b/test/source/TestAlgorithm.cpp index 699a2af9..b07488c2 100644 --- a/test/source/TestAlgorithm.cpp +++ b/test/source/TestAlgorithm.cpp @@ -888,11 +888,7 @@ int TestAlgorithm() eastl::move(src.begin(), src.end(), dest.begin()); EATEST_VERIFY((dest[0] == "0") && (dest[3] == "3")); - #if EASTL_MOVE_SEMANTICS_ENABLED - EATEST_VERIFY(src[0].empty() && src[3].empty()); - #else - // Else move_backward wasn't able to use C++11 move and instead did a copy. - #endif + EATEST_VERIFY(src[0].empty() && src[3].empty()); } { @@ -904,11 +900,7 @@ int TestAlgorithm() eastl::move_backward(src.begin(), src.end(), dest.end()); EATEST_VERIFY((dest[0] == "0") && (dest[3] == "3")); - #if EASTL_MOVE_SEMANTICS_ENABLED - EATEST_VERIFY(src[0].empty() && src[3].empty()); - #else - // Else move_backward wasn't able to use C++11 move and instead did a copy. - #endif + EATEST_VERIFY(src[0].empty() && src[3].empty()); } } diff --git a/test/source/TestAllocator.cpp b/test/source/TestAllocator.cpp index 3c9a1fc5..21957185 100644 --- a/test/source/TestAllocator.cpp +++ b/test/source/TestAllocator.cpp @@ -10,6 +10,7 @@ #include #include #include +#include @@ -338,6 +339,44 @@ static int TestSwapAllocator() return nErrorCount; } +static int TestAllocationOffsetAndAlignment() +{ + int nErrorCount = 0; + + auto testAllocatorAlignment = [&nErrorCount](int requestedSize, int requestedAlignment, int requestedOffset) + { + CountingAllocator::resetCount(); + CountingAllocator a; + + void* p = allocate_memory(a, requestedSize, requestedAlignment, requestedOffset); + + EATEST_VERIFY(p != nullptr); + EATEST_VERIFY(EA::StdC::IsAligned(p, requestedAlignment)); + + a.deallocate(p, requestedSize); + EATEST_VERIFY(CountingAllocator::getActiveAllocationSize() == 0); + }; + + testAllocatorAlignment(100, 1, 0); + testAllocatorAlignment(100, 2, 0); + testAllocatorAlignment(100, 4, 0); + testAllocatorAlignment(100, 8, 0); + testAllocatorAlignment(100, 16, 0); + + testAllocatorAlignment(100, 1, 8); + testAllocatorAlignment(100, 2, 8); + testAllocatorAlignment(100, 4, 8); + testAllocatorAlignment(100, 8, 8); + + testAllocatorAlignment(100, 1, 16); + testAllocatorAlignment(100, 2, 16); + testAllocatorAlignment(100, 4, 16); + testAllocatorAlignment(100, 8, 16); + testAllocatorAlignment(100, 16, 16); + + return nErrorCount; +} + /////////////////////////////////////////////////////////////////////////////// // TestAllocator @@ -346,6 +385,7 @@ int TestAllocator() { int nErrorCount = 0; + nErrorCount += TestAllocationOffsetAndAlignment(); nErrorCount += TestFixedAllocator(); nErrorCount += TestAllocatorMalloc(); nErrorCount += TestCoreAllocatorAdapter(); diff --git a/test/source/TestArray.cpp b/test/source/TestArray.cpp index e4b02464..83b79db9 100644 --- a/test/source/TestArray.cpp +++ b/test/source/TestArray.cpp @@ -124,6 +124,72 @@ int TestArray() VERIFY(!(a > c)); } + // constexpr tests + { + #ifndef EA_NO_CPP14_CONSTEXPR + EA_CPP14_CONSTEXPR eastl::array a = {{ 0, 1, 2, 3 }}; + + static_assert(a == eastl::array{{ 0, 1, 2, 3 }}, "array constexpr failure"); + + static_assert(a[0] == 0, "array constexpr failure"); + static_assert(a[1] == 1, "array constexpr failure"); + static_assert(a[2] == 2, "array constexpr failure"); + static_assert(a[3] == 3, "array constexpr failure"); + + static_assert(a.at(0) == 0, "array constexpr failure"); + static_assert(a.at(1) == 1, "array constexpr failure"); + static_assert(a.at(2) == 2, "array constexpr failure"); + static_assert(a.at(3) == 3, "array constexpr failure"); + + static_assert(a.data()[0] == 0, "array constexpr failure"); + static_assert(a.data()[1] == 1, "array constexpr failure"); + static_assert(a.data()[2] == 2, "array constexpr failure"); + static_assert(a.data()[3] == 3, "array constexpr failure"); + + static_assert(a.empty() == false, "array constexpr failure"); + static_assert(a.size() == 4, "array constexpr failure"); + static_assert(a.max_size() == 4, "array constexpr failure"); + + static_assert(a.front() == 0, "array constexpr failure"); + static_assert(a.back() == 3, "array constexpr failure"); + + static_assert(a.begin()[0] == 0, "array constexpr failure"); + static_assert(a.begin()[1] == 1, "array constexpr failure"); + static_assert(a.begin()[2] == 2, "array constexpr failure"); + static_assert(a.begin()[3] == 3, "array constexpr failure"); + + static_assert(a.cbegin()[0] == 0, "array constexpr failure"); + static_assert(a.cbegin()[1] == 1, "array constexpr failure"); + static_assert(a.cbegin()[2] == 2, "array constexpr failure"); + static_assert(a.cbegin()[3] == 3, "array constexpr failure"); + + static_assert(a.end()[-1] == 3, "array constexpr failure"); + static_assert(a.end()[-2] == 2, "array constexpr failure"); + static_assert(a.end()[-3] == 1, "array constexpr failure"); + static_assert(a.end()[-4] == 0, "array constexpr failure"); + + static_assert(a.cend()[-1] == 3, "array constexpr failure"); + static_assert(a.cend()[-2] == 2, "array constexpr failure"); + static_assert(a.cend()[-3] == 1, "array constexpr failure"); + static_assert(a.cend()[-4] == 0, "array constexpr failure"); + + #if !(defined(EA_COMPILER_GNUC) && EA_COMPILER_CPP14_ENABLED) + // Disable these tests on GCC compilers pre-C++17 as + // reverse_iterator implementations are strictly not allowed to + // be constexpr until C++17. + static_assert(a.crbegin()[0] == 3, "array constexpr failure"); + static_assert(a.crbegin()[1] == 2, "array constexpr failure"); + static_assert(a.crbegin()[2] == 1, "array constexpr failure"); + static_assert(a.crbegin()[3] == 0, "array constexpr failure"); + + static_assert(a.crend()[-1] == 0, "array constexpr failure"); + static_assert(a.crend()[-2] == 1, "array constexpr failure"); + static_assert(a.crend()[-3] == 2, "array constexpr failure"); + static_assert(a.crend()[-4] == 3, "array constexpr failure"); + #endif + #endif + } + return nErrorCount; } diff --git a/test/source/TestDeque.cpp b/test/source/TestDeque.cpp index b16af5aa..f8e04339 100644 --- a/test/source/TestDeque.cpp +++ b/test/source/TestDeque.cpp @@ -17,6 +17,7 @@ #include #include #include +#include "ConceptImpls.h" #if !defined(EA_COMPILER_NO_STANDARD_CPP_LIBRARY) EA_DISABLE_ALL_VC_WARNINGS() @@ -720,6 +721,84 @@ int TestDeque() } #endif // EA_COMPILER_NO_STANDARD_CPP_LIBRARY + // test deque support of move-only types + { + { + eastl::deque d; + d.emplace_back(MoveAssignable::Create()); + d.emplace_front(MoveAssignable::Create()); + + auto cd = eastl::move(d); + EATEST_VERIFY( d.size() == 0); + EATEST_VERIFY(cd.size() == 2); + } + + { + // User regression but passing end() to deque::erase is not valid. + // Iterator passed to deque::erase but must valid and dereferencable. + // + // eastl::deque d; // empty deque + // d.erase(d.begin()); + // EATEST_VERIFY(d.size() == 0); + } + + // simply test the basic api of deque with a move-only type + { + eastl::deque d; + + // emplace_back + d.emplace_back(MoveAssignable::Create()); + d.emplace_back(MoveAssignable::Create()); + d.emplace_back(MoveAssignable::Create()); + + // erase + d.erase(d.begin()); + EATEST_VERIFY(d.size() == 2); + + // at / front / back / operator[] + EATEST_VERIFY(d[0].value == 42); + EATEST_VERIFY(d.at(0).value == 42); + EATEST_VERIFY(d.front().value == 42); + EATEST_VERIFY(d.back().value == 42); + + // clear + d.clear(); + EATEST_VERIFY(d.size() == 0); + + // emplace + d.emplace(d.begin(), MoveAssignable::Create()); + d.emplace(d.begin(), MoveAssignable::Create()); + EATEST_VERIFY(d.size() == 2); + + // pop_back + d.pop_back(); + EATEST_VERIFY(d.size() == 1); + + // push_back / push_front / resize requires T be 'CopyConstructible' + + { + eastl::deque swapped_d; + + // emplace_front + swapped_d.emplace_front(MoveAssignable::Create()); + swapped_d.emplace_front(MoveAssignable::Create()); + swapped_d.emplace_front(MoveAssignable::Create()); + + // swap + swapped_d.swap(d); + EATEST_VERIFY(swapped_d.size() == 1); + EATEST_VERIFY(d.size() == 3); + } + + // pop_front + d.pop_front(); + EATEST_VERIFY(d.size() == 2); + + // insert + d.insert(d.end(), MoveAssignable::Create()); + EATEST_VERIFY(d.size() == 3); + } + } { // deque(std::initializer_list ilist, const allocator_type& allocator = EASTL_DEQUE_DEFAULT_ALLOCATOR); @@ -791,7 +870,7 @@ int TestDeque() EATEST_VERIFY_F((toDequeA.size() == 3) && (toDequeA.front().mX == (6+7+8)) && (TestObject::sTOCtorCount == 4), "size: %u, mX: %u, count: %d", (unsigned)toDequeA.size(), (unsigned)toDequeA.front().mX, (int)TestObject::sTOCtorCount); - // This test is similar to the emplace EASTL_MOVE_SEMANTICS_ENABLED pathway above. + // This test is similar to the emplace pathway above. TestObject::Reset(); //void push_front(T&& x); diff --git a/test/source/TestExtra.cpp b/test/source/TestExtra.cpp index f3f02085..f086db4d 100644 --- a/test/source/TestExtra.cpp +++ b/test/source/TestExtra.cpp @@ -355,52 +355,32 @@ static int TestQueue() for(int i = 0; i < 100; i++) toVector.push_back(TestObject(i)); - #if EASTL_MOVE_SEMANTICS_ENABLED - // template - // queue(this_type&& x, const Allocator& allocator, typename eastl::enable_if::value>::type* = NULL); - // - // explicit queue(container_type&& x); - // - // void push(value_type&& x); - - queue > toQ_0; - queue > toQ_A(eastl::move(toQ_0), toQ_0.get_container().get_allocator()); // It would be better if we also tested an alternative allocator. - EATEST_VERIFY(toQ_A.size() == 0); - toQ_A.push(TestObject(1000)); - EATEST_VERIFY(toQ_A.size() == 1); - - queue > toQ_B(eastl::move(toQ_A), toQ_A.get_container().get_allocator()); // It would be better if we also tested an alternative allocator. - EATEST_VERIFY((toQ_B.size() == 1) && toQ_A.empty()); - - eastl::vector toVectorM(toVector); - queue > toQ_C(eastl::move(toVectorM)); - EATEST_VERIFY((toQ_C.size() == toVector.size()) && toVectorM.empty()); - - #endif - - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - // template - // void emplace_back(Args&&... args); - - queue > toQ_D; - toQ_D.emplace_back(0, 1, 2); - EATEST_VERIFY(toQ_D.size() == 1) && (toQ_D.back() == TestObject(0, 1, 2)); - - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - // void emplace_back(value_type&& x); - queue > toQ_D; - toQ_D.emplace_back(TestObject(0, 1, 2)); - EATEST_VERIFY(toQ_D.size() == 1) && (toQ_D.back() == TestObject(0, 1, 2)); - - #endif - // void emplace_back(const value_type& x); - queue > toQ_E; - TestObject to(0, 1, 2); - toQ_E.emplace_back(to); - EATEST_VERIFY(toQ_E.size() == 1) && (toQ_E.back() == TestObject(0, 1, 2)); - #endif - + // template + // queue(this_type&& x, const Allocator& allocator, typename eastl::enable_if::value>::type* = NULL); + // + // explicit queue(container_type&& x); + // + // void push(value_type&& x); + + queue > toQ_0; + queue > toQ_A(eastl::move(toQ_0), toQ_0.get_container().get_allocator()); // It would be better if we also tested an alternative allocator. + EATEST_VERIFY(toQ_A.size() == 0); + toQ_A.push(TestObject(1000)); + EATEST_VERIFY(toQ_A.size() == 1); + + queue > toQ_B(eastl::move(toQ_A), toQ_A.get_container().get_allocator()); // It would be better if we also tested an alternative allocator. + EATEST_VERIFY((toQ_B.size() == 1) && toQ_A.empty()); + + eastl::vector toVectorM(toVector); + queue > toQ_C(eastl::move(toVectorM)); + EATEST_VERIFY((toQ_C.size() == toVector.size()) && toVectorM.empty()); + + // template + // void emplace_back(Args&&... args); + + queue > toQ_D; + toQ_D.emplace_back(0, 1, 2); + EATEST_VERIFY(toQ_D.size() == 1) && (toQ_D.back() == TestObject(0, 1, 2)); } @@ -554,54 +534,34 @@ static int TestPriorityQueue() for(int i = 0; i < 100; i++) toVector.push_back(TestObject(i)); - #if EASTL_MOVE_SEMANTICS_ENABLED - // template - // priority_queue(this_type&& x, const Allocator& allocator, typename eastl::enable_if::value>::type* = NULL); - // - // explicit priority_queue(const compare_type& compare, container_type&& x); - // - // template - // priority_queue(InputIterator first, InputIterator last, const compare_type& compare, container_type&& x); - // - // void push(value_type&& x); - - priority_queue > toPQ_0; - priority_queue > toPQ_A(toPQ_0.get_container().begin(), toPQ_0.get_container().begin(), eastl::less(), toPQ_0.get_container()); - EATEST_VERIFY(toPQ_A.size() == 0); - toPQ_A.push(TestObject(1000)); - EATEST_VERIFY(toPQ_A.size() == 1); - - priority_queue > toPQ_B(eastl::move(toPQ_A), toPQ_A.get_container().get_allocator()); // It would be better if we also tested an alternative allocator. - EATEST_VERIFY((toPQ_B.size() == 1) && toPQ_A.empty()); - - eastl::vector toVectorM(toVector); - priority_queue > toPQ_C(eastl::less(), eastl::move(toVectorM)); - EATEST_VERIFY((toPQ_C.size() == toVector.size()) && toVectorM.empty()); - - #endif - - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - // template - // void emplace(Args&&... args); - - priority_queue > toPQ_D; - toPQ_D.emplace(0, 1, 2); - EATEST_VERIFY(toPQ_D.size() == 1) && (toPQ_D.top() == TestObject(0, 1, 2)); - - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - // void emplace(value_type&& x); - priority_queue > toPQ_D; - toPQ_D.emplace(TestObject(0, 1, 2)); - EATEST_VERIFY(toPQ_D.size() == 1) && (toPQ_D.top() == TestObject(0, 1, 2)); - - #endif - // void emplace(const value_type& x); - priority_queue > toPQ_E; - TestObject to(0, 1, 2); - toPQ_E.emplace(to); - EATEST_VERIFY(toPQ_E.size() == 1) && (toPQ_E.top() == TestObject(0, 1, 2)); - #endif + // template + // priority_queue(this_type&& x, const Allocator& allocator, typename eastl::enable_if::value>::type* = NULL); + // + // explicit priority_queue(const compare_type& compare, container_type&& x); + // + // template + // priority_queue(InputIterator first, InputIterator last, const compare_type& compare, container_type&& x); + // + // void push(value_type&& x); + + priority_queue > toPQ_0; + priority_queue > toPQ_A(toPQ_0.get_container().begin(), toPQ_0.get_container().begin(), eastl::less(), toPQ_0.get_container()); + EATEST_VERIFY(toPQ_A.size() == 0); + toPQ_A.push(TestObject(1000)); + EATEST_VERIFY(toPQ_A.size() == 1); + + priority_queue > toPQ_B(eastl::move(toPQ_A), toPQ_A.get_container().get_allocator()); // It would be better if we also tested an alternative allocator. + EATEST_VERIFY((toPQ_B.size() == 1) && toPQ_A.empty()); + + eastl::vector toVectorM(toVector); + priority_queue > toPQ_C(eastl::less(), eastl::move(toVectorM)); + EATEST_VERIFY((toPQ_C.size() == toVector.size()) && toVectorM.empty()); + + // template + // void emplace(Args&&... args); + priority_queue > toPQ_D; + toPQ_D.emplace(0, 1, 2); + EATEST_VERIFY(toPQ_D.size() == 1) && (toPQ_D.top() == TestObject(0, 1, 2)); } @@ -705,51 +665,30 @@ static int TestStack() for(int i = 0; i < 100; i++) toVector.push_back(TestObject(i)); - #if EASTL_MOVE_SEMANTICS_ENABLED - // template - // stack(this_type&& x, const Allocator& allocator, typename eastl::enable_if::value>::type* = NULL); - // - // explicit stack(container_type&& x); - // - // void push(value_type&& x); - - stack > toS_0; - stack > toS_A(eastl::move(toS_0), toS_0.get_container().get_allocator()); // It would be better if we also tested an alternative allocator. - EATEST_VERIFY(toS_A.size() == 0); - toS_A.push(TestObject(1000)); - EATEST_VERIFY(toS_A.size() == 1); - - stack > toS_B(eastl::move(toS_A), toS_A.get_container().get_allocator()); // It would be better if we also tested an alternative allocator. - EATEST_VERIFY((toS_B.size() == 1) && toS_A.empty()); - - eastl::vector toVectorM(toVector); - stack > toS_C(eastl::move(toVectorM)); - EATEST_VERIFY((toS_C.size() == toVector.size()) && toVectorM.empty()); - - #endif - - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - // template - // void emplace_back(Args&&... args); - - stack > toS_D; - toS_D.emplace_back(0, 1, 2); - EATEST_VERIFY(toS_D.size() == 1) && (toS_D.top() == TestObject(0, 1, 2)); - - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - // void emplace_back(value_type&& x); - stack > toS_D; - toS_D.emplace_back(TestObject(0, 1, 2)); - EATEST_VERIFY(toS_D.size() == 1) && (toS_D.top() == TestObject(0, 1, 2)); - - #endif - // void emplace_back(const value_type& x); - stack > toS_E; - TestObject to(0, 1, 2); - toS_E.emplace_back(to); - EATEST_VERIFY(toS_E.size() == 1) && (toS_E.top() == TestObject(0, 1, 2)); - #endif + // template + // stack(this_type&& x, const Allocator& allocator, typename eastl::enable_if::value>::type* = NULL); + // + // explicit stack(container_type&& x); + // + // void push(value_type&& x); + stack > toS_0; + stack > toS_A(eastl::move(toS_0), toS_0.get_container().get_allocator()); // It would be better if we also tested an alternative allocator. + EATEST_VERIFY(toS_A.size() == 0); + toS_A.push(TestObject(1000)); + EATEST_VERIFY(toS_A.size() == 1); + + stack > toS_B(eastl::move(toS_A), toS_A.get_container().get_allocator()); // It would be better if we also tested an alternative allocator. + EATEST_VERIFY((toS_B.size() == 1) && toS_A.empty()); + + eastl::vector toVectorM(toVector); + stack > toS_C(eastl::move(toVectorM)); + EATEST_VERIFY((toS_C.size() == toVector.size()) && toVectorM.empty()); + + // template + // void emplace_back(Args&&... args); + stack > toS_D; + toS_D.emplace_back(0, 1, 2); + EATEST_VERIFY(toS_D.size() == 1) && (toS_D.top() == TestObject(0, 1, 2)); } diff --git a/test/source/TestFixedList.cpp b/test/source/TestFixedList.cpp index 6e4db230..9ae7b1d8 100644 --- a/test/source/TestFixedList.cpp +++ b/test/source/TestFixedList.cpp @@ -439,117 +439,62 @@ int TestFixedList() // fixed_list(this_type&& x); // fixed_list(this_type&&, const allocator_type&); // this_type& operator=(this_type&& x); - - #if EASTL_MOVE_SEMANTICS_ENABLED - fixed_list list3TO33(3, TestObject(33)); - fixed_list toListA(eastl::move(list3TO33)); - EATEST_VERIFY((toListA.size() == 3) && (toListA.front().mX == 33) /* && (list3TO33.size() == 0) fixed_list usually can't honor the move request. */); - - // The following is not as strong a test of this ctor as it could be. A stronger test would be to use IntanceAllocator with different instances. - fixed_list list4TO44(4, TestObject(44)); - fixed_list toListB(eastl::move(list4TO44), MallocAllocator()); - EATEST_VERIFY((toListB.size() == 4) && (toListB.front().mX == 44) /* && (list4TO44.size() == 0) fixed_list usually can't honor the move request. */); - - fixed_list list5TO55(5, TestObject(55)); - toListB = eastl::move(list5TO55); - EATEST_VERIFY((toListB.size() == 5) && (toListB.front().mX == 55) /* && (list5TO55.size() == 0) fixed_list usually can't honor the move request. */); - #endif + fixed_list list3TO33(3, TestObject(33)); + fixed_list toListA(eastl::move(list3TO33)); + EATEST_VERIFY((toListA.size() == 3) && (toListA.front().mX == 33) /* && (list3TO33.size() == 0) fixed_list usually can't honor the move request. */); + + // The following is not as strong a test of this ctor as it could be. A stronger test would be to use IntanceAllocator with different instances. + fixed_list list4TO44(4, TestObject(44)); + fixed_list toListB(eastl::move(list4TO44), MallocAllocator()); + EATEST_VERIFY((toListB.size() == 4) && (toListB.front().mX == 44) /* && (list4TO44.size() == 0) fixed_list usually can't honor the move request. */); + + fixed_list list5TO55(5, TestObject(55)); + toListB = eastl::move(list5TO55); + EATEST_VERIFY((toListB.size() == 5) && (toListB.front().mX == 55) /* && (list5TO55.size() == 0) fixed_list usually can't honor the move request. */); } { - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - // template - // void emplace_front(Args&&... args); - - // template - // void emplace_back(Args&&... args); - - // template - // iterator emplace(const_iterator position, Args&&... args); - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - // void emplace_front(value_type&& value); - // void emplace_back(value_type&& value); - // iterator emplace(const_iterator position, value_type&& value); - #endif - // void emplace_front(const value_type& value); - // void emplace_back(const value_type& value); - // iterator emplace(const_iterator position, const value_type& value); - #endif - - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - TestObject::Reset(); - - fixed_list toListA; + // template + // void emplace_front(Args&&... args); - toListA.emplace_front(1, 2, 3); // This uses the TestObject(int x0, int x1, int x2, bool bThrowOnCopy) constructor. - EATEST_VERIFY((toListA.size() == 1) && (toListA.front().mX == (1+2+3)) && (TestObject::sTOCtorCount == 1)); + // template + // void emplace_back(Args&&... args); - toListA.emplace_back(2, 3, 4); - EATEST_VERIFY((toListA.size() == 2) && (toListA.back().mX == (2+3+4)) && (TestObject::sTOCtorCount == 2)); + // template + // iterator emplace(const_iterator position, Args&&... args); - toListA.emplace(toListA.begin(), 3, 4, 5); - EATEST_VERIFY((toListA.size() == 3) && (toListA.front().mX == (3+4+5)) && (TestObject::sTOCtorCount == 3)); - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - TestObject::Reset(); + TestObject::Reset(); - // We have a potential problem here in that the compiler is not required to use move construction below. - // It is allowed to use standard copy construction if it wants. We could force it with eastl::move() usage. - fixed_list toListA; + fixed_list toListA; - toListA.emplace_front(TestObject(1, 2, 3)); - EATEST_VERIFY((toListA.size() == 1) && (toListA.front().mX == (1+2+3)) && (TestObject::sTOMoveCtorCount == 1)); + toListA.emplace_front(1, 2, 3); // This uses the TestObject(int x0, int x1, int x2, bool bThrowOnCopy) constructor. + EATEST_VERIFY((toListA.size() == 1) && (toListA.front().mX == (1+2+3)) && (TestObject::sTOCtorCount == 1)); - toListA.emplace_back(TestObject(2, 3, 4)); - EATEST_VERIFY((toListA.size() == 2) && (toListA.back().mX == (2+3+4)) && (TestObject::sTOMoveCtorCount == 2)); + toListA.emplace_back(2, 3, 4); + EATEST_VERIFY((toListA.size() == 2) && (toListA.back().mX == (2+3+4)) && (TestObject::sTOCtorCount == 2)); - toListA.emplace(toListA.begin(), TestObject(3, 4, 5)); - EATEST_VERIFY((toListA.size() == 3) && (toListA.front().mX == (3+4+5)) && (TestObject::sTOMoveCtorCount == 3)); - #endif - - TestObject::Reset(); + toListA.emplace(toListA.begin(), 3, 4, 5); + EATEST_VERIFY((toListA.size() == 3) && (toListA.front().mX == (3+4+5)) && (TestObject::sTOCtorCount == 3)); - list toListB; - TestObject to123(1, 2, 3); - TestObject to234(2, 3, 4); - TestObject to345(3, 4, 5); - toListB.emplace_front(to123); // This should use the const value_type& version and not the value_type&& version of emplace_front. - EATEST_VERIFY((toListB.size() == 1) && (toListB.front().mX == (1+2+3)) && (TestObject::sTOCopyCtorCount == 1)); + // This test is similar to the emplace pathway above. + TestObject::Reset(); - toListB.emplace_back(to234); - EATEST_VERIFY((toListB.size() == 2) && (toListB.back().mX == (2+3+4)) && (TestObject::sTOCopyCtorCount == 2)); + // void push_front(T&& x); + // void push_back(T&& x); + // iterator insert(const_iterator position, T&& x); - toListB.emplace(toListB.begin(), to345); - EATEST_VERIFY((toListB.size() == 3) && (toListB.front().mX == (3+4+5)) && (TestObject::sTOCopyCtorCount == 3)); + fixed_list toListC; - EATEST_VERIFY(to123.mX == (1+2+3)); // Verify that the object was copied and not moved. If it was moved then mX would be 0 and not 1+2+3. - EATEST_VERIFY(to234.mX == (2+3+4)); - EATEST_VERIFY(to345.mX == (3+4+5)); - #endif - - - #if EASTL_MOVE_SEMANTICS_ENABLED - // This test is similar to the emplace EASTL_MOVE_SEMANTICS_ENABLED pathway above. - TestObject::Reset(); - - // void push_front(T&& x); - // void push_back(T&& x); - // iterator insert(const_iterator position, T&& x); + toListC.push_front(TestObject(1, 2, 3)); + EATEST_VERIFY((toListC.size() == 1) && (toListC.front().mX == (1+2+3)) && (TestObject::sTOMoveCtorCount == 1)); - fixed_list toListC; + toListC.push_back(TestObject(2, 3, 4)); + EATEST_VERIFY((toListC.size() == 2) && (toListC.back().mX == (2+3+4)) && (TestObject::sTOMoveCtorCount == 2)); - toListC.push_front(TestObject(1, 2, 3)); - EATEST_VERIFY((toListC.size() == 1) && (toListC.front().mX == (1+2+3)) && (TestObject::sTOMoveCtorCount == 1)); - - toListC.push_back(TestObject(2, 3, 4)); - EATEST_VERIFY((toListC.size() == 2) && (toListC.back().mX == (2+3+4)) && (TestObject::sTOMoveCtorCount == 2)); - - toListC.insert(toListC.begin(), TestObject(3, 4, 5)); - EATEST_VERIFY((toListC.size() == 3) && (toListC.front().mX == (3+4+5)) && (TestObject::sTOMoveCtorCount == 3)); - #endif + toListC.insert(toListC.begin(), TestObject(3, 4, 5)); + EATEST_VERIFY((toListC.size() == 3) && (toListC.front().mX == (3+4+5)) && (TestObject::sTOMoveCtorCount == 3)); } diff --git a/test/source/TestFixedSList.cpp b/test/source/TestFixedSList.cpp index a5c805e9..6620c799 100644 --- a/test/source/TestFixedSList.cpp +++ b/test/source/TestFixedSList.cpp @@ -201,96 +201,52 @@ int TestFixedSList() // fixed_slist(this_type&&, const allocator_type&); // this_type& operator=(this_type&& x); - #if EASTL_MOVE_SEMANTICS_ENABLED - fixed_slist slist3TO33(3, TestObject(33)); - fixed_slist toListA(eastl::move(slist3TO33)); - EATEST_VERIFY((toListA.size() == 3) && (toListA.front().mX == 33) /* && (slist3TO33.size() == 0) fixed_list usually can't honor the move request. */); - - // The following is not as strong a test of this ctor as it could be. A stronger test would be to use IntanceAllocator with different instances. - fixed_slist slist4TO44(4, TestObject(44)); - fixed_slist toListB(eastl::move(slist4TO44), MallocAllocator()); - EATEST_VERIFY((toListB.size() == 4) && (toListB.front().mX == 44) /* && (slist4TO44.size() == 0) fixed_list usually can't honor the move request. */); - - fixed_slist slist5TO55(5, TestObject(55)); - toListB = eastl::move(slist5TO55); - EATEST_VERIFY((toListB.size() == 5) && (toListB.front().mX == 55) /* && (slist5TO55.size() == 0) fixed_list usually can't honor the move request. */); - #endif + fixed_slist slist3TO33(3, TestObject(33)); + fixed_slist toListA(eastl::move(slist3TO33)); + EATEST_VERIFY((toListA.size() == 3) && (toListA.front().mX == 33) /* && (slist3TO33.size() == 0) fixed_list usually can't honor the move request. */); + + // The following is not as strong a test of this ctor as it could be. A stronger test would be to use IntanceAllocator with different instances. + fixed_slist slist4TO44(4, TestObject(44)); + fixed_slist toListB(eastl::move(slist4TO44), MallocAllocator()); + EATEST_VERIFY((toListB.size() == 4) && (toListB.front().mX == 44) /* && (slist4TO44.size() == 0) fixed_list usually can't honor the move request. */); + + fixed_slist slist5TO55(5, TestObject(55)); + toListB = eastl::move(slist5TO55); + EATEST_VERIFY((toListB.size() == 5) && (toListB.front().mX == 55) /* && (slist5TO55.size() == 0) fixed_list usually can't honor the move request. */); } { - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - // template - // void emplace_front(Args&&... args); + // template + // void emplace_front(Args&&... args); - // template - // iterator emplace_after(const_iterator position, Args&&... args); - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - // void emplace_front(value_type&& value); - // iterator emplace_after(const_iterator position, value_type&& value); - #endif - // void emplace_front(const value_type& value); - // iterator emplace_after(const_iterator position, const value_type& value); - #endif + // template + // iterator emplace_after(const_iterator position, Args&&... args); - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - TestObject::Reset(); + TestObject::Reset(); - fixed_slist toListA; + fixed_slist toListA; - toListA.emplace_front(1, 2, 3); // This uses the TestObject(int x0, int x1, int x2, bool bThrowOnCopy) constructor. - EATEST_VERIFY((toListA.size() == 1) && (toListA.front().mX == (1+2+3)) && (TestObject::sTOCtorCount == 1)); + toListA.emplace_front(1, 2, 3); // This uses the TestObject(int x0, int x1, int x2, bool bThrowOnCopy) constructor. + EATEST_VERIFY((toListA.size() == 1) && (toListA.front().mX == (1+2+3)) && (TestObject::sTOCtorCount == 1)); - toListA.emplace_after(toListA.before_begin(), 3, 4, 5); - EATEST_VERIFY((toListA.size() == 2) && (toListA.front().mX == (3+4+5)) && (TestObject::sTOCtorCount == 2)); - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - TestObject::Reset(); + toListA.emplace_after(toListA.before_begin(), 3, 4, 5); + EATEST_VERIFY((toListA.size() == 2) && (toListA.front().mX == (3+4+5)) && (TestObject::sTOCtorCount == 2)); - // We have a potential problem here in that the compiler is not required to use move construction below. - // It is allowed to use standard copy construction if it wants. We could force it with eastl::move() usage. - fixed_slist toListA; - toListA.emplace_front(TestObject(1, 2, 3)); - EATEST_VERIFY((toListA.size() == 1) && (toListA.front().mX == (1+2+3)) && (TestObject::sTOMoveCtorCount == 1)); + // This test is similar to the emplace pathway above. + TestObject::Reset(); - toListA.emplace_after(toListA.before_begin(), TestObject(3, 4, 5)); - EATEST_VERIFY((toListA.size() == 2) && (toListA.front().mX == (3+4+5)) && (TestObject::sTOMoveCtorCount == 2)); - #endif - - TestObject::Reset(); + // void push_front(T&& x); + // iterator insert(const_iterator position, T&& x); - fixed_slist toListB; - TestObject to123(1, 2, 3); - TestObject to345(3, 4, 5); + fixed_slist toListC; - toListB.emplace_front(to123); // This should use the const value_type& version and not the value_type&& version of emplace_front. - EATEST_VERIFY((toListB.size() == 1) && (toListB.front().mX == (1+2+3)) && (TestObject::sTOCopyCtorCount == 1)); - - toListB.emplace_after(toListB.before_begin(), to345); - EATEST_VERIFY((toListB.size() == 2) && (toListB.front().mX == (3+4+5)) && (TestObject::sTOCopyCtorCount == 2)); - - EATEST_VERIFY(to123.mX == (1+2+3)); // Verify that the object was copied and not moved. If it was moved then mX would be 0 and not 1+2+3. - EATEST_VERIFY(to345.mX == (3+4+5)); - #endif + toListC.push_front(TestObject(1, 2, 3)); + EATEST_VERIFY((toListC.size() == 1) && (toListC.front().mX == (1+2+3)) && (TestObject::sTOMoveCtorCount == 1)); - - #if EASTL_MOVE_SEMANTICS_ENABLED - // This test is similar to the emplace EASTL_MOVE_SEMANTICS_ENABLED pathway above. - TestObject::Reset(); - - // void push_front(T&& x); - // iterator insert(const_iterator position, T&& x); - - fixed_slist toListC; - - toListC.push_front(TestObject(1, 2, 3)); - EATEST_VERIFY((toListC.size() == 1) && (toListC.front().mX == (1+2+3)) && (TestObject::sTOMoveCtorCount == 1)); - - toListC.insert_after(toListC.before_begin(), TestObject(3, 4, 5)); - EATEST_VERIFY((toListC.size() == 2) && (toListC.front().mX == (3+4+5)) && (TestObject::sTOMoveCtorCount == 2)); - #endif + toListC.insert_after(toListC.before_begin(), TestObject(3, 4, 5)); + EATEST_VERIFY((toListC.size() == 2) && (toListC.front().mX == (3+4+5)) && (TestObject::sTOMoveCtorCount == 2)); } diff --git a/test/source/TestFixedString.cpp b/test/source/TestFixedString.cpp index 05c67708..0b4571eb 100644 --- a/test/source/TestFixedString.cpp +++ b/test/source/TestFixedString.cpp @@ -47,55 +47,6 @@ template class eastl::fixed_substring; template class eastl::fixed_substring; -/* -namespace Test -{ - namespace Allocator - { - struct ITestAllocator - { - virtual void* Alloc(size_t size, const char* name, unsigned int flags) = 0; - virtual void Free(void* block, size_t size = 0) = 0; - }; - } - - class TestAllocator - { - public: - typedef Allocator::ITestAllocator allocator_type; - typedef TestAllocator this_type; - - public: - TestAllocator(const char* = NULL) : mpTestAllocator(NULL) {} - TestAllocator(const char*, allocator_type* pTestAllocator) : mpTestAllocator(pTestAllocator) {} - TestAllocator(const char*, allocator_type* pTestAllocator, int) : mpTestAllocator(pTestAllocator) {} - TestAllocator(const TestAllocator& x) : mpTestAllocator(x.mpTestAllocator) {} - TestAllocator(const TestAllocator& x, const char*) : mpTestAllocator(x.mpTestAllocator) {} - - TestAllocator& operator=(const TestAllocator& x) { mpTestAllocator = x.mpTestAllocator; } - - void* allocate(size_t n, int = 0) { return malloc(n); } - void* allocate(size_t n, size_t, size_t, int = 0) { return malloc(n); } // This is broken, but we don't actually use it so it doesn't matter. - void deallocate(void* p, size_t) { free(p); } - - allocator_type* get_allocator() const { return mpTestAllocator; } - void set_allocator(allocator_type* pAllocator) { mpTestAllocator = pAllocator; } - - int get_flags() const { return 0; } - void set_flags(int) {} - - const char* get_name() const { return ""; } - void set_name(const char*) {} - - public: // Public because otherwise VC++ generates (possibly invalid) warnings about inline friend template specializations. - allocator_type* mpTestAllocator; - }; - - bool operator==(const TestAllocator& a, const TestAllocator& b) { return a.mpTestAllocator == b.mpTestAllocator; } - bool operator!=(const TestAllocator& a, const TestAllocator& b) { return a.mpTestAllocator != b.mpTestAllocator; } -} -*/ - /* @@ -372,38 +323,36 @@ int TestFixedString() c = 'g' + a; EATEST_VERIFY(c == "gabc"); - #if EASTL_MOVE_SEMANTICS_ENABLED - // fixed_string operator+(fixed_string&& a, fixed_string&& b); - // fixed_string operator+(fixed_string&& a, const fixed_string& b); - // fixed_string operator+(const value_type* p, fixed_string&& b); - // fixed_string operator+(fixed_string&& a, const value_type* p); - // fixed_string operator+(fixed_string&& a, value_type b); - - c = eastl::move(a) + eastl::move(b); - EATEST_VERIFY(c == "abcdef"); - c.clear(); - - FSTest a1("abc"); - FSTest b1("def"); - c = eastl::move(a1) + b1; - EATEST_VERIFY(c == "abcdef"); - c.clear(); - - FSTest b2("def"); - c = "abc" + eastl::move(b2); - EATEST_VERIFY(c == "abcdef"); - c.clear(); - - FSTest a3("abc"); - c = eastl::move(a3) + "def"; - EATEST_VERIFY(c == "abcdef"); - c.clear(); - - FSTest a4("abc"); - c = eastl::move(a4) + 'd'; - EATEST_VERIFY(c == "abcd"); - c.clear(); - #endif + // fixed_string operator+(fixed_string&& a, fixed_string&& b); + // fixed_string operator+(fixed_string&& a, const fixed_string& b); + // fixed_string operator+(const value_type* p, fixed_string&& b); + // fixed_string operator+(fixed_string&& a, const value_type* p); + // fixed_string operator+(fixed_string&& a, value_type b); + + c = eastl::move(a) + eastl::move(b); + EATEST_VERIFY(c == "abcdef"); + c.clear(); + + FSTest a1("abc"); + FSTest b1("def"); + c = eastl::move(a1) + b1; + EATEST_VERIFY(c == "abcdef"); + c.clear(); + + FSTest b2("def"); + c = "abc" + eastl::move(b2); + EATEST_VERIFY(c == "abcdef"); + c.clear(); + + FSTest a3("abc"); + c = eastl::move(a3) + "def"; + EATEST_VERIFY(c == "abcdef"); + c.clear(); + + FSTest a4("abc"); + c = eastl::move(a4) + 'd'; + EATEST_VERIFY(c == "abcd"); + c.clear(); } @@ -457,17 +406,15 @@ int TestFixedString() overflowAllocator.deallocate(p, 1); } - /* { // Regression for compile failure when EASTL_NO_RVALUE_REFERENCES is 0. - typedef eastl::fixed_string TestString; + typedef eastl::fixed_string TestString; TestString ts1; TestString ts2(ts1 + "Test"); EATEST_VERIFY(ts1.empty() && ts2.size() == 4); } - */ { // Test equality tests of differently-sized fixed_strings. diff --git a/test/source/TestFixedTupleVector.cpp b/test/source/TestFixedTupleVector.cpp index d1b0cc3b..eeeb6d6a 100644 --- a/test/source/TestFixedTupleVector.cpp +++ b/test/source/TestFixedTupleVector.cpp @@ -1506,7 +1506,7 @@ int TestFixedTupleVectorVariant() EATEST_VERIFY(get<0>(movedTup) == 1); EATEST_VERIFY(get<0>(*v1.begin()) == 1); - for (unsigned int i = 0; i < v1.size(); ++i) + for (int i = 0; i < static_cast(v1.size()); ++i) { EATEST_VERIFY(v1.template get<0>()[i] == i + 1); } diff --git a/test/source/TestFixedVector.cpp b/test/source/TestFixedVector.cpp index 21b64f73..e14b2f15 100644 --- a/test/source/TestFixedVector.cpp +++ b/test/source/TestFixedVector.cpp @@ -501,7 +501,6 @@ int TestFixedVector() } // "Crash here." - #if EASTL_MOVE_SEMANTICS_ENABLED { const int FV_SIZE = 100; fixed_vector, FV_SIZE> fvmv1; // to move via move assignment operator @@ -536,8 +535,7 @@ int TestFixedVector() } EATEST_VERIFY(fv.validate()); } - #endif - + #if defined(EA_COMPILER_CPP17_ENABLED) //Test pairing of std::variant with fixed_vector { diff --git a/test/source/TestFunctional.cpp b/test/source/TestFunctional.cpp index 38e1ae4c..9510224a 100644 --- a/test/source/TestFunctional.cpp +++ b/test/source/TestFunctional.cpp @@ -410,6 +410,13 @@ int TestFunctional() nErrorCount += TestHashHelper(4330.099999f); nErrorCount += TestHashHelper(4330.055); nErrorCount += TestHashHelper(4330.0654l); + + { + enum hash_enum_test { e1, e2, e3 }; + nErrorCount += TestHashHelper(e1); + nErrorCount += TestHashHelper(e2); + nErrorCount += TestHashHelper(e3); + } } @@ -868,6 +875,26 @@ int TestFunctional() EATEST_VERIFY(result == 21); } + // user regression "self assigment" tests + { + eastl::function fn = [cache = 0] () mutable { return cache++; }; + + EATEST_VERIFY(fn() == 0); + EATEST_VERIFY(fn() == 1); + EATEST_VERIFY(fn() == 2); + + fn = fn; + + EATEST_VERIFY(fn() == 3); + EATEST_VERIFY(fn() == 4); + EATEST_VERIFY(fn() == 5); + + fn = eastl::move(fn); + + EATEST_VERIFY(fn() == 6); + EATEST_VERIFY(fn() == 7); + EATEST_VERIFY(fn() == 8); + } } // Checking _MSC_EXTENSIONS is required because the Microsoft calling convention classifiers are only available when diff --git a/test/source/TestHash.cpp b/test/source/TestHash.cpp index 9a8589fc..39b6a254 100644 --- a/test/source/TestHash.cpp +++ b/test/source/TestHash.cpp @@ -1261,34 +1261,20 @@ int TestHash() #endif { - #if EASTL_MOVE_SEMANTICS_ENABLED - // hashtable(this_type&& x); - // hashtable(this_type&& x, const allocator_type& allocator); - // this_type& operator=(this_type&& x); - #endif - - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - // template - // insert_return_type emplace(Args&&... args); + // hashtable(this_type&& x); + // hashtable(this_type&& x, const allocator_type& allocator); + // this_type& operator=(this_type&& x); - // template - // iterator emplace_hint(const_iterator position, Args&&... args); - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - // insert_return_type emplace(value_type&& value); - // iterator emplace_hint(const_iterator position, value_type&& value); - #endif + // template + // insert_return_type emplace(Args&&... args); - // insert_return_type emplace(const value_type& value); - // iterator emplace_hint(const_iterator position, const value_type& value); - #endif + // template + // iterator emplace_hint(const_iterator position, Args&&... args); - #if EASTL_MOVE_SEMANTICS_ENABLED - // template // Requires that "value_type is constructible from forward

(otherValue)." - // insert_return_type insert(P&& otherValue); + // template // Requires that "value_type is constructible from forward

(otherValue)." + // insert_return_type insert(P&& otherValue); - // iterator insert(const_iterator hint, value_type&& value); - #endif + // iterator insert(const_iterator hint, value_type&& value); // Regression of user reported compiler error in hashtable sfinae mechanism { @@ -1337,7 +1323,7 @@ int TestHash() // // error: 'eastl::pair::pair(T1&&) [with T1 = const int&; T2 = const int&]' cannot be overloaded // error: with 'eastl::pair::pair(const T1&) [with T1 = const int&; T2 = const int&]' - #if EASTL_MOVE_SEMANTICS_ENABLED && !defined(EA_COMPILER_GNUC) + #if !defined(EA_COMPILER_GNUC) { EA_DISABLE_VC_WARNING(4626) struct Key diff --git a/test/source/TestIterator.cpp b/test/source/TestIterator.cpp index 37d5d913..c4782204 100644 --- a/test/source/TestIterator.cpp +++ b/test/source/TestIterator.cpp @@ -124,7 +124,6 @@ int TestIterator_moveIterator() { int nErrorCount = 0; - #if EASTL_MOVE_SEMANTICS_ENABLED { eastl::vector v = {0, 1, 42, 2}; const auto constBeginMoveIter = eastl::make_move_iterator(v.begin()); @@ -139,7 +138,6 @@ int TestIterator_moveIterator() 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)); } - #endif return nErrorCount; } @@ -182,19 +180,17 @@ int TestIterator() { // move_iterator // move_iterator make_move_iterator(Iterator mi) - #if EASTL_MOVE_SEMANTICS_ENABLED - typedef eastl::vector StringArray; + typedef eastl::vector StringArray; - StringArray src; - for(eastl_size_t i = 0; i < 4; i++) - src.push_back(eastl::string(1, (char8_t)('0' + i))); // v should become {"0", "1", "2", "3"}; + StringArray src; + for(eastl_size_t i = 0; i < 4; i++) + src.push_back(eastl::string(1, (char8_t)('0' + i))); // v should become {"0", "1", "2", "3"}; - // Moves the values out of the string array and into the result. - StringArray dst(eastl::make_move_iterator(src.begin()), eastl::make_move_iterator(src.end())); + // Moves the values out of the string array and into the result. + StringArray dst(eastl::make_move_iterator(src.begin()), eastl::make_move_iterator(src.end())); - EATEST_VERIFY((src.size() == 4) && (src[0] == "") && (src[3] == "")); - EATEST_VERIFY((dst.size() == 4) && (dst[0] == "0") && (dst[3] == "3")); - #endif + EATEST_VERIFY((src.size() == 4) && (src[0] == "") && (src[3] == "")); + EATEST_VERIFY((dst.size() == 4) && (dst[0] == "0") && (dst[3] == "3")); } { @@ -333,9 +329,7 @@ int TestIterator() static_assert((eastl::is_iterator_wrapper*>::value == false), "is_iterator_wrapper failure"); static_assert((eastl::is_iterator_wrapper >::value == false), "is_iterator_wrapper failure"); static_assert((eastl::is_iterator_wrapper >::value == true), "is_iterator_wrapper failure"); - #if EASTL_MOVE_SEMANTICS_ENABLED - static_assert((eastl::is_iterator_wrapper::iterator> >::value == true), "is_iterator_wrapper failure"); - #endif + static_assert((eastl::is_iterator_wrapper::iterator> >::value == true), "is_iterator_wrapper failure"); } @@ -345,34 +339,24 @@ int TestIterator() int* pInt = eastl::unwrap_iterator(&intArray[0]); intArray[0] = 17; EATEST_VERIFY(*pInt == 17); - #if !defined(EA_COMPILER_NO_DECLTYPE) - static_assert((eastl::is_same::value == true), "unwrap_iterator failure"); - #endif + static_assert((eastl::is_same::value == true), "unwrap_iterator failure"); eastl::generic_iterator giIntArray(intArray); pInt = eastl::unwrap_iterator(giIntArray); intArray[0] = 18; EATEST_VERIFY(*pInt == 18); - #if !defined(EA_COMPILER_NO_DECLTYPE) - static_assert((eastl::is_same::value == true), "unwrap_iterator failure"); - #endif + static_assert((eastl::is_same::value == true), "unwrap_iterator failure"); eastl::vector intVector(4, 19); eastl::vector::iterator itVector = eastl::unwrap_iterator(intVector.begin()); EATEST_VERIFY(*itVector == 19); - #if !defined(EA_COMPILER_NO_DECLTYPE) - static_assert((eastl::is_same::iterator>::value == true), "unwrap_iterator failure"); - #endif + static_assert((eastl::is_same::iterator>::value == true), "unwrap_iterator failure"); - #if EASTL_MOVE_SEMANTICS_ENABLED - eastl::move_iterator::iterator> miIntVector(intVector.begin()); - itVector = eastl::unwrap_iterator(miIntVector); - intVector[0] = 20; - EATEST_VERIFY(*itVector == 20); - #if !defined(EA_COMPILER_NO_DECLTYPE) - static_assert((eastl::is_same::iterator>::value == true), "unwrap_iterator failure"); - #endif - #endif + eastl::move_iterator::iterator> miIntVector(intVector.begin()); + itVector = eastl::unwrap_iterator(miIntVector); + intVector[0] = 20; + EATEST_VERIFY(*itVector == 20); + static_assert((eastl::is_same::iterator>::value == true), "unwrap_iterator failure"); } return nErrorCount; diff --git a/test/source/TestList.cpp b/test/source/TestList.cpp index 6c2a7de4..490fdc04 100644 --- a/test/source/TestList.cpp +++ b/test/source/TestList.cpp @@ -944,6 +944,45 @@ int TestList() VERIFY(a == ref); } + #if 0 + // user reported regression + // + // Details can be found at: https://github.com/electronicarts/EASTL/issues/199 + // + // The eastl::list has a fallback mechanism to copy node values if the list + // allocator instances don't compare equal. The standard allows this to be + // undefined behaviour but we could potential break user code so we have to + // deprecate it over time. + // + // https://en.cppreference.com/w/cpp/container/list/splice + // + // "No elements are copied or moved, only the internal pointers of the list + // nodes are re-pointed. The behavior is undefined if: get_allocator() != + // other.get_allocator()." + // + { + struct C + { + C() = default; + C(const C&) = delete; + C(C&&) = delete; + + C& operator=(const C&) = delete; + C& operator=(C&&) = delete; + }; + + eastl::list l0, l1; + + l0.emplace_back(); + l0.emplace_back(); + + l1.emplace_back(); + l1.emplace_back(); + + l0.splice(l0.end(), l1, l1.begin()); + } + #endif + return nErrorCount; } diff --git a/test/source/TestMap.h b/test/source/TestMap.h index 864e441b..db0ff9da 100644 --- a/test/source/TestMap.h +++ b/test/source/TestMap.h @@ -94,39 +94,38 @@ int TestMapConstruction() // operator=(map&&) - #if EASTL_MOVE_SEMANTICS_ENABLED - // We test just the EASTL container here. - eastl::scoped_ptr pT1P(new T1); - eastl::scoped_ptr pT1Q(new T1); - T1& t1P = *pT1P; - T1& t1Q = *pT1Q; - - typename T1::key_type k10(0); - typename T1::key_type k11(1); - typename T1::key_type k12(2); - typename T1::key_type k13(3); - typename T1::key_type k14(4); - typename T1::key_type k15(5); - - typename T1::value_type v10(k10, typename T1::mapped_type(0)); - typename T1::value_type v11(k11, typename T1::mapped_type(1)); - typename T1::value_type v12(k12, typename T1::mapped_type(2)); - typename T1::value_type v13(k13, typename T1::mapped_type(3)); - typename T1::value_type v14(k14, typename T1::mapped_type(4)); - typename T1::value_type v15(k15, typename T1::mapped_type(5)); - - t1P.insert(v10); - t1P.insert(v11); - t1P.insert(v12); - - t1Q.insert(v13); - t1Q.insert(v14); - t1Q.insert(v15); - - t1Q = eastl::move(t1P); // We are effectively requesting to swap t1A with t1B. - //EATEST_VERIFY((t1P.size() == 3) && (t1P.find(k13) != t1P.end()) && (t1P.find(k14) != t1P.end()) && (t1P.find(k15) != t1P.end())); // Currently operator=(this_type&& x) clears x instead of swapping with it. - EATEST_VERIFY((t1Q.size() == 3) && (t1Q.find(k10) != t1Q.end()) && (t1Q.find(k11) != t1Q.end()) && (t1Q.find(k12) != t1Q.end())); - #endif + // We test just the EASTL container here. + eastl::scoped_ptr pT1P(new T1); + eastl::scoped_ptr pT1Q(new T1); + T1& t1P = *pT1P; + T1& t1Q = *pT1Q; + + typename T1::key_type k10(0); + typename T1::key_type k11(1); + typename T1::key_type k12(2); + typename T1::key_type k13(3); + typename T1::key_type k14(4); + typename T1::key_type k15(5); + + typename T1::value_type v10(k10, typename T1::mapped_type(0)); + typename T1::value_type v11(k11, typename T1::mapped_type(1)); + typename T1::value_type v12(k12, typename T1::mapped_type(2)); + typename T1::value_type v13(k13, typename T1::mapped_type(3)); + typename T1::value_type v14(k14, typename T1::mapped_type(4)); + typename T1::value_type v15(k15, typename T1::mapped_type(5)); + + t1P.insert(v10); + t1P.insert(v11); + t1P.insert(v12); + + t1Q.insert(v13); + t1Q.insert(v14); + t1Q.insert(v15); + + t1Q = eastl::move(t1P); // We are effectively requesting to swap t1A with t1B. + //EATEST_VERIFY((t1P.size() == 3) && (t1P.find(k13) != t1P.end()) && (t1P.find(k14) != t1P.end()) && (t1P.find(k15) != t1P.end())); // Currently operator=(this_type&& x) clears x instead of swapping with it. + EATEST_VERIFY((t1Q.size() == 3) && (t1Q.find(k10) != t1Q.end()) && (t1Q.find(k11) != t1Q.end()) && (t1Q.find(k12) != t1Q.end())); + // swap t1E.swap(t1D); @@ -707,47 +706,45 @@ int TestMapCpp11() TestObject to0(0); TestObject to1(1); - #if EASTL_MOVE_SEMANTICS_ENABLED - toMapInsertResult = toMap.emplace(value_type(0, to0)); - EATEST_VERIFY(toMapInsertResult.second == true); - //EATEST_VERIFY((TestObject::sTOCopyCtorCount == 2) && (TestObject::sTOMoveCtorCount == 1)); // Disabled until we can guarantee its behavior and deal with how it's different between compilers of differing C++11 support. - - toMapInsertResult = toMap.emplace(value_type(1, eastl::move(to1))); - EATEST_VERIFY(toMapInsertResult.second == true); - - // insert_return_type t1A.emplace(value_type&& value); - TestObject to4(4); - value_type value40(4, to4); - EATEST_VERIFY(toMap.find(4) == toMap.end()); - EATEST_VERIFY(value40.second.mX == 4); // It should change to 0 below during the move swap. - toMapInsertResult = toMap.emplace(eastl::move(value40)); - EATEST_VERIFY(toMapInsertResult.second == true); - EATEST_VERIFY(toMap.find(4) != toMap.end()); - EATEST_VERIFY(value40.second.mX == 0); - - value_type value41(4, to4); - toMapInsertResult = toMap.emplace(eastl::move(value41)); - EATEST_VERIFY(toMapInsertResult.second == false); - EATEST_VERIFY(toMap.find(4) != toMap.end()); - - // iterator t1A.emplace_hint(const_iterator position, value_type&& value); - TestObject to5(5); - value_type value50(5, to5); - toMapInsertResult = toMap.emplace(eastl::move(value50)); - EATEST_VERIFY(toMapInsertResult.second == true); - EATEST_VERIFY(toMap.find(5) != toMap.end()); - - value_type value51(5, to5); - toMapIterator = toMap.emplace_hint(toMapInsertResult.first, eastl::move(value51)); - EATEST_VERIFY(toMapIterator->first == 5); - EATEST_VERIFY(toMap.find(5) != toMap.end()); - - TestObject to6(6); - value_type value6(6, to6); - toMapIterator = toMap.emplace_hint(toMap.begin(), eastl::move(value6)); // specify a bad hint. Insertion should still work. - EATEST_VERIFY(toMapIterator->first == 6); - EATEST_VERIFY(toMap.find(6) != toMap.end()); - #endif + toMapInsertResult = toMap.emplace(value_type(0, to0)); + EATEST_VERIFY(toMapInsertResult.second == true); + //EATEST_VERIFY((TestObject::sTOCopyCtorCount == 2) && (TestObject::sTOMoveCtorCount == 1)); // Disabled until we can guarantee its behavior and deal with how it's different between compilers of differing C++11 support. + + toMapInsertResult = toMap.emplace(value_type(1, eastl::move(to1))); + EATEST_VERIFY(toMapInsertResult.second == true); + + // insert_return_type t1A.emplace(value_type&& value); + TestObject to4(4); + value_type value40(4, to4); + EATEST_VERIFY(toMap.find(4) == toMap.end()); + EATEST_VERIFY(value40.second.mX == 4); // It should change to 0 below during the move swap. + toMapInsertResult = toMap.emplace(eastl::move(value40)); + EATEST_VERIFY(toMapInsertResult.second == true); + EATEST_VERIFY(toMap.find(4) != toMap.end()); + EATEST_VERIFY(value40.second.mX == 0); + + value_type value41(4, to4); + toMapInsertResult = toMap.emplace(eastl::move(value41)); + EATEST_VERIFY(toMapInsertResult.second == false); + EATEST_VERIFY(toMap.find(4) != toMap.end()); + + // iterator t1A.emplace_hint(const_iterator position, value_type&& value); + TestObject to5(5); + value_type value50(5, to5); + toMapInsertResult = toMap.emplace(eastl::move(value50)); + EATEST_VERIFY(toMapInsertResult.second == true); + EATEST_VERIFY(toMap.find(5) != toMap.end()); + + value_type value51(5, to5); + toMapIterator = toMap.emplace_hint(toMapInsertResult.first, eastl::move(value51)); + EATEST_VERIFY(toMapIterator->first == 5); + EATEST_VERIFY(toMap.find(5) != toMap.end()); + + TestObject to6(6); + value_type value6(6, to6); + toMapIterator = toMap.emplace_hint(toMap.begin(), eastl::move(value6)); // specify a bad hint. Insertion should still work. + EATEST_VERIFY(toMapIterator->first == 6); + EATEST_VERIFY(toMap.find(6) != toMap.end()); TestObject to2(2); EATEST_VERIFY(toMap.find(2) == toMap.end()); @@ -776,36 +773,34 @@ int TestMapCpp11() EATEST_VERIFY(toMapIterator->first == 8); EATEST_VERIFY(toMap.find(8) != toMap.end()); - #if EASTL_MOVE_SEMANTICS_ENABLED - // insert_return_type t1A.insert(value_type&& value); - TestObject to3(3); - EATEST_VERIFY(toMap.find(3) == toMap.end()); - toMapInsertResult = toMap.insert(value_type(3, to3)); - EATEST_VERIFY(toMapInsertResult.second == true); - EATEST_VERIFY(toMap.find(3) != toMap.end()); - toMapInsertResult = toMap.insert(value_type(3, to3)); - EATEST_VERIFY(toMapInsertResult.second == false); - EATEST_VERIFY(toMap.find(3) != toMap.end()); - - - // iterator t1A.insert(const_iterator position, value_type&& value); - TestObject to9(9); - value_type value90(9, to9); - toMapInsertResult = toMap.emplace(eastl::move(value90)); - EATEST_VERIFY(toMapInsertResult.second == true); - EATEST_VERIFY(toMap.find(9) != toMap.end()); - - value_type value91(9, to9); - toMapIterator = toMap.emplace_hint(toMapInsertResult.first, eastl::move(value91)); - EATEST_VERIFY(toMapIterator->first == 9); - EATEST_VERIFY(toMap.find(9) != toMap.end()); - - TestObject to10(10); - value_type value10(10, to10); - toMapIterator = toMap.emplace_hint(toMap.begin(), eastl::move(value10)); // specify a bad hint. Insertion should still work. - EATEST_VERIFY(toMapIterator->first == 10); - EATEST_VERIFY(toMap.find(10) != toMap.end()); - #endif + // insert_return_type t1A.insert(value_type&& value); + TestObject to3(3); + EATEST_VERIFY(toMap.find(3) == toMap.end()); + toMapInsertResult = toMap.insert(value_type(3, to3)); + EATEST_VERIFY(toMapInsertResult.second == true); + EATEST_VERIFY(toMap.find(3) != toMap.end()); + toMapInsertResult = toMap.insert(value_type(3, to3)); + EATEST_VERIFY(toMapInsertResult.second == false); + EATEST_VERIFY(toMap.find(3) != toMap.end()); + + + // iterator t1A.insert(const_iterator position, value_type&& value); + TestObject to9(9); + value_type value90(9, to9); + toMapInsertResult = toMap.emplace(eastl::move(value90)); + EATEST_VERIFY(toMapInsertResult.second == true); + EATEST_VERIFY(toMap.find(9) != toMap.end()); + + value_type value91(9, to9); + toMapIterator = toMap.emplace_hint(toMapInsertResult.first, eastl::move(value91)); + EATEST_VERIFY(toMapIterator->first == 9); + EATEST_VERIFY(toMap.find(9) != toMap.end()); + + TestObject to10(10); + value_type value10(10, to10); + toMapIterator = toMap.emplace_hint(toMap.begin(), eastl::move(value10)); // specify a bad hint. Insertion should still work. + EATEST_VERIFY(toMapIterator->first == 10); + EATEST_VERIFY(toMap.find(10) != toMap.end()); return nErrorCount; } @@ -867,47 +862,45 @@ int TestMultimapCpp11() TestObject to0(0); TestObject to1(1); - #if EASTL_MOVE_SEMANTICS_ENABLED - toMapIterator = toMap.emplace(value_type(0, to0)); - EATEST_VERIFY(toMapIterator->first == 0); - //EATEST_VERIFY((TestObject::sTOCopyCtorCount == 2) && (TestObject::sTOMoveCtorCount == 1)); // Disabled until we can guarantee its behavior and deal with how it's different between compilers of differing C++11 support. - - toMapIterator = toMap.emplace(value_type(1, eastl::move(to1))); - EATEST_VERIFY(toMapIterator->first == 1); - - // insert_return_type t1A.emplace(value_type&& value); - TestObject to4(4); - value_type value40(4, to4); - EATEST_VERIFY(toMap.find(4) == toMap.end()); - EATEST_VERIFY(value40.second.mX == 4); // It should change to 0 below during the move swap. - toMapIterator = toMap.emplace(eastl::move(value40)); - EATEST_VERIFY(toMapIterator->first == 4); - EATEST_VERIFY(toMap.find(4) != toMap.end()); - EATEST_VERIFY(value40.second.mX == 0); - - value_type value41(4, to4); - toMapIterator = toMap.emplace(eastl::move(value41)); - EATEST_VERIFY(toMapIterator->first == 4); - EATEST_VERIFY(toMap.find(4) != toMap.end()); - - // iterator t1A.emplace_hint(const_iterator position, value_type&& value); - TestObject to5(5); - value_type value50(5, to5); - toMapIterator = toMap.emplace(eastl::move(value50)); - EATEST_VERIFY(toMapIterator->first == 5); - EATEST_VERIFY(toMap.find(5) != toMap.end()); - - value_type value51(5, to5); - toMapIterator = toMap.emplace_hint(toMapIterator, eastl::move(value51)); - EATEST_VERIFY(toMapIterator->first == 5); - EATEST_VERIFY(toMap.find(5) != toMap.end()); - - TestObject to6(6); - value_type value6(6, to6); - toMapIterator = toMap.emplace_hint(toMap.begin(), eastl::move(value6)); // specify a bad hint. Insertion should still work. - EATEST_VERIFY(toMapIterator->first == 6); - EATEST_VERIFY(toMap.find(6) != toMap.end()); - #endif + toMapIterator = toMap.emplace(value_type(0, to0)); + EATEST_VERIFY(toMapIterator->first == 0); + //EATEST_VERIFY((TestObject::sTOCopyCtorCount == 2) && (TestObject::sTOMoveCtorCount == 1)); // Disabled until we can guarantee its behavior and deal with how it's different between compilers of differing C++11 support. + + toMapIterator = toMap.emplace(value_type(1, eastl::move(to1))); + EATEST_VERIFY(toMapIterator->first == 1); + + // insert_return_type t1A.emplace(value_type&& value); + TestObject to4(4); + value_type value40(4, to4); + EATEST_VERIFY(toMap.find(4) == toMap.end()); + EATEST_VERIFY(value40.second.mX == 4); // It should change to 0 below during the move swap. + toMapIterator = toMap.emplace(eastl::move(value40)); + EATEST_VERIFY(toMapIterator->first == 4); + EATEST_VERIFY(toMap.find(4) != toMap.end()); + EATEST_VERIFY(value40.second.mX == 0); + + value_type value41(4, to4); + toMapIterator = toMap.emplace(eastl::move(value41)); + EATEST_VERIFY(toMapIterator->first == 4); + EATEST_VERIFY(toMap.find(4) != toMap.end()); + + // iterator t1A.emplace_hint(const_iterator position, value_type&& value); + TestObject to5(5); + value_type value50(5, to5); + toMapIterator = toMap.emplace(eastl::move(value50)); + EATEST_VERIFY(toMapIterator->first == 5); + EATEST_VERIFY(toMap.find(5) != toMap.end()); + + value_type value51(5, to5); + toMapIterator = toMap.emplace_hint(toMapIterator, eastl::move(value51)); + EATEST_VERIFY(toMapIterator->first == 5); + EATEST_VERIFY(toMap.find(5) != toMap.end()); + + TestObject to6(6); + value_type value6(6, to6); + toMapIterator = toMap.emplace_hint(toMap.begin(), eastl::move(value6)); // specify a bad hint. Insertion should still work. + EATEST_VERIFY(toMapIterator->first == 6); + EATEST_VERIFY(toMap.find(6) != toMap.end()); TestObject to2(2); EATEST_VERIFY(toMap.find(2) == toMap.end()); @@ -936,36 +929,34 @@ int TestMultimapCpp11() EATEST_VERIFY(toMapIterator->first == 8); EATEST_VERIFY(toMap.find(8) != toMap.end()); - #if EASTL_MOVE_SEMANTICS_ENABLED - // insert_return_type t1A.insert(value_type&& value); - TestObject to3(3); - EATEST_VERIFY(toMap.find(3) == toMap.end()); - toMapIterator = toMap.insert(value_type(3, to3)); - EATEST_VERIFY(toMapIterator->first == 3); - EATEST_VERIFY(toMap.find(3) != toMap.end()); - toMapIterator = toMap.insert(value_type(3, to3)); - EATEST_VERIFY(toMapIterator->first == 3); - EATEST_VERIFY(toMap.find(3) != toMap.end()); - - - // iterator t1A.insert(const_iterator position, value_type&& value); - TestObject to9(9); - value_type value90(9, to9); - toMapIterator = toMap.emplace(eastl::move(value90)); - EATEST_VERIFY(toMapIterator->first == 9); - EATEST_VERIFY(toMap.find(9) != toMap.end()); - - value_type value91(9, to9); - toMapIterator = toMap.emplace_hint(toMapIterator, eastl::move(value91)); - EATEST_VERIFY(toMapIterator->first == 9); - EATEST_VERIFY(toMap.find(9) != toMap.end()); - - TestObject to10(10); - value_type value10(10, to10); - toMapIterator = toMap.emplace_hint(toMap.begin(), eastl::move(value10)); // specify a bad hint. Insertion should still work. - EATEST_VERIFY(toMapIterator->first == 10); - EATEST_VERIFY(toMap.find(10) != toMap.end()); - #endif + // insert_return_type t1A.insert(value_type&& value); + TestObject to3(3); + EATEST_VERIFY(toMap.find(3) == toMap.end()); + toMapIterator = toMap.insert(value_type(3, to3)); + EATEST_VERIFY(toMapIterator->first == 3); + EATEST_VERIFY(toMap.find(3) != toMap.end()); + toMapIterator = toMap.insert(value_type(3, to3)); + EATEST_VERIFY(toMapIterator->first == 3); + EATEST_VERIFY(toMap.find(3) != toMap.end()); + + + // iterator t1A.insert(const_iterator position, value_type&& value); + TestObject to9(9); + value_type value90(9, to9); + toMapIterator = toMap.emplace(eastl::move(value90)); + EATEST_VERIFY(toMapIterator->first == 9); + EATEST_VERIFY(toMap.find(9) != toMap.end()); + + value_type value91(9, to9); + toMapIterator = toMap.emplace_hint(toMapIterator, eastl::move(value91)); + EATEST_VERIFY(toMapIterator->first == 9); + EATEST_VERIFY(toMap.find(9) != toMap.end()); + + TestObject to10(10); + value_type value10(10, to10); + toMapIterator = toMap.emplace_hint(toMap.begin(), eastl::move(value10)); // specify a bad hint. Insertion should still work. + EATEST_VERIFY(toMapIterator->first == 10); + EATEST_VERIFY(toMap.find(10) != toMap.end()); return nErrorCount; } diff --git a/test/source/TestRingBuffer.cpp b/test/source/TestRingBuffer.cpp index e4f41224..d6403807 100644 --- a/test/source/TestRingBuffer.cpp +++ b/test/source/TestRingBuffer.cpp @@ -32,11 +32,23 @@ template class eastl::ring_buffer< int, eastl::list >; template class eastl::ring_buffer< Align64, eastl::list >; template class eastl::ring_buffer< TestObject, eastl::list >; +// TODO(rparolin): To consider adding support for eastl::array. +// template class eastl::ring_buffer< int, eastl::array>; + typedef eastl::fixed_string RBFixedString; typedef eastl::fixed_vector RBFixedStringVector; typedef RBFixedStringVector::overflow_allocator_type RBFixedStringVectorOverflowAllocator; template class eastl::ring_buffer; +typedef eastl::fixed_vector RBFixedIntVector; +template class eastl::ring_buffer; +// template class eastl::ring_buffer; // currently fails to compile + +typedef eastl::fixed_vector RBFixedIntVectorWithOverFlow; +template class eastl::ring_buffer; +// template class eastl::ring_buffer; // currently fails to compile + + int TestRingBuffer() { diff --git a/test/source/TestSList.cpp b/test/source/TestSList.cpp index c3f3a8e4..048f1a3e 100644 --- a/test/source/TestSList.cpp +++ b/test/source/TestSList.cpp @@ -106,7 +106,6 @@ int TestSList() // slist(this_type&& x); { - #if EASTL_MOVE_SEMANTICS_ENABLED slist list1; list1.resize(100,42); @@ -115,7 +114,6 @@ int TestSList() VERIFY(list1.empty()); VERIFY(!list2.empty()); VERIFY(list1 != list2); - #endif } // slist(this_type&& x, const allocator_type& allocator); @@ -145,15 +143,12 @@ int TestSList() // this_type& operator=(std::initializer_list); { - #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) slist list1 = {1,2,3,4,5,6,7,8}; VERIFY(!list1.empty()); - #endif } // this_type& operator=(this_type&& x); { - #if EASTL_MOVE_SEMANTICS_ENABLED slist list1; list1.resize(100, 42); slist list2 = eastl::move(list1); @@ -161,7 +156,6 @@ int TestSList() VERIFY(list1.empty()); VERIFY(!list2.empty()); VERIFY(list1 != list2); - #endif } // void swap(this_type& x); @@ -294,94 +288,42 @@ int TestSList() // void emplace_front(value_type&& value); // void emplace_front(const value_type& value); { - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - { - slist list1; - list1.emplace_front(42); - VERIFY(list1.front().mI == 42); - VERIFY(list1.front().mCopyCtor == 0); - VERIFY(list1.front().mMoveCtor == 0); - VERIFY(list1.size() == 1); - VERIFY(list1.validate()); + slist list1; + list1.emplace_front(42); + VERIFY(list1.front().mI == 42); + VERIFY(list1.front().mCopyCtor == 0); + VERIFY(list1.front().mMoveCtor == 0); + VERIFY(list1.size() == 1); + VERIFY(list1.validate()); - list1.emplace_front(1,2,3,4); - VERIFY(list1.front().mCopyCtor == 0); - VERIFY(list1.front().mMoveCtor == 0); - VERIFY(list1.front().mI == (1+2+3+4)); - VERIFY(list1.size() == 2); - VERIFY(list1.validate()); - } - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - { - slist list1; - list1.emplace_front(TestObj(1,2,3,4)); - VERIFY(list1.front().mI == (1+2+3+4)); - VERIFY(list1.front().mCopyCtor == 0); - VERIFY(list1.front().mMoveCtor == 1); - VERIFY(list1.size() == 1); - VERIFY(list1.validate()); - } - #endif - { - TestObj to1(1,2,3,4); - slist list1; - list1.emplace_front(to1); - VERIFY(list1.front().mI == (1+2+3+4)); - VERIFY(list1.front().mCopyCtor == 1); - VERIFY(list1.front().mMoveCtor == 0); - VERIFY(list1.size() == 1); - VERIFY(list1.validate()); - } - #endif + list1.emplace_front(1,2,3,4); + VERIFY(list1.front().mCopyCtor == 0); + VERIFY(list1.front().mMoveCtor == 0); + VERIFY(list1.front().mI == (1+2+3+4)); + VERIFY(list1.size() == 2); + VERIFY(list1.validate()); } // void push_front(const value_type& value); // reference push_front(); // void push_front(value_type&& value); { - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - { - slist list1; - list1.push_front(TestObj(42)); - VERIFY(list1.front().mI == 42); - VERIFY(list1.front().mCopyCtor == 0); - VERIFY(list1.front().mMoveCtor == 1); - VERIFY(list1.size() == 1); - - list1.push_front(); - VERIFY(list1.front().mCopyCtor == 0); - VERIFY(list1.front().mMoveCtor == 0); - VERIFY(list1.front().mI == 0); - VERIFY(list1.size() == 2); - - list1.push_front().mI = 1492; - VERIFY(list1.front().mI == 1492); - VERIFY(list1.validate()); - } - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - { - slist list1; - list1.push_front(TestObj(1,2,3,4)); - VERIFY(list1.front().mI == (1+2+3+4)); - VERIFY(list1.front().mCopyCtor == 0); - VERIFY(list1.front().mMoveCtor == 1); - VERIFY(list1.size() == 1); - VERIFY(list1.validate()); - } - #endif - { - TestObj to1(1,2,3,4); - slist list1; - list1.push_front(to1); - VERIFY(list1.front().mI == (1+2+3+4)); - VERIFY(list1.front().mCopyCtor == 1); - VERIFY(list1.front().mMoveCtor == 0); - VERIFY(list1.size() == 1); - VERIFY(list1.validate()); - } - #endif + slist list1; + list1.push_front(TestObj(42)); + VERIFY(list1.front().mI == 42); + VERIFY(list1.front().mCopyCtor == 0); + VERIFY(list1.front().mMoveCtor == 1); + VERIFY(list1.size() == 1); + + list1.push_front(); + VERIFY(list1.front().mCopyCtor == 0); + VERIFY(list1.front().mMoveCtor == 0); + VERIFY(list1.front().mI == 0); + VERIFY(list1.size() == 2); + + list1.push_front().mI = 1492; + VERIFY(list1.front().mI == 1492); + VERIFY(list1.validate()); } // void pop_front(); @@ -536,16 +478,13 @@ int TestSList() VERIFY(eastl::count_if(list1.begin(), list1.end(), [](int i) { return i == 42; }) == 10); VERIFY(list1.validate()); - #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) list1.insert_after(list1.begin(), {1,2,3,4,5,6,7,8,9,0}); VERIFY(list1.size() == 23); VERIFY(list1.validate()); - #endif } // iterator insert_after(const_iterator position, value_type&& value); { - #if EASTL_MOVE_SEMANTICS_ENABLED slist list1; VERIFY(list1.empty()); list1.push_front(); @@ -554,24 +493,20 @@ int TestSList() VERIFY(!list1.empty()); VERIFY((*inserted).mCopyCtor == 0); VERIFY((*inserted).mMoveCtor == 1); - #endif } // iterator insert_after(const_iterator position, InputIterator first, InputIterator last); { - #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) slist list1 = {0,1,2,3,4}; slist list2 = {9,8,7,6,5}; list1.insert_after(list1.begin(), list2.begin(), list2.end()); VERIFY(list1 == slist({0,9,8,7,6,5,1,2,3,4})); - #endif } // iterator emplace_after(const_iterator position, Args&&... args); // iterator emplace_after(const_iterator position, value_type&& value); // iterator emplace_after(const_iterator position, const value_type& value); { - #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED slist list1; list1.emplace_after(list1.before_begin(), 42); VERIFY(list1.front().mI == 42); @@ -586,35 +521,11 @@ int TestSList() VERIFY(list1.front().mI == (1+2+3+4)); VERIFY(list1.size() == 2); VERIFY(list1.validate()); - #else - #if EASTL_MOVE_SEMANTICS_ENABLED - { - slist list1; - list1.emplace_after(list1.before_begin(), TestObj(42)); - VERIFY(list1.front().mI == 42); - VERIFY(list1.front().mCopyCtor == 0); - VERIFY(list1.front().mMoveCtor == 1); - VERIFY(list1.size() == 1); - VERIFY(list1.validate()); - } - #endif - { - slist list1; - TestObj to(42); - list1.emplace_after(list1.before_begin(), to); - VERIFY(list1.front().mI == 42); - VERIFY(list1.front().mCopyCtor == 1); - VERIFY(list1.front().mMoveCtor == 0); - VERIFY(list1.size() == 1); - VERIFY(list1.validate()); - } - #endif } // iterator erase(const_iterator position); // iterator erase(const_iterator first, const_iterator last); { - #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) slist list1 = {0,1,2,3,4,5,6,7}; auto p = list1.begin(); @@ -627,13 +538,11 @@ int TestSList() VERIFY(list1 == slist({})); VERIFY(list1.size() == 0); VERIFY(list1.empty()); - #endif } // iterator erase_after(const_iterator position); // iterator erase_after(const_iterator before_first, const_iterator last); { - #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) slist list1 = {0,1,2,3,4,5,6,7}; auto p = list1.begin(); @@ -652,7 +561,6 @@ int TestSList() list1.erase_after(p, list1.end()); VERIFY(list1 == slist({0})); VERIFY(list1.validate()); - #endif } // void clear(); @@ -685,7 +593,6 @@ int TestSList() // void remove(const value_type& value); { - #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) slist list1 = {0,1,2,3,4}; slist list2 = {0,1,3,4}; @@ -694,7 +601,6 @@ int TestSList() VERIFY(list1 == list2); VERIFY(list1.validate()); VERIFY(list2.validate()); - #endif } // void remove_if(Predicate predicate); @@ -715,21 +621,18 @@ int TestSList() // void reverse() EA_NOEXCEPT; { - #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) slist list1 = {0,1,2,3,4}; slist list2 = {4,3,2,1,0}; VERIFY(list1 != list2); list1.reverse(); VERIFY(list1 == list2); - #endif } // void splice(const_iterator position, this_type& x); // void splice(const_iterator position, this_type& x, const_iterator i); // void splice(const_iterator position, this_type& x, const_iterator first, const_iterator last); { - #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) slist valid = {0,1,2,3,4,5,6,7}; { slist list1 = {0,1,2,3}; @@ -762,14 +665,12 @@ int TestSList() VERIFY(list1.validate()); VERIFY(list2.validate()); } - #endif } // void splice(const_iterator position, this_type&& x); // void splice(const_iterator position, this_type&& x, const_iterator i); // void splice(const_iterator position, this_type&& x, const_iterator first, const_iterator last); { - #if EASTL_MOVE_SEMANTICS_ENABLED && !defined(EA_COMPILER_NO_INITIALIZER_LISTS) { slist list1 = {0,1,2,3}; slist list2 = {4,5,6,7}; @@ -796,14 +697,12 @@ int TestSList() list1.splice(list1.begin(), eastl::move(list2), b, e); VERIFY(list1 == slist({4,5,0,1,2,3})); } - #endif } // void splice_after(const_iterator position, this_type& x); // void splice_after(const_iterator position, this_type& x, const_iterator i); // void splice_after(const_iterator position, this_type& x, const_iterator first, const_iterator last); { - #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) slist list1 = {0,1,2,3}; slist list2 = {4,5,6,7}; @@ -811,14 +710,12 @@ int TestSList() VERIFY(list1 == slist({0,4,5,6,7,1,2,3})); VERIFY(list1.validate()); VERIFY(list2.validate()); - #endif } // void splice_after(const_iterator position, this_type&& x); // void splice_after(const_iterator position, this_type&& x, const_iterator i); // void splice_after(const_iterator position, this_type&& x, const_iterator first, const_iterator last); { - #if EASTL_MOVE_SEMANTICS_ENABLED && !defined(EA_COMPILER_NO_INITIALIZER_LISTS) { slist list1 = {0,1,2,3}; slist list2 = {4,5,6,7}; @@ -845,12 +742,10 @@ int TestSList() list1.splice_after(list1.begin(), eastl::move(list2), b, e); VERIFY(list1 == slist({0,5,6,1,2,3})); } - #endif } // void sort(); { - #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) slist list1 = {0, 1, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 2, 2, 1, 0}; VERIFY(!eastl::is_sorted(eastl::begin(list1), eastl::end(list1))); VERIFY(list1.validate()); @@ -859,20 +754,17 @@ int TestSList() VERIFY(eastl::is_sorted(eastl::begin(list1), eastl::end(list1))); VERIFY(list1.validate()); - #endif } // template // void sort(Compare compare); { - #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) auto compare = [](int a, int b) { return a > b;}; slist list1 = {0, 1, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 2, 2, 1, 0}; VERIFY(!eastl::is_sorted(eastl::begin(list1), eastl::end(list1), compare)); list1.sort(compare); VERIFY(eastl::is_sorted(eastl::begin(list1), eastl::end(list1), compare)); - #endif } return nErrorCount; diff --git a/test/source/TestSet.h b/test/source/TestSet.h index e2db25d4..16f55c7a 100644 --- a/test/source/TestSet.h +++ b/test/source/TestSet.h @@ -95,31 +95,29 @@ int TestSetConstruction() // operator=(set&&) - #if EASTL_MOVE_SEMANTICS_ENABLED - // We test just the EASTL container here. - eastl::scoped_ptr pT1P(new T1); // We use a pointers instead of concrete object because it's size may be huge. - eastl::scoped_ptr pT1Q(new T1); - T1& t1P = *pT1P; - T1& t1Q = *pT1Q; - - typename T1::value_type v10(0); - typename T1::value_type v11(1); - typename T1::value_type v12(2); - typename T1::value_type v13(3); - typename T1::value_type v14(4); - typename T1::value_type v15(5); - - t1P.insert(v10); - t1P.insert(v11); - t1P.insert(v12); - - t1Q.insert(v13); - t1Q.insert(v14); - t1Q.insert(v15); - - t1Q = eastl::move(t1P); // We are effectively requesting to swap t1A with t1B. - //EATEST_VERIFY((t1P.size() == 3) && (t1P.find(v13) != t1P.end()) && (t1P.find(v14) != t1P.end()) && (t1P.find(v15) != t1P.end())); // Currently operator=(this_type&& x) clears x instead of swapping with it. - #endif + // We test just the EASTL container here. + eastl::scoped_ptr pT1P(new T1); // We use a pointers instead of concrete object because it's size may be huge. + eastl::scoped_ptr pT1Q(new T1); + T1& t1P = *pT1P; + T1& t1Q = *pT1Q; + + typename T1::value_type v10(0); + typename T1::value_type v11(1); + typename T1::value_type v12(2); + typename T1::value_type v13(3); + typename T1::value_type v14(4); + typename T1::value_type v15(5); + + t1P.insert(v10); + t1P.insert(v11); + t1P.insert(v12); + + t1Q.insert(v13); + t1Q.insert(v14); + t1Q.insert(v15); + + t1Q = eastl::move(t1P); // We are effectively requesting to swap t1A with t1B. + //EATEST_VERIFY((t1P.size() == 3) && (t1P.find(v13) != t1P.end()) && (t1P.find(v14) != t1P.end()) && (t1P.find(v15) != t1P.end())); // Currently operator=(this_type&& x) clears x instead of swapping with it. // swap @@ -664,26 +662,14 @@ int TestSetCpp11() { int nErrorCount = 0; - //#if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - // template - // insert_return_type emplace(Args&&... args); - // - // template - // iterator emplace_hint(const_iterator position, Args&&... args); - //#else - // #if EASTL_MOVE_SEMANTICS_ENABLED - // insert_return_type emplace(value_type&& value); - // iterator emplace_hint(const_iterator position, value_type&& value); - // #endif + // template + // insert_return_type emplace(Args&&... args); // - // insert_return_type emplace(const value_type& value); - // iterator emplace_hint(const_iterator position, const value_type& value); - //#endif + // template + // iterator emplace_hint(const_iterator position, Args&&... args); // - //#if EASTL_MOVE_SEMANTICS_ENABLED - // insert_return_type insert(value_type&& value); - // iterator insert(const_iterator position, value_type&& value); - //#endif + // insert_return_type insert(value_type&& value); + // iterator insert(const_iterator position, value_type&& value); TestObject::Reset(); typedef T1 TOSet; @@ -694,44 +680,42 @@ int TestSetCpp11() TestObject to0(0); TestObject to1(1); - #if EASTL_MOVE_SEMANTICS_ENABLED - toSetInsertResult = toSet.emplace(to0); - EATEST_VERIFY(toSetInsertResult.second == true); - //EATEST_VERIFY((TestObject::sTOCopyCtorCount == 2) && (TestObject::sTOMoveCtorCount == 1)); // Disabled until we can guarantee its behavior and deal with how it's different between compilers of differing C++11 support. - - toSetInsertResult = toSet.emplace(eastl::move(to1)); - EATEST_VERIFY(toSetInsertResult.second == true); - - // insert_return_type t1A.emplace(value_type&& value); - TestObject to40(4); - EATEST_VERIFY(toSet.find(to40) == toSet.end()); - EATEST_VERIFY(to40.mX == 4); // It should change to 0 below during the move swap. - toSetInsertResult = toSet.emplace(eastl::move(to40)); - EATEST_VERIFY(toSetInsertResult.second == true); - EATEST_VERIFY(toSet.find(to40) != toSet.end()); - EATEST_VERIFY(to40.mX == 0); - - TestObject to41(4); - toSetInsertResult = toSet.emplace(eastl::move(to41)); - EATEST_VERIFY(toSetInsertResult.second == false); - EATEST_VERIFY(toSet.find(to41) != toSet.end()); - - // iterator t1A.emplace_hint(const_iterator position, value_type&& value); - TestObject to50(5); - toSetInsertResult = toSet.emplace(eastl::move(to50)); - EATEST_VERIFY(toSetInsertResult.second == true); - EATEST_VERIFY(toSet.find(to50) != toSet.end()); - - TestObject to51(5); - toSetIterator = toSet.emplace_hint(toSetInsertResult.first, eastl::move(to51)); - EATEST_VERIFY(*toSetIterator == TestObject(5)); - EATEST_VERIFY(toSet.find(to51) != toSet.end()); - - TestObject to6(6); - toSetIterator = toSet.emplace_hint(toSet.begin(), eastl::move(to6)); // specify a bad hint. Insertion should still work. - EATEST_VERIFY(*toSetIterator == TestObject(6)); - EATEST_VERIFY(toSet.find(to6) != toSet.end()); - #endif + toSetInsertResult = toSet.emplace(to0); + EATEST_VERIFY(toSetInsertResult.second == true); + //EATEST_VERIFY((TestObject::sTOCopyCtorCount == 2) && (TestObject::sTOMoveCtorCount == 1)); // Disabled until we can guarantee its behavior and deal with how it's different between compilers of differing C++11 support. + + toSetInsertResult = toSet.emplace(eastl::move(to1)); + EATEST_VERIFY(toSetInsertResult.second == true); + + // insert_return_type t1A.emplace(value_type&& value); + TestObject to40(4); + EATEST_VERIFY(toSet.find(to40) == toSet.end()); + EATEST_VERIFY(to40.mX == 4); // It should change to 0 below during the move swap. + toSetInsertResult = toSet.emplace(eastl::move(to40)); + EATEST_VERIFY(toSetInsertResult.second == true); + EATEST_VERIFY(toSet.find(to40) != toSet.end()); + EATEST_VERIFY(to40.mX == 0); + + TestObject to41(4); + toSetInsertResult = toSet.emplace(eastl::move(to41)); + EATEST_VERIFY(toSetInsertResult.second == false); + EATEST_VERIFY(toSet.find(to41) != toSet.end()); + + // iterator t1A.emplace_hint(const_iterator position, value_type&& value); + TestObject to50(5); + toSetInsertResult = toSet.emplace(eastl::move(to50)); + EATEST_VERIFY(toSetInsertResult.second == true); + EATEST_VERIFY(toSet.find(to50) != toSet.end()); + + TestObject to51(5); + toSetIterator = toSet.emplace_hint(toSetInsertResult.first, eastl::move(to51)); + EATEST_VERIFY(*toSetIterator == TestObject(5)); + EATEST_VERIFY(toSet.find(to51) != toSet.end()); + + TestObject to6(6); + toSetIterator = toSet.emplace_hint(toSet.begin(), eastl::move(to6)); // specify a bad hint. Insertion should still work. + EATEST_VERIFY(*toSetIterator == TestObject(6)); + EATEST_VERIFY(toSet.find(to6) != toSet.end()); TestObject to2(2); EATEST_VERIFY(toSet.find(to2) == toSet.end()); @@ -758,34 +742,32 @@ int TestSetCpp11() EATEST_VERIFY(*toSetIterator == to8); EATEST_VERIFY(toSet.find(to8) != toSet.end()); - #if EASTL_MOVE_SEMANTICS_ENABLED - //pair t1A.insert(value_type&& value); - TestObject to3(3); - EATEST_VERIFY(toSet.find(to3) == toSet.end()); - toSetInsertResult = toSet.insert(TestObject(to3)); - EATEST_VERIFY(toSetInsertResult.second == true); - EATEST_VERIFY(toSet.find(to3) != toSet.end()); - toSetInsertResult = toSet.insert(TestObject(to3)); - EATEST_VERIFY(toSetInsertResult.second == false); - EATEST_VERIFY(toSet.find(to3) != toSet.end()); - - - // iterator t1A.insert(const_iterator position, value_type&& value); - TestObject to90(9); - toSetInsertResult = toSet.emplace(eastl::move(to90)); - EATEST_VERIFY(toSetInsertResult.second == true); - EATEST_VERIFY(toSet.find(to90) != toSet.end()); - - TestObject to91(9); - toSetIterator = toSet.emplace_hint(toSetInsertResult.first, eastl::move(to91)); - EATEST_VERIFY(*toSetIterator == TestObject(9)); - EATEST_VERIFY(toSet.find(to91) != toSet.end()); - - TestObject to10(10); - toSetIterator = toSet.emplace_hint(toSet.begin(), eastl::move(to10)); // specify a bad hint. Insertion should still work. - EATEST_VERIFY(*toSetIterator == TestObject(10)); - EATEST_VERIFY(toSet.find(to10) != toSet.end()); - #endif + //pair t1A.insert(value_type&& value); + TestObject to3(3); + EATEST_VERIFY(toSet.find(to3) == toSet.end()); + toSetInsertResult = toSet.insert(TestObject(to3)); + EATEST_VERIFY(toSetInsertResult.second == true); + EATEST_VERIFY(toSet.find(to3) != toSet.end()); + toSetInsertResult = toSet.insert(TestObject(to3)); + EATEST_VERIFY(toSetInsertResult.second == false); + EATEST_VERIFY(toSet.find(to3) != toSet.end()); + + + // iterator t1A.insert(const_iterator position, value_type&& value); + TestObject to90(9); + toSetInsertResult = toSet.emplace(eastl::move(to90)); + EATEST_VERIFY(toSetInsertResult.second == true); + EATEST_VERIFY(toSet.find(to90) != toSet.end()); + + TestObject to91(9); + toSetIterator = toSet.emplace_hint(toSetInsertResult.first, eastl::move(to91)); + EATEST_VERIFY(*toSetIterator == TestObject(9)); + EATEST_VERIFY(toSet.find(to91) != toSet.end()); + + TestObject to10(10); + toSetIterator = toSet.emplace_hint(toSet.begin(), eastl::move(to10)); // specify a bad hint. Insertion should still work. + EATEST_VERIFY(*toSetIterator == TestObject(10)); + EATEST_VERIFY(toSet.find(to10) != toSet.end()); return nErrorCount; } @@ -808,26 +790,14 @@ int TestMultisetCpp11() { int nErrorCount = 0; - //#if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED - // template - // insert_return_type emplace(Args&&... args); - // - // template - // iterator emplace_hint(const_iterator position, Args&&... args); - //#else - // #if EASTL_MOVE_SEMANTICS_ENABLED - // insert_return_type emplace(value_type&& value); - // iterator emplace_hint(const_iterator position, value_type&& value); - // #endif + // template + // insert_return_type emplace(Args&&... args); // - // insert_return_type emplace(const value_type& value); - // iterator emplace_hint(const_iterator position, const value_type& value); - //#endif + // template + // iterator emplace_hint(const_iterator position, Args&&... args); // - //#if EASTL_MOVE_SEMANTICS_ENABLED - // insert_return_type insert(value_type&& value); - // iterator insert(const_iterator position, value_type&& value); - //#endif + // insert_return_type insert(value_type&& value); + // iterator insert(const_iterator position, value_type&& value); TestObject::Reset(); typedef T1 TOSet; @@ -837,44 +807,42 @@ int TestMultisetCpp11() TestObject to0(0); TestObject to1(1); - #if EASTL_MOVE_SEMANTICS_ENABLED - toSetIterator = toSet.emplace(to0); - EATEST_VERIFY(*toSetIterator == TestObject(0)); - //EATEST_VERIFY((TestObject::sTOCopyCtorCount == 2) && (TestObject::sTOMoveCtorCount == 1)); // Disabled until we can guarantee its behavior and deal with how it's different between compilers of differing C++11 support. - - toSetIterator = toSet.emplace(eastl::move(to1)); - EATEST_VERIFY(*toSetIterator == TestObject(1)); - - // insert_return_type t1A.emplace(value_type&& value); - TestObject to40(4); - EATEST_VERIFY(toSet.find(to40) == toSet.end()); - EATEST_VERIFY(to40.mX == 4); // It should change to 0 below during the move swap. - toSetIterator = toSet.emplace(eastl::move(to40)); - EATEST_VERIFY(*toSetIterator == TestObject(4)); - EATEST_VERIFY(toSet.find(to40) != toSet.end()); - EATEST_VERIFY(to40.mX == 0); - - TestObject to41(4); - toSetIterator = toSet.emplace(eastl::move(to41)); // multiset can insert another of these. - EATEST_VERIFY(*toSetIterator == TestObject(4)); - EATEST_VERIFY(toSet.find(to41) != toSet.end()); - - // iterator t1A.emplace_hint(const_iterator position, value_type&& value); - TestObject to50(5); - toSetIterator = toSet.emplace(eastl::move(to50)); - EATEST_VERIFY(*toSetIterator == TestObject(5)); - EATEST_VERIFY(toSet.find(to50) != toSet.end()); - - TestObject to51(5); - toSetIterator = toSet.emplace_hint(toSetIterator, eastl::move(to51)); - EATEST_VERIFY(*toSetIterator == TestObject(5)); - EATEST_VERIFY(toSet.find(to51) != toSet.end()); - - TestObject to6(6); - toSetIterator = toSet.emplace_hint(toSet.begin(), eastl::move(to6)); // specify a bad hint. Insertion should still work. - EATEST_VERIFY(*toSetIterator == TestObject(6)); - EATEST_VERIFY(toSet.find(to6) != toSet.end()); - #endif + toSetIterator = toSet.emplace(to0); + EATEST_VERIFY(*toSetIterator == TestObject(0)); + //EATEST_VERIFY((TestObject::sTOCopyCtorCount == 2) && (TestObject::sTOMoveCtorCount == 1)); // Disabled until we can guarantee its behavior and deal with how it's different between compilers of differing C++11 support. + + toSetIterator = toSet.emplace(eastl::move(to1)); + EATEST_VERIFY(*toSetIterator == TestObject(1)); + + // insert_return_type t1A.emplace(value_type&& value); + TestObject to40(4); + EATEST_VERIFY(toSet.find(to40) == toSet.end()); + EATEST_VERIFY(to40.mX == 4); // It should change to 0 below during the move swap. + toSetIterator = toSet.emplace(eastl::move(to40)); + EATEST_VERIFY(*toSetIterator == TestObject(4)); + EATEST_VERIFY(toSet.find(to40) != toSet.end()); + EATEST_VERIFY(to40.mX == 0); + + TestObject to41(4); + toSetIterator = toSet.emplace(eastl::move(to41)); // multiset can insert another of these. + EATEST_VERIFY(*toSetIterator == TestObject(4)); + EATEST_VERIFY(toSet.find(to41) != toSet.end()); + + // iterator t1A.emplace_hint(const_iterator position, value_type&& value); + TestObject to50(5); + toSetIterator = toSet.emplace(eastl::move(to50)); + EATEST_VERIFY(*toSetIterator == TestObject(5)); + EATEST_VERIFY(toSet.find(to50) != toSet.end()); + + TestObject to51(5); + toSetIterator = toSet.emplace_hint(toSetIterator, eastl::move(to51)); + EATEST_VERIFY(*toSetIterator == TestObject(5)); + EATEST_VERIFY(toSet.find(to51) != toSet.end()); + + TestObject to6(6); + toSetIterator = toSet.emplace_hint(toSet.begin(), eastl::move(to6)); // specify a bad hint. Insertion should still work. + EATEST_VERIFY(*toSetIterator == TestObject(6)); + EATEST_VERIFY(toSet.find(to6) != toSet.end()); TestObject to2(2); EATEST_VERIFY(toSet.find(to2) == toSet.end()); @@ -901,33 +869,31 @@ int TestMultisetCpp11() EATEST_VERIFY(*toSetIterator == to8); EATEST_VERIFY(toSet.find(to8) != toSet.end()); - #if EASTL_MOVE_SEMANTICS_ENABLED - // insert_return_type t1A.insert(value_type&& value); - TestObject to3(3); - EATEST_VERIFY(toSet.find(to3) == toSet.end()); - toSetIterator = toSet.insert(TestObject(to3)); - EATEST_VERIFY(*toSetIterator == TestObject(3)); - EATEST_VERIFY(toSet.find(to3) != toSet.end()); - toSetIterator = toSet.insert(TestObject(to3)); - EATEST_VERIFY(*toSetIterator == TestObject(3)); - EATEST_VERIFY(toSet.find(to3) != toSet.end()); - - // iterator t1A.insert(const_iterator position, value_type&& value); - TestObject to90(9); - toSetIterator = toSet.emplace(eastl::move(to90)); - EATEST_VERIFY(*toSetIterator == TestObject(9)); - EATEST_VERIFY(toSet.find(to90) != toSet.end()); - - TestObject to91(9); - toSetIterator = toSet.emplace_hint(toSetIterator, eastl::move(to91)); - EATEST_VERIFY(*toSetIterator == TestObject(9)); - EATEST_VERIFY(toSet.find(to91) != toSet.end()); - - TestObject to10(10); - toSetIterator = toSet.emplace_hint(toSet.begin(), eastl::move(to10)); // specify a bad hint. Insertion should still work. - EATEST_VERIFY(*toSetIterator == TestObject(10)); - EATEST_VERIFY(toSet.find(to10) != toSet.end()); - #endif + // insert_return_type t1A.insert(value_type&& value); + TestObject to3(3); + EATEST_VERIFY(toSet.find(to3) == toSet.end()); + toSetIterator = toSet.insert(TestObject(to3)); + EATEST_VERIFY(*toSetIterator == TestObject(3)); + EATEST_VERIFY(toSet.find(to3) != toSet.end()); + toSetIterator = toSet.insert(TestObject(to3)); + EATEST_VERIFY(*toSetIterator == TestObject(3)); + EATEST_VERIFY(toSet.find(to3) != toSet.end()); + + // iterator t1A.insert(const_iterator position, value_type&& value); + TestObject to90(9); + toSetIterator = toSet.emplace(eastl::move(to90)); + EATEST_VERIFY(*toSetIterator == TestObject(9)); + EATEST_VERIFY(toSet.find(to90) != toSet.end()); + + TestObject to91(9); + toSetIterator = toSet.emplace_hint(toSetIterator, eastl::move(to91)); + EATEST_VERIFY(*toSetIterator == TestObject(9)); + EATEST_VERIFY(toSet.find(to91) != toSet.end()); + + TestObject to10(10); + toSetIterator = toSet.emplace_hint(toSet.begin(), eastl::move(to10)); // specify a bad hint. Insertion should still work. + EATEST_VERIFY(*toSetIterator == TestObject(10)); + EATEST_VERIFY(toSet.find(to10) != toSet.end()); return nErrorCount; } diff --git a/test/source/TestSmartPtr.cpp b/test/source/TestSmartPtr.cpp index 387320b5..182044cf 100644 --- a/test/source/TestSmartPtr.cpp +++ b/test/source/TestSmartPtr.cpp @@ -54,11 +54,9 @@ namespace SmartPtrTest CustomDeleter() {} CustomDeleter(const CustomDeleter&) {} - #if EASTL_MOVE_SEMANTICS_ENABLED - CustomDeleter(CustomDeleter&&) {} - CustomDeleter& operator=(const CustomDeleter&) { return *this; } - CustomDeleter& operator=(CustomDeleter&&) { return *this; } - #endif + CustomDeleter(CustomDeleter&&) {} + CustomDeleter& operator=(const CustomDeleter&) { return *this; } + CustomDeleter& operator=(CustomDeleter&&) { return *this; } }; @@ -70,11 +68,9 @@ namespace SmartPtrTest CustomArrayDeleter() {} CustomArrayDeleter(const CustomArrayDeleter&) {} - #if EASTL_MOVE_SEMANTICS_ENABLED - CustomArrayDeleter(CustomArrayDeleter&&) {} - CustomArrayDeleter& operator=(const CustomArrayDeleter&) { return *this; } - CustomArrayDeleter& operator=(CustomArrayDeleter&&) { return *this; } - #endif + CustomArrayDeleter(CustomArrayDeleter&&) {} + CustomArrayDeleter& operator=(const CustomArrayDeleter&) { return *this; } + CustomArrayDeleter& operator=(CustomArrayDeleter&&) { return *this; } }; @@ -500,28 +496,26 @@ static int Test_unique_ptr() unique_ptr pT6(new A(17), customADeleter); EATEST_VERIFY(pT6->mc == 17); - #if EASTL_MOVE_SEMANTICS_ENABLED - // unique_ptr(pointer pValue, typename eastl::remove_reference::type&& deleter) noexcept - unique_ptr pT7(new A(18), CustomDeleter()); - EATEST_VERIFY(pT7->mc == 18); + // unique_ptr(pointer pValue, typename eastl::remove_reference::type&& deleter) noexcept + unique_ptr pT7(new A(18), CustomDeleter()); + EATEST_VERIFY(pT7->mc == 18); - // unique_ptr(this_type&& x) noexcept - unique_ptr pT8(eastl::move(pT7)); - EATEST_VERIFY(pT8->mc == 18); + // unique_ptr(this_type&& x) noexcept + unique_ptr pT8(eastl::move(pT7)); + EATEST_VERIFY(pT8->mc == 18); - // unique_ptr(unique_ptr&& u, ...) - unique_ptr > pT9(eastl::move(pT2)); + // unique_ptr(unique_ptr&& u, ...) + unique_ptr > pT9(eastl::move(pT2)); - // this_type& operator=(this_type&& u) noexcept - // operator=(unique_ptr&& u) noexcept - //unique_ptr pTVoid; - //unique_ptr pTInt(new int(1)); - //pTVoid.operator=(eastl::move(pTInt)); // This doesn't work because CustomDeleter doesn't know how to delete void*. Need to rework this test. + // this_type& operator=(this_type&& u) noexcept + // operator=(unique_ptr&& u) noexcept + //unique_ptr pTVoid; + //unique_ptr pTInt(new int(1)); + //pTVoid.operator=(eastl::move(pTInt)); // This doesn't work because CustomDeleter doesn't know how to delete void*. Need to rework this test. - // this_type& operator=(nullptr_t) noexcept - pT6 = nullptr; - EATEST_VERIFY(pT6.get() == (A*)0); - #endif + // this_type& operator=(nullptr_t) noexcept + pT6 = nullptr; + EATEST_VERIFY(pT6.get() == (A*)0); } { @@ -636,55 +630,51 @@ static int Test_unique_ptr() pT6[0].mc = 17; EATEST_VERIFY(pT6[0].mc == 17); - #if EASTL_MOVE_SEMANTICS_ENABLED - // unique_ptr(pointer pValue, typename eastl::remove_reference::type&& deleter) noexcept - unique_ptr pT7(new A[18], CustomArrayDeleter()); - pT7[0].mc = 18; - EATEST_VERIFY(pT7[0].mc == 18); - - // unique_ptr(this_type&& x) noexcept - unique_ptr pT8(eastl::move(pT7)); - EATEST_VERIFY(pT8[0].mc == 18); - - // unique_ptr(unique_ptr&& u, ...) - unique_ptr > pT9(eastl::move(pT2)); - EATEST_VERIFY(pT9[0].mc == 3); - - // this_type& operator=(this_type&& u) noexcept - // operator=(unique_ptr&& u) noexcept - //unique_ptr pTVoid; - //unique_ptr pTInt(new int(1)); - //pTVoid.operator=(eastl::move(pTInt)); // This doesn't work because CustomDeleter doesn't know how to delete void*. Need to rework this test. - - // this_type& operator=(nullptr_t) noexcept - pT6 = nullptr; - EATEST_VERIFY(pT6.get() == (A*)0); - #endif + // unique_ptr(pointer pValue, typename eastl::remove_reference::type&& deleter) noexcept + unique_ptr pT7(new A[18], CustomArrayDeleter()); + pT7[0].mc = 18; + EATEST_VERIFY(pT7[0].mc == 18); - // unique_ptr<> make_unique(Args&&... args); - #if EASTL_MOVE_SEMANTICS_ENABLED - unique_ptr p = eastl::make_unique("test", "test2"); - EATEST_VERIFY(EA::StdC::Strcmp(p->mpName, "test") == 0 && EA::StdC::Strcmp(p->mpName2, "test2") == 0); + // unique_ptr(this_type&& x) noexcept + unique_ptr pT8(eastl::move(pT7)); + EATEST_VERIFY(pT8[0].mc == 18); - unique_ptr pArray = eastl::make_unique(4); - pArray[0].mpName = "test"; - EATEST_VERIFY(EA::StdC::Strcmp(p->mpName, "test") == 0); + // unique_ptr(unique_ptr&& u, ...) + unique_ptr > pT9(eastl::move(pT2)); + EATEST_VERIFY(pT9[0].mc == 3); - #ifdef EASTL_TEST_DISABLED_PENDING_SUPPORT - { - const size_t kAlignedStructAlignment = 512; - struct AlignedStruct {} EA_ALIGN(kAlignedStructAlignment); + // this_type& operator=(this_type&& u) noexcept + // operator=(unique_ptr&& u) noexcept + //unique_ptr pTVoid; + //unique_ptr pTInt(new int(1)); + //pTVoid.operator=(eastl::move(pTInt)); // This doesn't work because CustomDeleter doesn't know how to delete void*. Need to rework this test. - unique_ptr pAlignedStruct = eastl::make_unique(); - EATEST_VERIFY_F(intptr_t(pAlignedStruct.get()) % kAlignedStructAlignment == 0, "pAlignedStruct didn't have proper alignment"); - } - #endif + // this_type& operator=(nullptr_t) noexcept + pT6 = nullptr; + EATEST_VERIFY(pT6.get() == (A*)0); - //Expected to not be valid: - //unique_ptr p2Array4 = eastl::make_unique(); - //p2Array4[0].mpName = "test"; - //EATEST_VERIFY(EA::StdC::Strcmp(p2Array4[0].mpName, "test") == 0); + // unique_ptr<> make_unique(Args&&... args); + unique_ptr p = eastl::make_unique("test", "test2"); + EATEST_VERIFY(EA::StdC::Strcmp(p->mpName, "test") == 0 && EA::StdC::Strcmp(p->mpName2, "test2") == 0); + + unique_ptr pArray = eastl::make_unique(4); + pArray[0].mpName = "test"; + EATEST_VERIFY(EA::StdC::Strcmp(p->mpName, "test") == 0); + + #ifdef EASTL_TEST_DISABLED_PENDING_SUPPORT + { + const size_t kAlignedStructAlignment = 512; + struct AlignedStruct {} EA_ALIGN(kAlignedStructAlignment); + + unique_ptr pAlignedStruct = eastl::make_unique(); + EATEST_VERIFY_F(intptr_t(pAlignedStruct.get()) % kAlignedStructAlignment == 0, "pAlignedStruct didn't have proper alignment"); + } #endif + + //Expected to not be valid: + //unique_ptr p2Array4 = eastl::make_unique(); + //p2Array4[0].mpName = "test"; + //EATEST_VERIFY(EA::StdC::Strcmp(p2Array4[0].mpName, "test") == 0); } EATEST_VERIFY(A::mCount == 0); // This check verifies that no A instances were lost, which also verifies that the [] version of the deleter was used in all cases. diff --git a/test/source/TestString.inl b/test/source/TestString.inl index bca7f43c..3e78617f 100644 --- a/test/source/TestString.inl +++ b/test/source/TestString.inl @@ -282,47 +282,43 @@ int TEST_STRING_NAME() // basic_string(this_type&& x); // basic_string(this_type&& x, const allocator_type& allocator); - { - #if EASTL_MOVE_SEMANTICS_ENABLED - { // test heap string - StringType str1(LITERAL("abcdefghijklmnopqrstuvwxyz")); - StringType str2(eastl::move(str1)); + { // test heap string + StringType str1(LITERAL("abcdefghijklmnopqrstuvwxyz")); + StringType str2(eastl::move(str1)); - VERIFY(str1 != LITERAL("abcdefghijklmnopqrstuvwxyz")); - VERIFY(str2 == LITERAL("abcdefghijklmnopqrstuvwxyz")); + VERIFY(str1 != LITERAL("abcdefghijklmnopqrstuvwxyz")); + VERIFY(str2 == LITERAL("abcdefghijklmnopqrstuvwxyz")); - VERIFY(str1.empty()); - VERIFY(!str2.empty()); + VERIFY(str1.empty()); + VERIFY(!str2.empty()); - VERIFY(str1.length() == 0); - VERIFY(str2.length() == 26); + VERIFY(str1.length() == 0); + VERIFY(str2.length() == 26); - VERIFY(str1.size() == 0); - VERIFY(str2.size() == 26); + VERIFY(str1.size() == 0); + VERIFY(str2.size() == 26); - VERIFY(str1.validate()); - VERIFY(str2.validate()); - } - { // test sso string - StringType str1(LITERAL("a")); - StringType str2(eastl::move(str1)); + VERIFY(str1.validate()); + VERIFY(str2.validate()); + } + { // test sso string + StringType str1(LITERAL("a")); + StringType str2(eastl::move(str1)); - VERIFY(str1 != LITERAL("a")); - VERIFY(str2 == LITERAL("a")); + VERIFY(str1 != LITERAL("a")); + VERIFY(str2 == LITERAL("a")); - VERIFY(str1.empty()); - VERIFY(!str2.empty()); + VERIFY(str1.empty()); + VERIFY(!str2.empty()); - VERIFY(str1.length() == 0); - VERIFY(str2.length() == 1); + VERIFY(str1.length() == 0); + VERIFY(str2.length() == 1); - VERIFY(str1.size() == 0); - VERIFY(str2.size() == 1); + VERIFY(str1.size() == 0); + VERIFY(str2.size() == 1); - VERIFY(str1.validate()); - VERIFY(str2.validate()); - } - #endif + VERIFY(str1.validate()); + VERIFY(str2.validate()); } // basic_string(const view_type& sv, const allocator_type& allocator); @@ -510,46 +506,42 @@ int TEST_STRING_NAME() // this_type& operator=(this_type&& x); { - #if EASTL_MOVE_SEMANTICS_ENABLED - { - StringType str1(LITERAL("abcdefghijklmnopqrstuvwxyz")); - StringType str2 = eastl::move(str1); + StringType str1(LITERAL("abcdefghijklmnopqrstuvwxyz")); + StringType str2 = eastl::move(str1); - VERIFY(str1 != LITERAL("abcdefghijklmnopqrstuvwxyz")); - VERIFY(str2 == LITERAL("abcdefghijklmnopqrstuvwxyz")); + VERIFY(str1 != LITERAL("abcdefghijklmnopqrstuvwxyz")); + VERIFY(str2 == LITERAL("abcdefghijklmnopqrstuvwxyz")); - VERIFY(str1.empty()); - VERIFY(!str2.empty()); + VERIFY(str1.empty()); + VERIFY(!str2.empty()); - VERIFY(str1.length() == 0); - VERIFY(str2.length() == 26); + VERIFY(str1.length() == 0); + VERIFY(str2.length() == 26); - VERIFY(str1.size() == 0); - VERIFY(str2.size() == 26); + VERIFY(str1.size() == 0); + VERIFY(str2.size() == 26); - VERIFY(str1.validate()); - VERIFY(str2.validate()); - } - { - StringType str1(LITERAL("a")); - StringType str2 = eastl::move(str1); + VERIFY(str1.validate()); + VERIFY(str2.validate()); + } + { + StringType str1(LITERAL("a")); + StringType str2 = eastl::move(str1); - VERIFY(str1 != LITERAL("a")); - VERIFY(str2 == LITERAL("a")); + VERIFY(str1 != LITERAL("a")); + VERIFY(str2 == LITERAL("a")); - VERIFY(str1.empty()); - VERIFY(!str2.empty()); + VERIFY(str1.empty()); + VERIFY(!str2.empty()); - VERIFY(str1.length() == 0); - VERIFY(str2.length() == 1); + VERIFY(str1.length() == 0); + VERIFY(str2.length() == 1); - VERIFY(str1.size() == 0); - VERIFY(str2.size() == 1); + VERIFY(str1.size() == 0); + VERIFY(str2.size() == 1); - VERIFY(str1.validate()); - VERIFY(str2.validate()); - } - #endif + VERIFY(str1.validate()); + VERIFY(str2.validate()); } // this_type& operator=(value_type* p); @@ -737,7 +729,6 @@ int TEST_STRING_NAME() // this_type& assign(this_type&& x); { - #if EASTL_MOVE_SEMANTICS_ENABLED StringType str1(LITERAL("abcdefghijklmnopqrstuvwxyz")); StringType str2; @@ -756,18 +747,15 @@ int TEST_STRING_NAME() VERIFY(str1.validate()); VERIFY(str2.validate()); - #endif } // this_type& assign(std::initializer_list); { - #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) StringType str(LITERAL("abcdefghijklmnopqrstuvwxyz")); str.assign({'1','2','3'}); VERIFY(str == LITERAL("123")); VERIFY(str.validate()); - #endif } // template diff --git a/test/source/TestTuple.cpp b/test/source/TestTuple.cpp index 4df4d4ae..f0ef50d2 100644 --- a/test/source/TestTuple.cpp +++ b/test/source/TestTuple.cpp @@ -456,6 +456,7 @@ int TestTuple() {3, 3.0f, TestObject(3)}, {4, 4.0f, TestObject(4)} }; + (void)arrayTup; #if false // the following code should not compile with conditionally-explicit behaviour (but does with fully implicit behaviour) @@ -471,6 +472,17 @@ int TestTuple() #endif } + #ifndef EA_COMPILER_NO_STRUCTURED_BINDING + // tuple structured bindings test + { + eastl::tuple t = {1,2,3}; + auto [x,y,z] = t; + EATEST_VERIFY(x == 1); + EATEST_VERIFY(y == 2); + EATEST_VERIFY(z == 3); + } + #endif + return nErrorCount; } diff --git a/test/source/TestTupleVector.cpp b/test/source/TestTupleVector.cpp index 0e18f993..7d9c77db 100644 --- a/test/source/TestTupleVector.cpp +++ b/test/source/TestTupleVector.cpp @@ -112,19 +112,19 @@ int TestTupleVector() struct EA_ALIGN(16) AlignTestVec4 { float a[4]; - AlignTestVec4() :a{ 1.0f, 2.0f, 3.0f, 4.0f } {} + AlignTestVec4() : a{1.0f, 2.0f, 3.0f, 4.0f} {} }; struct AlignTestByte3 { char a[3]; - AlignTestByte3() :a{ 1, 2, 3 } {} + AlignTestByte3() : a{1, 2, 3} {} }; struct EA_ALIGN(8) AlignTestFourByte { int a[5]; - AlignTestFourByte() :a{ -1, -2, -3, -4, -5 } {} + AlignTestFourByte() : a{-1, -2, -3, -4, -5} {} }; tuple_vector alignElementVec; @@ -143,6 +143,7 @@ int TestTupleVector() TestObject::Reset(); tuple_vector testVec; + typedef tuple_vector::size_type tuple_vector_size_type; testVec.reserve(10); for (int i = 0; i < 10; ++i) { @@ -187,7 +188,7 @@ int TestTupleVector() auto newTestVecSize = testVecCapacity + 5; testVec.resize(newTestVecSize, true, TestObject(5), 5.0f); EATEST_VERIFY(testVec.size() == newTestVecSize); - EATEST_VERIFY(TestObject::sTOCount == newTestVecSize); + EATEST_VERIFY(static_cast(TestObject::sTOCount) == newTestVecSize); EATEST_VERIFY(testVec.capacity() > newTestVecSize); EATEST_VERIFY(testVec.validate()); for (unsigned int i = 5; i < newTestVecSize; ++i) @@ -199,6 +200,8 @@ int TestTupleVector() { tuple resizeTup(true, TestObject(10), 10.0f); + typedef tuple_vector::size_type tuple_vector_size_type; + // test resize with tuple that does destruction of objects testVecCapacity = testVec.capacity(); EATEST_VERIFY(testVecCapacity >= 15); // check for next two resizes to make sure we don't grow vec @@ -218,7 +221,7 @@ int TestTupleVector() newTestVecSize = testVecCapacity + 5; testVec.resize(newTestVecSize, resizeTup); EATEST_VERIFY(testVec.size() == newTestVecSize); - EATEST_VERIFY(TestObject::sTOCount == newTestVecSize + 1); + EATEST_VERIFY(static_cast(TestObject::sTOCount) == newTestVecSize + 1); EATEST_VERIFY(testVec.capacity() > newTestVecSize); EATEST_VERIFY(testVec.validate()); for (unsigned int i = 5; i < 20; ++i) @@ -238,7 +241,7 @@ int TestTupleVector() // test other modifiers testVec.pop_back(); EATEST_VERIFY(testVec.size() == newTestVecSize - 1); - EATEST_VERIFY(TestObject::sTOCount == newTestVecSize - 1); // down 2 from last sTOCount check - resizeTup dtor and pop_back + EATEST_VERIFY(static_cast(TestObject::sTOCount) == newTestVecSize - 1); // down 2 from last sTOCount check - resizeTup dtor and pop_back EATEST_VERIFY(testVec.capacity() > newTestVecSize); testVec.shrink_to_fit(); @@ -1447,7 +1450,7 @@ int TestTupleVector() EATEST_VERIFY(get<0>(movedTup) == 1); EATEST_VERIFY(get<0>(*v1.begin()) == 1); - for (unsigned int i = 0; i < v1.size(); ++i) + for (int i = 0; i < static_cast(v1.size()); ++i) { EATEST_VERIFY(v1.get<0>()[i] == i + 1); } diff --git a/test/source/TestTypeTraits.cpp b/test/source/TestTypeTraits.cpp index 25d9cc52..b24a27bd 100644 --- a/test/source/TestTypeTraits.cpp +++ b/test/source/TestTypeTraits.cpp @@ -7,6 +7,7 @@ #include #include #include +#include "ConceptImpls.h" @@ -1909,6 +1910,16 @@ int TestTypeTraits() #endif } + // has_equality + { + static_assert( has_equality_v, "has_equality failure"); + static_assert( has_equality_v, "has_equality failure"); + static_assert( has_equality_v, "has_equality failure"); + static_assert( has_equality_v, "has_equality failure"); + static_assert( has_equality_v, "has_equality failure"); + static_assert(!has_equality_v, "has_equality failure"); + } + return nErrorCount; } diff --git a/test/source/TestUtility.cpp b/test/source/TestUtility.cpp index bf0cde0c..71517506 100644 --- a/test/source/TestUtility.cpp +++ b/test/source/TestUtility.cpp @@ -348,7 +348,7 @@ static int TestUtilitySwap() return nErrorCount; } -#if !defined(EA_COMPILER_NO_NOEXCEPT) && EASTL_MOVE_SEMANTICS_ENABLED +#if !defined(EA_COMPILER_NO_NOEXCEPT) /////////////////////////////////////////////////////////////////////////////////////////////////////////// // Warning C4626 warns against an implicitly deleted move assignment operator. @@ -417,7 +417,7 @@ static int TestUtilityMove() int nErrorCount = 0; // move_if_noexcept -#if !defined(EA_COMPILER_NO_NOEXCEPT) && EASTL_MOVE_SEMANTICS_ENABLED +#if !defined(EA_COMPILER_NO_NOEXCEPT) noexcept_move_copy nemcA; noexcept_move_copy nemcB = eastl::move_if_noexcept(nemcA); // nemcB should be constructed via noexcept_move_copy(noexcept_move_copy&&) diff --git a/test/source/TestVector.cpp b/test/source/TestVector.cpp index e5f90351..d859377a 100644 --- a/test/source/TestVector.cpp +++ b/test/source/TestVector.cpp @@ -31,9 +31,6 @@ template class eastl::vector; template class eastl::vector; template class eastl::vector; -// TODO(rparolin): Fix compiler errors and enable this -// template class eastl::vector>; - // This tests "uninitialized_fill" usage in vector when T has a user provided // address-of operator overload. In these situations, EASTL containers must use @@ -138,24 +135,22 @@ struct testmovable { EA_NON_COPYABLE(testmovable) public: - testmovable() {} + testmovable() EA_NOEXCEPT {} testmovable(testmovable&&) EA_NOEXCEPT {} testmovable& operator=(testmovable&&) EA_NOEXCEPT { return *this; } }; -#if EASTL_MOVE_SEMANTICS_ENABLED - struct TestMoveAssignToSelf - { - TestMoveAssignToSelf() : mMovedToSelf(false) {} - TestMoveAssignToSelf(const TestMoveAssignToSelf& other) { mMovedToSelf = other.mMovedToSelf; } - TestMoveAssignToSelf& operator=(TestMoveAssignToSelf&& other) { mMovedToSelf = true; return *this; } - TestMoveAssignToSelf& operator=(const TestMoveAssignToSelf&) = delete; +struct TestMoveAssignToSelf +{ + TestMoveAssignToSelf() EA_NOEXCEPT : mMovedToSelf(false) {} + TestMoveAssignToSelf(const TestMoveAssignToSelf& other) { mMovedToSelf = other.mMovedToSelf; } + TestMoveAssignToSelf& operator=(TestMoveAssignToSelf&& other) { mMovedToSelf = true; return *this; } + TestMoveAssignToSelf& operator=(const TestMoveAssignToSelf&) = delete; - bool mMovedToSelf; - }; -#endif + bool mMovedToSelf; +}; #if EASTL_VARIABLE_TEMPLATES_ENABLED /// custom type-trait which checks if a type is comparable via the -// iterator emplace(const_iterator position, Args&&... args); - -// template -// void emplace_back(Args&&... args); -#else -#if EASTL_MOVE_SEMANTICS_ENABLED -// iterator emplace(const_iterator position, value_type&& value); -// void emplace_back(value_type&& value); -#endif + // template + // iterator emplace(const_iterator position, Args&&... args); -// iterator emplace(const_iterator position, value_type& value); -// void emplace_back(value_type& value); -#endif + // template + // void emplace_back(Args&&... args); -#if EASTL_MOVE_SEMANTICS_ENABLED -// iterator insert(const_iterator position, value_type&& value); -// void push_back(value_type&& value); -#endif + // iterator insert(const_iterator position, value_type&& value); + // void push_back(value_type&& value); -#if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED TestObject::Reset(); vector toVectorA; @@ -560,58 +536,9 @@ int TestVector() EATEST_VERIFY((toVectorA.size() == 2) && (toVectorA.front().mX == (3 + 4 + 5)) && (TestObject::sTOCtorCount == 3)); // 3 because the original count of 1, plus the existing vector // element will be moved, plus the one being emplaced. -#else -#if EASTL_MOVE_SEMANTICS_ENABLED - TestObject::Reset(); - - // We have a potential problem here in that the compiler is not required to use move construction below. - // It is allowed to use standard copy construction if it wants. We could force it with eastl::move() usage. - vector toVectorA; - - TestObject& ref = toVectorA.emplace_back(TestObject(2, 3, 4)); - EATEST_VERIFY((toVectorA.size() == 1) && (toVectorA.back().mX == (2 + 3 + 4)) && - (TestObject::sTOMoveCtorCount == 1)); - EATEST_VERIFY(ref.mX == (2 + 3 + 4)); - - toVectorA.emplace(toVectorA.begin(), TestObject(3, 4, 5)); - EATEST_VERIFY((toVectorA.size() == 2) && (toVectorA.front().mX == (3 + 4 + 5)) && - (TestObject::sTOMoveCtorCount == 3)); // 3 because the original count of 1, plus the existing - // vector element will be moved, plus the one being - // emplaced. -#endif TestObject::Reset(); - vector toVectorB; - TestObject to234(2, 3, 4); - TestObject to345(3, 4, 5); - - toVectorB.emplace_back(to234); // This will be copied (not moved) by compilers that don't support rvalue move - // because it's not a temporary and we don't use eastl::move() on it. - EATEST_VERIFY((toVectorB.size() == 1) && (toVectorB.back().mX == (2 + 3 + 4)) && - (TestObject::sTOArgCtorCount == 2)); - EATEST_VERIFY((TestObject::sTOCopyCtorCount + TestObject::sTOMoveCtorCount) == - 1); // A compiler that supports move may in fact take advantage of that internally. - - toVectorB.emplace(toVectorB.begin(), to345); // This will be copied (not moved) by compilers that don't support - // rvalue move because it's not a temporary and we don't use - // eastl::move() on it. - EATEST_VERIFY((toVectorB.size() == 2) && (toVectorB.front().mX == (3 + 4 + 5)) && - (TestObject::sTOArgCtorCount == 2)); - EATEST_VERIFY((TestObject::sTOCopyCtorCount + TestObject::sTOMoveCtorCount) == - 3); // A compiler that supports move may in fact take advantage of that internally. - - EATEST_VERIFY( - to234.mX == - (2 + 3 + - 4)); // Verify that the object was copied and not moved. If it was moved then mX would be 0 and not 2+3+4. - EATEST_VERIFY(to345.mX == (3 + 4 + 5)); -#endif - -#if EASTL_MOVE_SEMANTICS_ENABLED - // This test is similar to the emplace EASTL_MOVE_SEMANTICS_ENABLED pathway above. - TestObject::Reset(); - // void push_back(T&& x); // iterator insert(const_iterator position, T&& x); @@ -626,7 +553,6 @@ int TestVector() (TestObject::sTOMoveCtorCount == 3)); // 3 because the original count of 1, plus the existing // vector element will be moved, plus the one being // emplaced. -#endif } // We don't check for TestObject::IsClear because we messed with state above and don't currently have a matching set @@ -1096,7 +1022,6 @@ int TestVector() EATEST_VERIFY(TestObject::IsClear()); TestObject::Reset(); -#if EASTL_MOVE_SEMANTICS_ENABLED { // Test insert move objects eastl::vector toVector1; @@ -1146,7 +1071,6 @@ int TestVector() TestObject::sTOCopyCtorCount + TestObject::sTOCopyAssignCount == 11); // Move 7 existing element and copy the 10 inserted + // the temporary one inside the function } -#endif TestObject::Reset(); @@ -1236,7 +1160,6 @@ int TestVector() EATEST_VERIFY(v.capacity() == 0); EATEST_VERIFY(VerifySequence(v.begin(), v.end(), int(), "vector.reset", -1)); -#if EASTL_MOVE_SEMANTICS_ENABLED // Test set_capacity make a move when reducing size vector toArray2(10, TestObject(7)); TestObject::Reset(); @@ -1244,7 +1167,6 @@ int TestVector() EATEST_VERIFY(TestObject::sTOMoveCtorCount == 5 && TestObject::sTOCopyCtorCount + TestObject::sTOCopyAssignCount == 0); // Move the 5 existing elements, no copy EATEST_VERIFY(VerifySequence(toArray2.begin(), toArray2.end(), int(), "vector.set_capacity", 7, 7, 7, 7, 7, -1)); -#endif } TestObject::Reset(); @@ -1598,7 +1520,6 @@ int TestVector() v2.push_back(StructWithConstRefToInt(j)); } -#if EASTL_MOVE_SEMANTICS_ENABLED { // Regression for issue with vector containing non-copyable values reported by user eastl::vector moveablevec; @@ -1614,10 +1535,8 @@ int TestVector() v1.erase(v1.begin(), v1.begin()); EATEST_VERIFY(!v1[0].mMovedToSelf); } -#endif #if defined(EASTL_TEST_CONCEPT_IMPLS) - { // vector default constructor should require no more than Destructible eastl::vector v1; @@ -1655,7 +1574,6 @@ int TestVector() EATEST_VERIFY(v4.size() == 2 && v4[0].value == v4[1].value && v4[0].value == CopyConstructible::defaultValue); } -#if EASTL_MOVE_SEMANTICS_ENABLED { // vector::reserve() should only require MoveInsertible eastl::vector v5; @@ -1678,7 +1596,6 @@ int TestVector() eastl::move_iterator(eastl::end(moveConstructibleArray))); EATEST_VERIFY(v7.size() == 1 && v7[0].value == MoveConstructible::defaultValue); } -#endif { // vector::swap() should only require Destructible. We also test with DefaultConstructible as it gives us a @@ -1693,7 +1610,6 @@ int TestVector() EATEST_VERIFY(v6.size() == 2 && v7.size() == 1); } -#if EASTL_MOVE_SEMANTICS_ENABLED { // vector::resize() should only require MoveInsertable and DefaultInsertable eastl::vector v8; @@ -1711,8 +1627,6 @@ int TestVector() v1.erase(begin(v1)); EATEST_VERIFY(v1.empty()); } -#endif - #endif // EASTL_TEST_CONCEPT_IMPLS { @@ -1735,7 +1649,7 @@ int TestVector() container_value_type operator*() { return {}; } }; - container_with_custom_iterator() {} + container_with_custom_iterator() EA_NOEXCEPT {} iterator begin() const { return {}; } iterator end() const { return {}; }