aboutsummaryrefslogtreecommitdiff
path: root/EASTL/include
diff options
context:
space:
mode:
Diffstat (limited to 'EASTL/include')
-rw-r--r--EASTL/include/EASTL/algorithm.h151
-rw-r--r--EASTL/include/EASTL/allocator.h10
-rw-r--r--EASTL/include/EASTL/allocator_malloc.h2
-rw-r--r--EASTL/include/EASTL/array.h131
-rw-r--r--EASTL/include/EASTL/bit.h172
-rw-r--r--EASTL/include/EASTL/bitset.h8
-rw-r--r--EASTL/include/EASTL/bonus/lru_cache.h2
-rw-r--r--EASTL/include/EASTL/bonus/overloaded.h81
-rw-r--r--EASTL/include/EASTL/bonus/tuple_vector.h12
-rw-r--r--EASTL/include/EASTL/chrono.h113
-rw-r--r--EASTL/include/EASTL/compare.h45
-rw-r--r--EASTL/include/EASTL/deque.h45
-rw-r--r--EASTL/include/EASTL/fixed_hash_map.h36
-rw-r--r--EASTL/include/EASTL/fixed_hash_set.h54
-rw-r--r--EASTL/include/EASTL/fixed_list.h8
-rw-r--r--EASTL/include/EASTL/fixed_slist.h8
-rw-r--r--EASTL/include/EASTL/fixed_substring.h10
-rw-r--r--EASTL/include/EASTL/functional.h27
-rw-r--r--EASTL/include/EASTL/hash_map.h186
-rw-r--r--EASTL/include/EASTL/hash_set.h28
-rw-r--r--EASTL/include/EASTL/heap.h4
-rw-r--r--EASTL/include/EASTL/internal/atomic/arch/arm/arch_arm_memory_barrier.h4
-rw-r--r--EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86.h21
-rw-r--r--EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_add_fetch.h2
-rw-r--r--EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_and_fetch.h2
-rw-r--r--EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_strong.h2
-rw-r--r--EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_weak.h2
-rw-r--r--EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_exchange.h4
-rw-r--r--EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_add.h2
-rw-r--r--EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_and.h2
-rw-r--r--EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_or.h2
-rw-r--r--EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_sub.h2
-rw-r--r--EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_xor.h2
-rw-r--r--EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_load.h84
-rw-r--r--EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_memory_barrier.h2
-rw-r--r--EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_or_fetch.h2
-rw-r--r--EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_store.h2
-rw-r--r--EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_sub_fetch.h2
-rw-r--r--EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_thread_fence.h2
-rw-r--r--EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_xor_fetch.h2
-rw-r--r--EASTL/include/EASTL/internal/atomic/atomic.h6
-rw-r--r--EASTL/include/EASTL/internal/atomic/atomic_base_width.h2
-rw-r--r--EASTL/include/EASTL/internal/atomic/atomic_flag.h12
-rw-r--r--EASTL/include/EASTL/internal/atomic/atomic_integral.h10
-rw-r--r--EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros.h11
-rw-r--r--EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros_base.h7
-rw-r--r--EASTL/include/EASTL/internal/atomic/atomic_memory_order.h12
-rw-r--r--EASTL/include/EASTL/internal/atomic/atomic_pointer.h8
-rw-r--r--EASTL/include/EASTL/internal/atomic/atomic_size_aligned.h40
-rw-r--r--EASTL/include/EASTL/internal/atomic/compiler/compiler.h2
-rw-r--r--EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc.h1
-rw-r--r--EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_barrier.h4
-rw-r--r--EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cmpxchg_strong.h1
-rw-r--r--EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cpu_pause.h19
-rw-r--r--EASTL/include/EASTL/internal/config.h103
-rw-r--r--EASTL/include/EASTL/internal/copy_help.h88
-rw-r--r--EASTL/include/EASTL/internal/fill_help.h4
-rw-r--r--EASTL/include/EASTL/internal/fixed_pool.h14
-rw-r--r--EASTL/include/EASTL/internal/function.h6
-rw-r--r--EASTL/include/EASTL/internal/function_detail.h2
-rw-r--r--EASTL/include/EASTL/internal/functional_base.h97
-rw-r--r--EASTL/include/EASTL/internal/generic_iterator.h17
-rw-r--r--EASTL/include/EASTL/internal/hashtable.h311
-rw-r--r--EASTL/include/EASTL/internal/integer_sequence.h62
-rw-r--r--EASTL/include/EASTL/internal/red_black_tree.h50
-rw-r--r--EASTL/include/EASTL/internal/smart_ptr.h5
-rw-r--r--EASTL/include/EASTL/internal/thread_support.h98
-rw-r--r--EASTL/include/EASTL/internal/type_compound.h143
-rw-r--r--EASTL/include/EASTL/internal/type_detected.h180
-rw-r--r--EASTL/include/EASTL/internal/type_fundamental.h59
-rw-r--r--EASTL/include/EASTL/internal/type_pod.h73
-rw-r--r--EASTL/include/EASTL/internal/type_properties.h195
-rw-r--r--EASTL/include/EASTL/internal/type_transformations.h360
-rw-r--r--EASTL/include/EASTL/internal/type_void_t.h43
-rw-r--r--EASTL/include/EASTL/intrusive_list.h8
-rw-r--r--EASTL/include/EASTL/iterator.h200
-rw-r--r--EASTL/include/EASTL/list.h35
-rw-r--r--EASTL/include/EASTL/map.h142
-rw-r--r--EASTL/include/EASTL/memory.h41
-rw-r--r--EASTL/include/EASTL/meta.h57
-rw-r--r--EASTL/include/EASTL/numeric.h97
-rw-r--r--EASTL/include/EASTL/numeric_limits.h111
-rw-r--r--EASTL/include/EASTL/optional.h24
-rw-r--r--EASTL/include/EASTL/queue.h9
-rw-r--r--EASTL/include/EASTL/set.h24
-rw-r--r--EASTL/include/EASTL/shared_ptr.h61
-rw-r--r--EASTL/include/EASTL/slist.h42
-rw-r--r--EASTL/include/EASTL/sort.h25
-rw-r--r--EASTL/include/EASTL/span.h44
-rw-r--r--EASTL/include/EASTL/stack.h8
-rw-r--r--EASTL/include/EASTL/string.h232
-rw-r--r--EASTL/include/EASTL/string_view.h248
-rw-r--r--EASTL/include/EASTL/tuple.h67
-rw-r--r--EASTL/include/EASTL/type_traits.h143
-rw-r--r--EASTL/include/EASTL/unique_ptr.h53
-rw-r--r--EASTL/include/EASTL/utility.h104
-rw-r--r--EASTL/include/EASTL/variant.h806
-rw-r--r--EASTL/include/EASTL/vector.h45
98 files changed, 4187 insertions, 1760 deletions
diff --git a/EASTL/include/EASTL/algorithm.h b/EASTL/include/EASTL/algorithm.h
index da35c2e..6257514 100644
--- a/EASTL/include/EASTL/algorithm.h
+++ b/EASTL/include/EASTL/algorithm.h
@@ -128,6 +128,7 @@
// iter_swap
// lexicographical_compare
// lexicographical_compare<Compare>
+// lexicographical_compare_three_way
// lower_bound
// lower_bound<Compare>
// make_heap Found in heap.h
@@ -163,6 +164,8 @@
// random_shuffle<Random>
// remove
// remove_if
+// +apply_and_remove
+// +apply_and_remove_if
// remove_copy
// remove_copy_if
// +remove_heap Found in heap.h
@@ -247,6 +250,7 @@
#include <EASTL/utility.h>
#include <EASTL/internal/generic_iterator.h>
#include <EASTL/random.h>
+#include <EASTL/compare.h>
EA_DISABLE_ALL_VC_WARNINGS();
@@ -806,18 +810,18 @@ namespace eastl
template <typename T>
inline T&& median_impl(T&& a, T&& b, T&& c)
{
- if(a < b)
+ if(eastl::less<T>()(a, b))
{
- if(b < c)
+ if(eastl::less<T>()(b, c))
return eastl::forward<T>(b);
- else if(a < c)
+ else if(eastl::less<T>()(a, c))
return eastl::forward<T>(c);
else
return eastl::forward<T>(a);
}
- else if(a < c)
+ else if(eastl::less<T>()(a, c))
return eastl::forward<T>(a);
- else if(b < c)
+ else if(eastl::less<T>()(b, c))
return eastl::forward<T>(c);
return eastl::forward<T>(b);
}
@@ -1259,14 +1263,8 @@ namespace eastl
inline BidirectionalIterator2 move_and_copy_backward_chooser(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 resultEnd)
{
typedef typename eastl::iterator_traits<BidirectionalIterator1>::iterator_category IIC;
- typedef typename eastl::iterator_traits<BidirectionalIterator2>::iterator_category OIC;
- typedef typename eastl::iterator_traits<BidirectionalIterator1>::value_type value_type_input;
- typedef typename eastl::iterator_traits<BidirectionalIterator2>::value_type value_type_output;
- const bool canBeMemmoved = eastl::is_trivially_copyable<value_type_output>::value &&
- eastl::is_same<value_type_input, value_type_output>::value &&
- (eastl::is_pointer<BidirectionalIterator1>::value || eastl::is_same<IIC, eastl::contiguous_iterator_tag>::value) &&
- (eastl::is_pointer<BidirectionalIterator2>::value || eastl::is_same<OIC, eastl::contiguous_iterator_tag>::value);
+ const bool canBeMemmoved = internal::can_be_memmoved_helper<BidirectionalIterator1, BidirectionalIterator2>::value;
return eastl::move_and_copy_backward_helper<IIC, isMove, canBeMemmoved>::move_or_copy_backward(first, last, resultEnd); // Need to chose based on the input iterator tag and not the output iterator tag, because containers accept input ranges of iterator types different than self.
}
@@ -2114,6 +2112,42 @@ namespace eastl
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+
+ /// lexicographical_compare_three_way
+ ///
+ /// Returns: The comparison category ordering between both ranges. For the first non-equivalent pair in the ranges,
+ /// the comparison will be returned. Else if the first range is a subset (superset) of the second range, then the
+ /// less (greater) ordering will be returned.
+ ///
+ /// Complexity: At most N iterations, where N = min(last1-first1, last2-first2) of the applications
+ /// of the corresponding comparison.
+ ///
+ /// Note: If two sequences have the same number of elements and their
+ /// corresponding elements are equivalent, then neither sequence is
+ /// lexicographically less than the other. If one sequence is a prefix
+ /// of the other, then the shorter sequence is lexicographically less
+ /// than the longer sequence. Otherwise, the lexicographical comparison
+ /// of the sequences yields the same result as the comparison of the first
+ /// corresponding pair of elements that are not equivalent.
+ ///
+ template <typename InputIterator1, typename InputIterator2, typename Compare>
+ constexpr auto lexicographical_compare_three_way(InputIterator1 first1, InputIterator1 last1,
+ InputIterator2 first2, InputIterator2 last2,
+ Compare compare) -> decltype(compare(*first1, *first2))
+ {
+ for (; (first1 != last1) && (first2 != last2); ++first1, ++first2)
+ {
+ if (auto c = compare(*first1, *first2); c != 0)
+ return c;
+ }
+
+ return (first1 != last1) ? std::strong_ordering::greater :
+ (first2 != last2) ? std::strong_ordering::less :
+ std::strong_ordering::equal;
+ }
+#endif
+
/// mismatch
///
/// Finds the first position where the two ranges [first1, last1) and
@@ -2628,6 +2662,94 @@ namespace eastl
}
+ /// apply_and_remove_if
+ ///
+ /// Calls the Function function for all elements referred to my iterator i in the range
+ /// [first, last) for which the following corresponding condition holds:
+ /// predicate(*i) == true
+ /// and then left shift moves potential non-matching elements over it.
+ ///
+ /// Returns: a past-the-end iterator for the new end of the range.
+ ///
+ /// Complexity: Exactly 'last - first' applications of the corresponding predicate + applies
+ /// function once for every time the condition holds.
+ ///
+ /// Note: Since removing is done by shifting (by means of copy move assignment) the elements
+ /// in the range in such a way that the elements that are not to be removed appear in the
+ /// beginning of the range doesn't actually remove it from the given container, the user must call
+ /// the container erase function if the user wants to erase the element
+ /// from the container. I.e. in the same they as for remove_if the excess elements
+ /// are left in a valid but possibly moved from state.
+ ///
+ template <typename ForwardIterator, typename Function, typename Predicate>
+ inline ForwardIterator apply_and_remove_if(ForwardIterator first,
+ ForwardIterator last,
+ Function function,
+ Predicate predicate)
+ {
+ first = eastl::find_if(first, last, predicate);
+ if (first != last)
+ {
+ function(*first);
+ for (auto i = next(first); i != last; ++i)
+ {
+ if (predicate(*i))
+ {
+ function(*i);
+ continue;
+ }
+ *first = eastl::move(*i);
+ ++first;
+ }
+ }
+ return first;
+ }
+
+
+ /// apply_and_remove
+ ///
+ /// Calls the Function function for all elements referred to my iterator i in the range
+ /// [first, last) for which the following corresponding condition holds:
+ /// value == *i
+ /// and then left shift moves potential non-matching elements over it.
+ ///
+ /// Returns: a past-the-end iterator for the new end of the range.
+ ///
+ /// Complexity: Exactly 'last - first' applications of the corresponding equality test
+ /// + applies function once for every time the condition holds.
+ ///
+ /// Note: Since removing is done by shifting (by means of copy move assignment) the elements
+ /// in the range in such a way that the elements that are not to be removed appear in the
+ /// beginning of the range doesn't actually remove it from the given container, the user must call
+ /// the container erase function if the user wants to erase the element
+ /// from the container. I.e. in the same they as for remove_if the excess elements
+ /// are left in a valid but possibly moved from state.
+ ///
+ template <typename ForwardIterator, typename Function, typename T>
+ inline ForwardIterator apply_and_remove(ForwardIterator first,
+ ForwardIterator last,
+ Function function,
+ const T& value)
+ {
+ first = eastl::find(first, last, value);
+ if (first != last)
+ {
+ function(*first);
+ for (auto i = next(first); i != last; ++i)
+ {
+ if (value == *i)
+ {
+ function(*i);
+ continue;
+ }
+ *first = eastl::move(*i);
+ ++first;
+ }
+ }
+ return first;
+ }
+
+
/// replace_copy
///
/// Effects: Assigns to every iterator i in the range [result, result + (last - first))
@@ -4187,9 +4309,8 @@ namespace eastl
template <class T, class Compare>
EA_CONSTEXPR const T& clamp(const T& v, const T& lo, const T& hi, Compare comp)
{
- // code collapsed to a single line due to constexpr requirements
- return [&] { EASTL_ASSERT(!comp(hi, lo)); }(),
- comp(v, lo) ? lo : comp(hi, v) ? hi : v;
+ EASTL_ASSERT(!comp(hi, lo));
+ return comp(v, lo) ? lo : comp(hi, v) ? hi : v;
}
template <class T>
diff --git a/EASTL/include/EASTL/allocator.h b/EASTL/include/EASTL/allocator.h
index ad20e4d..d645466 100644
--- a/EASTL/include/EASTL/allocator.h
+++ b/EASTL/include/EASTL/allocator.h
@@ -71,8 +71,9 @@ namespace eastl
};
bool operator==(const allocator& a, const allocator& b);
+#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
bool operator!=(const allocator& a, const allocator& b);
-
+#endif
/// dummy_allocator
@@ -97,8 +98,9 @@ namespace eastl
};
inline bool operator==(const dummy_allocator&, const dummy_allocator&) { return true; }
+#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
inline bool operator!=(const dummy_allocator&, const dummy_allocator&) { return false; }
-
+#endif
/// Defines a static default allocator which is constant across all types.
@@ -299,12 +301,12 @@ namespace eastl
return true; // All allocators are considered equal, as they merely use global new/delete.
}
-
+#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
inline bool operator!=(const allocator&, const allocator&)
{
return false; // All allocators are considered equal, as they merely use global new/delete.
}
-
+#endif
} // namespace eastl
diff --git a/EASTL/include/EASTL/allocator_malloc.h b/EASTL/include/EASTL/allocator_malloc.h
index 31f8dec..78f4f69 100644
--- a/EASTL/include/EASTL/allocator_malloc.h
+++ b/EASTL/include/EASTL/allocator_malloc.h
@@ -40,7 +40,7 @@
#endif
#elif defined(EA_PLATFORM_BSD)
#include <malloc/malloc.h>
- #elif defined(EA_COMPILER_CLANG)
+ #elif defined(__clang__)
#if __has_include(<malloc/malloc.h>)
#include <malloc/malloc.h>
#elif __has_include(<malloc.h>)
diff --git a/EASTL/include/EASTL/array.h b/EASTL/include/EASTL/array.h
index 590aa94..34ad07d 100644
--- a/EASTL/include/EASTL/array.h
+++ b/EASTL/include/EASTL/array.h
@@ -279,12 +279,6 @@ namespace eastl
EA_CPP14_CONSTEXPR inline typename array<T, N>::reference
array<T, N>::operator[](size_type i)
{
- #if EASTL_ASSERT_ENABLED
- if(EASTL_UNLIKELY(i >= N))
- EASTL_FAIL_MSG("array::operator[] -- out of range");
- #endif
-
- EA_ANALYSIS_ASSUME(i < N);
return mValue[i];
}
@@ -293,13 +287,6 @@ namespace eastl
EA_CPP14_CONSTEXPR inline typename array<T, N>::const_reference
array<T, N>::operator[](size_type i) const
{
- #if EASTL_ASSERT_ENABLED
- if(EASTL_UNLIKELY(i >= N))
- EASTL_FAIL_MSG("array::operator[] -- out of range");
-
- #endif
-
- EA_ANALYSIS_ASSUME(i < N);
return mValue[i];
}
@@ -308,11 +295,6 @@ namespace eastl
EA_CPP14_CONSTEXPR inline typename array<T, N>::reference
array<T, N>::front()
{
- #if EASTL_ASSERT_ENABLED
- if(EASTL_UNLIKELY(empty())) // We don't allow the user to reference an empty container.
- EASTL_FAIL_MSG("array::front -- empty array");
- #endif
-
return mValue[0];
}
@@ -321,11 +303,6 @@ namespace eastl
EA_CPP14_CONSTEXPR inline typename array<T, N>::const_reference
array<T, N>::front() const
{
- #if EASTL_ASSERT_ENABLED
- if(EASTL_UNLIKELY(empty())) // We don't allow the user to reference an empty container.
- EASTL_FAIL_MSG("array::front -- empty array");
- #endif
-
return mValue[0];
}
@@ -334,11 +311,6 @@ namespace eastl
EA_CPP14_CONSTEXPR inline typename array<T, N>::reference
array<T, N>::back()
{
- #if EASTL_ASSERT_ENABLED
- if(EASTL_UNLIKELY(empty())) // We don't allow the user to reference an empty container.
- EASTL_FAIL_MSG("array::back -- empty array");
- #endif
-
return mValue[N - 1];
}
@@ -347,11 +319,6 @@ namespace eastl
EA_CPP14_CONSTEXPR inline typename array<T, N>::const_reference
array<T, N>::back() const
{
- #if EASTL_ASSERT_ENABLED
- if(EASTL_UNLIKELY(empty())) // We don't allow the user to reference an empty container.
- EASTL_FAIL_MSG("array::back -- empty array");
- #endif
-
return mValue[N - 1];
}
@@ -381,7 +348,6 @@ namespace eastl
EASTL_FAIL_MSG("array::at -- out of range");
#endif
- EA_ANALYSIS_ASSUME(i < N);
return static_cast<const_reference>(mValue[i]);
}
@@ -397,7 +363,6 @@ namespace eastl
EASTL_FAIL_MSG("array::at -- out of range");
#endif
- EA_ANALYSIS_ASSUME(i < N);
return static_cast<reference>(mValue[i]);
}
@@ -436,6 +401,13 @@ namespace eastl
return eastl::equal(&a.mValue[0], &a.mValue[N], &b.mValue[0]);
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T, size_t N>
+ inline synth_three_way_result<T> operator<=>(const array<T, N>& a, const array<T,N>& b)
+ {
+ return eastl::lexicographical_compare_three_way(&a.mValue[0], &a.mValue[N], &b.mValue[0], &b.mValue[N], synth_three_way{});
+ }
+#else
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline bool operator<(const array<T, N>& a, const array<T, N>& b)
@@ -470,7 +442,7 @@ namespace eastl
{
return !eastl::lexicographical_compare(&a.mValue[0], &a.mValue[N], &b.mValue[0], &b.mValue[N]);
}
-
+#endif
template <typename T, size_t N>
inline void swap(array<T, N>& a, array<T, N>& b)
@@ -513,9 +485,96 @@ namespace eastl
return internal::to_array(eastl::move(a), eastl::make_index_sequence<N>{});
}
+#if EASTL_TUPLE_ENABLED
+
+ template <typename T, size_t N>
+ class tuple_size<array<T, N>> : public integral_constant<size_t, N>
+ {
+ };
+
+ template <typename T, size_t N>
+ class tuple_size<const array<T, N>> : public integral_constant<size_t, N>
+ {
+ };
+
+ template <size_t I, typename T, size_t N>
+ class tuple_element<I, array<T, N>>
+ {
+ public:
+ using type = T;
+ };
+
+ template <size_t I, typename T, size_t N>
+ class tuple_element<I, const array<T, N>>
+ {
+ public:
+ using type = const T;
+ };
+
+ template <size_t I>
+ struct GetArray
+ {
+ template <typename T, size_t N>
+ static EA_CONSTEXPR T& getInternal(array<T, N>& a)
+ {
+ return a[I];
+ }
+
+ template <typename T, size_t N>
+ static EA_CONSTEXPR const T& getInternal(const array<T, N>& a)
+ {
+ return a[I];
+ }
+
+ template <typename T, size_t N>
+ static EA_CONSTEXPR T&& getInternal(array<T, N>&& a)
+ {
+ return eastl::forward<T>(a[I]);
+ }
+ };
+
+ template <size_t I, typename T, size_t N>
+ EA_CONSTEXPR tuple_element_t<I, array<T, N>>& get(array<T, N>& p)
+ {
+ return GetArray<I>::getInternal(p);
+ }
+
+ template <size_t I, typename T, size_t N>
+ EA_CONSTEXPR const tuple_element_t<I, array<T, N>>& get(const array<T, N>& p)
+ {
+ return GetArray<I>::getInternal(p);
+ }
+
+ template <size_t I, typename T, size_t N>
+ EA_CONSTEXPR tuple_element_t<I, array<T, N>>&& get(array<T, N>&& p)
+ {
+ return GetArray<I>::getInternal(eastl::move(p));
+ }
+
+#endif // EASTL_TUPLE_ENABLED
+
} // namespace eastl
+///////////////////////////////////////////////////////////////
+// C++17 structured binding support for eastl::array
+//
+#ifndef EA_COMPILER_NO_STRUCTURED_BINDING
+ #include <tuple>
+
+ template <typename T, size_t N>
+ class std::tuple_size<::eastl::array<T, N>> : public ::eastl::integral_constant<size_t, N>
+ {
+ };
+
+ template <size_t I, typename T, size_t N>
+ struct std::tuple_element<I, ::eastl::array<T, N>>
+ {
+ static_assert(I < N, "index is out of bounds");
+ using type = T;
+ };
+#endif // EA_COMPILER_NO_STRUCTURED_BINDING
+
#endif // Header include guard
diff --git a/EASTL/include/EASTL/bit.h b/EASTL/include/EASTL/bit.h
new file mode 100644
index 0000000..0eeeed0
--- /dev/null
+++ b/EASTL/include/EASTL/bit.h
@@ -0,0 +1,172 @@
+/////////////////////////////////////////////////////////////////////////////
+// Copyright (c) Electronic Arts Inc. All rights reserved.
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef EASTL_BIT_H
+#define EASTL_BIT_H
+
+#include <EASTL/internal/config.h>
+
+#if defined(EA_PRAGMA_ONCE_SUPPORTED)
+ #pragma once
+#endif
+
+#include <EASTL/internal/memory_base.h>
+#include <EASTL/type_traits.h>
+#include <string.h> // memcpy
+
+namespace eastl
+{
+ // eastl::bit_cast
+ // Obtains a value of type To by reinterpreting the object representation of 'from'.
+ // Every bit in the value representation of the returned To object is equal to the
+ // corresponding bit in the object representation of 'from'.
+ //
+ // In order for bit_cast to be constexpr, the compiler needs to explicitly support
+ // it by providing the __builtin_bit_cast builtin. If that builtin is not available,
+ // then we memcpy into aligned storage at runtime and return that instead.
+ //
+ // Both types To and From must be equal in size, and must be trivially copyable.
+
+ #if defined(EASTL_CONSTEXPR_BIT_CAST_SUPPORTED) && EASTL_CONSTEXPR_BIT_CAST_SUPPORTED
+
+ template<typename To, typename From,
+ typename = eastl::enable_if_t<
+ sizeof(To) == sizeof(From)
+ && eastl::is_trivially_copyable<To>::value
+ && eastl::is_trivially_copyable<From>::value
+ >
+ >
+ EA_CONSTEXPR To bit_cast(const From& from) EA_NOEXCEPT
+ {
+ return __builtin_bit_cast(To, from);
+ }
+
+ #else
+
+ template<typename To, typename From,
+ typename = eastl::enable_if_t<
+ sizeof(To) == sizeof(From)
+ && eastl::is_trivially_copyable<To>::value
+ && eastl::is_trivially_copyable<From>::value
+ >
+ >
+ inline To bit_cast(const From& from) EA_NOEXCEPT
+ {
+ typename eastl::aligned_storage<sizeof(To), alignof(To)>::type to;
+ ::memcpy(eastl::addressof(to), eastl::addressof(from), sizeof(To));
+ return reinterpret_cast<To&>(to);
+ }
+
+ #endif // EASTL_CONSTEXPR_BIT_CAST_SUPPORTED
+
+ #if defined(EA_COMPILER_CPP20_ENABLED)
+ #ifndef EASTL_COUNT_LEADING_ZEROES
+ #if defined(__GNUC__)
+ #if (EA_PLATFORM_PTR_SIZE == 8)
+ #define EASTL_COUNT_LEADING_ZEROES __builtin_clzll
+ #else
+ #define EASTL_COUNT_LEADING_ZEROES __builtin_clz
+ #endif
+ #endif
+
+ #ifndef EASTL_COUNT_LEADING_ZEROES
+ static inline int eastl_count_leading_zeroes(uint64_t x)
+ {
+ if(x)
+ {
+ int n = 0;
+ if(x & UINT64_C(0xFFFFFFFF00000000)) { n += 32; x >>= 32; }
+ if(x & 0xFFFF0000) { n += 16; x >>= 16; }
+ if(x & 0xFFFFFF00) { n += 8; x >>= 8; }
+ if(x & 0xFFFFFFF0) { n += 4; x >>= 4; }
+ if(x & 0xFFFFFFFC) { n += 2; x >>= 2; }
+ if(x & 0xFFFFFFFE) { n += 1; }
+ return 63 - n;
+ }
+ return 64;
+ }
+
+ static inline int eastl_count_leading_zeroes(uint32_t x)
+ {
+ if(x)
+ {
+ int n = 0;
+ if(x <= 0x0000FFFF) { n += 16; x <<= 16; }
+ if(x <= 0x00FFFFFF) { n += 8; x <<= 8; }
+ if(x <= 0x0FFFFFFF) { n += 4; x <<= 4; }
+ if(x <= 0x3FFFFFFF) { n += 2; x <<= 2; }
+ if(x <= 0x7FFFFFFF) { n += 1; }
+ return n;
+ }
+ return 32;
+ }
+
+ #define EASTL_COUNT_LEADING_ZEROES eastl_count_leading_zeroes
+ #endif
+ #endif
+
+ template <typename T, typename = eastl::enable_if_t<eastl::is_unsigned_v<T>>>
+ EA_CONSTEXPR int countl_zero(const T num) EA_NOEXCEPT
+ {
+ EA_CONSTEXPR auto DIGITS = eastl::numeric_limits<T>::digits;
+ EA_CONSTEXPR auto DIGITS_U = eastl::numeric_limits<unsigned>::digits;
+ EA_CONSTEXPR auto DIGITS_ULL = eastl::numeric_limits<unsigned long long>::digits;
+
+ if (num == 0)
+ {
+ return DIGITS;
+ }
+
+ if constexpr (DIGITS <= DIGITS_U)
+ {
+ EA_CONSTEXPR auto DIFF = DIGITS_U - DIGITS;
+ return EASTL_COUNT_LEADING_ZEROES(static_cast<uint32_t>(num)) - DIFF;
+ }
+ else
+ {
+ EA_CONSTEXPR auto DIFF = DIGITS_ULL - DIGITS;
+ return EASTL_COUNT_LEADING_ZEROES(static_cast<uint64_t>(num)) - DIFF;
+ }
+ }
+
+ template <typename T, typename = eastl::enable_if_t<eastl::is_unsigned_v<T>>>
+ EA_CONSTEXPR bool has_single_bit(const T num) EA_NOEXCEPT
+ {
+ return num != 0 && (num & (num - 1)) == 0;
+ }
+
+ template <typename T, typename = eastl::enable_if_t<eastl::is_unsigned_v<T>>>
+ EA_CONSTEXPR T bit_ceil(const T num) EA_NOEXCEPT
+ {
+ if (num <= 1U)
+ {
+ return T(1);
+ }
+
+ const auto shift = eastl::numeric_limits<T>::digits - eastl::countl_zero(static_cast<T>(num - 1));
+ return static_cast<T>(T(1) << shift);
+ }
+
+ template <typename T, typename = eastl::enable_if_t<eastl::is_unsigned_v<T>>>
+ EA_CONSTEXPR T bit_floor(const T num) EA_NOEXCEPT
+ {
+ if (num == 0)
+ {
+ return T(0);
+ }
+
+ const auto shift = eastl::numeric_limits<T>::digits - eastl::countl_zero(num) - 1;
+ return static_cast<T>(T(1) << shift);
+ }
+
+ template <typename T, typename = eastl::enable_if_t<eastl::is_unsigned_v<T>>>
+ EA_CONSTEXPR T bit_width(const T num) EA_NOEXCEPT
+ {
+ return static_cast<T>(eastl::numeric_limits<T>::digits - eastl::countl_zero(num));
+ }
+ #endif
+
+} // namespace eastl
+
+#endif // EASTL_BIT_H
diff --git a/EASTL/include/EASTL/bitset.h b/EASTL/include/EASTL/bitset.h
index d926105..c31831a 100644
--- a/EASTL/include/EASTL/bitset.h
+++ b/EASTL/include/EASTL/bitset.h
@@ -405,7 +405,9 @@ namespace eastl
size_type size() const;
bool operator==(const this_type& x) const;
+#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
bool operator!=(const this_type& x) const;
+#endif
bool test(size_type i) const;
//bool any() const; // We inherit this from the base class.
@@ -1505,7 +1507,7 @@ EA_RESTORE_GCC_WARNING()
inline typename BitsetBase<2, WordType>::size_type
BitsetBase<2, WordType>::count() const
{
- #if defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 304) // GCC 3.4 or later
+ #if (defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 304)) || defined(__clang__) // GCC 3.4 or later
#if(EA_PLATFORM_WORD_SIZE == 4)
return (size_type)__builtin_popcountl(mWord[0]) + (size_type)__builtin_popcountl(mWord[1]);
#else
@@ -2078,13 +2080,13 @@ EA_RESTORE_GCC_WARNING()
return base_type::operator==(x);
}
-
+#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <size_t N, typename WordType>
inline bool bitset<N, WordType>::operator!=(const this_type& x) const
{
return !base_type::operator==(x);
}
-
+#endif
template <size_t N, typename WordType>
inline bool bitset<N, WordType>::test(size_type i) const
diff --git a/EASTL/include/EASTL/bonus/lru_cache.h b/EASTL/include/EASTL/bonus/lru_cache.h
index 46d053d..a8d7c33 100644
--- a/EASTL/include/EASTL/bonus/lru_cache.h
+++ b/EASTL/include/EASTL/bonus/lru_cache.h
@@ -122,7 +122,7 @@ namespace eastl
}
lru_cache(std::initializer_list<eastl::pair<Key, Value>> il)
- : lru_cache(il.size())
+ : lru_cache(static_cast<size_type>(il.size()))
{
for(auto& p : il)
insert_or_assign(p.first, p.second);
diff --git a/EASTL/include/EASTL/bonus/overloaded.h b/EASTL/include/EASTL/bonus/overloaded.h
new file mode 100644
index 0000000..55ca158
--- /dev/null
+++ b/EASTL/include/EASTL/bonus/overloaded.h
@@ -0,0 +1,81 @@
+/////////////////////////////////////////////////////////////////////////////
+// Copyright (c) Electronic Arts Inc. All rights reserved.
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef EASTL_OVERLOADED_H
+#define EASTL_OVERLOADED_H
+
+#include <EASTL/internal/move_help.h>
+#include <EASTL/type_traits.h>
+
+
+#if defined(EA_PRAGMA_ONCE_SUPPORTED)
+#pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed
+ // improvements in apps as a result.
+#endif
+
+namespace eastl
+{
+ ///////////////////////////////////////////////////////////////////////////
+ /// overloaded
+ ///
+ /// A helper class that permits you to combine multiple function objects into one.
+ /// Typically, this helper is really handy when visiting an eastl::variant with multiple lambdas.
+ /// Example:
+ ///
+ /// eastl::variant<int, string> v{42};
+ ///
+ /// eastl::visit(
+ /// eastl::overloaded{
+ /// [](const int& x) { std::cout << "Visited an integer: " << x << "\n"; }, // Will reach that lambda with x == 42.
+ /// [](const string& s) { std::cout << "Visited an string: " << s << "\n"; }
+ /// },
+ /// v
+ /// );
+ ///////////////////////////////////////////////////////////////////////////
+ template <class... T>
+ struct overloaded;
+
+ template <class T>
+ struct overloaded<T> : T
+ {
+ template <class U>
+ EA_CPP14_CONSTEXPR overloaded(U&& u) : T(eastl::forward<U>(u))
+ {
+ }
+
+ using T::operator();
+ };
+
+ template <class T, class... R>
+ struct overloaded<T, R...> : T, overloaded<R...>
+ {
+ template <class U, class... V>
+ EA_CPP14_CONSTEXPR overloaded(U&& u, V&&... v) : T(eastl::forward<U>(u)), overloaded<R...>(eastl::forward<V>(v)...)
+ {
+ }
+
+ using T::operator();
+ using overloaded<R...>::operator();
+ };
+
+ #ifdef __cpp_deduction_guides
+ template <class... T>
+ overloaded(T...) -> overloaded<T...>;
+ #endif
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// make_overloaded
+ ///
+ /// Helper function to create an overloaded instance when lacking deduction guides.
+ /// make_overloaded(f1, f2, f3) == overloaded{f1, f2, f3}
+ ///////////////////////////////////////////////////////////////////////////
+ template <class... T>
+ EA_CPP14_CONSTEXPR overloaded<typename eastl::remove_cvref<T>::type...> make_overloaded(T&&... t)
+ {
+ return overloaded<typename eastl::remove_cvref<T>::type...>{eastl::forward<T>(t)...};
+ }
+
+} // namespace eastl
+
+#endif // EASTL_OVERLOADED_H \ No newline at end of file
diff --git a/EASTL/include/EASTL/bonus/tuple_vector.h b/EASTL/include/EASTL/bonus/tuple_vector.h
index 7123c57..6ade75a 100644
--- a/EASTL/include/EASTL/bonus/tuple_vector.h
+++ b/EASTL/include/EASTL/bonus/tuple_vector.h
@@ -340,13 +340,13 @@ struct TupleVecIterCompatible<TupleTypes<Us...>, TupleTypes<Ts...>> :
// storing - and harmoniously updating on each modification - a full tuple of pointers to the tupleVec's data
template <eastl_size_t... Indices, typename... Ts>
struct TupleVecIter<index_sequence<Indices...>, Ts...>
- : public iterator<random_access_iterator_tag, tuple<Ts...>, eastl_size_t, tuple<Ts*...>, tuple<Ts&...>>
+ : public iterator<EASTL_ITC_NS::random_access_iterator_tag, tuple<Ts...>, eastl_size_t, tuple<Ts*...>, tuple<Ts&...>>
{
private:
typedef TupleVecIter<index_sequence<Indices...>, Ts...> this_type;
typedef eastl_size_t size_type;
- typedef iterator<random_access_iterator_tag, tuple<Ts...>, eastl_size_t, tuple<Ts*...>, tuple<Ts&...>> iter_type;
+ typedef iterator<EASTL_ITC_NS::random_access_iterator_tag, tuple<Ts...>, eastl_size_t, tuple<Ts*...>, tuple<Ts&...>> iter_type;
template<typename U, typename... Us>
friend struct TupleVecIter;
@@ -1411,7 +1411,6 @@ class move_iterator<TupleVecInternal::TupleVecIter<index_sequence<Indices...>, T
{
public:
typedef TupleVecInternal::TupleVecIter<index_sequence<Indices...>, Ts...> iterator_type;
- typedef iterator_type wrapped_iterator_type; // This is not in the C++ Standard; it's used by use to identify it as
// a wrapping iterator type.
typedef iterator_traits<iterator_type> traits_type;
typedef typename traits_type::iterator_category iterator_category;
@@ -1477,6 +1476,13 @@ private:
{
return reference(eastl::move(((Ts*)mIterator.mpData[Indices])[mIterator.mIndex])...);
}
+
+ // Unwrapping interface, not part of the public API.
+ iterator_type unwrap() const { return mIterator; }
+
+ // The unwrapper helpers need access to unwrap().
+ friend is_iterator_wrapper_helper<this_type, true>;
+ friend is_iterator_wrapper<this_type>;
};
template <typename AllocatorA, typename AllocatorB, typename Indices, typename... Ts>
diff --git a/EASTL/include/EASTL/chrono.h b/EASTL/include/EASTL/chrono.h
index 453ab0f..4b94fe4 100644
--- a/EASTL/include/EASTL/chrono.h
+++ b/EASTL/include/EASTL/chrono.h
@@ -16,7 +16,7 @@
#define EASTL_CHRONO_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
- #pragma once
+ #pragma once
#endif
#include <EASTL/internal/config.h>
@@ -50,12 +50,9 @@
#if defined(EA_PLATFORM_MICROSOFT) && !defined(EA_PLATFORM_MINGW)
// Nothing to do
-#elif defined(EA_PLATFORM_SONY)
- #include <Dinkum/threads/xtimec.h>
- #include <kernel.h>
#elif defined(EA_PLATFORM_APPLE)
#include <mach/mach_time.h>
-#elif defined(EA_PLATFORM_POSIX) || defined(EA_PLATFORM_MINGW) || defined(EA_PLATFORM_ANDROID)
+#elif defined(EA_PLATFORM_POSIX) || defined(EA_PLATFORM_MINGW) || defined(EA_PLATFORM_ANDROID)
// Posix means Linux, Unix, and Macintosh OSX, among others (including Linux-based mobile platforms).
#if defined(EA_PLATFORM_MINGW)
#include <pthread_time.h>
@@ -104,7 +101,7 @@ namespace chrono
namespace Internal
{
///////////////////////////////////////////////////////////////////////////////
- // IsRatio
+ // IsRatio
///////////////////////////////////////////////////////////////////////////////
template <typename> struct IsRatio : eastl::false_type {};
template <intmax_t N, intmax_t D> struct IsRatio<ratio<N, D>> : eastl::true_type {};
@@ -114,7 +111,7 @@ namespace chrono
///////////////////////////////////////////////////////////////////////////////
- // IsDuration
+ // IsDuration
///////////////////////////////////////////////////////////////////////////////
template<typename> struct IsDuration : eastl::false_type{};
template<typename Rep, typename Period> struct IsDuration<duration<Rep, Period>> : eastl::true_type{};
@@ -124,7 +121,7 @@ namespace chrono
///////////////////////////////////////////////////////////////////////////////
- // RatioGCD
+ // RatioGCD
///////////////////////////////////////////////////////////////////////////////
template <class Period1, class Period2>
struct RatioGCD
@@ -197,10 +194,10 @@ namespace chrono
///////////////////////////////////////////////////////////////////////////////
- // duration_cast
+ // duration_cast
///////////////////////////////////////////////////////////////////////////////
template <typename ToDuration, typename Rep, typename Period>
- inline typename eastl::enable_if<Internal::IsDuration<ToDuration>::value, ToDuration>::type
+ inline typename eastl::enable_if<Internal::IsDuration<ToDuration>::value, ToDuration>::type
duration_cast(const duration<Rep, Period>& d)
{
typedef typename duration<Rep, Period>::this_type FromDuration;
@@ -209,12 +206,12 @@ namespace chrono
///////////////////////////////////////////////////////////////////////////////
- // duration
+ // duration
///////////////////////////////////////////////////////////////////////////////
template <class Rep, class Period>
class duration
{
- Rep mRep;
+ Rep mRep;
public:
typedef Rep rep;
@@ -222,7 +219,7 @@ namespace chrono
typedef duration<Rep, Period> this_type;
#if defined(EA_COMPILER_NO_DEFAULTED_FUNCTIONS)
- EA_CONSTEXPR duration()
+ EA_CONSTEXPR duration()
: mRep() {}
duration(const duration& other)
@@ -238,7 +235,7 @@ namespace chrono
///////////////////////////////////////////////////////////////////////////////
- // conversion constructors
+ // conversion constructors
///////////////////////////////////////////////////////////////////////////////
template <class Rep2>
inline EA_CONSTEXPR explicit duration(
@@ -258,12 +255,12 @@ namespace chrono
: mRep(duration_cast<duration>(d2).count()) {}
///////////////////////////////////////////////////////////////////////////////
- // returns the count of ticks
+ // returns the count of ticks
///////////////////////////////////////////////////////////////////////////////
EA_CONSTEXPR Rep count() const { return mRep; }
///////////////////////////////////////////////////////////////////////////////
- // static accessors of special duration values
+ // static accessors of special duration values
///////////////////////////////////////////////////////////////////////////////
EA_CONSTEXPR inline static duration zero() { return duration(duration_values<Rep>::zero()); }
EA_CONSTEXPR inline static duration min() { return duration(duration_values<Rep>::min()); }
@@ -314,7 +311,7 @@ namespace chrono
duration<typename eastl::common_type<Rep1, Rep2>::type, Period1> EASTL_FORCE_INLINE
operator*(const duration<Rep1, Period1>& lhs, const Rep2& rhs)
{
- typedef typename duration<eastl::common_type<Rep1, Rep2>, Period1>::type common_duration_t;
+ typedef duration<typename eastl::common_type<Rep1, Rep2>::type, Period1> common_duration_t;
return common_duration_t(common_duration_t(lhs).count() * rhs);
}
@@ -421,7 +418,7 @@ namespace chrono
///////////////////////////////////////////////////////////////////////////////
// 20.12.6, time_point
///////////////////////////////////////////////////////////////////////////////
- template <typename Clock, typename Duration = typename Clock::duration>
+ template <typename Clock, typename Duration = typename Clock::duration>
class time_point
{
Duration mDuration;
@@ -443,7 +440,7 @@ namespace chrono
EA_CONSTEXPR Duration time_since_epoch() const { return mDuration; }
- time_point& operator+=(const Duration& d) { mDuration += d; return *this; }
+ time_point& operator+=(const Duration& d) { mDuration += d; return *this; }
time_point& operator-=(const Duration& d) { mDuration -= d; return *this; }
static EA_CONSTEXPR time_point min() { return time_point(Duration::min()); }
@@ -546,26 +543,26 @@ namespace chrono
namespace Internal
{
#if defined(EA_PLATFORM_MICROSOFT) && !defined(EA_PLATFORM_MINGW)
- #define EASTL_NS_PER_TICK 1
+ #define EASTL_NS_PER_TICK 1
#elif defined EA_PLATFORM_SONY
- #define EASTL_NS_PER_TICK _XTIME_NSECS_PER_TICK
+ #define EASTL_NS_PER_TICK 1
#elif defined EA_PLATFORM_POSIX
#define EASTL_NS_PER_TICK _XTIME_NSECS_PER_TICK
#else
- #define EASTL_NS_PER_TICK 100
+ #define EASTL_NS_PER_TICK 100
#endif
- #if defined(EA_PLATFORM_POSIX)
+ #if defined(EA_PLATFORM_POSIX)
typedef chrono::nanoseconds::period SystemClock_Period;
typedef chrono::nanoseconds::period SteadyClock_Period;
#else
- typedef eastl::ratio_multiply<eastl::ratio<EASTL_NS_PER_TICK, 1>, nano>::type SystemClock_Period;
- typedef eastl::ratio_multiply<eastl::ratio<EASTL_NS_PER_TICK, 1>, nano>::type SteadyClock_Period;
+ typedef eastl::ratio_multiply<eastl::ratio<EASTL_NS_PER_TICK, 1>, nano>::type SystemClock_Period;
+ typedef eastl::ratio_multiply<eastl::ratio<EASTL_NS_PER_TICK, 1>, nano>::type SteadyClock_Period;
#endif
///////////////////////////////////////////////////////////////////////////////
- // Internal::GetTicks
+ // Internal::GetTicks
///////////////////////////////////////////////////////////////////////////////
inline uint64_t GetTicks()
{
@@ -574,7 +571,7 @@ namespace chrono
{
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
- return double(1000000000.0L / frequency.QuadPart); // nanoseconds per tick
+ return double(1000000000.0L / (long double)frequency.QuadPart); // nanoseconds per tick
};
auto queryCounter = []
@@ -587,18 +584,29 @@ namespace chrono
EA_DISABLE_VC_WARNING(4640) // warning C4640: construction of local static object is not thread-safe (VS2013)
static auto frequency = queryFrequency(); // cache cpu frequency on first call
EA_RESTORE_VC_WARNING()
- return uint64_t(frequency * queryCounter());
- #elif defined EA_PLATFORM_SONY
- return sceKernelGetProcessTimeCounter();
+ return uint64_t(frequency * (double)queryCounter());
+ #elif defined EA_PLATFORM_SONY
+ static_assert(false, "Implementing GetTicks() requires first party support");
+ return 0;
#elif defined(EA_PLATFORM_APPLE)
- return mach_absolute_time();
+ auto queryTimeInfo = []
+ {
+ mach_timebase_info_data_t info;
+ mach_timebase_info(&info);
+ return info;
+ };
+
+ static auto timeInfo = queryTimeInfo();
+ uint64_t t = mach_absolute_time();
+ t *= timeInfo.numer;
+ t /= timeInfo.denom;
+ return t;
#elif defined(EA_PLATFORM_POSIX) // Posix means Linux, Unix, and Macintosh OSX, among others (including Linux-based mobile platforms).
#if (defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC))
timespec ts;
int result = clock_gettime(CLOCK_MONOTONIC, &ts);
- if(result == EINVAL
- )
+ if (result == -1 && errno == EINVAL)
result = clock_gettime(CLOCK_REALTIME, &ts);
const uint64_t nNanoseconds = (uint64_t)ts.tv_nsec + ((uint64_t)ts.tv_sec * UINT64_C(1000000000));
@@ -617,7 +625,7 @@ namespace chrono
///////////////////////////////////////////////////////////////////////////////
- // system_clock
+ // system_clock
///////////////////////////////////////////////////////////////////////////////
class system_clock
{
@@ -631,15 +639,15 @@ namespace chrono
EA_CONSTEXPR_OR_CONST static bool is_steady = false;
// returns a time point representing the current point in time.
- static time_point now() EA_NOEXCEPT
- {
- return time_point(duration(Internal::GetTicks()));
+ static time_point now() EA_NOEXCEPT
+ {
+ return time_point(duration(Internal::GetTicks()));
}
};
///////////////////////////////////////////////////////////////////////////////
- // steady_clock
+ // steady_clock
///////////////////////////////////////////////////////////////////////////////
class steady_clock
{
@@ -653,24 +661,24 @@ namespace chrono
EA_CONSTEXPR_OR_CONST static bool is_steady = true;
// returns a time point representing the current point in time.
- static time_point now() EA_NOEXCEPT
- {
- return time_point(duration(Internal::GetTicks()));
+ static time_point now() EA_NOEXCEPT
+ {
+ return time_point(duration(Internal::GetTicks()));
}
};
///////////////////////////////////////////////////////////////////////////////
- // high_resolution_clock
+ // high_resolution_clock
///////////////////////////////////////////////////////////////////////////////
typedef system_clock high_resolution_clock;
-} // namespace chrono
+} // namespace chrono
///////////////////////////////////////////////////////////////////////////////
- // duration common_type specialization
+ // duration common_type specialization
///////////////////////////////////////////////////////////////////////////////
template <typename Rep1, typename Period1, typename Rep2, typename Period2>
struct common_type<chrono::duration<Rep1, Period1>, chrono::duration<Rep2, Period2>>
@@ -681,7 +689,7 @@ namespace chrono
///////////////////////////////////////////////////////////////////////////////
- // time_point common_type specialization
+ // time_point common_type specialization
///////////////////////////////////////////////////////////////////////////////
template <typename Clock, typename Duration1, typename Duration2>
struct common_type<chrono::time_point<Clock, Duration1>, chrono::time_point<Clock, Duration2>>
@@ -691,10 +699,15 @@ namespace chrono
///////////////////////////////////////////////////////////////////////////////
- // chrono_literals
+ // chrono_literals
///////////////////////////////////////////////////////////////////////////////
#if EASTL_USER_LITERALS_ENABLED && EASTL_INLINE_NAMESPACES_ENABLED
- EA_DISABLE_VC_WARNING(4455) // disable warning C4455: literal suffix identifiers that do not start with an underscore are reserved
+ // Disabling the Clang/GCC/MSVC warning about using user
+ // defined literals without a leading '_' as they are reserved
+ // for standard libary usage.
+ EA_DISABLE_VC_WARNING(4455)
+ EA_DISABLE_CLANG_WARNING(-Wuser-defined-literals)
+ EA_DISABLE_GCC_WARNING(-Wliteral-suffix)
inline namespace literals
{
inline namespace chrono_literals
@@ -727,7 +740,9 @@ namespace chrono
} // namespace chrono_literals
}// namespace literals
- EA_RESTORE_VC_WARNING() // warning: 4455
+ EA_RESTORE_GCC_WARNING() // -Wliteral-suffix
+ EA_RESTORE_CLANG_WARNING() // -Wuser-defined-literals
+ EA_RESTORE_VC_WARNING() // warning: 4455
#endif
} // namespace eastl
@@ -741,4 +756,4 @@ namespace chrono
#endif
-#endif
+#endif
diff --git a/EASTL/include/EASTL/compare.h b/EASTL/include/EASTL/compare.h
new file mode 100644
index 0000000..9bc3bd6
--- /dev/null
+++ b/EASTL/include/EASTL/compare.h
@@ -0,0 +1,45 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) Electronic Arts Inc. All rights reserved.
+///////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef EASTL_COMPARE_H
+#define EASTL_COMPARE_H
+
+
+#include <EABase/eabase.h>
+
+namespace eastl
+{
+
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ struct synth_three_way
+ {
+ template <typename T, typename U>
+ constexpr auto operator()(const T& t, const U& u) const requires requires
+ {
+ {t < u}->std::convertible_to<bool>;
+ {u < t}->std::convertible_to<bool>;
+ }
+ {
+ if constexpr (std::three_way_comparable_with<T, U>)
+ {
+ return t <=> u;
+ }
+ else
+ {
+ return (t < u) ? std::weak_ordering::less :
+ (u < t) ? std::weak_ordering::greater :
+ std::weak_ordering::equivalent;
+ }
+ }
+ };
+
+ template <typename T, typename U=T>
+ using synth_three_way_result = decltype(synth_three_way{}(declval<T&>(), declval<U&>()));
+#endif
+
+} // namespace eastl
+
+
+#endif // Header include guard \ No newline at end of file
diff --git a/EASTL/include/EASTL/deque.h b/EASTL/include/EASTL/deque.h
index c2d55b1..9a812c9 100644
--- a/EASTL/include/EASTL/deque.h
+++ b/EASTL/include/EASTL/deque.h
@@ -2619,6 +2619,14 @@ namespace eastl
return ((a.size() == b.size()) && eastl::equal(a.begin(), a.end(), b.begin()));
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T, typename Allocator, unsigned kDequeSubarraySize>
+ inline synth_three_way_result<T> operator<=>(const deque<T, Allocator, kDequeSubarraySize>& a, const deque<T, Allocator, kDequeSubarraySize>& b)
+ {
+ return eastl::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end(), synth_three_way{});
+ }
+
+#else
template <typename T, typename Allocator, unsigned kDequeSubarraySize>
inline bool operator!=(const deque<T, Allocator, kDequeSubarraySize>& a, const deque<T, Allocator, kDequeSubarraySize>& b)
{
@@ -2648,6 +2656,7 @@ namespace eastl
{
return !(a < b);
}
+#endif
template <typename T, typename Allocator, unsigned kDequeSubarraySize>
inline void swap(deque<T, Allocator, kDequeSubarraySize>& a, deque<T, Allocator, kDequeSubarraySize>& b)
@@ -2661,17 +2670,39 @@ namespace eastl
// https://en.cppreference.com/w/cpp/container/deque/erase2
///////////////////////////////////////////////////////////////////////
template <class T, class Allocator, class U>
- void erase(deque<T, Allocator>& c, const U& value)
+ typename deque<T, Allocator>::size_type erase(deque<T, Allocator>& c, const U& value)
{
- // Erases all elements that compare equal to value from the container.
- c.erase(eastl::remove(c.begin(), c.end(), value), c.end());
+ // Erases all elements that compare equal to value from the container.
+ auto origEnd = c.end();
+ auto newEnd = eastl::remove(c.begin(), origEnd, value);
+ auto numRemoved = eastl::distance(newEnd, origEnd);
+ c.erase(newEnd, origEnd);
+
+ // Note: This is technically a lossy conversion when size_type
+ // is 32bits and ptrdiff_t is 64bits (could happen on 64bit
+ // systems when EASTL_SIZE_T_32BIT is set). In practice this
+ // is fine because if EASTL_SIZE_T_32BIT is set then the deque
+ // should not have more elements than fit in a uint32_t and so
+ // the distance here should fit in a size_type.
+ return static_cast<typename deque<T, Allocator>::size_type>(numRemoved);
}
template <class T, class Allocator, class Predicate>
- void erase_if(deque<T, Allocator>& c, Predicate predicate)
- {
- // Erases all elements that satisfy the predicate pred from the container.
- c.erase(eastl::remove_if(c.begin(), c.end(), predicate), c.end());
+ typename deque<T, Allocator>::size_type erase_if(deque<T, Allocator>& c, Predicate predicate)
+ {
+ // Erases all elements that satisfy the predicate pred from the container.
+ auto origEnd = c.end();
+ auto newEnd = eastl::remove_if(c.begin(), origEnd, predicate);
+ auto numRemoved = eastl::distance(newEnd, origEnd);
+ c.erase(newEnd, origEnd);
+
+ // Note: This is technically a lossy conversion when size_type
+ // is 32bits and ptrdiff_t is 64bits (could happen on 64bit
+ // systems when EASTL_SIZE_T_32BIT is set). In practice this
+ // is fine because if EASTL_SIZE_T_32BIT is set then the deque
+ // should not have more elements than fit in a uint32_t and so
+ // the distance here should fit in a size_type.
+ return static_cast<typename deque<T, Allocator>::size_type>(numRemoved);
}
diff --git a/EASTL/include/EASTL/fixed_hash_map.h b/EASTL/include/EASTL/fixed_hash_map.h
index af6663d..b94ea54 100644
--- a/EASTL/include/EASTL/fixed_hash_map.h
+++ b/EASTL/include/EASTL/fixed_hash_map.h
@@ -251,7 +251,7 @@ namespace eastl
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
- mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME);
+ mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
@@ -267,11 +267,13 @@ namespace eastl
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
- if(!bEnableOverflow)
+ if (!bEnableOverflow)
+ {
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
+ }
#if EASTL_NAME_ENABLED
- mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME);
+ mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
@@ -288,11 +290,13 @@ namespace eastl
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
- if(!bEnableOverflow)
+ if (!bEnableOverflow)
+ {
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
+ }
#if EASTL_NAME_ENABLED
- mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME);
+ mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
@@ -314,7 +318,7 @@ namespace eastl
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
- mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME);
+ mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
@@ -377,7 +381,7 @@ namespace eastl
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
- mAllocator.set_name(x.mAllocator.get_name());
+ mAllocator.set_name(x.mAllocator.get_name());
#endif
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
@@ -402,7 +406,7 @@ namespace eastl
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
- mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME);
+ mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
@@ -532,8 +536,10 @@ namespace eastl
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
- if(!bEnableOverflow)
+ if (!bEnableOverflow)
+ {
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
+ }
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME);
@@ -556,7 +562,7 @@ namespace eastl
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
- mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME);
+ mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
@@ -577,7 +583,7 @@ namespace eastl
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
- mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME);
+ mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
@@ -599,7 +605,7 @@ namespace eastl
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
- mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME);
+ mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
@@ -616,7 +622,7 @@ namespace eastl
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
- mAllocator.set_name(x.mAllocator.get_name());
+ mAllocator.set_name(x.mAllocator.get_name());
#endif
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
@@ -662,7 +668,7 @@ namespace eastl
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
- mAllocator.set_name(x.mAllocator.get_name());
+ mAllocator.set_name(x.mAllocator.get_name());
#endif
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
@@ -687,7 +693,7 @@ namespace eastl
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
- mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME);
+ mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
diff --git a/EASTL/include/EASTL/fixed_hash_set.h b/EASTL/include/EASTL/fixed_hash_set.h
index 0db9f49..fa2783a 100644
--- a/EASTL/include/EASTL/fixed_hash_set.h
+++ b/EASTL/include/EASTL/fixed_hash_set.h
@@ -75,7 +75,7 @@ namespace eastl
bucketCount + 1,
sizeof(typename hash_set<Value, Hash, Predicate, OverflowAllocator, bCacheHashCode>::node_type),
nodeCount,
- EASTL_ALIGN_OF(Value),
+ EASTL_ALIGN_OF(typename hash_set<Value, Hash, Predicate, OverflowAllocator, bCacheHashCode>::node_type),
0,
bEnableOverflow,
OverflowAllocator>,
@@ -83,8 +83,9 @@ namespace eastl
{
public:
typedef fixed_hashtable_allocator<bucketCount + 1, sizeof(typename hash_set<Value, Hash, Predicate,
- OverflowAllocator, bCacheHashCode>::node_type), nodeCount, EASTL_ALIGN_OF(Value), 0,
- bEnableOverflow, OverflowAllocator> fixed_allocator_type;
+ OverflowAllocator, bCacheHashCode>::node_type), nodeCount,
+ EASTL_ALIGN_OF(typename hash_set<Value, Hash, Predicate, OverflowAllocator, bCacheHashCode>::node_type),
+ 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type;
typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type;
typedef fixed_hash_set<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator> this_type;
typedef hash_set<Value, Hash, Predicate, fixed_allocator_type, bCacheHashCode> base_type;
@@ -162,7 +163,7 @@ namespace eastl
bucketCount + 1,
sizeof(typename hash_multiset<Value, Hash, Predicate, OverflowAllocator, bCacheHashCode>::node_type),
nodeCount,
- EASTL_ALIGN_OF(Value),
+ EASTL_ALIGN_OF(typename hash_multiset<Value, Hash, Predicate, OverflowAllocator, bCacheHashCode>::node_type),
0,
bEnableOverflow,
OverflowAllocator>,
@@ -170,7 +171,8 @@ namespace eastl
{
public:
typedef fixed_hashtable_allocator<bucketCount + 1, sizeof(typename hash_multiset<Value, Hash, Predicate,
- OverflowAllocator, bCacheHashCode>::node_type), nodeCount, EASTL_ALIGN_OF(Value), 0,
+ OverflowAllocator, bCacheHashCode>::node_type), nodeCount, EASTL_ALIGN_OF(typename hash_multiset<Value, Hash, Predicate,
+ OverflowAllocator, bCacheHashCode>::node_type), 0,
bEnableOverflow, OverflowAllocator> fixed_allocator_type;
typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type;
typedef hash_multiset<Value, Hash, Predicate, fixed_allocator_type, bCacheHashCode> base_type;
@@ -238,11 +240,13 @@ namespace eastl
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
- if(!bEnableOverflow)
+ if (!bEnableOverflow)
+ {
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
+ }
#if EASTL_NAME_ENABLED
- mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME);
+ mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
@@ -262,7 +266,7 @@ namespace eastl
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
- mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME);
+ mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
@@ -279,11 +283,13 @@ namespace eastl
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
- if(!bEnableOverflow)
+ if (!bEnableOverflow)
+ {
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
+ }
#if EASTL_NAME_ENABLED
- mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME);
+ mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
@@ -302,10 +308,12 @@ namespace eastl
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
+ {
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
+ }
#if EASTL_NAME_ENABLED
- mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME);
+ mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
@@ -322,7 +330,7 @@ namespace eastl
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
- mAllocator.set_name(x.mAllocator.get_name());
+ mAllocator.set_name(x.mAllocator.get_name());
#endif
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
@@ -344,7 +352,7 @@ namespace eastl
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
- mAllocator.set_name(x.mAllocator.get_name());
+ mAllocator.set_name(x.mAllocator.get_name());
#endif
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
@@ -366,7 +374,7 @@ namespace eastl
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
- mAllocator.set_name(x.mAllocator.get_name());
+ mAllocator.set_name(x.mAllocator.get_name());
#endif
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
@@ -391,7 +399,7 @@ namespace eastl
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
- mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME);
+ mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
@@ -515,7 +523,7 @@ namespace eastl
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
- mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME);
+ mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
@@ -535,7 +543,7 @@ namespace eastl
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
- mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME);
+ mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
@@ -556,7 +564,7 @@ namespace eastl
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
- mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME);
+ mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
@@ -578,7 +586,7 @@ namespace eastl
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
- mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME);
+ mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
@@ -595,7 +603,7 @@ namespace eastl
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
- mAllocator.set_name(x.mAllocator.get_name());
+ mAllocator.set_name(x.mAllocator.get_name());
#endif
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
@@ -617,7 +625,7 @@ namespace eastl
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
- mAllocator.set_name(x.mAllocator.get_name());
+ mAllocator.set_name(x.mAllocator.get_name());
#endif
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
@@ -639,7 +647,7 @@ namespace eastl
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
- mAllocator.set_name(x.mAllocator.get_name());
+ mAllocator.set_name(x.mAllocator.get_name());
#endif
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
@@ -664,7 +672,7 @@ namespace eastl
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
- mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME);
+ mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
diff --git a/EASTL/include/EASTL/fixed_list.h b/EASTL/include/EASTL/fixed_list.h
index 9e48089..e57c08b 100644
--- a/EASTL/include/EASTL/fixed_list.h
+++ b/EASTL/include/EASTL/fixed_list.h
@@ -63,12 +63,12 @@ namespace eastl
/// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap.
///
template <typename T, size_t nodeCount, bool bEnableOverflow = true, typename OverflowAllocator = EASTLAllocatorType>
- class fixed_list : public list<T, fixed_node_allocator<sizeof(typename list<T>::node_type),
- nodeCount, EASTL_ALIGN_OF(T), 0, bEnableOverflow, OverflowAllocator> >
+ class fixed_list : public list<T, fixed_node_allocator<sizeof(typename list<T>::node_type),
+ nodeCount, EASTL_ALIGN_OF(typename list<T>::node_type), 0, bEnableOverflow, OverflowAllocator> >
{
public:
- typedef fixed_node_allocator<sizeof(typename list<T>::node_type), nodeCount,
- EASTL_ALIGN_OF(T), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type;
+ typedef fixed_node_allocator<sizeof(typename list<T>::node_type), nodeCount,
+ EASTL_ALIGN_OF(typename list<T>::node_type), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type;
typedef OverflowAllocator overflow_allocator_type;
typedef list<T, fixed_allocator_type> base_type;
typedef fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator> this_type;
diff --git a/EASTL/include/EASTL/fixed_slist.h b/EASTL/include/EASTL/fixed_slist.h
index 85a7a7b..abad7ad 100644
--- a/EASTL/include/EASTL/fixed_slist.h
+++ b/EASTL/include/EASTL/fixed_slist.h
@@ -63,12 +63,12 @@ namespace eastl
/// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap.
///
template <typename T, size_t nodeCount, bool bEnableOverflow = true, typename OverflowAllocator = EASTLAllocatorType>
- class fixed_slist : public slist<T, fixed_node_allocator<sizeof(typename slist<T>::node_type),
- nodeCount, EASTL_ALIGN_OF(T), 0, bEnableOverflow, OverflowAllocator> >
+ class fixed_slist : public slist<T, fixed_node_allocator<sizeof(typename slist<T>::node_type),
+ nodeCount, EASTL_ALIGN_OF(typename slist<T>::node_type), 0, bEnableOverflow, OverflowAllocator> >
{
public:
- typedef fixed_node_allocator<sizeof(typename slist<T>::node_type), nodeCount,
- EASTL_ALIGN_OF(T), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type;
+ typedef fixed_node_allocator<sizeof(typename slist<T>::node_type), nodeCount,
+ EASTL_ALIGN_OF(typename slist<T>::node_type), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type;
typedef OverflowAllocator overflow_allocator_type;
typedef slist<T, fixed_allocator_type> base_type;
typedef fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator> this_type;
diff --git a/EASTL/include/EASTL/fixed_substring.h b/EASTL/include/EASTL/fixed_substring.h
index 033052f..e186cfc 100644
--- a/EASTL/include/EASTL/fixed_substring.h
+++ b/EASTL/include/EASTL/fixed_substring.h
@@ -108,6 +108,10 @@ namespace eastl
{
}
+ fixed_substring(const fixed_substring& x)
+ : fixed_substring(static_cast<const base_type&>(x))
+ {}
+
fixed_substring(const base_type& x)
: base_type()
{
@@ -156,6 +160,12 @@ namespace eastl
AllocateSelf();
}
+ this_type& operator=(const this_type& x)
+ {
+ assign(x);
+ return *this;
+ }
+
this_type& operator=(const base_type& x)
{
assign(x);
diff --git a/EASTL/include/EASTL/functional.h b/EASTL/include/EASTL/functional.h
index 556bf02..6fa3489 100644
--- a/EASTL/include/EASTL/functional.h
+++ b/EASTL/include/EASTL/functional.h
@@ -389,52 +389,41 @@ namespace eastl
// Dual type functions
///////////////////////////////////////////////////////////////////////
+
template <typename T, typename U>
struct equal_to_2 : public binary_function<T, U, bool>
{
EA_CPP14_CONSTEXPR bool operator()(const T& a, const U& b) const
{ return a == b; }
- EA_CPP14_CONSTEXPR bool operator()(const U& b, const T& a) const // If you are getting a 'operator() already defined' error related to on this line while compiling a
- { return b == a; } // hashtable class (e.g. hash_map), it's likely that you are using hashtable::find_as when you should
- }; // be using hashtable::find instead. The problem is that (const T, U) collide. To do: make this work.
- template <typename T>
- struct equal_to_2<T, T> : public equal_to<T>
- {
+ template <typename T_ = T, typename U_ = U, typename = eastl::enable_if_t<!eastl::is_same_v<eastl::remove_const_t<T_>, eastl::remove_const_t<U_>>>>
+ EA_CPP14_CONSTEXPR bool operator()(const U& b, const T& a) const
+ { return b == a; }
};
-
template <typename T, typename U>
struct not_equal_to_2 : public binary_function<T, U, bool>
{
EA_CPP14_CONSTEXPR bool operator()(const T& a, const U& b) const
{ return a != b; }
+
+ template <typename T_ = T, typename U_ = U, typename = eastl::enable_if_t<!eastl::is_same_v<eastl::remove_const_t<T_>, eastl::remove_const_t<U_>>>>
EA_CPP14_CONSTEXPR bool operator()(const U& b, const T& a) const
{ return b != a; }
};
- template <typename T>
- struct not_equal_to_2<T, T> : public not_equal_to<T>
- {
- };
-
template <typename T, typename U>
struct less_2 : public binary_function<T, U, bool>
{
EA_CPP14_CONSTEXPR bool operator()(const T& a, const U& b) const
{ return a < b; }
+
+ template <typename T_ = T, typename U_ = U, typename = eastl::enable_if_t<!eastl::is_same_v<eastl::remove_const_t<T_>, eastl::remove_const_t<U_>>>>
EA_CPP14_CONSTEXPR bool operator()(const U& b, const T& a) const
{ return b < a; }
};
- template <typename T>
- struct less_2<T, T> : public less<T>
- {
- };
-
-
-
/// unary_negate
///
diff --git a/EASTL/include/EASTL/hash_map.h b/EASTL/include/EASTL/hash_map.h
index c363597..e7cad7b 100644
--- a/EASTL/include/EASTL/hash_map.h
+++ b/EASTL/include/EASTL/hash_map.h
@@ -5,9 +5,9 @@
///////////////////////////////////////////////////////////////////////////////
// This file is based on the TR1 (technical report 1) reference implementation
// of the unordered_set/unordered_map C++ classes as of about 4/2005. Most likely
-// many or all C++ library vendors' implementations of this classes will be
+// many or all C++ library vendors' implementations of this classes will be
// based off of the reference version and so will look pretty similar to this
-// file as well as other vendors' versions.
+// file as well as other vendors' versions.
///////////////////////////////////////////////////////////////////////////////
@@ -64,7 +64,7 @@ namespace eastl
/// hash_map
///
/// Implements a hash_map, which is a hashed associative container.
- /// Lookups are O(1) (that is, they are fast) but the container is
+ /// Lookups are O(1) (that is, they are fast) but the container is
/// not sorted. Note that lookups are only O(1) if the hash table
/// is well-distributed (non-colliding). The lookup approaches
/// O(n) behavior as the table becomes increasingly poorly distributed.
@@ -74,17 +74,17 @@ namespace eastl
/// call set_max_load_factor with a very high value such as 100000.f.
///
/// bCacheHashCode
- /// We provide the boolean bCacheHashCode template parameter in order
- /// to allow the storing of the hash code of the key within the map.
- /// When this option is disabled, the rehashing of the table will
- /// call the hash function on the key. Setting bCacheHashCode to true
+ /// We provide the boolean bCacheHashCode template parameter in order
+ /// to allow the storing of the hash code of the key within the map.
+ /// When this option is disabled, the rehashing of the table will
+ /// call the hash function on the key. Setting bCacheHashCode to true
/// is useful for cases whereby the calculation of the hash value for
/// a contained object is very expensive.
///
/// find_as
/// In order to support the ability to have a hashtable of strings but
- /// be able to do efficiently lookups via char pointers (i.e. so they
- /// aren't converted to string objects), we provide the find_as
+ /// be able to do efficiently lookups via char pointers (i.e. so they
+ /// aren't converted to string objects), we provide the find_as
/// function. This function allows you to do a find with a key of a
/// type other than the hashtable key type.
///
@@ -96,16 +96,16 @@ namespace eastl
/// hash_map<string, int> hashMap;
/// i = hashMap.find_as("hello", hash<char*>(), equal_to_2<string, char*>());
///
- template <typename Key, typename T, typename Hash = eastl::hash<Key>, typename Predicate = eastl::equal_to<Key>,
+ template <typename Key, typename T, typename Hash = eastl::hash<Key>, typename Predicate = eastl::equal_to<Key>,
typename Allocator = EASTLAllocatorType, bool bCacheHashCode = false>
class hash_map
: public hashtable<Key, eastl::pair<const Key, T>, Allocator, eastl::use_first<eastl::pair<const Key, T> >, Predicate,
Hash, mod_range_hashing, default_ranged_hash, prime_rehash_policy, bCacheHashCode, true, true>
{
public:
- typedef hashtable<Key, eastl::pair<const Key, T>, Allocator,
- eastl::use_first<eastl::pair<const Key, T> >,
- Predicate, Hash, mod_range_hashing, default_ranged_hash,
+ typedef hashtable<Key, eastl::pair<const Key, T>, Allocator,
+ eastl::use_first<eastl::pair<const Key, T> >,
+ Predicate, Hash, mod_range_hashing, default_ranged_hash,
prime_rehash_policy, bCacheHashCode, true, true> base_type;
typedef hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode> this_type;
typedef typename base_type::size_type size_type;
@@ -125,8 +125,19 @@ namespace eastl
///
/// Default constructor.
///
- explicit hash_map(const allocator_type& allocator = EASTL_HASH_MAP_DEFAULT_ALLOCATOR)
- : base_type(0, Hash(), mod_range_hashing(), default_ranged_hash(),
+ hash_map()
+ : this_type(EASTL_HASH_MAP_DEFAULT_ALLOCATOR)
+ {
+ // Empty
+ }
+
+
+ /// hash_map
+ ///
+ /// Constructor which creates an empty container with allocator.
+ ///
+ explicit hash_map(const allocator_type& allocator)
+ : base_type(0, Hash(), mod_range_hashing(), default_ranged_hash(),
Predicate(), eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
@@ -136,12 +147,12 @@ namespace eastl
/// hash_map
///
/// Constructor which creates an empty container, but start with nBucketCount buckets.
- /// We default to a small nBucketCount value, though the user really should manually
+ /// We default to a small nBucketCount value, though the user really should manually
/// specify an appropriate value in order to prevent memory from being reallocated.
///
- explicit hash_map(size_type nBucketCount, const Hash& hashFunction = Hash(),
+ explicit hash_map(size_type nBucketCount, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MAP_DEFAULT_ALLOCATOR)
- : base_type(nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
+ : base_type(nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
@@ -168,12 +179,12 @@ namespace eastl
/// hash_map
///
- /// initializer_list-based constructor.
+ /// initializer_list-based constructor.
/// Allows for initializing with brace values (e.g. hash_map<int, char*> hm = { {3,"c"}, {4,"d"}, {5,"e"} }; )
- ///
- hash_map(std::initializer_list<value_type> ilist, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
+ ///
+ hash_map(std::initializer_list<value_type> ilist, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MAP_DEFAULT_ALLOCATOR)
- : base_type(ilist.begin(), ilist.end(), nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
+ : base_type(ilist.begin(), ilist.end(), nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
@@ -182,13 +193,13 @@ namespace eastl
/// hash_map
///
- /// An input bucket count of <= 1 causes the bucket count to be equal to the number of
+ /// An input bucket count of <= 1 causes the bucket count to be equal to the number of
/// elements in the input range.
///
template <typename ForwardIterator>
- hash_map(ForwardIterator first, ForwardIterator last, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
+ hash_map(ForwardIterator first, ForwardIterator last, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MAP_DEFAULT_ALLOCATOR)
- : base_type(first, last, nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
+ : base_type(first, last, nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
@@ -215,8 +226,8 @@ namespace eastl
/// insert
///
- /// This is an extension to the C++ standard. We insert a default-constructed
- /// element with the given key. The reason for this is that we can avoid the
+ /// This is an extension to the C++ standard. We insert a default-constructed
+ /// element with the given key. The reason for this is that we can avoid the
/// potentially expensive operation of creating and/or copying a mapped_type
/// object on the stack.
insert_return_type insert(const key_type& key)
@@ -285,15 +296,61 @@ namespace eastl
return (*base_type::DoInsertKey(true_type(), eastl::move(key)).first).second;
}
+ // try_emplace API added in C++17
+ template <class... Args>
+ inline insert_return_type try_emplace(const key_type& k, Args&&... args)
+ {
+ return try_emplace_forwarding(k, eastl::forward<Args>(args)...);
+ }
+
+ template <class... Args>
+ inline insert_return_type try_emplace(key_type&& k, Args&&... args) {
+ return try_emplace_forwarding(eastl::move(k), eastl::forward<Args>(args)...);
+ }
+
+ template <class... Args>
+ inline iterator try_emplace(const_iterator, const key_type& k, Args&&... args) {
+ // Currently, the first parameter is ignored.
+ insert_return_type result = try_emplace(k, eastl::forward<Args>(args)...);
+ return base_type::DoGetResultIterator(true_type(), result);
+ }
+
+ template <class... Args>
+ inline iterator try_emplace(const_iterator, key_type&& k, Args&&... args) {
+ // Currently, the first parameter is ignored.
+ insert_return_type result = try_emplace(eastl::move(k), eastl::forward<Args>(args)...);
+ return base_type::DoGetResultIterator(true_type(), result);
+ }
+ private:
+ template <class K, class... Args>
+ insert_return_type try_emplace_forwarding(K&& k, Args&&... args)
+ {
+ const auto key_data = base_type::DoFindKeyData(k);
+ if (key_data.node)
+ { // Node exists, no insertion needed.
+ return eastl::pair<iterator, bool>(
+ iterator(key_data.node, base_type::mpBucketArray + key_data.bucket_index), false);
+ }
+ else
+ {
+ node_type* const pNodeNew =
+ base_type::DoAllocateNode(piecewise_construct, eastl::forward_as_tuple(eastl::forward<K>(k)),
+ forward_as_tuple(eastl::forward<Args>(args)...));
+ // the key might have been moved from above, so we can't use `k` anymore.
+ const auto& key = base_type::mExtractKey(pNodeNew->mValue);
+ return base_type::template DoInsertUniqueNode<true>(key, key_data.code, key_data.bucket_index, pNodeNew);
+ }
+ }
}; // hash_map
/// hash_map erase_if
///
/// https://en.cppreference.com/w/cpp/container/unordered_map/erase_if
template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode, typename UserPredicate>
- void erase_if(eastl::hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& c, UserPredicate predicate)
+ typename eastl::hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>::size_type erase_if(eastl::hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& c, UserPredicate predicate)
{
+ auto oldSize = c.size();
// Erases all elements that satisfy the predicate from the container.
for (auto i = c.begin(), last = c.end(); i != last;)
{
@@ -306,13 +363,14 @@ namespace eastl
++i;
}
}
+ return oldSize - c.size();
}
/// hash_multimap
///
- /// Implements a hash_multimap, which is the same thing as a hash_map
- /// except that contained elements need not be unique. See the
+ /// Implements a hash_multimap, which is the same thing as a hash_map
+ /// except that contained elements need not be unique. See the
/// documentation for hash_set for details.
///
template <typename Key, typename T, typename Hash = eastl::hash<Key>, typename Predicate = eastl::equal_to<Key>,
@@ -322,9 +380,9 @@ namespace eastl
Hash, mod_range_hashing, default_ranged_hash, prime_rehash_policy, bCacheHashCode, true, false>
{
public:
- typedef hashtable<Key, eastl::pair<const Key, T>, Allocator,
- eastl::use_first<eastl::pair<const Key, T> >,
- Predicate, Hash, mod_range_hashing, default_ranged_hash,
+ typedef hashtable<Key, eastl::pair<const Key, T>, Allocator,
+ eastl::use_first<eastl::pair<const Key, T> >,
+ Predicate, Hash, mod_range_hashing, default_ranged_hash,
prime_rehash_policy, bCacheHashCode, true, false> base_type;
typedef hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode> this_type;
typedef typename base_type::size_type size_type;
@@ -339,7 +397,6 @@ namespace eastl
using base_type::insert;
private:
- using base_type::try_emplace;
using base_type::insert_or_assign;
public:
@@ -348,7 +405,7 @@ namespace eastl
/// Default constructor.
///
explicit hash_multimap(const allocator_type& allocator = EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR)
- : base_type(0, Hash(), mod_range_hashing(), default_ranged_hash(),
+ : base_type(0, Hash(), mod_range_hashing(), default_ranged_hash(),
Predicate(), eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
@@ -358,12 +415,12 @@ namespace eastl
/// hash_multimap
///
/// Constructor which creates an empty container, but start with nBucketCount buckets.
- /// We default to a small nBucketCount value, though the user really should manually
+ /// We default to a small nBucketCount value, though the user really should manually
/// specify an appropriate value in order to prevent memory from being reallocated.
///
- explicit hash_multimap(size_type nBucketCount, const Hash& hashFunction = Hash(),
+ explicit hash_multimap(size_type nBucketCount, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR)
- : base_type(nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
+ : base_type(nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
@@ -390,12 +447,12 @@ namespace eastl
/// hash_multimap
///
- /// initializer_list-based constructor.
+ /// initializer_list-based constructor.
/// Allows for initializing with brace values (e.g. hash_multimap<int, char*> hm = { {3,"c"}, {3,"C"}, {4,"d"} }; )
- ///
- hash_multimap(std::initializer_list<value_type> ilist, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
+ ///
+ hash_multimap(std::initializer_list<value_type> ilist, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR)
- : base_type(ilist.begin(), ilist.end(), nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
+ : base_type(ilist.begin(), ilist.end(), nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
@@ -404,13 +461,13 @@ namespace eastl
/// hash_multimap
///
- /// An input bucket count of <= 1 causes the bucket count to be equal to the number of
+ /// An input bucket count of <= 1 causes the bucket count to be equal to the number of
/// elements in the input range.
///
template <typename ForwardIterator>
- hash_multimap(ForwardIterator first, ForwardIterator last, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
+ hash_multimap(ForwardIterator first, ForwardIterator last, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR)
- : base_type(first, last, nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
+ : base_type(first, last, nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
@@ -437,8 +494,8 @@ namespace eastl
/// insert
///
- /// This is an extension to the C++ standard. We insert a default-constructed
- /// element with the given key. The reason for this is that we can avoid the
+ /// This is an extension to the C++ standard. We insert a default-constructed
+ /// element with the given key. The reason for this is that we can avoid the
/// potentially expensive operation of creating and/or copying a mapped_type
/// object on the stack.
insert_return_type insert(const key_type& key)
@@ -458,8 +515,9 @@ namespace eastl
///
/// https://en.cppreference.com/w/cpp/container/unordered_multimap/erase_if
template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode, typename UserPredicate>
- void erase_if(eastl::hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& c, UserPredicate predicate)
+ typename eastl::hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>::size_type erase_if(eastl::hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& c, UserPredicate predicate)
{
+ auto oldSize = c.size();
// Erases all elements that satisfy the predicate from the container.
for (auto i = c.begin(), last = c.end(); i != last;)
{
@@ -472,6 +530,7 @@ namespace eastl
++i;
}
}
+ return oldSize - c.size();
}
@@ -481,7 +540,7 @@ namespace eastl
///////////////////////////////////////////////////////////////////////
template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
- inline bool operator==(const hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
+ inline bool operator==(const hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
const hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& b)
{
typedef typename hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>::const_iterator const_iterator;
@@ -496,23 +555,24 @@ namespace eastl
{
const_iterator bi = b.find(ai->first);
- if((bi == biEnd) || !(*ai == *bi)) // We have to compare the values, because lookups are done by keys alone but the full value_type of a map is a key/value pair.
+ if((bi == biEnd) || !(*ai == *bi)) // We have to compare the values, because lookups are done by keys alone but the full value_type of a map is a key/value pair.
return false; // It's possible that two elements in the two containers have identical keys but different values.
}
return true;
}
+#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
- inline bool operator!=(const hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
+ inline bool operator!=(const hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
const hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& b)
{
return !(a == b);
}
-
+#endif
template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
- inline bool operator==(const hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
+ inline bool operator==(const hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
const hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& b)
{
typedef typename hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>::const_iterator const_iterator;
@@ -522,9 +582,9 @@ namespace eastl
if(a.size() != b.size())
return false;
- // We can't simply search for each element of a in b, as it may be that the bucket for
- // two elements in a has those same two elements in b but in different order (which should
- // still result in equality). Also it's possible that one bucket in a has two elements which
+ // We can't simply search for each element of a in b, as it may be that the bucket for
+ // two elements in a has those same two elements in b but in different order (which should
+ // still result in equality). Also it's possible that one bucket in a has two elements which
// both match a solitary element in the equivalent bucket in b (which shouldn't result in equality).
eastl::pair<const_iterator, const_iterator> aRange;
eastl::pair<const_iterator, const_iterator> bRange;
@@ -545,12 +605,12 @@ namespace eastl
// Implement a fast pathway for the case that there's just a single element.
if(aDistance == 1)
{
- if(!(*aRange.first == *bRange.first)) // We have to compare the values, because lookups are done by keys alone but the full value_type of a map is a key/value pair.
+ if(!(*aRange.first == *bRange.first)) // We have to compare the values, because lookups are done by keys alone but the full value_type of a map is a key/value pair.
return false; // It's possible that two elements in the two containers have identical keys but different values. Ditto for the permutation case below.
}
else
{
- // Check to see if these aRange and bRange are any permutation of each other.
+ // Check to see if these aRange and bRange are any permutation of each other.
// This check gets slower as there are more elements in the range.
if(!eastl::is_permutation(aRange.first, aRange.second, bRange.first))
return false;
@@ -560,21 +620,17 @@ namespace eastl
return true;
}
+#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
- inline bool operator!=(const hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
+ inline bool operator!=(const hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
const hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& b)
{
return !(a == b);
}
+#endif
} // namespace eastl
#endif // Header include guard
-
-
-
-
-
-
diff --git a/EASTL/include/EASTL/hash_set.h b/EASTL/include/EASTL/hash_set.h
index c075975..3215d36 100644
--- a/EASTL/include/EASTL/hash_set.h
+++ b/EASTL/include/EASTL/hash_set.h
@@ -117,8 +117,19 @@ namespace eastl
/// hash_set
///
/// Default constructor.
- ///
- explicit hash_set(const allocator_type& allocator = EASTL_HASH_SET_DEFAULT_ALLOCATOR)
+ ///
+ hash_set()
+ : this_type(EASTL_HASH_SET_DEFAULT_ALLOCATOR)
+ {
+ // Empty
+ }
+
+
+ /// hash_set
+ ///
+ /// Constructor which creates an empty container with allocator.
+ ///
+ explicit hash_set(const allocator_type& allocator)
: base_type(0, Hash(), mod_range_hashing(), default_ranged_hash(), Predicate(), eastl::use_self<Value>(), allocator)
{
// Empty
@@ -207,8 +218,9 @@ namespace eastl
///
/// https://en.cppreference.com/w/cpp/container/unordered_set/erase_if
template <typename Value, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode, typename UserPredicate>
- void erase_if(eastl::hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode>& c, UserPredicate predicate)
+ typename eastl::hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode>::size_type erase_if(eastl::hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode>& c, UserPredicate predicate)
{
+ auto oldSize = c.size();
// Erases all elements that satisfy the predicate pred from the container.
for (auto i = c.begin(), last = c.end(); i != last;)
{
@@ -221,6 +233,7 @@ namespace eastl
++i;
}
}
+ return oldSize - c.size();
}
@@ -341,8 +354,9 @@ namespace eastl
///
/// https://en.cppreference.com/w/cpp/container/unordered_multiset/erase_if
template <typename Value, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode, typename UserPredicate>
- void erase_if(eastl::hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>& c, UserPredicate predicate)
+ typename eastl::hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>::size_type erase_if(eastl::hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>& c, UserPredicate predicate)
{
+ auto oldSize = c.size();
// Erases all elements that satisfy the predicate pred from the container.
for (auto i = c.begin(), last = c.end(); i != last;)
{
@@ -355,6 +369,7 @@ namespace eastl
++i;
}
}
+ return oldSize - c.size();
}
@@ -386,13 +401,14 @@ namespace eastl
return true;
}
+#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <typename Value, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
inline bool operator!=(const hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode>& a,
const hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode>& b)
{
return !(a == b);
}
-
+#endif
template <typename Value, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
inline bool operator==(const hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>& a,
@@ -443,12 +459,14 @@ namespace eastl
return true;
}
+#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <typename Value, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
inline bool operator!=(const hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>& a,
const hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>& b)
{
return !(a == b);
}
+#endif
} // namespace eastl
diff --git a/EASTL/include/EASTL/heap.h b/EASTL/include/EASTL/heap.h
index f0e770b..a8e4260 100644
--- a/EASTL/include/EASTL/heap.h
+++ b/EASTL/include/EASTL/heap.h
@@ -55,7 +55,7 @@ namespace eastl
inline void promote_heap_impl(RandomAccessIterator first, Distance topPosition, Distance position, T value)
{
for(Distance parentPosition = (position - 1) >> 1; // This formula assumes that (position > 0). // We use '>> 1' instead of '/ 2' because we have seen VC++ generate better code with >>.
- (position > topPosition) && (*(first + parentPosition) < value);
+ (position > topPosition) && eastl::less<ValueType>()(*(first + parentPosition), value);
parentPosition = (position - 1) >> 1)
{
*(first + position) = eastl::forward<ValueType>(*(first + parentPosition)); // Swap the node with its parent.
@@ -170,7 +170,7 @@ namespace eastl
for(; childPosition < heapSize; childPosition = (2 * childPosition) + 2)
{
- if(*(first + childPosition) < *(first + (childPosition - 1))) // Choose the larger of the two children.
+ if(eastl::less<ValueType>()(*(first + childPosition), *(first + (childPosition - 1)))) // Choose the larger of the two children.
--childPosition;
*(first + position) = eastl::forward<ValueType>(*(first + childPosition)); // Swap positions with this child.
position = childPosition;
diff --git a/EASTL/include/EASTL/internal/atomic/arch/arm/arch_arm_memory_barrier.h b/EASTL/include/EASTL/internal/atomic/arch/arm/arch_arm_memory_barrier.h
index c52962e..44dc991 100644
--- a/EASTL/include/EASTL/internal/atomic/arch/arm/arch_arm_memory_barrier.h
+++ b/EASTL/include/EASTL/internal/atomic/arch/arm/arch_arm_memory_barrier.h
@@ -11,7 +11,7 @@
#endif
-#if defined(EA_COMPILER_MSVC)
+#if defined(EA_COMPILER_MSVC) && !defined(EA_COMPILER_CLANG_CL)
#if defined(EA_PROCESSOR_ARM32)
@@ -46,7 +46,7 @@
EASTL_ATOMIC_COMPILER_BARRIER()
-#elif defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)
+#elif defined(EA_COMPILER_GNUC) || defined(__clang__)
#define EASTL_ARM_DMB_ISH ish
diff --git a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86.h b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86.h
index 5087c13..77c383a 100644
--- a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86.h
+++ b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86.h
@@ -32,23 +32,14 @@
/////////////////////////////////////////////////////////////////////////////////
-
-#if defined(EA_COMPILER_MSVC)
-
+#if (defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)
+ #define EASTL_ARCH_ATOMIC_HAS_128BIT
+#elif defined(EA_COMPILER_MSVC)
#if EA_PLATFORM_PTR_SIZE == 8
#define EASTL_ARCH_ATOMIC_HAS_128BIT
#endif
-
#endif
-
-#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
-
- #define EASTL_ARCH_ATOMIC_HAS_128BIT
-
-#endif
-
-
/////////////////////////////////////////////////////////////////////////////////
@@ -77,7 +68,7 @@
#define EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, MemoryOrder, PRE_COMPUTE_DESIRED, POST_COMPUTE_RET) \
{ \
- bool cmpxchgRet; \
+ EASTL_ATOMIC_DEFAULT_INIT(bool, cmpxchgRet); \
EASTL_ATOMIC_LOAD_RELAXED_64(type, ret, ptr); \
do \
{ \
@@ -104,7 +95,7 @@
* SSE 128-bit loads are not guaranteed to be atomic even though some CPUs
* make them atomic such as AMD Ryzen or Intel SandyBridge.
*/
-#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
+#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_NOP_PRE_COMPUTE_DESIRED(ret, observed, val) \
@@ -115,7 +106,7 @@
#define EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, MemoryOrder, PRE_COMPUTE_DESIRED, POST_COMPUTE_RET) \
{ \
- bool cmpxchgRet; \
+ EASTL_ATOMIC_DEFAULT_INIT(bool, cmpxchgRet); \
/* This is intentionally a non-atomic 128-bit load which may observe shearing. */ \
/* Either we do not observe *(ptr) but then the cmpxchg will fail and the observed */ \
/* atomic load will be returned. Or the non-atomic load got lucky and the cmpxchg succeeds */ \
diff --git a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_add_fetch.h b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_add_fetch.h
index 4534806..7b77528 100644
--- a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_add_fetch.h
+++ b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_add_fetch.h
@@ -54,7 +54,7 @@
#endif
-#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
+#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_ADD_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \
diff --git a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_and_fetch.h b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_and_fetch.h
index c38ba41..0583163 100644
--- a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_and_fetch.h
+++ b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_and_fetch.h
@@ -54,7 +54,7 @@
#endif
-#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
+#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_AND_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \
diff --git a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_strong.h b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_strong.h
index e028398..1968e9a 100644
--- a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_strong.h
+++ b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_strong.h
@@ -15,7 +15,7 @@
//
// void EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_*_*_N(type, bool ret, type * ptr, type * expected, type desired)
//
-#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
+#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_CMPXCHG_STRONG_128_IMPL(type, ret, ptr, expected, desired) \
diff --git a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_weak.h b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_weak.h
index f8b956a..61a126c 100644
--- a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_weak.h
+++ b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_cmpxchg_weak.h
@@ -15,7 +15,7 @@
//
// void EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_*_*_N(type, bool ret, type * ptr, type * expected, type desired)
//
-#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
+#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_128(type, ret, ptr, expected, desired) \
diff --git a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_exchange.h b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_exchange.h
index 0f05800..b1de7d8 100644
--- a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_exchange.h
+++ b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_exchange.h
@@ -51,12 +51,12 @@
#endif
-#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
+#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_EXCHANGE_128(type, ret, ptr, val, MemoryOrder) \
{ \
- bool cmpxchgRet; \
+ EASTL_ATOMIC_DEFAULT_INIT(bool, cmpxchgRet); \
/* This is intentionally a non-atomic 128-bit load which may observe shearing. */ \
/* Either we do not observe *(ptr) but then the cmpxchg will fail and the observed */ \
/* atomic load will be returned. Or the non-atomic load got lucky and the cmpxchg succeeds */ \
diff --git a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_add.h b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_add.h
index d78b333..e816af9 100644
--- a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_add.h
+++ b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_add.h
@@ -51,7 +51,7 @@
#endif
-#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
+#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_FETCH_ADD_PRE_COMPUTE_DESIRED(ret, observed, val) \
diff --git a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_and.h b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_and.h
index fd7dbb9..ff27b1a 100644
--- a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_and.h
+++ b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_and.h
@@ -51,7 +51,7 @@
#endif
-#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
+#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_FETCH_AND_PRE_COMPUTE_DESIRED(ret, observed, val) \
diff --git a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_or.h b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_or.h
index 50da6db..8627d3a 100644
--- a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_or.h
+++ b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_or.h
@@ -51,7 +51,7 @@
#endif
-#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
+#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_FETCH_OR_PRE_COMPUTE_DESIRED(ret, observed, val) \
diff --git a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_sub.h b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_sub.h
index 77bee83..14b43f9 100644
--- a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_sub.h
+++ b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_sub.h
@@ -51,7 +51,7 @@
#endif
-#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
+#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_FETCH_SUB_PRE_COMPUTE_DESIRED(ret, observed, val) \
diff --git a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_xor.h b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_xor.h
index 2e76b0c..666df8b 100644
--- a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_xor.h
+++ b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_fetch_xor.h
@@ -51,7 +51,7 @@
#endif
-#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
+#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_FETCH_XOR_PRE_COMPUTE_DESIRED(ret, observed, val) \
diff --git a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_load.h b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_load.h
index b044190..644a2a1 100644
--- a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_load.h
+++ b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_load.h
@@ -15,7 +15,46 @@
//
// void EASTL_ARCH_ATOMIC_LOAD_*_N(type, type ret, type * ptr)
//
-#if defined(EA_COMPILER_MSVC)
+
+#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
+
+
+ /**
+ * NOTE:
+ *
+ * Since the cmpxchg 128-bit inline assembly does a sete in the asm to set the return boolean,
+ * it doesn't get dead-store removed even though we don't care about the success of the
+ * cmpxchg since the compiler cannot reason about what is inside asm blocks.
+ * Thus this variant just does the minimum required to do an atomic load.
+ */
+#define EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, MemoryOrder) \
+ { \
+ EASTL_ATOMIC_FIXED_WIDTH_TYPE_128 expected = 0; \
+ ret = EASTL_ATOMIC_TYPE_PUN_CAST(type, expected); \
+ \
+ /* Compare RDX:RAX with m128. If equal, set ZF and load RCX:RBX into m128. Else, clear ZF and load m128 into RDX:RAX. */ \
+ __asm__ __volatile__ ("lock; cmpxchg16b %2" /* cmpxchg16b sets/clears ZF */ \
+ /* Output Operands */ \
+ : "=a"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[0]), "=d"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[1]), \
+ "+m"(*(EASTL_ATOMIC_VOLATILE_INTEGRAL_CAST(__uint128_t, (ptr)))) \
+ /* Input Operands */ \
+ : "b"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[0]), "c"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[1]), \
+ "a"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[0]), "d"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[1]) \
+ /* Clobbers */ \
+ : "memory", "cc"); \
+ }
+
+
+#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_128(type, ret, ptr) \
+ EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, RELAXED)
+
+#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_128(type, ret, ptr) \
+ EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, ACQUIRE)
+
+#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_128(type, ret, ptr) \
+ EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, SEQ_CST)
+
+#elif defined(EA_COMPILER_MSVC)
#if defined(EA_COMPILER_MSVC) && (EA_COMPILER_VERSION >= 1920) // >= VS2019
@@ -119,49 +158,6 @@
#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_128(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, SEQ_CST)
-
-#endif
-
-
-#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
-
-
- /**
- * NOTE:
- *
- * Since the cmpxchg 128-bit inline assembly does a sete in the asm to set the return boolean,
- * it doesn't get dead-store removed even though we don't care about the success of the
- * cmpxchg since the compiler cannot reason about what is inside asm blocks.
- * Thus this variant just does the minimum required to do an atomic load.
- */
- #define EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, MemoryOrder) \
- { \
- EASTL_ATOMIC_FIXED_WIDTH_TYPE_128 expected = 0; \
- ret = EASTL_ATOMIC_TYPE_PUN_CAST(type, expected); \
- \
- /* Compare RDX:RAX with m128. If equal, set ZF and load RCX:RBX into m128. Else, clear ZF and load m128 into RDX:RAX. */ \
- __asm__ __volatile__ ("lock; cmpxchg16b %2" /* cmpxchg16b sets/clears ZF */ \
- /* Output Operands */ \
- : "=a"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[0]), "=d"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[1]), \
- "+m"(*(EASTL_ATOMIC_VOLATILE_INTEGRAL_CAST(__uint128_t, (ptr)))) \
- /* Input Operands */ \
- : "b"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[0]), "c"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[1]), \
- "a"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[0]), "d"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[1]) \
- /* Clobbers */ \
- : "memory", "cc"); \
- }
-
-
- #define EASTL_ARCH_ATOMIC_LOAD_RELAXED_128(type, ret, ptr) \
- EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, RELAXED)
-
- #define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_128(type, ret, ptr) \
- EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, ACQUIRE)
-
- #define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_128(type, ret, ptr) \
- EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, SEQ_CST)
-
-
#endif
diff --git a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_memory_barrier.h b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_memory_barrier.h
index 1d1c8fc..7bad141 100644
--- a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_memory_barrier.h
+++ b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_memory_barrier.h
@@ -46,7 +46,7 @@
#endif
-#elif defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)
+#elif defined(__clang__) || defined(EA_COMPILER_GNUC)
/**
* NOTE:
diff --git a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_or_fetch.h b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_or_fetch.h
index 751cc2a..42f7d61 100644
--- a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_or_fetch.h
+++ b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_or_fetch.h
@@ -54,7 +54,7 @@
#endif
-#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
+#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_OR_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \
diff --git a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_store.h b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_store.h
index 397ff5f..31655c3 100644
--- a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_store.h
+++ b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_store.h
@@ -145,7 +145,7 @@
#endif
-#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
+#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_STORE_128(type, ptr, val, MemoryOrder) \
diff --git a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_sub_fetch.h b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_sub_fetch.h
index 124b586..a1d0932 100644
--- a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_sub_fetch.h
+++ b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_sub_fetch.h
@@ -54,7 +54,7 @@
#endif
-#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
+#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_SUB_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \
diff --git a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_thread_fence.h b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_thread_fence.h
index fe3bd58..183c7f3 100644
--- a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_thread_fence.h
+++ b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_thread_fence.h
@@ -31,7 +31,7 @@
#endif
-#if defined(EA_COMPILER_MSVC) || defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)
+#if defined(EA_COMPILER_MSVC) || defined(__clang__) || defined(EA_COMPILER_GNUC)
#define EASTL_ARCH_ATOMIC_THREAD_FENCE_SEQ_CST() \
EASTL_ATOMIC_CPU_MB()
diff --git a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_xor_fetch.h b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_xor_fetch.h
index 28cb958..a5b62c3 100644
--- a/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_xor_fetch.h
+++ b/EASTL/include/EASTL/internal/atomic/arch/x86/arch_x86_xor_fetch.h
@@ -54,7 +54,7 @@
#endif
-#if ((defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
+#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_XOR_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \
diff --git a/EASTL/include/EASTL/internal/atomic/atomic.h b/EASTL/include/EASTL/internal/atomic/atomic.h
index e1c5286..eb27d2d 100644
--- a/EASTL/include/EASTL/internal/atomic/atomic.h
+++ b/EASTL/include/EASTL/internal/atomic/atomic.h
@@ -62,7 +62,7 @@ namespace internal
template <typename T>
struct is_atomic_lockfree_size
{
- static EASTL_CPP17_INLINE_VARIABLE constexpr bool value = false ||
+ static EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR_OR_CONST bool value = false ||
#if defined(EASTL_ATOMIC_HAS_8BIT)
sizeof(T) == 1 ||
#endif
@@ -85,7 +85,7 @@ namespace internal
template <typename T>
struct is_user_type_suitable_for_primary_template
{
- static EASTL_CPP17_INLINE_VARIABLE constexpr bool value = eastl::internal::is_atomic_lockfree_size<T>::value;
+ static EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR_OR_CONST bool value = eastl::internal::is_atomic_lockfree_size<T>::value;
};
@@ -116,7 +116,7 @@ namespace internal
\
public: \
\
- static EASTL_CPP17_INLINE_VARIABLE constexpr bool is_always_lock_free = eastl::internal::is_atomic_lockfree_size<type>::value; \
+ static EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR_OR_CONST bool is_always_lock_free = eastl::internal::is_atomic_lockfree_size<type>::value; \
\
public: /* deleted ctors && assignment operators */ \
\
diff --git a/EASTL/include/EASTL/internal/atomic/atomic_base_width.h b/EASTL/include/EASTL/internal/atomic/atomic_base_width.h
index ca47618..ac76097 100644
--- a/EASTL/include/EASTL/internal/atomic/atomic_base_width.h
+++ b/EASTL/include/EASTL/internal/atomic/atomic_base_width.h
@@ -64,7 +64,7 @@ namespace internal
#define EASTL_ATOMIC_CMPXCHG_FUNC_IMPL(op, bits) \
- bool retVal; \
+ EASTL_ATOMIC_DEFAULT_INIT(bool, retVal); \
EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits) fixedWidthDesired = EASTL_ATOMIC_TYPE_PUN_CAST(EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits), desired); \
EA_PREPROCESSOR_JOIN(op, bits)(EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits), \
retVal, \
diff --git a/EASTL/include/EASTL/internal/atomic/atomic_flag.h b/EASTL/include/EASTL/internal/atomic/atomic_flag.h
index e135d61..eed448a 100644
--- a/EASTL/include/EASTL/internal/atomic/atomic_flag.h
+++ b/EASTL/include/EASTL/internal/atomic/atomic_flag.h
@@ -42,13 +42,13 @@ public: /* deleted ctors && assignment operators */
public: /* clear */
template <typename Order>
- void clear(Order order) volatile EA_NOEXCEPT
+ void clear(Order /*order*/) volatile EA_NOEXCEPT
{
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(Order);
}
template <typename Order>
- void clear(Order order) EA_NOEXCEPT
+ void clear(Order /*order*/) EA_NOEXCEPT
{
EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(Order);
}
@@ -76,14 +76,14 @@ public: /* clear */
public: /* test_and_set */
template <typename Order>
- bool test_and_set(Order order) volatile EA_NOEXCEPT
+ bool test_and_set(Order /*order*/) volatile EA_NOEXCEPT
{
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(Order);
return false;
}
template <typename Order>
- bool test_and_set(Order order) EA_NOEXCEPT
+ bool test_and_set(Order /*order*/) EA_NOEXCEPT
{
EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(Order);
return false;
@@ -122,14 +122,14 @@ public: /* test_and_set */
public: /* test */
template <typename Order>
- bool test(Order order) const volatile EA_NOEXCEPT
+ bool test(Order /*order*/) const volatile EA_NOEXCEPT
{
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(Order);
return false;
}
template <typename Order>
- bool test(Order order) const EA_NOEXCEPT
+ bool test(Order /*order*/) const EA_NOEXCEPT
{
EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(Order);
return false;
diff --git a/EASTL/include/EASTL/internal/atomic/atomic_integral.h b/EASTL/include/EASTL/internal/atomic/atomic_integral.h
index 7c94db3..a9c96c7 100644
--- a/EASTL/include/EASTL/internal/atomic/atomic_integral.h
+++ b/EASTL/include/EASTL/internal/atomic/atomic_integral.h
@@ -24,18 +24,18 @@ namespace internal
#define EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_FUNCS_IMPL(funcName) \
template <typename Order> \
- T funcName(T arg, Order order) EA_NOEXCEPT \
+ T funcName(T /*arg*/, Order /*order*/) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(T); \
} \
\
template <typename Order> \
- T funcName(T arg, Order order) volatile EA_NOEXCEPT \
+ T funcName(T /*arg*/, Order /*order*/) volatile EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \
} \
\
- T funcName(T arg) volatile EA_NOEXCEPT \
+ T funcName(T /*arg*/) volatile EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \
}
@@ -54,7 +54,7 @@ namespace internal
#define EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_ASSIGNMENT_OPERATOR_IMPL(operatorOp) \
- T operator operatorOp(T arg) volatile EA_NOEXCEPT \
+ T operator operatorOp(T /*arg*/) volatile EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \
}
@@ -156,7 +156,7 @@ namespace internal
struct atomic_integral_width;
#define EASTL_ATOMIC_INTEGRAL_FUNC_IMPL(op, bits) \
- T retVal; \
+ EASTL_ATOMIC_DEFAULT_INIT(T, retVal); \
EA_PREPROCESSOR_JOIN(op, bits)(T, retVal, this->GetAtomicAddress(), arg); \
return retVal;
diff --git a/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros.h b/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros.h
index 941ac51..437b221 100644
--- a/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros.h
+++ b/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros.h
@@ -10,6 +10,7 @@
#pragma once
#endif
+#include <EABase/eabase.h>
#include "atomic_macros_base.h"
@@ -141,5 +142,15 @@
#endif
+// We write some of our variables in inline assembly, which MSAN
+// doesn't understand. This macro forces initialization of those
+// variables when MSAN is enabled and doesn't pay the initialization
+// cost when it's not enabled.
+#if EA_MSAN_ENABLED
+ #define EASTL_ATOMIC_DEFAULT_INIT(type, var) type var{}
+#else
+ #define EASTL_ATOMIC_DEFAULT_INIT(type, var) type var
+#endif // EA_MSAN_ENABLED
+
#endif /* EASTL_ATOMIC_INTERNAL_ATOMIC_MACROS_H */
diff --git a/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros_base.h b/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros_base.h
index f03720d..486e137 100644
--- a/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros_base.h
+++ b/EASTL/include/EASTL/internal/atomic/atomic_macros/atomic_macros_base.h
@@ -17,8 +17,13 @@
#define EASTL_ATOMIC_INTERNAL_ARCH_AVAILABLE(op) \
EA_PREPROCESSOR_JOIN(EA_PREPROCESSOR_JOIN(EASTL_ARCH_, op), _AVAILABLE)
+
+// We can't just use static_assert(false, ...) here, since on MSVC 17.10
+// the /Zc:static_assert flag makes non-dependent static_asserts in the body of a template
+// be evaluated at template-parse time, rather than at template instantion time.
+// So instead we just make the assert dependent on the type.
#define EASTL_ATOMIC_INTERNAL_NOT_IMPLEMENTED_ERROR(...) \
- static_assert(false, "eastl::atomic<T> atomic macro not implemented!")
+ static_assert(!eastl::is_same_v<T,T>, "eastl::atomic<T> atomic macro not implemented!")
/* Compiler && Arch Not Implemented */
diff --git a/EASTL/include/EASTL/internal/atomic/atomic_memory_order.h b/EASTL/include/EASTL/internal/atomic/atomic_memory_order.h
index b1c1403..1564d87 100644
--- a/EASTL/include/EASTL/internal/atomic/atomic_memory_order.h
+++ b/EASTL/include/EASTL/internal/atomic/atomic_memory_order.h
@@ -30,12 +30,12 @@ struct memory_order_seq_cst_s {};
} // namespace internal
-EASTL_CPP17_INLINE_VARIABLE constexpr auto memory_order_relaxed = internal::memory_order_relaxed_s{};
-EASTL_CPP17_INLINE_VARIABLE constexpr auto memory_order_read_depends = internal::memory_order_read_depends_s{};
-EASTL_CPP17_INLINE_VARIABLE constexpr auto memory_order_acquire = internal::memory_order_acquire_s{};
-EASTL_CPP17_INLINE_VARIABLE constexpr auto memory_order_release = internal::memory_order_release_s{};
-EASTL_CPP17_INLINE_VARIABLE constexpr auto memory_order_acq_rel = internal::memory_order_acq_rel_s{};
-EASTL_CPP17_INLINE_VARIABLE constexpr auto memory_order_seq_cst = internal::memory_order_seq_cst_s{};
+EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR auto memory_order_relaxed = internal::memory_order_relaxed_s{};
+EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR auto memory_order_read_depends = internal::memory_order_read_depends_s{};
+EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR auto memory_order_acquire = internal::memory_order_acquire_s{};
+EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR auto memory_order_release = internal::memory_order_release_s{};
+EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR auto memory_order_acq_rel = internal::memory_order_acq_rel_s{};
+EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR auto memory_order_seq_cst = internal::memory_order_seq_cst_s{};
} // namespace eastl
diff --git a/EASTL/include/EASTL/internal/atomic/atomic_pointer.h b/EASTL/include/EASTL/internal/atomic/atomic_pointer.h
index 18f6691..c0b19e6 100644
--- a/EASTL/include/EASTL/internal/atomic/atomic_pointer.h
+++ b/EASTL/include/EASTL/internal/atomic/atomic_pointer.h
@@ -27,18 +27,18 @@ namespace internal
#define EASTL_ATOMIC_POINTER_STATIC_ASSERT_FUNCS_IMPL(funcName) \
template <typename Order> \
- T* funcName(ptrdiff_t arg, Order order) EA_NOEXCEPT \
+ T* funcName(ptrdiff_t /*arg*/, Order /*order*/) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(T); \
} \
\
template <typename Order> \
- T* funcName(ptrdiff_t arg, Order order) volatile EA_NOEXCEPT \
+ T* funcName(ptrdiff_t /*arg*/, Order /*order*/) volatile EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \
} \
\
- T* funcName(ptrdiff_t arg) volatile EA_NOEXCEPT \
+ T* funcName(ptrdiff_t /*arg*/) volatile EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \
}
@@ -55,7 +55,7 @@ namespace internal
}
#define EASTL_ATOMIC_POINTER_STATIC_ASSERT_ASSIGNMENT_OPERATOR_IMPL(operatorOp) \
- T* operator operatorOp(ptrdiff_t arg) volatile EA_NOEXCEPT \
+ T* operator operatorOp(ptrdiff_t /*arg*/) volatile EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \
}
diff --git a/EASTL/include/EASTL/internal/atomic/atomic_size_aligned.h b/EASTL/include/EASTL/internal/atomic/atomic_size_aligned.h
index db23e47..f503375 100644
--- a/EASTL/include/EASTL/internal/atomic/atomic_size_aligned.h
+++ b/EASTL/include/EASTL/internal/atomic/atomic_size_aligned.h
@@ -24,40 +24,40 @@ namespace internal
#define EASTL_ATOMIC_SIZE_ALIGNED_STATIC_ASSERT_CMPXCHG_IMPL(funcName) \
template <typename OrderSuccess, typename OrderFailure> \
- bool funcName(T& expected, T desired, \
- OrderSuccess orderSuccess, \
- OrderFailure orderFailure) EA_NOEXCEPT \
+ bool funcName(T& /*expected*/, T /*desired*/, \
+ OrderSuccess /*orderSuccess*/, \
+ OrderFailure /*orderFailure*/) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(T); \
return false; \
} \
\
template <typename OrderSuccess, typename OrderFailure> \
- bool funcName(T& expected, T desired, \
- OrderSuccess orderSuccess, \
- OrderFailure orderFailure) volatile EA_NOEXCEPT \
+ bool funcName(T& /*expected*/, T /*desired*/, \
+ OrderSuccess /*orderSuccess*/, \
+ OrderFailure /*orderFailure*/) volatile EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \
return false; \
} \
\
template <typename Order> \
- bool funcName(T& expected, T desired, \
- Order order) EA_NOEXCEPT \
+ bool funcName(T& /*expected*/, T /*desired*/, \
+ Order /*order*/) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(T); \
return false; \
} \
\
template <typename Order> \
- bool funcName(T& expected, T desired, \
- Order order) volatile EA_NOEXCEPT \
+ bool funcName(T& /*expected*/, T /*desired*/, \
+ Order /*order*/) volatile EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \
return false; \
} \
\
- bool funcName(T& expected, T desired) volatile EA_NOEXCEPT \
+ bool funcName(T& /*expected*/, T /*desired*/) volatile EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \
return false; \
@@ -90,18 +90,18 @@ namespace internal
public: /* store */
template <typename Order>
- void store(T desired, Order order) EA_NOEXCEPT
+ void store(T /*desired*/, Order /*order*/) EA_NOEXCEPT
{
EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(T);
}
template <typename Order>
- void store(T desired, Order order) volatile EA_NOEXCEPT
+ void store(T /*desired*/, Order /*order*/) volatile EA_NOEXCEPT
{
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T);
}
- void store(T desired) volatile EA_NOEXCEPT
+ void store(T /*desired*/) volatile EA_NOEXCEPT
{
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T);
}
@@ -109,13 +109,13 @@ namespace internal
public: /* load */
template <typename Order>
- T load(Order order) const EA_NOEXCEPT
+ T load(Order /*order*/) const EA_NOEXCEPT
{
EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(T);
}
template <typename Order>
- T load(Order order) const volatile EA_NOEXCEPT
+ T load(Order /*order*/) const volatile EA_NOEXCEPT
{
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T);
}
@@ -128,18 +128,18 @@ namespace internal
public: /* exchange */
template <typename Order>
- T exchange(T desired, Order order) EA_NOEXCEPT
+ T exchange(T /*desired*/, Order /*order*/) EA_NOEXCEPT
{
EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(T);
}
template <typename Order>
- T exchange(T desired, Order order) volatile EA_NOEXCEPT
+ T exchange(T /*desired*/, Order /*order*/) volatile EA_NOEXCEPT
{
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T);
}
- T exchange(T desired) volatile EA_NOEXCEPT
+ T exchange(T /*desired*/) volatile EA_NOEXCEPT
{
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T);
}
@@ -154,7 +154,7 @@ namespace internal
public: /* assignment operator */
- T operator=(T desired) volatile EA_NOEXCEPT
+ T operator=(T /*desired*/) volatile EA_NOEXCEPT
{
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T);
}
diff --git a/EASTL/include/EASTL/internal/atomic/compiler/compiler.h b/EASTL/include/EASTL/internal/atomic/compiler/compiler.h
index 65a4cd0..fc12879 100644
--- a/EASTL/include/EASTL/internal/atomic/compiler/compiler.h
+++ b/EASTL/include/EASTL/internal/atomic/compiler/compiler.h
@@ -15,7 +15,7 @@
//
// Include the compiler specific implementations
//
-#if defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)
+#if defined(EA_COMPILER_GNUC) || defined(__clang__)
#include "gcc/compiler_gcc.h"
diff --git a/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc.h b/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc.h
index 6df8c05..90901ee 100644
--- a/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc.h
+++ b/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc.h
@@ -12,7 +12,6 @@
EA_DISABLE_ALL_VC_WARNINGS();
-#include <Windows.h>
#include <intrin.h>
EA_RESTORE_ALL_VC_WARNINGS();
diff --git a/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_barrier.h b/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_barrier.h
index 02e2d03..90b78a6 100644
--- a/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_barrier.h
+++ b/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_barrier.h
@@ -16,7 +16,9 @@
// void EASTL_COMPILER_ATOMIC_COMPILER_BARRIER()
//
#define EASTL_COMPILER_ATOMIC_COMPILER_BARRIER() \
- _ReadWriteBarrier()
+ EA_DISABLE_CLANG_WARNING(-Wdeprecated-declarations) \
+ _ReadWriteBarrier() \
+ EA_RESTORE_CLANG_WARNING()
/////////////////////////////////////////////////////////////////////////////////
diff --git a/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cmpxchg_strong.h b/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cmpxchg_strong.h
index 42117a1..8217f23 100644
--- a/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cmpxchg_strong.h
+++ b/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cmpxchg_strong.h
@@ -10,7 +10,6 @@
#pragma once
#endif
-
#if defined(EA_PROCESSOR_X86_64)
#define EASTL_MSVC_ATOMIC_CMPXCHG_STRONG_INTRIN_8 _InterlockedCompareExchange8
diff --git a/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cpu_pause.h b/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cpu_pause.h
index 720701a..5f436b8 100644
--- a/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cpu_pause.h
+++ b/EASTL/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc_cpu_pause.h
@@ -10,18 +10,13 @@
#pragma once
#endif
-
-/////////////////////////////////////////////////////////////////////////////////
-//
-// void EASTL_COMPILER_ATOMIC_CPU_PAUSE()
-//
-// NOTE:
-// Rather obscure macro in Windows.h that expands to pause or rep; nop on
-// compatible x86 cpus or the arm yield on compatible arm processors.
-// This is nicer than switching on platform specific intrinsics.
-//
-#define EASTL_COMPILER_ATOMIC_CPU_PAUSE() \
- YieldProcessor()
+#if defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64)
+ #define EASTL_COMPILER_ATOMIC_CPU_PAUSE() _mm_pause()
+#elif defined(EA_PROCESSOR_ARM32) || defined(EA_PROCESSOR_ARM64)
+ #define EASTL_COMPILER_ATOMIC_CPU_PAUSE() __yield()
+#else
+ #error Unsupported CPU architecture for EASTL_COMPILER_ATOMIC_CPU_PAUSE
+#endif
#endif /* EASTL_ATOMIC_INTERNAL_COMPILER_MSVC_CPU_PAUSE_H */
diff --git a/EASTL/include/EASTL/internal/config.h b/EASTL/include/EASTL/internal/config.h
index 530bbc8..0564e18 100644
--- a/EASTL/include/EASTL/internal/config.h
+++ b/EASTL/include/EASTL/internal/config.h
@@ -89,8 +89,8 @@
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_VERSION
- #define EASTL_VERSION "3.17.06"
- #define EASTL_VERSION_N 31706
+ #define EASTL_VERSION "3.20.02"
+ #define EASTL_VERSION_N 32002
#endif
@@ -670,6 +670,17 @@ namespace eastl
///////////////////////////////////////////////////////////////////////////////
+// EASTL_CRASH
+//
+// Executes an invalid memory write, which should result in an exception
+// on most platforms.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#define EASTL_CRASH() *((volatile int*)0) = 0xDEADC0DE;
+
+
+///////////////////////////////////////////////////////////////////////////////
// EASTL_ALLOCATOR_COPY_ENABLED
//
// Defined as 0 or 1. Default is 0 (disabled) until some future date.
@@ -825,7 +836,7 @@ namespace eastl
// Defined as 0 or 1.
//
#ifndef EASTL_INT128_SUPPORTED
- #if defined(__SIZEOF_INT128__) || (defined(EA_COMPILER_INTMAX_SIZE) && (EA_COMPILER_INTMAX_SIZE >= 16))
+ #if defined(EA_COMPILER_INTMAX_SIZE) && (EA_COMPILER_INTMAX_SIZE >= 16)
#define EASTL_INT128_SUPPORTED 1
#else
#define EASTL_INT128_SUPPORTED 0
@@ -833,6 +844,21 @@ namespace eastl
#endif
+///////////////////////////////////////////////////////////////////////////////
+// EASTL_GCC_STYLE_INT128_SUPPORTED
+//
+// Defined as 0 or 1.
+// Specifies whether __int128_t/__uint128_t are defined.
+//
+#ifndef EASTL_GCC_STYLE_INT128_SUPPORTED
+#if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(__clang__))
+#define EASTL_GCC_STYLE_INT128_SUPPORTED 1
+#else
+#define EASTL_GCC_STYLE_INT128_SUPPORTED 0
+#endif
+#endif
+
+
///////////////////////////////////////////////////////////////////////////////
// EASTL_DEFAULT_ALLOCATOR_ALIGNED_ALLOCATIONS_SUPPORTED
@@ -859,12 +885,15 @@ namespace eastl
//
// Defined as 0 or 1.
// Specifies whether eastl_int128_t/eastl_uint128_t have been typedef'd yet.
+// NB: these types are not considered fundamental, arithmetic or integral when using the EAStdC implementation.
+// this changes the compiler type traits defined in type_traits.h.
+// eg. is_signed<eastl_int128_t>::value may be false, because it is not arithmetic.
//
#ifndef EASTL_INT128_DEFINED
#if EASTL_INT128_SUPPORTED
#define EASTL_INT128_DEFINED 1
- #if defined(__SIZEOF_INT128__) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)
+ #if EASTL_GCC_STYLE_INT128_SUPPORTED
typedef __int128_t eastl_int128_t;
typedef __uint128_t eastl_uint128_t;
#else
@@ -875,7 +904,6 @@ namespace eastl
#endif
-
///////////////////////////////////////////////////////////////////////////////
// EASTL_BITSET_WORD_TYPE_DEFAULT / EASTL_BITSET_WORD_SIZE_DEFAULT
//
@@ -1274,7 +1302,7 @@ namespace eastl
// useful macro identifier for our type traits implementation.
//
#ifndef EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE
- #if defined(_MSC_VER) && (_MSC_VER >= 1500) // VS2008 or later
+ #if defined(_MSC_VER) && (_MSC_VER >= 1500) && !defined(EA_COMPILER_CLANG_CL) // VS2008 or later
#pragma warning(push, 0)
#include <yvals.h>
#pragma warning(pop)
@@ -1283,9 +1311,9 @@ namespace eastl
#else
#define EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE 0
#endif
- #elif defined(EA_COMPILER_CLANG) && defined(__APPLE__) && defined(_CXXCONFIG) // Apple clang but with GCC's libstdc++.
+ #elif defined(__clang__) && defined(__APPLE__) && defined(_CXXCONFIG) // Apple clang but with GCC's libstdc++.
#define EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE 0
- #elif defined(EA_COMPILER_CLANG)
+ #elif defined(__clang__)
#define EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE 1
#elif defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003) && !defined(__GCCXML__)
#define EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE 1
@@ -1779,16 +1807,6 @@ typedef EASTL_SSIZE_T eastl_ssize_t; // Signed version of eastl_size_t. Concept
#ifndef EASTL_USER_LITERALS_ENABLED
#if defined(EA_COMPILER_CPP14_ENABLED)
#define EASTL_USER_LITERALS_ENABLED 1
-
- // Disabling the Clang/GCC/MSVC warning about using user defined literals without a leading '_' as they are
- // reserved for standard libary usage.
- EA_DISABLE_CLANG_WARNING(-Wuser-defined-literals)
- EA_DISABLE_CLANG_WARNING(-Wreserved-user-defined-literal)
- EA_DISABLE_GCC_WARNING(-Wliteral-suffix)
- #ifdef _MSC_VER
- #pragma warning(disable: 4455) // disable warning C4455: literal suffix identifiers that do not start with an underscore are reserved
- #endif
-
#else
#define EASTL_USER_LITERALS_ENABLED 0
#endif
@@ -1836,18 +1854,49 @@ typedef EASTL_SSIZE_T eastl_ssize_t; // Signed version of eastl_size_t. Concept
/// EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE
-#if defined(_MSC_VER) && (_MSC_VER >= 1913) // VS2017+
- #define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 1
-#elif defined(EA_COMPILER_CLANG)
+#if defined(__clang__)
+ // NB: !__is_identifier() is correct: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66970#c11
#if !__is_identifier(__has_unique_object_representations)
#define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 1
#else
#define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 0
#endif
+#elif defined(_MSC_VER) && (_MSC_VER >= 1913) // VS2017 15.6+
+ #define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 1
#else
#define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 0
#endif
+#if defined(__clang__)
+ // NB: !__is_identifier() is correct: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66970#c11
+ #if !__is_identifier(__is_final)
+ #define EASTL_IS_FINAL_AVAILABLE 1
+ #else
+ #define EASTL_IS_FINAL_AVAILABLE 0
+ #endif
+#elif defined(_MSC_VER) && (_MSC_VER >= 1914) // VS2017 15.7+
+ #define EASTL_IS_FINAL_AVAILABLE 1
+#elif defined(EA_COMPILER_GNUC)
+ #define EASTL_IS_FINAL_AVAILABLE 1
+#else
+ #define EASTL_IS_FINAL_AVAILABLE 0
+#endif
+
+#if defined(__clang__)
+ // NB: !__is_identifier() is correct: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66970#c11
+ #if !__is_identifier(__is_aggregate)
+ #define EASTL_IS_AGGREGATE_AVAILABLE 1
+ #else
+ #define EASTL_IS_AGGREGATE_AVAILABLE 0
+ #endif
+#elif defined(_MSC_VER) && (_MSC_VER >= 1915) // VS2017 15.8+
+ #define EASTL_IS_AGGREGATE_AVAILABLE 1
+#elif defined(EA_COMPILER_GNUC)
+ #define EASTL_IS_AGGREGATE_AVAILABLE 1
+#else
+ #define EASTL_IS_AGGREGATE_AVAILABLE 0
+#endif
+
/// EASTL_ENABLE_PAIR_FIRST_ELEMENT_CONSTRUCTOR
/// This feature define allows users to toggle the problematic eastl::pair implicit
@@ -1873,5 +1922,17 @@ typedef EASTL_SSIZE_T eastl_ssize_t; // Signed version of eastl_size_t. Concept
#define EASTL_SYSTEM_LITTLE_ENDIAN_STATEMENT(...)
#endif
+/// EASTL_CONSTEXPR_BIT_CAST_SUPPORTED
+/// eastl::bit_cast, in order to be implemented as constexpr, requires explicit compiler support.
+/// This macro defines whether it's possible for bit_cast to be constexpr.
+///
+#if (defined(EA_COMPILER_MSVC) && defined(EA_COMPILER_MSVC_VERSION_14_26) && EA_COMPILER_VERSION >= EA_COMPILER_MSVC_VERSION_14_26) \
+ || EA_COMPILER_HAS_BUILTIN(__builtin_bit_cast)
+ #define EASTL_CONSTEXPR_BIT_CAST_SUPPORTED 1
+#else
+ #define EASTL_CONSTEXPR_BIT_CAST_SUPPORTED 0
+#endif
+
+
#endif // Header include guard
diff --git a/EASTL/include/EASTL/internal/copy_help.h b/EASTL/include/EASTL/internal/copy_help.h
index e5fb2ab..0b2c1b8 100644
--- a/EASTL/include/EASTL/internal/copy_help.h
+++ b/EASTL/include/EASTL/internal/copy_help.h
@@ -6,12 +6,12 @@
#ifndef EASTL_INTERNAL_COPY_HELP_H
#define EASTL_INTERNAL_COPY_HELP_H
+#include <EASTL/internal/config.h>
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
-#include <EASTL/internal/config.h>
#include <EASTL/type_traits.h>
#include <EASTL/iterator.h>
#include <string.h> // memcpy, memcmp, memmove
@@ -19,15 +19,15 @@
namespace eastl
{
- /// move / move_n / move_backward
+ /// move / move_n / move_backward
/// copy / copy_n / copy_backward
///
/// We want to optimize move, move_n, move_backward, copy, copy_backward, copy_n to do memmove operations
- /// when possible.
+ /// when possible.
///
- /// We could possibly use memcpy, though it has stricter overlap requirements than the move and copy
- /// algorithms and would require a runtime if/else to choose it over memmove. In particular, memcpy
- /// allows no range overlap at all, whereas move/copy allow output end overlap and move_backward/copy_backward
+ /// We could possibly use memcpy, though it has stricter overlap requirements than the move and copy
+ /// algorithms and would require a runtime if/else to choose it over memmove. In particular, memcpy
+ /// allows no range overlap at all, whereas move/copy allow output end overlap and move_backward/copy_backward
/// allow output begin overlap. Despite this it might be useful to use memcpy for any platforms where
/// memcpy is significantly faster than memmove, and since in most cases the copy/move operation in fact
/// doesn't target overlapping memory and so memcpy would be usable.
@@ -36,13 +36,13 @@ namespace eastl
/// InputIterator and OutputIterator are of the same type.
/// InputIterator and OutputIterator are of type contiguous_iterator_tag or simply are pointers (the two are virtually synonymous).
/// is_trivially_copyable<T>::value is true. i.e. the constructor T(const T& t) (or T(T&& t) if present) can be replaced by memmove(this, &t, sizeof(T))
- ///
- /// copy normally differs from move, but there is a case where copy is the same as move: when copy is
- /// used with a move_iterator. We handle that case here by detecting that copy is being done with a
+ ///
+ /// copy normally differs from move, but there is a case where copy is the same as move: when copy is
+ /// used with a move_iterator. We handle that case here by detecting that copy is being done with a
/// move_iterator and redirect it to move (which can take advantage of memmove/memcpy).
///
- /// The generic_iterator class is typically used for wrapping raw memory pointers so they can act like
- /// formal iterators. Since pointers provide an opportunity for memmove/memcpy operations, we can
+ /// The generic_iterator class is typically used for wrapping raw memory pointers so they can act like
+ /// formal iterators. Since pointers provide an opportunity for memmove/memcpy operations, we can
/// detect a generic iterator and use it's wrapped type as a pointer if it happens to be one.
// Implementation moving copying both trivial and non-trivial data via a lesser iterator than random-access.
@@ -61,7 +61,7 @@ namespace eastl
// Specialization for copying non-trivial data via a random-access iterator. It's theoretically faster because the compiler can see the count when its a compile-time const.
// This specialization converts the random access InputIterator last-first to an integral type. There's simple way for us to take advantage of a random access output iterator,
// as the range is specified by the input instead of the output, and distance(first, last) for a non-random-access iterator is potentially slow.
- template <>
+ template <>
struct move_and_copy_helper<EASTL_ITC_NS::random_access_iterator_tag, false, false>
{
template <typename InputIterator, typename OutputIterator>
@@ -88,7 +88,7 @@ namespace eastl
return result;
}
};
-
+
// Specialization for moving non-trivial data via a random-access iterator. It's theoretically faster because the compiler can see the count when its a compile-time const.
template <>
struct move_and_copy_helper<EASTL_ITC_NS::random_access_iterator_tag, true, false>
@@ -121,19 +121,40 @@ namespace eastl
};
+ namespace internal {
+ // This exists to handle the case when EASTL_ITC_NS is `std`
+ // and the C++ version is older than C++20, in this case
+ // std::contiguous_iterator_tag does not exist so we can't use
+ // is_same<> directly.
+ #if !EASTL_STD_ITERATOR_CATEGORY_ENABLED || defined(EA_COMPILER_CPP20_ENABLED)
+ template <typename IC>
+ using is_contiguous_iterator_helper = eastl::is_same<IC, EASTL_ITC_NS::contiguous_iterator_tag>;
+ #else
+ template <typename IC>
+ using is_contiguous_iterator_helper = eastl::false_type;
+ #endif
+
+ template <typename InputIterator, typename OutputIterator>
+ struct can_be_memmoved_helper {
+ using IIC = typename eastl::iterator_traits<InputIterator>::iterator_category;
+ using OIC = typename eastl::iterator_traits<OutputIterator>::iterator_category;
+ using value_type_input = typename eastl::iterator_traits<InputIterator>::value_type;
+ using value_type_output = typename eastl::iterator_traits<OutputIterator>::value_type;
+
+ static constexpr bool value = eastl::is_trivially_copyable<value_type_output>::value &&
+ eastl::is_same<value_type_input, value_type_output>::value &&
+ (eastl::is_pointer<InputIterator>::value || is_contiguous_iterator_helper<IIC>::value) &&
+ (eastl::is_pointer<OutputIterator>::value || is_contiguous_iterator_helper<OIC>::value);
+
+ };
+ }
template <bool isMove, typename InputIterator, typename OutputIterator>
inline OutputIterator move_and_copy_chooser(InputIterator first, InputIterator last, OutputIterator result)
{
typedef typename eastl::iterator_traits<InputIterator>::iterator_category IIC;
- typedef typename eastl::iterator_traits<OutputIterator>::iterator_category OIC;
- typedef typename eastl::iterator_traits<InputIterator>::value_type value_type_input;
- typedef typename eastl::iterator_traits<OutputIterator>::value_type value_type_output;
- const bool canBeMemmoved = eastl::is_trivially_copyable<value_type_output>::value &&
- eastl::is_same<value_type_input, value_type_output>::value &&
- (eastl::is_pointer<InputIterator>::value || eastl::is_same<IIC, eastl::contiguous_iterator_tag>::value) &&
- (eastl::is_pointer<OutputIterator>::value || eastl::is_same<OIC, eastl::contiguous_iterator_tag>::value);
+ const bool canBeMemmoved = internal::can_be_memmoved_helper<InputIterator, OutputIterator>::value;
return eastl::move_and_copy_helper<IIC, isMove, canBeMemmoved>::move_or_copy(first, last, result); // Need to chose based on the input iterator tag and not the output iterator tag, because containers accept input ranges of iterator types different than self.
}
@@ -143,17 +164,17 @@ namespace eastl
template <bool isMove, typename InputIterator, typename OutputIterator>
inline OutputIterator move_and_copy_unwrapper(InputIterator first, InputIterator last, OutputIterator result)
{
- return OutputIterator(eastl::move_and_copy_chooser<isMove>(eastl::unwrap_iterator(first), eastl::unwrap_iterator(last), eastl::unwrap_iterator(result))); // Have to convert to OutputIterator because result.base() could be a T*
+ return OutputIterator(eastl::move_and_copy_chooser<isMove>(eastl::unwrap_iterator(first), eastl::unwrap_iterator(last), eastl::unwrap_iterator(result))); // Have to convert to OutputIterator because unwrap_iterator(result) could be a T*
}
/// move
///
- /// After this operation the elements in the moved-from range will still contain valid values of the
- /// appropriate type, but not necessarily the same values as before the move.
+ /// After this operation the elements in the moved-from range will still contain valid values of the
+ /// appropriate type, but not necessarily the same values as before the move.
/// Returns the end of the result range.
/// Note: When moving between containers, the dest range must be valid; this function doesn't resize containers.
- /// Note: if result is within [first, last), move_backward must be used instead of move.
+ /// Note: if result is within [first, last), move_backward must be used instead of move.
///
/// Example usage:
/// eastl::move(myArray.begin(), myArray.end(), myDestArray.begin());
@@ -180,7 +201,7 @@ namespace eastl
/// starting from first and proceeding to last. For each nonnegative integer n < (last - first),
/// performs *(result + n) = *(first + n).
///
- /// Returns: result + (last - first). That is, returns the end of the result. Note that this
+ /// Returns: result + (last - first). That is, returns the end of the result. Note that this
/// is different from how memmove/memcpy work, as they return the beginning of the result.
///
/// Requires: result shall not be in the range [first, last). But the end of the result range
@@ -197,19 +218,4 @@ namespace eastl
}
} // namespace eastl
-#endif // Header include guard
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+#endif // EASTL_INTERNAL_COPY_HELP_H
diff --git a/EASTL/include/EASTL/internal/fill_help.h b/EASTL/include/EASTL/internal/fill_help.h
index 235a24e..07e3b62 100644
--- a/EASTL/include/EASTL/internal/fill_help.h
+++ b/EASTL/include/EASTL/internal/fill_help.h
@@ -85,7 +85,7 @@ namespace eastl
}
- #if(defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) && (defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64))
+ #if (defined(EA_COMPILER_GNUC) || defined(__clang__)) && (defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64))
#if defined(EA_PROCESSOR_X86_64)
template <typename Value>
inline void fill(uint64_t* first, uint64_t* last, Value c)
@@ -327,7 +327,7 @@ namespace eastl
}
#endif
- #if(defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) && (defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64))
+ #if (defined(EA_COMPILER_GNUC) || defined(__clang__)) && (defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64))
#if defined(EA_PROCESSOR_X86_64)
template <typename Size, typename Value>
inline uint64_t* fill_n(uint64_t* first, Size n, Value c)
diff --git a/EASTL/include/EASTL/internal/fixed_pool.h b/EASTL/include/EASTL/internal/fixed_pool.h
index 5a38004..61c0557 100644
--- a/EASTL/include/EASTL/internal/fixed_pool.h
+++ b/EASTL/include/EASTL/internal/fixed_pool.h
@@ -1362,12 +1362,10 @@ namespace eastl
{
}
- // Disabled because the default is sufficient.
- //fixed_vector_allocator(const fixed_vector_allocator& x)
- //{
- // mpPoolBegin = x.mpPoolBegin;
- // mOverflowAllocator = x.mOverflowAllocator;
- //}
+ fixed_vector_allocator(const fixed_vector_allocator& x)
+ : mOverflowAllocator(x.mOverflowAllocator), mpPoolBegin(x.mpPoolBegin)
+ {
+ }
fixed_vector_allocator& operator=(const fixed_vector_allocator& x)
{
@@ -1481,12 +1479,14 @@ namespace eastl
void* allocate(size_t /*n*/, int /*flags*/ = 0)
{
EASTL_ASSERT(false); // A fixed_vector should not reallocate, else the user has exhausted its space.
+ EASTL_CRASH(); // We choose to crash here since the owning vector can't handle an allocator returning null. Better to crash earlier.
return NULL;
}
void* allocate(size_t /*n*/, size_t /*alignment*/, size_t /*offset*/, int /*flags*/ = 0)
{
- EASTL_ASSERT(false);
+ EASTL_ASSERT(false); // A fixed_vector should not reallocate, else the user has exhausted its space.
+ EASTL_CRASH(); // We choose to crash here since the owning vector can't handle an allocator returning null. Better to crash earlier.
return NULL;
}
diff --git a/EASTL/include/EASTL/internal/function.h b/EASTL/include/EASTL/internal/function.h
index 6e857f0..ace71d8 100644
--- a/EASTL/include/EASTL/internal/function.h
+++ b/EASTL/include/EASTL/internal/function.h
@@ -5,6 +5,8 @@
#ifndef EASTL_FUNCTION_H
#define EASTL_FUNCTION_H
+#include <EASTL/internal/config.h>
+
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
@@ -131,7 +133,7 @@ namespace eastl
{
return !f;
}
-
+#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <typename R, typename... Args>
bool operator==(std::nullptr_t, const function<R(Args...)>& f) EA_NOEXCEPT
{
@@ -149,7 +151,7 @@ namespace eastl
{
return !!f;
}
-
+#endif
template <typename R, typename... Args>
void swap(function<R(Args...)>& lhs, function<R(Args...)>& rhs)
{
diff --git a/EASTL/include/EASTL/internal/function_detail.h b/EASTL/include/EASTL/internal/function_detail.h
index dc18b63..3ee3667 100644
--- a/EASTL/include/EASTL/internal/function_detail.h
+++ b/EASTL/include/EASTL/internal/function_detail.h
@@ -95,7 +95,7 @@ namespace eastl
template <typename Functor, int SIZE_IN_BYTES>
struct is_functor_inplace_allocatable
{
- static constexpr bool value =
+ static EA_CONSTEXPR bool value =
sizeof(Functor) <= sizeof(functor_storage<SIZE_IN_BYTES>) &&
(eastl::alignment_of_v<functor_storage<SIZE_IN_BYTES>> % eastl::alignment_of_v<Functor>) == 0;
};
diff --git a/EASTL/include/EASTL/internal/functional_base.h b/EASTL/include/EASTL/internal/functional_base.h
index a7d2dc9..de446db 100644
--- a/EASTL/include/EASTL/internal/functional_base.h
+++ b/EASTL/include/EASTL/internal/functional_base.h
@@ -6,21 +6,23 @@
#ifndef EASTL_INTERNAL_FUNCTIONAL_BASE_H
#define EASTL_INTERNAL_FUNCTIONAL_BASE_H
+#include <EASTL/internal/config.h>
+
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
-#include <EASTL/internal/config.h>
#include <EASTL/internal/memory_base.h>
#include <EASTL/internal/move_help.h>
#include <EASTL/type_traits.h>
+
namespace eastl
{
// foward declaration for swap
template <typename T>
inline void swap(T& a, T& b)
- EA_NOEXCEPT_IF(eastl::is_nothrow_move_constructible<T>::value&& eastl::is_nothrow_move_assignable<T>::value);
+ EA_NOEXCEPT_IF(eastl::is_nothrow_move_constructible<T>::value && eastl::is_nothrow_move_assignable<T>::value);
/// invoke
@@ -39,44 +41,47 @@ namespace eastl
/// http://en.cppreference.com/w/cpp/utility/functional/invoke
///
template <typename R, typename C, typename T, typename... Args>
- auto invoke_impl(R C::*func, T&& obj, Args&&... args) ->
- typename enable_if<is_base_of<C, decay_t<decltype(obj)>>::value,
+ EA_CONSTEXPR auto invoke_impl(R C::*func, T&& obj, Args&&... args) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR((eastl::forward<T>(obj).*func)(eastl::forward<Args>(args)...)))
+ -> typename enable_if<is_base_of<C, decay_t<T>>::value,
decltype((eastl::forward<T>(obj).*func)(eastl::forward<Args>(args)...))>::type
{
return (eastl::forward<T>(obj).*func)(eastl::forward<Args>(args)...);
}
template <typename F, typename... Args>
- auto invoke_impl(F&& func, Args&&... args) -> decltype(eastl::forward<F>(func)(eastl::forward<Args>(args)...))
+ EA_CONSTEXPR auto invoke_impl(F&& func, Args&&... args) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(eastl::forward<F>(func)(eastl::forward<Args>(args)...)))
+ -> decltype(eastl::forward<F>(func)(eastl::forward<Args>(args)...))
{
return eastl::forward<F>(func)(eastl::forward<Args>(args)...);
}
template <typename R, typename C, typename T, typename... Args>
- auto invoke_impl(R C::*func, T&& obj, Args&&... args) -> decltype(((*eastl::forward<T>(obj)).*func)(eastl::forward<Args>(args)...))
+ EA_CONSTEXPR auto invoke_impl(R C::*func, T&& obj, Args&&... args) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(((*eastl::forward<T>(obj)).*func)(eastl::forward<Args>(args)...)))
+ -> decltype(((*eastl::forward<T>(obj)).*func)(eastl::forward<Args>(args)...))
{
return ((*eastl::forward<T>(obj)).*func)(eastl::forward<Args>(args)...);
}
template <typename M, typename C, typename T>
- auto invoke_impl(M C::*member, T&& obj) ->
- typename enable_if<
- is_base_of<C, decay_t<decltype(obj)>>::value,
- decltype(obj.*member)
+ EA_CONSTEXPR auto invoke_impl(M C::*member, T&& obj) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(eastl::forward<T>(obj).*member))
+ -> typename enable_if<
+ is_base_of<C, decay_t<T>>::value,
+ decltype(eastl::forward<T>(obj).*member)
>::type
{
- return obj.*member;
+ return eastl::forward<T>(obj).*member;
}
template <typename M, typename C, typename T>
- auto invoke_impl(M C::*member, T&& obj) -> decltype((*eastl::forward<T>(obj)).*member)
+ EA_CONSTEXPR auto invoke_impl(M C::*member, T&& obj) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR((*eastl::forward<T>(obj)).*member))
+ -> decltype((*eastl::forward<T>(obj)).*member)
{
return (*eastl::forward<T>(obj)).*member;
}
template <typename F, typename... Args>
- inline decltype(auto) invoke(F&& func, Args&&... args)
+ EA_CONSTEXPR decltype(auto) invoke(F&& func, Args&&... args) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(invoke_impl(eastl::forward<F>(func), eastl::forward<Args>(args)...)))
{
return invoke_impl(eastl::forward<F>(func), eastl::forward<Args>(args)...);
}
@@ -86,9 +91,9 @@ namespace eastl
};
template <typename F, typename... Args>
- struct invoke_result_impl<F, void_t<decltype(invoke_impl(eastl::declval<decay_t<F>>(), eastl::declval<Args>()...))>, Args...>
+ struct invoke_result_impl<F, void_t<decltype(invoke_impl(eastl::declval<F>(), eastl::declval<Args>()...))>, Args...>
{
- typedef decltype(invoke_impl(eastl::declval<decay_t<F>>(), eastl::declval<Args>()...)) type;
+ typedef decltype(invoke_impl(eastl::declval<F>(), eastl::declval<Args>()...)) type;
};
template <typename F, typename... Args>
@@ -113,18 +118,46 @@ namespace eastl
template <typename R, typename F, typename... Args>
struct is_invocable_r_impl<R, F, void_t<typename invoke_result<F, Args...>::type>, Args...>
- : public is_convertible<typename invoke_result<F, Args...>::type, R> {};
+ : public disjunction<is_convertible<typename invoke_result<F, Args...>::type, R>,
+ is_same<typename remove_cv<R>::type, void>> {};
template <typename R, typename F, typename... Args>
struct is_invocable_r : public is_invocable_r_impl<R, F, void, Args...> {};
- #if EASTL_VARIABLE_TEMPLATES_ENABLED
- template <typename F, typename... Args>
- EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool is_invocable_v = is_invocable<F, Args...>::value;
+ template <typename F, typename... Args>
+ EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool is_invocable_v = is_invocable<F, Args...>::value;
- template <typename R, typename F, typename... Args>
- EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool is_invocable_r_v = is_invocable_r<R, F, Args...>::value;
- #endif
+ template <typename R, typename F, typename... Args>
+ EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool is_invocable_r_v = is_invocable_r<R, F, Args...>::value;
+
+ template <typename F, typename = void, typename... Args>
+ struct is_nothrow_invocable_impl : public eastl::false_type {};
+
+ template <typename F, typename... Args>
+ struct is_nothrow_invocable_impl<F, void_t<typename eastl::invoke_result<F, Args...>::type>, Args...>
+ : public eastl::bool_constant<EA_NOEXCEPT_EXPR(eastl::invoke(eastl::declval<F>(), eastl::declval<Args>()...))> {};
+
+ template <typename F, typename... Args>
+ struct is_nothrow_invocable : public is_nothrow_invocable_impl<F, void, Args...> {};
+
+ template <typename R, typename F, typename = void, typename... Args>
+ struct is_nothrow_invocable_r_impl : public eastl::false_type {};
+
+ template <typename R, typename F, typename... Args>
+ struct is_nothrow_invocable_r_impl<R, F, void_t<typename eastl::invoke_result<F, Args...>::type>, Args...>
+ {
+ static EA_CONSTEXPR_OR_CONST bool value = eastl::is_convertible<typename eastl::invoke_result<F, Args...>::type, R>::value
+ && eastl::is_nothrow_invocable<F, Args...>::value;
+ };
+
+ template <typename R, typename F, typename... Args>
+ struct is_nothrow_invocable_r : public is_nothrow_invocable_r_impl<R, F, void, Args...> {};
+
+ template <typename F, typename... Args>
+ EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool is_no_throw_invocable_v = is_nothrow_invocable<F, Args...>::value;
+
+ template <typename R, typename F, typename... Args>
+ EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool is_nothrow_invocable_r_v = is_nothrow_invocable_r<R, F, Args...>::value;
/// allocator_arg_t
///
@@ -144,9 +177,7 @@ namespace eastl
/// such as tuple, function, promise, and packaged_task.
/// http://en.cppreference.com/w/cpp/memory/allocator_arg
///
- #if !defined(EA_COMPILER_NO_CONSTEXPR)
- EA_CONSTEXPR allocator_arg_t allocator_arg = allocator_arg_t();
- #endif
+ EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR allocator_arg_t allocator_arg = allocator_arg_t();
template <typename Argument, typename Result>
@@ -202,7 +233,7 @@ namespace eastl
T& get() const EA_NOEXCEPT;
template <typename... ArgTypes>
- typename eastl::result_of<T&(ArgTypes&&...)>::type operator() (ArgTypes&&...) const;
+ typename eastl::invoke_result<T&, ArgTypes...>::type operator() (ArgTypes&&...) const;
private:
T* val;
@@ -239,7 +270,7 @@ namespace eastl
template <typename T>
template <typename... ArgTypes>
- typename eastl::result_of<T&(ArgTypes&&...)>::type reference_wrapper<T>::operator() (ArgTypes&&... args) const
+ typename eastl::invoke_result<T&, ArgTypes...>::type reference_wrapper<T>::operator() (ArgTypes&&... args) const
{
return eastl::invoke(*val, eastl::forward<ArgTypes>(args)...);
}
@@ -248,7 +279,7 @@ namespace eastl
template <typename T>
reference_wrapper<T> ref(T& t) EA_NOEXCEPT
{
- return eastl::reference_wrapper<T>(t);
+ return eastl::reference_wrapper<T>(t);
}
template <typename T>
@@ -307,16 +338,16 @@ namespace eastl
// These have to come after reference_wrapper is defined, but reference_wrapper needs to have a
// definition of invoke, so these specializations need to come after everything else has been defined.
template <typename R, typename C, typename T, typename... Args>
- auto invoke_impl(R (C::*func)(Args...), T&& obj, Args&&... args) ->
- typename enable_if<is_reference_wrapper<typename remove_reference<T>::type>::value,
+ EA_CONSTEXPR auto invoke_impl(R C::*func, T&& obj, Args&&... args) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR((obj.get().*func)(eastl::forward<Args>(args)...)))
+ -> typename enable_if<is_reference_wrapper<eastl::decay_t<T>>::value,
decltype((obj.get().*func)(eastl::forward<Args>(args)...))>::type
{
return (obj.get().*func)(eastl::forward<Args>(args)...);
}
template <typename M, typename C, typename T>
- auto invoke_impl(M(C::*member), T&& obj) ->
- typename enable_if<is_reference_wrapper<typename remove_reference<T>::type>::value,
+ EA_CONSTEXPR auto invoke_impl(M C::*member, T&& obj) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(obj.get().*member))
+ -> typename enable_if<is_reference_wrapper<eastl::decay_t<T>>::value,
decltype(obj.get().*member)>::type
{
return obj.get().*member;
@@ -386,4 +417,4 @@ namespace eastl
} // namespace eastl
-#endif // Header include guard
+#endif // EASTL_INTERNAL_FUNCTIONAL_BASE_H
diff --git a/EASTL/include/EASTL/internal/generic_iterator.h b/EASTL/include/EASTL/internal/generic_iterator.h
index b32998a..0f1e28b 100644
--- a/EASTL/include/EASTL/internal/generic_iterator.h
+++ b/EASTL/include/EASTL/internal/generic_iterator.h
@@ -56,7 +56,6 @@ namespace eastl
typedef typename eastl::iterator_traits<Iterator>::reference reference;
typedef typename eastl::iterator_traits<Iterator>::pointer pointer;
typedef Iterator iterator_type;
- typedef iterator_type wrapped_iterator_type; // This is not in the C++ Standard; it's used by use to identify it as a wrapping iterator type.
typedef Container container_type;
typedef generic_iterator<Iterator, Container> this_type;
@@ -109,6 +108,15 @@ namespace eastl
const iterator_type& base() const
{ return mIterator; }
+ private:
+ // Unwrapping interface, not part of the public API.
+ const iterator_type& unwrap() const
+ { return mIterator; }
+
+ // The unwrapper helpers need access to unwrap().
+ friend is_iterator_wrapper_helper<this_type, true>;
+ friend is_iterator_wrapper<this_type>;
+
}; // class generic_iterator
@@ -187,7 +195,7 @@ namespace eastl
/// unwrap_generic_iterator
///
- /// Returns Iterator::get_base() if it's a generic_iterator, else returns Iterator as-is.
+ /// Returns `it.base()` if it's a generic_iterator, else returns `it` as-is.
///
/// Example usage:
/// vector<int> intVector;
@@ -196,7 +204,10 @@ namespace eastl
///
template <typename Iterator>
inline typename eastl::is_iterator_wrapper_helper<Iterator, eastl::is_generic_iterator<Iterator>::value>::iterator_type unwrap_generic_iterator(Iterator it)
- { return eastl::is_iterator_wrapper_helper<Iterator, eastl::is_generic_iterator<Iterator>::value>::get_base(it); }
+ {
+ // get_unwrapped(it) -> it.unwrap() which is equivalent to `it.base()` for generic_iterator and to `it` otherwise.
+ return eastl::is_iterator_wrapper_helper<Iterator, eastl::is_generic_iterator<Iterator>::value>::get_unwrapped(it);
+ }
} // namespace eastl
diff --git a/EASTL/include/EASTL/internal/hashtable.h b/EASTL/include/EASTL/internal/hashtable.h
index bb6d27e..077f5b4 100644
--- a/EASTL/include/EASTL/internal/hashtable.h
+++ b/EASTL/include/EASTL/internal/hashtable.h
@@ -879,6 +879,12 @@ namespace eastl
RehashPolicy mRehashPolicy; // To do: Use base class optimization to make this go away.
allocator_type mAllocator; // To do: Use base class optimization to make this go away.
+ struct NodeFindKeyData {
+ node_type* node;
+ hash_code_t code;
+ size_type bucket_index;
+ };
+
public:
hashtable(size_type nBucketCount, const H1&, const H2&, const H&, const Equal&, const ExtractKey&,
const allocator_type& allocator = EASTL_HASHTABLE_DEFAULT_ALLOCATOR);
@@ -1003,11 +1009,6 @@ namespace eastl
template <class... Args>
iterator emplace_hint(const_iterator position, Args&&... args);
- template <class... Args> insert_return_type try_emplace(const key_type& k, Args&&... args);
- template <class... Args> insert_return_type try_emplace(key_type&& k, Args&&... args);
- template <class... Args> iterator try_emplace(const_iterator position, const key_type& k, Args&&... args);
- template <class... Args> iterator try_emplace(const_iterator position, key_type&& k, Args&&... args);
-
insert_return_type insert(const value_type& value);
insert_return_type insert(value_type&& otherValue);
iterator insert(const_iterator hint, const value_type& value);
@@ -1200,6 +1201,9 @@ namespace eastl
node_type** DoAllocateBuckets(size_type n);
void DoFreeBuckets(node_type** pBucketArray, size_type n);
+ template <bool bDeleteOnException, typename Enabled = bool_constant<bUniqueKeys>, ENABLE_IF_TRUETYPE(Enabled) = nullptr> // only enabled when keys are unique
+ eastl::pair<iterator, bool> DoInsertUniqueNode(const key_type& k, hash_code_t c, size_type n, node_type* pNodeNew);
+
template <typename BoolConstantT, class... Args, ENABLE_IF_TRUETYPE(BoolConstantT) = nullptr>
eastl::pair<iterator, bool> DoInsertValue(BoolConstantT, Args&&... args);
@@ -1278,6 +1282,7 @@ namespace eastl
void DoRehash(size_type nBucketCount);
node_type* DoFindNode(node_type* pNode, const key_type& k, hash_code_t c) const;
+ NodeFindKeyData DoFindKeyData(const key_type& k) const;
template <typename T>
ENABLE_IF_HAS_HASHCODE(T, node_type) DoFindNode(T* pNode, hash_code_t c) const
@@ -1293,6 +1298,14 @@ namespace eastl
template <typename U, typename BinaryPredicate>
node_type* DoFindNodeT(node_type* pNode, const U& u, BinaryPredicate predicate) const;
+ private:
+ template <typename V, typename Enabled = bool_constant<bUniqueKeys>, ENABLE_IF_TRUETYPE(Enabled) = nullptr>
+ eastl::pair<iterator, bool> DoInsertValueExtraForwarding(const key_type& k,
+ hash_code_t c,
+ node_type* pNodeNew,
+ V&& value);
+
+
}; // class hashtable
@@ -1572,7 +1585,7 @@ namespace eastl
typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::node_type*
hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoAllocateNodeFromKey(const key_type& key)
{
- node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0);
+ node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0);
EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined.");
#if EASTL_EXCEPTIONS_ENABLED
@@ -1598,7 +1611,7 @@ namespace eastl
typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::node_type*
hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoAllocateNodeFromKey(key_type&& key)
{
- node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0);
+ node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0);
EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined.");
#if EASTL_EXCEPTIONS_ENABLED
@@ -1953,6 +1966,16 @@ namespace eastl
}
+ template <typename K, typename V, typename A, typename EK, typename Eq,
+ typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
+ inline typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::NodeFindKeyData
+ hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoFindKeyData(const key_type& k) const {
+ NodeFindKeyData d;
+ d.code = get_hash_code(k);
+ d.bucket_index = (size_type)bucket_index(k, d.code, (uint32_t)mnBucketCount);
+ d.node = DoFindNode(mpBucketArray[d.bucket_index], k, d.code);
+ return d;
+ }
template <typename K, typename V, typename A, typename EK, typename Eq,
typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
@@ -1984,6 +2007,41 @@ namespace eastl
}
+ template <typename K, typename V, typename A, typename EK, typename Eq,
+ typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
+ template <bool bDeleteOnException, typename Enabled, ENABLE_IF_TRUETYPE(Enabled)> // only enabled when keys are unique
+ eastl::pair<typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::iterator, bool>
+ hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoInsertUniqueNode(const key_type& k, hash_code_t c, size_type n, node_type* pNodeNew)
+ {
+ const eastl::pair<bool, uint32_t> bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1);
+
+ set_code(pNodeNew, c); // This is a no-op for most hashtables.
+
+ #if EASTL_EXCEPTIONS_ENABLED
+ try
+ {
+ #endif
+ if(bRehash.first)
+ {
+ n = (size_type)bucket_index(k, c, (uint32_t)bRehash.second);
+ DoRehash(bRehash.second);
+ }
+
+ EASTL_ASSERT((uintptr_t)mpBucketArray != (uintptr_t)&gpEmptyBucketArray[0]);
+ pNodeNew->mpNext = mpBucketArray[n];
+ mpBucketArray[n] = pNodeNew;
+ ++mnElementCount;
+
+ return eastl::pair<iterator, bool>(iterator(pNodeNew, mpBucketArray + n), true);
+ #if EASTL_EXCEPTIONS_ENABLED
+ }
+ catch(...)
+ {
+ EA_CONSTEXPR_IF(bDeleteOnException) { DoFreeNode(pNodeNew); }
+ throw;
+ }
+ #endif
+ }
template <typename K, typename V, typename A, typename EK, typename Eq,
typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
@@ -2010,34 +2068,7 @@ namespace eastl
if(pNode == NULL) // If value is not present... add it.
{
- const eastl::pair<bool, uint32_t> bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1);
-
- set_code(pNodeNew, c); // This is a no-op for most hashtables.
-
- #if EASTL_EXCEPTIONS_ENABLED
- try
- {
- #endif
- if(bRehash.first)
- {
- n = (size_type)bucket_index(k, c, (uint32_t)bRehash.second);
- DoRehash(bRehash.second);
- }
-
- EASTL_ASSERT((uintptr_t)mpBucketArray != (uintptr_t)&gpEmptyBucketArray[0]);
- pNodeNew->mpNext = mpBucketArray[n];
- mpBucketArray[n] = pNodeNew;
- ++mnElementCount;
-
- return eastl::pair<iterator, bool>(iterator(pNodeNew, mpBucketArray + n), true);
- #if EASTL_EXCEPTIONS_ENABLED
- }
- catch(...)
- {
- DoFreeNode(pNodeNew);
- throw;
- }
- #endif
+ return DoInsertUniqueNode<true>(k, c, n, pNodeNew);
}
else
{
@@ -2105,7 +2136,7 @@ namespace eastl
typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::node_type*
hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoAllocateNode(Args&&... args)
{
- node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0);
+ node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0);
EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined.");
#if EASTL_EXCEPTIONS_ENABLED
@@ -2133,14 +2164,33 @@ namespace eastl
// The reason is because the specializations below are slightly more efficient because they can delay
// the creation of a node until it's known that it will be needed.
////////////////////////////////////////////////////////////////////////////////////////////////////
-
template <typename K, typename V, typename A, typename EK, typename Eq,
typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
template <typename BoolConstantT>
- eastl::pair<typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::iterator, bool>
+ inline eastl::pair<typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::iterator, bool>
hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoInsertValueExtra(BoolConstantT, const key_type& k,
hash_code_t c, node_type* pNodeNew, value_type&& value, ENABLE_IF_TRUETYPE(BoolConstantT)) // true_type means bUniqueKeys is true.
{
+ return DoInsertValueExtraForwarding(k, c, pNodeNew, eastl::move(value));
+ }
+
+ template <typename K, typename V, typename A, typename EK, typename Eq,
+ typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
+ template <typename BoolConstantT>
+ inline eastl::pair<typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::iterator, bool>
+ hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoInsertValueExtra(BoolConstantT, const key_type& k,
+ hash_code_t c, node_type* pNodeNew, const value_type& value, ENABLE_IF_TRUETYPE(BoolConstantT)) // true_type means bUniqueKeys is true.
+ {
+ return DoInsertValueExtraForwarding(k, c, pNodeNew, value);
+ }
+
+ template <typename K, typename V, typename A, typename EK, typename Eq,
+ typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
+ template <typename VFwd, typename Enabled, ENABLE_IF_TRUETYPE(Enabled)> // true_type means bUniqueKeys is true.
+ eastl::pair<typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::iterator, bool>
+ hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoInsertValueExtraForwarding(const key_type& k,
+ hash_code_t c, node_type* pNodeNew, VFwd&& value)
+ {
// Adds the value to the hash table if not already present.
// If already present then the existing value is returned via an iterator/bool pair.
size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount);
@@ -2148,56 +2198,18 @@ namespace eastl
if(pNode == NULL) // If value is not present... add it.
{
- const eastl::pair<bool, uint32_t> bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1);
-
- // Allocate the new node before doing the rehash so that we don't
+ // Allocate the new node before doing the rehash so that we don't
// do a rehash if the allocation throws.
- #if EASTL_EXCEPTIONS_ENABLED
- bool nodeAllocated; // If exceptions are enabled then we we need to track if we allocated the node so we can free it in the catch block.
- #endif
-
if(pNodeNew)
{
- ::new(eastl::addressof(pNodeNew->mValue)) value_type(eastl::move(value)); // It's expected that pNodeNew was allocated with allocate_uninitialized_node.
- #if EASTL_EXCEPTIONS_ENABLED
- nodeAllocated = false;
- #endif
+ ::new(eastl::addressof(pNodeNew->mValue)) value_type(eastl::forward<VFwd>(value)); // It's expected that pNodeNew was allocated with allocate_uninitialized_node.
+ return DoInsertUniqueNode<false>(k, c, n, pNodeNew);
}
else
{
pNodeNew = DoAllocateNode(eastl::move(value));
- #if EASTL_EXCEPTIONS_ENABLED
- nodeAllocated = true;
- #endif
+ return DoInsertUniqueNode<true>(k, c, n, pNodeNew);
}
-
- set_code(pNodeNew, c); // This is a no-op for most hashtables.
-
- #if EASTL_EXCEPTIONS_ENABLED
- try
- {
- #endif
- if(bRehash.first)
- {
- n = (size_type)bucket_index(k, c, (uint32_t)bRehash.second);
- DoRehash(bRehash.second);
- }
-
- EASTL_ASSERT((uintptr_t)mpBucketArray != (uintptr_t)&gpEmptyBucketArray[0]);
- pNodeNew->mpNext = mpBucketArray[n];
- mpBucketArray[n] = pNodeNew;
- ++mnElementCount;
-
- return eastl::pair<iterator, bool>(iterator(pNodeNew, mpBucketArray + n), true);
- #if EASTL_EXCEPTIONS_ENABLED
- }
- catch(...)
- {
- if(nodeAllocated) // If we allocated the node within this function, free it. Else let the caller retain ownership of it.
- DoFreeNode(pNodeNew);
- throw;
- }
- #endif
}
// Else the value is already present, so don't add a new node. And don't free pNodeNew.
@@ -2283,7 +2295,7 @@ namespace eastl
typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::node_type*
hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoAllocateNode(value_type&& value)
{
- node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0);
+ node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0);
EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined.");
#if EASTL_EXCEPTIONS_ENABLED
@@ -2303,78 +2315,6 @@ namespace eastl
#endif
}
-
- template <typename K, typename V, typename A, typename EK, typename Eq,
- typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
- template<typename BoolConstantT>
- eastl::pair<typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::iterator, bool>
- hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoInsertValueExtra(BoolConstantT, const key_type& k, hash_code_t c, node_type* pNodeNew, const value_type& value,
- ENABLE_IF_TRUETYPE(BoolConstantT)) // true_type means bUniqueKeys is true.
- {
- // Adds the value to the hash table if not already present.
- // If already present then the existing value is returned via an iterator/bool pair.
- size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount);
- node_type* const pNode = DoFindNode(mpBucketArray[n], k, c);
-
- if(pNode == NULL) // If value is not present... add it.
- {
- const eastl::pair<bool, uint32_t> bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1);
-
- // Allocate the new node before doing the rehash so that we don't
- // do a rehash if the allocation throws.
- #if EASTL_EXCEPTIONS_ENABLED
- bool nodeAllocated; // If exceptions are enabled then we we need to track if we allocated the node so we can free it in the catch block.
- #endif
-
- if(pNodeNew)
- {
- ::new(eastl::addressof(pNodeNew->mValue)) value_type(value); // It's expected that pNodeNew was allocated with allocate_uninitialized_node.
- #if EASTL_EXCEPTIONS_ENABLED
- nodeAllocated = false;
- #endif
- }
- else
- {
- pNodeNew = DoAllocateNode(value);
- #if EASTL_EXCEPTIONS_ENABLED
- nodeAllocated = true;
- #endif
- }
-
- set_code(pNodeNew, c); // This is a no-op for most hashtables.
-
- #if EASTL_EXCEPTIONS_ENABLED
- try
- {
- #endif
- if(bRehash.first)
- {
- n = (size_type)bucket_index(k, c, (uint32_t)bRehash.second);
- DoRehash(bRehash.second);
- }
-
- EASTL_ASSERT((uintptr_t)mpBucketArray != (uintptr_t)&gpEmptyBucketArray[0]);
- pNodeNew->mpNext = mpBucketArray[n];
- mpBucketArray[n] = pNodeNew;
- ++mnElementCount;
-
- return eastl::pair<iterator, bool>(iterator(pNodeNew, mpBucketArray + n), true);
- #if EASTL_EXCEPTIONS_ENABLED
- }
- catch(...)
- {
- if(nodeAllocated) // If we allocated the node within this function, free it. Else let the caller retain ownership of it.
- DoFreeNode(pNodeNew);
- throw;
- }
- #endif
- }
- // Else the value is already present, so don't add a new node. And don't free pNodeNew.
-
- return eastl::pair<iterator, bool>(iterator(pNode, mpBucketArray + n), false);
- }
-
-
template <typename K, typename V, typename A, typename EK, typename Eq,
typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
template<typename BoolConstantT>
@@ -2453,7 +2393,7 @@ namespace eastl
typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::node_type*
hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoAllocateNode(const value_type& value)
{
- node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0);
+ node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0);
EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined.");
#if EASTL_EXCEPTIONS_ENABLED
@@ -2480,7 +2420,7 @@ namespace eastl
hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::allocate_uninitialized_node()
{
// We don't wrap this in try/catch because users of this function are expected to do that themselves as needed.
- node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0);
+ node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0);
EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined.");
// Leave pNode->mValue uninitialized.
pNode->mpNext = NULL;
@@ -2695,54 +2635,6 @@ namespace eastl
}
template <typename K, typename V, typename A, typename EK, typename Eq,
- typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
- template <class... Args>
- // inline eastl::pair<typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::iterator, bool>
- inline typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::insert_return_type
- hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::try_emplace(const key_type& key, Args&&... args)
- {
- return DoInsertValue(has_unique_keys_type(), piecewise_construct, eastl::forward_as_tuple(key),
- eastl::forward_as_tuple(eastl::forward<Args>(args)...));
- }
-
- template <typename K, typename V, typename A, typename EK, typename Eq,
- typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
- template <class... Args>
- // inline eastl::pair<typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::iterator, bool>
- inline typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::insert_return_type
- hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::try_emplace(key_type&& key, Args&&... args)
- {
- return DoInsertValue(has_unique_keys_type(), piecewise_construct, eastl::forward_as_tuple(eastl::move(key)),
- eastl::forward_as_tuple(eastl::forward<Args>(args)...));
- }
-
- template <typename K, typename V, typename A, typename EK, typename Eq,
- typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
- template <class... Args>
- inline typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::iterator
- hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::try_emplace(const_iterator, const key_type& key, Args&&... args)
- {
- insert_return_type result = DoInsertValue(
- has_unique_keys_type(),
- value_type(piecewise_construct, eastl::forward_as_tuple(key), eastl::forward_as_tuple(eastl::forward<Args>(args)...)));
-
- return DoGetResultIterator(has_unique_keys_type(), result);
- }
-
- template <typename K, typename V, typename A, typename EK, typename Eq,
- typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
- template <class... Args>
- inline typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::iterator
- hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::try_emplace(const_iterator, key_type&& key, Args&&... args)
- {
- insert_return_type result =
- DoInsertValue(has_unique_keys_type(), value_type(piecewise_construct, eastl::forward_as_tuple(eastl::move(key)),
- eastl::forward_as_tuple(eastl::forward<Args>(args)...)));
-
- return DoGetResultIterator(has_unique_keys_type(), result);
- }
-
- template <typename K, typename V, typename A, typename EK, typename Eq,
typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::insert_return_type
hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::insert(value_type&& otherValue)
@@ -2962,14 +2854,25 @@ namespace eastl
while(*pBucketArray && !compare(k, c, *pBucketArray))
pBucketArray = &(*pBucketArray)->mpNext;
+ node_type* pDeleteList = nullptr;
while(*pBucketArray && compare(k, c, *pBucketArray))
{
node_type* const pNode = *pBucketArray;
*pBucketArray = pNode->mpNext;
- DoFreeNode(pNode);
+ // Don't free the node here, k might be a reference to the key inside this node,
+ // and we're re-using it when we compare to the following nodes.
+ // Instead, add it to the list of things to be deleted.
+ pNode->mpNext = pDeleteList;
+ pDeleteList = pNode;
--mnElementCount;
}
+ while (pDeleteList) {
+ node_type* const pToDelete = pDeleteList;
+ pDeleteList = pDeleteList->mpNext;
+ DoFreeNode(pToDelete);
+ }
+
return nElementCountSaved - mnElementCount;
}
diff --git a/EASTL/include/EASTL/internal/integer_sequence.h b/EASTL/include/EASTL/internal/integer_sequence.h
index 88cf1b1..ba5dd4e 100644
--- a/EASTL/include/EASTL/internal/integer_sequence.h
+++ b/EASTL/include/EASTL/internal/integer_sequence.h
@@ -24,6 +24,21 @@ public:
static EA_CONSTEXPR size_t size() EA_NOEXCEPT { return sizeof...(Ints); }
};
+template <size_t... Is>
+using index_sequence = integer_sequence<size_t, Is...>;
+
+#if (defined(EA_COMPILER_GNUC) && EA_COMPILER_VERSION >= 8001)
+
+template <typename T, T N>
+using make_integer_sequence = integer_sequence<T, __integer_pack(N)...>;
+
+#elif (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_BUILTIN(__make_integer_seq)) || (defined(EA_COMPILER_MSVC) && (EA_COMPILER_VERSION >= 1910))
+
+template <class T, T N>
+using make_integer_sequence = __make_integer_seq<integer_sequence, T, N>;
+
+#else
+
template <size_t N, typename IndexSeq>
struct make_index_sequence_impl;
@@ -39,12 +54,6 @@ struct make_index_sequence_impl<0, integer_sequence<size_t, Is...>>
typedef integer_sequence<size_t, Is...> type;
};
-template <size_t... Is>
-using index_sequence = integer_sequence<size_t, Is...>;
-
-template <size_t N>
-using make_index_sequence = typename make_index_sequence_impl<N, integer_sequence<size_t>>::type;
-
template <typename Target, typename Seq>
struct integer_sequence_convert_impl;
@@ -54,19 +63,54 @@ struct integer_sequence_convert_impl<Target, integer_sequence<size_t, Is...>>
typedef integer_sequence<Target, Is...> type;
};
-template <typename T, size_t N>
+template <typename T, T N>
struct make_integer_sequence_impl
{
- typedef typename integer_sequence_convert_impl<T, make_index_sequence<N>>::type type;
+ typedef typename integer_sequence_convert_impl<T, typename make_index_sequence_impl<N, integer_sequence<size_t>>::type>::type type;
};
-template <typename T, size_t N>
+template <typename T, T N>
using make_integer_sequence = typename make_integer_sequence_impl<T, N>::type;
+#endif
+
+template <size_t N>
+using make_index_sequence = make_integer_sequence<size_t, N>;
+
// Helper alias template that converts any type parameter pack into an index sequence of the same length
template<typename... T>
using index_sequence_for = make_index_sequence<sizeof...(T)>;
+namespace internal
+{
+
+template <typename T>
+struct integer_sequence_size_helper;
+
+template <typename T, T... Ints>
+struct integer_sequence_size_helper<eastl::integer_sequence<T, Ints...>> : public integral_constant<size_t, sizeof...(Ints)>
+{
+};
+
+template <typename T>
+struct integer_sequence_size : public integer_sequence_size_helper<eastl::remove_cv_t<T>>
+{
+};
+
+template <typename T>
+struct index_sequence_size : public integer_sequence_size_helper<eastl::remove_cv_t<T>>
+{
+};
+
+template <typename T>
+EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR size_t integer_sequence_size_v = integer_sequence_size<T>::value;
+
+template <typename T>
+EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR size_t index_sequence_size_v = index_sequence_size<T>::value;
+
+
+} // namespace internal
+
#endif // EASTL_VARIADIC_TEMPLATES_ENABLED
} // namespace eastl
diff --git a/EASTL/include/EASTL/internal/red_black_tree.h b/EASTL/include/EASTL/internal/red_black_tree.h
index 7448bd4..5b29b7c 100644
--- a/EASTL/include/EASTL/internal/red_black_tree.h
+++ b/EASTL/include/EASTL/internal/red_black_tree.h
@@ -169,6 +169,7 @@ namespace eastl
rbtree_iterator();
explicit rbtree_iterator(const node_type* pNode);
rbtree_iterator(const iterator& x);
+ rbtree_iterator& operator=(const iterator& x);
reference operator*() const;
pointer operator->() const;
@@ -477,11 +478,6 @@ namespace eastl
template <class... Args>
iterator emplace_hint(const_iterator position, Args&&... args);
- template <class... Args> eastl::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
- template <class... Args> eastl::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);
- template <class... Args> iterator try_emplace(const_iterator position, const key_type& k, Args&&... args);
- template <class... Args> iterator try_emplace(const_iterator position, key_type&& k, Args&&... args);
-
// Standard conversion overload to avoid the overhead of mismatched 'pair<const Key, Value>' types.
template <class P, class = typename eastl::enable_if<eastl::is_constructible<value_type, P&&>::value>::type>
insert_return_type insert(P&& otherValue);
@@ -662,6 +658,13 @@ namespace eastl
rbtree_iterator<T, Pointer, Reference>::rbtree_iterator(const iterator& x)
: mpNode(x.mpNode) { }
+ template <typename T, typename Pointer, typename Reference>
+ typename rbtree_iterator<T, Pointer, Reference>::this_type&
+ rbtree_iterator<T, Pointer, Reference>::operator=(const iterator& x)
+ {
+ mpNode = x.mpNode;
+ return *this;
+ }
template <typename T, typename Pointer, typename Reference>
typename rbtree_iterator<T, Pointer, Reference>::reference
@@ -1101,43 +1104,6 @@ namespace eastl
}
template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <class... Args>
- inline eastl::pair<typename rbtree<K, V, C, A, E, bM, bU>::iterator, bool>
- rbtree<K, V, C, A, E, bM, bU>::try_emplace(const key_type& key, Args&&... args)
- {
- return DoInsertValue(has_unique_keys_type(), piecewise_construct, eastl::forward_as_tuple(key), eastl::forward_as_tuple(eastl::forward<Args>(args)...));
- }
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <class... Args>
- inline eastl::pair<typename rbtree<K, V, C, A, E, bM, bU>::iterator, bool>
- rbtree<K, V, C, A, E, bM, bU>::try_emplace(key_type&& key, Args&&... args)
- {
- return DoInsertValue(has_unique_keys_type(), piecewise_construct, eastl::forward_as_tuple(eastl::move(key)), eastl::forward_as_tuple(eastl::forward<Args>(args)...));
- }
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <class... Args>
- inline typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::try_emplace(const_iterator position, const key_type& key, Args&&... args)
- {
- return DoInsertValueHint(
- has_unique_keys_type(), position,
- piecewise_construct, eastl::forward_as_tuple(key), eastl::forward_as_tuple(eastl::forward<Args>(args)...));
- }
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <class... Args>
- inline typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::try_emplace(const_iterator position, key_type&& key, Args&&... args)
- {
- return DoInsertValueHint(
- has_unique_keys_type(), position,
- piecewise_construct, eastl::forward_as_tuple(eastl::move(key)), eastl::forward_as_tuple(eastl::forward<Args>(args)...));
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
template <class P, class>
inline typename rbtree<K, V, C, A, E, bM, bU>::insert_return_type // map/set::insert return a pair, multimap/multiset::iterator return an iterator.
rbtree<K, V, C, A, E, bM, bU>::insert(P&& otherValue)
diff --git a/EASTL/include/EASTL/internal/smart_ptr.h b/EASTL/include/EASTL/internal/smart_ptr.h
index f1d52e1..8a37950 100644
--- a/EASTL/include/EASTL/internal/smart_ptr.h
+++ b/EASTL/include/EASTL/internal/smart_ptr.h
@@ -162,7 +162,10 @@ namespace eastl
default_delete(const default_delete<U>&, typename eastl::enable_if<is_convertible<U*, T*>::value>::type* = 0) EA_NOEXCEPT {}
void operator()(T* p) const EA_NOEXCEPT
- { delete p; }
+ {
+ static_assert(eastl::internal::is_complete_type_v<T>, "Attempting to call the destructor of an incomplete type");
+ delete p;
+ }
};
diff --git a/EASTL/include/EASTL/internal/thread_support.h b/EASTL/include/EASTL/internal/thread_support.h
index 80386d2..49856c0 100644
--- a/EASTL/include/EASTL/internal/thread_support.h
+++ b/EASTL/include/EASTL/internal/thread_support.h
@@ -19,10 +19,12 @@
//
// fatal error C1189: <mutex> is not supported when compiling with /clr or /clr:pure
/////////////////////////////////////////////////////////////////////////////////////////////////////
-#if defined(EA_HAVE_CPP11_MUTEX) && !defined(EA_COMPILER_MANAGED_CPP)
- #define EASTL_CPP11_MUTEX_ENABLED 1
-#else
- #define EASTL_CPP11_MUTEX_ENABLED 0
+#if !defined(EASTL_CPP11_MUTEX_ENABLED)
+ #if defined(EA_HAVE_CPP11_MUTEX) && !defined(EA_COMPILER_MANAGED_CPP)
+ #define EASTL_CPP11_MUTEX_ENABLED 1
+ #else
+ #define EASTL_CPP11_MUTEX_ENABLED 0
+ #endif
#endif
#if EASTL_CPP11_MUTEX_ENABLED
@@ -77,7 +79,7 @@ EA_DISABLE_VC_WARNING(4625 4626 4275);
///////////////////////////////////////////////////////////////////////////////
#if !defined(EASTL_THREAD_SUPPORT_AVAILABLE)
- #if defined(EA_COMPILER_CLANG) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003))
+ #if defined(__clang__) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003))
#define EASTL_THREAD_SUPPORT_AVAILABLE 1
#elif defined(EA_COMPILER_MSVC)
#define EASTL_THREAD_SUPPORT_AVAILABLE 1
@@ -91,92 +93,6 @@ namespace eastl
{
namespace Internal
{
- /// atomic_increment
- /// Returns the new value.
- inline int32_t atomic_increment(int32_t* p32) EA_NOEXCEPT
- {
- #if defined(EA_COMPILER_CLANG) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003))
- return __sync_add_and_fetch(p32, 1);
- #elif defined(EA_COMPILER_MSVC)
- static_assert(sizeof(long) == sizeof(int32_t), "unexpected size");
- return _InterlockedIncrement((volatile long*)p32);
- #elif defined(EA_COMPILER_GNUC)
- int32_t result;
- __asm__ __volatile__ ("lock; xaddl %0, %1"
- : "=r" (result), "=m" (*p32)
- : "0" (1), "m" (*p32)
- : "memory"
- );
- return result + 1;
- #else
- EASTL_FAIL_MSG("EASTL thread safety is not implemented yet. See EAThread for how to do this for the given platform.");
- return ++*p32;
- #endif
- }
-
- /// atomic_decrement
- /// Returns the new value.
- inline int32_t atomic_decrement(int32_t* p32) EA_NOEXCEPT
- {
- #if defined(EA_COMPILER_CLANG) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003))
- return __sync_add_and_fetch(p32, -1);
- #elif defined(EA_COMPILER_MSVC)
- return _InterlockedDecrement((volatile long*)p32); // volatile long cast is OK because int32_t == long on Microsoft platforms.
- #elif defined(EA_COMPILER_GNUC)
- int32_t result;
- __asm__ __volatile__ ("lock; xaddl %0, %1"
- : "=r" (result), "=m" (*p32)
- : "0" (-1), "m" (*p32)
- : "memory"
- );
- return result - 1;
- #else
- EASTL_FAIL_MSG("EASTL thread safety is not implemented yet. See EAThread for how to do this for the given platform.");
- return --*p32;
- #endif
- }
-
-
- /// atomic_compare_and_swap
- /// Safely sets the value to a new value if the original value is equal to
- /// a condition value. Returns true if the condition was met and the
- /// assignment occurred. The comparison and value setting are done as
- /// an atomic operation and thus another thread cannot intervene between
- /// the two as would be the case with simple C code.
- inline bool atomic_compare_and_swap(int32_t* p32, int32_t newValue, int32_t condition)
- {
- #if defined(EA_COMPILER_CLANG) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003))
- return __sync_bool_compare_and_swap(p32, condition, newValue);
- #elif defined(EA_COMPILER_MSVC)
- return ((int32_t)_InterlockedCompareExchange((volatile long*)p32, (long)newValue, (long)condition) == condition);
- #elif defined(EA_COMPILER_GNUC)
- // GCC Inline ASM Constraints
- // r <--> Any general purpose register
- // a <--> The a register.
- // 1 <--> The constraint '1' for operand 2 says that it must occupy the same location as operand 1.
- // =a <--> output registers
- // =r <--> output registers
-
- int32_t result;
- __asm__ __volatile__(
- "lock; cmpxchgl %3, (%1) \n" // Test *p32 against EAX, if same, then *p32 = newValue
- : "=a" (result), "=r" (p32) // outputs
- : "a" (condition), "r" (newValue), "1" (p32) // inputs
- : "memory" // clobbered
- );
- return result == condition;
- #else
- EASTL_FAIL_MSG("EASTL thread safety is not implemented yet. See EAThread for how to do this for the given platform.");
- if(*p32 == condition)
- {
- *p32 = newValue;
- return true;
- }
- return false;
- #endif
- }
-
-
// mutex
#if EASTL_CPP11_MUTEX_ENABLED
using std::mutex;
diff --git a/EASTL/include/EASTL/internal/type_compound.h b/EASTL/include/EASTL/internal/type_compound.h
index 178a734..339dc8e 100644
--- a/EASTL/include/EASTL/internal/type_compound.h
+++ b/EASTL/include/EASTL/internal/type_compound.h
@@ -128,58 +128,18 @@ namespace eastl
#define EASTL_TYPE_TRAIT_is_member_function_pointer_CONFORMANCE 1 // is_member_function_pointer is conforming; doesn't make mistakes.
- // To do: Revise this to support C++11 variadic templates when possible.
- // To do: We can probably also use remove_cv to simply the multitude of types below.
-
- template <typename T> struct is_mem_fun_pointer_value : public false_type{};
-
- template <typename R, typename T> struct is_mem_fun_pointer_value<R (T::*)()> : public true_type{};
- template <typename R, typename T> struct is_mem_fun_pointer_value<R (T::*)() const> : public true_type{};
- template <typename R, typename T> struct is_mem_fun_pointer_value<R (T::*)() volatile> : public true_type{};
- template <typename R, typename T> struct is_mem_fun_pointer_value<R (T::*)() const volatile> : public true_type{};
-
- template <typename R, typename T, typename Arg0> struct is_mem_fun_pointer_value<R (T::*)(Arg0)> : public true_type{};
- template <typename R, typename T, typename Arg0> struct is_mem_fun_pointer_value<R (T::*)(Arg0) const> : public true_type{};
- template <typename R, typename T, typename Arg0> struct is_mem_fun_pointer_value<R (T::*)(Arg0) volatile> : public true_type{};
- template <typename R, typename T, typename Arg0> struct is_mem_fun_pointer_value<R (T::*)(Arg0) const volatile> : public true_type{};
-
- template <typename R, typename T, typename Arg0, typename Arg1> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1)> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1) const> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1) volatile> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1) const volatile> : public true_type{};
-
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2)> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2) const> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2) volatile> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2) const volatile> : public true_type{};
-
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3)> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3) const> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3) volatile> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3) const volatile> : public true_type{};
-
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4)> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4) const> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4) volatile> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4) const volatile> : public true_type{};
-
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5)> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5) const> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5) volatile> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5) const volatile> : public true_type{};
-
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6)> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) const> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) volatile> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) const volatile> : public true_type{};
-
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6, typename Arg7> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7)> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6, typename Arg7> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7) const> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6, typename Arg7> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7) volatile> : public true_type{};
- template <typename R, typename T, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6, typename Arg7> struct is_mem_fun_pointer_value<R (T::*)(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7) const volatile> : public true_type{};
+ namespace internal
+ {
+ template<typename T>
+ struct is_member_function_pointer_helper : false_type {};
- template <typename T>
- struct is_member_function_pointer : public integral_constant<bool, is_mem_fun_pointer_value<T>::value>{};
+ template<typename T, typename U>
+ struct is_member_function_pointer_helper<T U::*> : is_function<T> {};
+ }
+
+ template<typename T>
+ struct is_member_function_pointer
+ : internal::is_member_function_pointer_helper<typename remove_cv<T>::type> {};
#if EASTL_VARIABLE_TEMPLATES_ENABLED
template<typename T>
@@ -198,13 +158,19 @@ namespace eastl
#define EASTL_TYPE_TRAIT_is_member_pointer_CONFORMANCE 1 // is_member_pointer is conforming; doesn't make mistakes.
- template <typename T>
- struct is_member_pointer
- : public eastl::integral_constant<bool, eastl::is_member_function_pointer<T>::value>{};
+ namespace internal {
+ template <typename T>
+ struct is_member_pointer_helper
+ : public eastl::false_type {};
- template <typename T, typename U>
- struct is_member_pointer<U T::*>
- : public eastl::true_type{};
+ template <typename T, typename U>
+ struct is_member_pointer_helper<U T::*>
+ : public eastl::true_type {};
+ }
+
+ template<typename T>
+ struct is_member_pointer
+ : public internal::is_member_pointer_helper<typename remove_cv<T>::type>::type {};
#if EASTL_VARIABLE_TEMPLATES_ENABLED
template<typename T>
@@ -290,7 +256,7 @@ namespace eastl
// is_convertible<D*, A*>::value; // Generates compiler error.
///////////////////////////////////////////////////////////////////////
- #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_convertible_to)))
+ #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_convertible_to)))
#define EASTL_TYPE_TRAIT_is_convertible_CONFORMANCE 1 // is_convertible is conforming.
// Problem: VC++ reports that int is convertible to short, yet if you construct a short from an int then VC++ generates a warning:
@@ -371,7 +337,7 @@ namespace eastl
// via 'msl::is_union<T>::value'. The user can force something to be
// evaluated as a union via EASTL_DECLARE_UNION.
///////////////////////////////////////////////////////////////////////
- #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_union)))
+ #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_union)))
#define EASTL_TYPE_TRAIT_is_union_CONFORMANCE 1 // is_union is conforming.
template <typename T>
@@ -401,7 +367,7 @@ namespace eastl
// distinguish between unions and classes. As a result, is_class
// will erroneously evaluate to true for union types.
///////////////////////////////////////////////////////////////////////
- #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_class)))
+ #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_class)))
#define EASTL_TYPE_TRAIT_is_class_CONFORMANCE 1 // is_class is conforming.
template <typename T>
@@ -442,57 +408,6 @@ namespace eastl
#endif
- ///////////////////////////////////////////////////////////////////////
- // is_enum
- //
- // is_enum<T>::value == true if and only if T is an enumeration type.
- //
- ///////////////////////////////////////////////////////////////////////
-
- #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_enum)))
- #define EASTL_TYPE_TRAIT_is_enum_CONFORMANCE 1 // is_enum is conforming.
-
- template <typename T>
- struct is_enum : public integral_constant<bool, __is_enum(T)>{};
- #else
- #define EASTL_TYPE_TRAIT_is_enum_CONFORMANCE 1 // is_enum is conforming.
-
- struct int_convertible{ int_convertible(int); };
-
- template <bool is_arithmetic_or_reference>
- struct is_enum_helper { template <typename T> struct nest : public is_convertible<T, int_convertible>{}; };
-
- template <>
- struct is_enum_helper<true> { template <typename T> struct nest : public false_type {}; };
-
- template <typename T>
- struct is_enum_helper2
- {
- typedef type_or<is_arithmetic<T>::value, is_reference<T>::value, is_class<T>::value> selector;
- typedef is_enum_helper<selector::value> helper_t;
- typedef typename add_reference<T>::type ref_t;
- typedef typename helper_t::template nest<ref_t> result;
- };
-
- template <typename T>
- struct is_enum : public integral_constant<bool, is_enum_helper2<T>::result::value>{};
-
- template <> struct is_enum<void> : public false_type {};
- template <> struct is_enum<void const> : public false_type {};
- template <> struct is_enum<void volatile> : public false_type {};
- template <> struct is_enum<void const volatile> : public false_type {};
- #endif
-
- #if EASTL_VARIABLE_TEMPLATES_ENABLED
- template<typename T>
- EA_CONSTEXPR bool is_enum_v = is_enum<T>::value;
- #endif
-
- #define EASTL_DECLARE_ENUM(T) namespace eastl{ template <> struct is_enum<T> : public true_type{}; template <> struct is_enum<const T> : public true_type{}; }
-
-
-
-
///////////////////////////////////////////////////////////////////////
// is_polymorphic
@@ -503,7 +418,7 @@ namespace eastl
//
///////////////////////////////////////////////////////////////////////
- #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_polymorphic)))
+ #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_polymorphic)))
#define EASTL_TYPE_TRAIT_is_polymorphic_CONFORMANCE 1 // is_polymorphic is conforming.
template <typename T>
@@ -741,7 +656,7 @@ namespace eastl
///////////////////////////////////////////////////////////////////////
// is_final
///////////////////////////////////////////////////////////////////////
- #if EA_COMPILER_HAS_FEATURE(is_final)
+ #if EASTL_IS_FINAL_AVAILABLE == 1
template <typename T>
struct is_final : public integral_constant<bool, __is_final(T)> {};
#else
@@ -773,7 +688,7 @@ namespace eastl
// * no default member initializers
//
///////////////////////////////////////////////////////////////////////
- #if EA_COMPILER_HAS_FEATURE(is_aggregate) || defined(_MSC_VER) && (_MSC_VER >= 1916) // VS2017 15.9+
+ #if EASTL_IS_AGGREGATE_AVAILABLE == 1
#define EASTL_TYPE_TRAIT_is_aggregate_CONFORMANCE 1
template <typename T>
diff --git a/EASTL/include/EASTL/internal/type_detected.h b/EASTL/include/EASTL/internal/type_detected.h
new file mode 100644
index 0000000..e368a6f
--- /dev/null
+++ b/EASTL/include/EASTL/internal/type_detected.h
@@ -0,0 +1,180 @@
+/////////////////////////////////////////////////////////////////////////////
+// Copyright (c) Electronic Arts Inc. All rights reserved.
+/////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef EASTL_INTERNAL_TYPE_DETECTED_H
+#define EASTL_INTERNAL_TYPE_DETECTED_H
+
+
+#include <EABase/eabase.h>
+#if defined(EA_PRAGMA_ONCE_SUPPORTED)
+#pragma once
+#endif
+
+#include <EASTL/type_traits.h>
+
+namespace eastl
+{
+ ///////////////////////////////////////////////////////////////////////
+ // nonesuch
+ //
+ // Type given as a result from detected_t if the supplied arguments does not respect the constraint.
+ //
+ // https://en.cppreference.com/w/cpp/experimental/nonesuch
+ //
+ ///////////////////////////////////////////////////////////////////////
+ struct nonesuch
+ {
+ ~nonesuch() = delete;
+ nonesuch(nonesuch const&) = delete;
+ void operator=(nonesuch const&) = delete;
+ };
+
+ namespace internal
+ {
+ template <class Default, class AlwaysVoid, template <class...> class Op, class... Args>
+ struct detector
+ {
+ using type = Default;
+ using value_t = false_type;
+ };
+
+ template <class Default, template <class...> class Op, class... Args>
+ struct detector<Default, void_t<Op<Args...>>, Op, Args...>
+ {
+ using type = Op<Args...>;
+ using value_t = true_type;
+ };
+ } // namespace internal
+
+ ///////////////////////////////////////////////////////////////////////
+ // is_detected
+ //
+ // Checks if some supplied arguments (Args) respect a constraint (Op).
+ // is_detected expands to true_type if the arguments respect the constraint, false_type otherwise.
+ // This helper is convenient to use for compile time introspection.
+ //
+ // https://en.cppreference.com/w/cpp/experimental/is_detected
+ //
+ // Example:
+ // template <class T, class U>
+ // using detect_can_use_addition_operator = decltype(declval<T>() + declval<U>());
+ //
+ // template <class T, class U>
+ // void sum(const T& t, const U& u)
+ // {
+ // static_assert(is_detected<detect_can_use_addition_operator, T, U>::value, "Supplied types cannot be summedtogether.");
+ // // or...
+ // static_assert(is_detected_v<detect_can_use_addition_operator, T, U>, "Supplied types cannot be summedtogether.");
+ // return t + u;
+ // }
+ //
+ ///////////////////////////////////////////////////////////////////////
+ template <template <class...> class Op, class... Args>
+ using is_detected = typename internal::detector<nonesuch, void, Op, Args...>::value_t;
+
+#if EASTL_VARIABLE_TEMPLATES_ENABLED
+ template <template <class...> class Op, class... Args>
+ EA_CONSTEXPR bool is_detected_v = is_detected<Op, Args...>::value;
+#endif
+
+ ///////////////////////////////////////////////////////////////////////
+ // detected_t
+ //
+ // Check which type we obtain after expanding some arguments (Args) over a constraint (Op).
+ // If the constraint cannot be applied, the result type will be nonesuch.
+ //
+ // https://en.cppreference.com/w/cpp/experimental/is_detected
+ //
+ // Example:
+ // template <class T, class U>
+ // using detect_can_use_addition_operator = decltype(declval<T>() + declval<U>());
+ //
+ // using result_type = detected_t<detect_can_use_addition_operator, int, int>;
+ // // result_type == int
+ // using failed_result_type = detected_t<detect_can_use_addition_operator, int, string>;
+ // // failed_result_type == nonesuch
+ //
+ ///////////////////////////////////////////////////////////////////////
+ template <template <class...> class Op, class... Args>
+ using detected_t = typename internal::detector<nonesuch, void, Op, Args...>::type;
+
+ ///////////////////////////////////////////////////////////////////////
+ // detected_or
+ //
+ // Checks if some supplied arguments (Args) respect a constraint (Op).
+ // Expand to a struct that contains two type aliases:
+ // - type: the type we obtain after expanding some arguments (Args) over a constraint (Op).
+ // If the constraint cannot be applied, the result type will be the suplied Default type.
+ // - value_t: true_type if the arguments respect the constraint, false_type otherwise.
+ //
+ // https://en.cppreference.com/w/cpp/experimental/is_detected
+ //
+ // Example:
+ // template <class T, class U>
+ // using detected_calling_foo = decltype(declval<T>().foo());
+ //
+ // using result = detected_or<bool, detected_calling_foo, std::string>; // std::string doesn't have foo member.
+ // function.
+ // // result::type == bool
+ // // result::value_t == false_type
+ //
+ ///////////////////////////////////////////////////////////////////////
+ template <class Default, template <class...> class Op, class... Args>
+ using detected_or = internal::detector<Default, void, Op, Args...>;
+
+ ///////////////////////////////////////////////////////////////////////
+ // detected_or_t
+ //
+ // Equivalent to detected_or<Default, Op, Args...>::type.
+ //
+ ///////////////////////////////////////////////////////////////////////
+ template <class Default, template <class...> class Op, class... Args>
+ using detected_or_t = typename detected_or<Default, Op, Args...>::type;
+
+ ///////////////////////////////////////////////////////////////////////
+ // is_detected_exact
+ //
+ // Check that the type we obtain after expanding some arguments (Args) over a constraint (Op) is equivalent to
+ // Expected.
+ //
+ // template <class T, class U>
+ // using detected_calling_size = decltype(declval<T>().size());
+ //
+ // using result = is_detected_exact<int, detected_calling_size, std::string>;
+ // result == false_type // std::string::size returns eastl_size_t which is not the same as int.
+ //
+ ///////////////////////////////////////////////////////////////////////
+ template <class Expected, template <class...> class Op, class... Args>
+ using is_detected_exact = is_same<Expected, detected_t<Op, Args...>>;
+
+#if EASTL_VARIABLE_TEMPLATES_ENABLED
+ template <class Expected, template <class...> class Op, class... Args>
+ EA_CONSTEXPR bool is_detected_exact_v = is_detected_exact<Expected, Op, Args...>::value;
+#endif
+
+ ///////////////////////////////////////////////////////////////////////
+ // is_detected_convertible
+ //
+ // Check that the type we obtain after expanding some arguments (Args) over a constraint (Op) is convertible to
+ // Expected.
+ //
+ // template <class T, class U>
+ // using detected_calling_size = decltype(declval<T>().size());
+ //
+ // using result = is_detected_convertible<int, detected_calling_size, std::string>;
+ // result == true_type // std::string::size returns eastl_size_t which is convertible to int.
+ //
+ ///////////////////////////////////////////////////////////////////////
+ template <class To, template <class...> class Op, class... Args>
+ using is_detected_convertible = is_convertible<detected_t<Op, Args...>, To>;
+
+#if EASTL_VARIABLE_TEMPLATES_ENABLED
+ template <class To, template <class...> class Op, class... Args>
+ EA_CONSTEXPR bool is_detected_convertible_v = is_detected_convertible<To, Op, Args...>::value;
+#endif
+
+} // namespace eastl
+
+#endif // EASTL_INTERNAL_TYPE_DETECTED_H \ No newline at end of file
diff --git a/EASTL/include/EASTL/internal/type_fundamental.h b/EASTL/include/EASTL/internal/type_fundamental.h
index 950d15e..c99b70c 100644
--- a/EASTL/include/EASTL/internal/type_fundamental.h
+++ b/EASTL/include/EASTL/internal/type_fundamental.h
@@ -130,6 +130,10 @@ namespace eastl
template <> struct is_integral_helper<bool> : public true_type{};
template <> struct is_integral_helper<char> : public true_type{};
+
+ #if defined(EA_CHAR8_UNIQUE) && EA_CHAR8_UNIQUE
+ template <> struct is_integral_helper<char8_t> : public true_type{};
+ #endif
#if defined(EA_CHAR16_NATIVE) && EA_CHAR16_NATIVE
template <> struct is_integral_helper<char16_t> : public true_type{};
#endif
@@ -139,7 +143,7 @@ namespace eastl
#ifndef EA_WCHAR_T_NON_NATIVE // If wchar_t is a native type instead of simply a define to an existing type which is already handled above...
template <> struct is_integral_helper<wchar_t> : public true_type{};
#endif
- #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG))
+ #if EASTL_GCC_STYLE_INT128_SUPPORTED
template <> struct is_integral_helper<__int128_t> : public true_type{};
template <> struct is_integral_helper<__uint128_t> : public true_type{};
#endif
@@ -262,6 +266,59 @@ namespace eastl
EA_CONSTEXPR bool is_hat_type_v = is_hat_type<T>::value;
#endif
+
+
+ ///////////////////////////////////////////////////////////////////////
+ // is_enum
+ //
+ // is_enum<T>::value == true if and only if T is an enumeration type.
+ //
+ ///////////////////////////////////////////////////////////////////////
+
+ #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_enum)))
+ #define EASTL_TYPE_TRAIT_is_enum_CONFORMANCE 1 // is_enum is conforming.
+
+ template <typename T>
+ struct is_enum : public integral_constant<bool, __is_enum(T)>{};
+ #else
+ #define EASTL_TYPE_TRAIT_is_enum_CONFORMANCE 1 // is_enum is conforming.
+
+ struct int_convertible{ int_convertible(int); };
+
+ template <bool is_arithmetic_or_reference>
+ struct is_enum_helper { template <typename T> struct nest : public is_convertible<T, int_convertible>{}; };
+
+ template <>
+ struct is_enum_helper<true> { template <typename T> struct nest : public false_type {}; };
+
+ template <typename T>
+ struct is_enum_helper2
+ {
+ typedef type_or<is_arithmetic<T>::value, is_reference<T>::value, is_class<T>::value> selector;
+ typedef is_enum_helper<selector::value> helper_t;
+ typedef typename add_reference<T>::type ref_t;
+ typedef typename helper_t::template nest<ref_t> result;
+ };
+
+ template <typename T>
+ struct is_enum : public integral_constant<bool, is_enum_helper2<T>::result::value>{};
+
+ template <> struct is_enum<void> : public false_type {};
+ template <> struct is_enum<void const> : public false_type {};
+ template <> struct is_enum<void volatile> : public false_type {};
+ template <> struct is_enum<void const volatile> : public false_type {};
+ #endif
+
+ #if EASTL_VARIABLE_TEMPLATES_ENABLED
+ template<typename T>
+ EA_CONSTEXPR bool is_enum_v = is_enum<T>::value;
+ #endif
+
+ #define EASTL_DECLARE_ENUM(T) namespace eastl{ template <> struct is_enum<T> : public true_type{}; template <> struct is_enum<const T> : public true_type{}; }
+
+
+
+
} // namespace eastl
diff --git a/EASTL/include/EASTL/internal/type_pod.h b/EASTL/include/EASTL/internal/type_pod.h
index 8726a7e..fef5511 100644
--- a/EASTL/include/EASTL/internal/type_pod.h
+++ b/EASTL/include/EASTL/internal/type_pod.h
@@ -25,7 +25,7 @@ namespace eastl
//
// is_empty cannot be used with union types until is_union can be made to work.
///////////////////////////////////////////////////////////////////////
- #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_empty)))
+ #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_empty)))
#define EASTL_TYPE_TRAIT_is_empty_CONFORMANCE 1 // is_empty is conforming.
template <typename T>
@@ -90,7 +90,7 @@ namespace eastl
struct is_pod : public eastl::integral_constant<bool, (__has_trivial_constructor(T) && __is_pod(T) && !eastl::is_hat_type<T>::value) || eastl::is_void<T>::value || eastl::is_scalar<T>::value>{};
EA_RESTORE_VC_WARNING()
- #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_pod)))
+ #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_pod)))
#define EASTL_TYPE_TRAIT_is_pod_CONFORMANCE 1 // is_pod is conforming.
template <typename T>
@@ -128,7 +128,7 @@ namespace eastl
///////////////////////////////////////////////////////////////////////
// is_standard_layout
//
- #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(EA_COMPILER_MSVC) && (_MSC_VER >= 1700)) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4006)) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_standard_layout)))
+ #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(EA_COMPILER_MSVC) && (_MSC_VER >= 1700)) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4006)) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_standard_layout)))
#define EASTL_TYPE_TRAIT_is_standard_layout_CONFORMANCE 1 // is_standard_layout is conforming.
template <typename T>
@@ -182,12 +182,12 @@ namespace eastl
// can be called without an argument.
///////////////////////////////////////////////////////////////////////
- #if defined(_MSC_VER) && (_MSC_VER >= 1600) // VS2010+
+ #if defined(_MSC_VER) && (_MSC_VER >= 1600) && !defined(EA_COMPILER_CLANG_CL) // VS2010+
#define EASTL_TYPE_TRAIT_has_trivial_constructor_CONFORMANCE 1 // has_trivial_constructor is conforming.
template <typename T>
struct has_trivial_constructor : public eastl::integral_constant<bool, (__has_trivial_constructor(T) || eastl::is_pod<T>::value) && !eastl::is_hat_type<T>::value>{};
- #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG))
+ #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(__clang__))
#define EASTL_TYPE_TRAIT_has_trivial_constructor_CONFORMANCE 1 // has_trivial_constructor is conforming.
template <typename T>
@@ -242,12 +242,12 @@ namespace eastl
// use EASTL_DECLARE_TRIVIAL_COPY to help the compiler.
///////////////////////////////////////////////////////////////////////
- #if defined(_MSC_VER)
+ #if defined(_MSC_VER) && !defined(EA_COMPILER_CLANG_CL)
#define EASTL_TYPE_TRAIT_has_trivial_copy_CONFORMANCE 1 // has_trivial_copy is conforming.
template <typename T>
struct has_trivial_copy : public eastl::integral_constant<bool, (__has_trivial_copy(T) || eastl::is_pod<T>::value) && !eastl::is_volatile<T>::value && !eastl::is_hat_type<T>::value>{};
- #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG))
+ #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(__clang__))
#define EASTL_TYPE_TRAIT_has_trivial_copy_CONFORMANCE 1 // has_trivial_copy is conforming.
template <typename T>
@@ -292,12 +292,12 @@ namespace eastl
// can use EASTL_DECLARE_TRIVIAL_ASSIGN to help the compiler.
///////////////////////////////////////////////////////////////////////
- #if defined(_MSC_VER) && (_MSC_VER >= 1600)
+ #if defined(_MSC_VER) && (_MSC_VER >= 1600) && !defined(EA_COMPILER_CLANG_CL)
#define EASTL_TYPE_TRAIT_has_trivial_assign_CONFORMANCE 1 // has_trivial_assign is conforming.
template <typename T>
struct has_trivial_assign : public integral_constant<bool, (__has_trivial_assign(T) || eastl::is_pod<T>::value) && !eastl::is_const<T>::value && !eastl::is_volatile<T>::value && !eastl::is_hat_type<T>::value>{};
- #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG))
+ #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(__clang__))
#define EASTL_TYPE_TRAIT_has_trivial_assign_CONFORMANCE 1 // has_trivial_assign is conforming.
template <typename T>
@@ -341,12 +341,12 @@ namespace eastl
// The user can use EASTL_DECLARE_TRIVIAL_DESTRUCTOR to help the compiler.
///////////////////////////////////////////////////////////////////////
- #if defined(_MSC_VER) && (_MSC_VER >= 1600)
+ #if defined(_MSC_VER) && (_MSC_VER >= 1600) && !defined(EA_COMPILER_CLANG_CL)
#define EASTL_TYPE_TRAIT_has_trivial_destructor_CONFORMANCE 1 // has_trivial_destructor is conforming.
template <typename T>
struct has_trivial_destructor : public eastl::integral_constant<bool, (__has_trivial_destructor(T) || eastl::is_pod<T>::value) && !eastl::is_hat_type<T>::value>{};
- #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG))
+ #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(__clang__))
#define EASTL_TYPE_TRAIT_has_trivial_destructor_CONFORMANCE 1 // has_trivial_destructor is conforming.
template <typename T>
@@ -412,7 +412,7 @@ namespace eastl
//
///////////////////////////////////////////////////////////////////////
- #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG))
+ #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(__clang__))
#define EASTL_TYPE_TRAIT_has_nothrow_constructor_CONFORMANCE 1
template <typename T>
@@ -452,7 +452,7 @@ namespace eastl
//
///////////////////////////////////////////////////////////////////////
- #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG))
+ #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(__clang__))
#define EASTL_TYPE_TRAIT_has_nothrow_copy_CONFORMANCE 1
template <typename T>
@@ -491,7 +491,7 @@ namespace eastl
//
///////////////////////////////////////////////////////////////////////
- #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG))
+ #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(__clang__))
#define EASTL_TYPE_TRAIT_has_nothrow_assign_CONFORMANCE 1
template <typename T>
@@ -529,7 +529,7 @@ namespace eastl
//
///////////////////////////////////////////////////////////////////////
- #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG))
+ #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(__clang__))
#define EASTL_TYPE_TRAIT_has_virtual_destructor_CONFORMANCE 1
template <typename T>
@@ -571,7 +571,7 @@ namespace eastl
//
///////////////////////////////////////////////////////////////////////
- #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_literal))
+ #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_literal))
#define EASTL_TYPE_TRAIT_is_literal_type_CONFORMANCE 1
template <typename T>
@@ -615,7 +615,7 @@ namespace eastl
//
///////////////////////////////////////////////////////////////////////
- #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_abstract)))
+ #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_abstract)))
#define EASTL_TYPE_TRAIT_is_abstract_CONFORMANCE 1 // is_abstract is conforming.
template <typename T>
@@ -672,7 +672,7 @@ namespace eastl
// up obj1 are copied into obj2, obj2 shall subsequently hold the
// same value as obj1. In other words, you can memcpy/memmove it.
///////////////////////////////////////////////////////////////////////
- #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(_MSC_VER) && (_MSC_VER >= 1700)) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 5003)) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_trivially_copyable)))
+ #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(_MSC_VER) && (_MSC_VER >= 1700)) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 5003)) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_trivially_copyable)))
#define EASTL_TYPE_TRAIT_is_trivially_copyable_CONFORMANCE 1
// https://connect.microsoft.com/VisualStudio/feedback/details/808827/c-std-is-trivially-copyable-produces-wrong-result-for-arrays
@@ -693,7 +693,7 @@ namespace eastl
//
template <typename T>
- struct is_trivially_copyable { static const bool value = __is_trivially_copyable(T); };
+ struct is_trivially_copyable : public bool_constant<__is_trivially_copyable(T)> {};
#elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_MSVC) || defined(EA_COMPILER_GNUC))
#define EASTL_TYPE_TRAIT_is_trivially_copyable_CONFORMANCE 1
@@ -731,7 +731,7 @@ namespace eastl
#define EASTL_TYPE_TRAIT_is_constructible_CONFORMANCE 1
- #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_constructible)))
+ #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_constructible)))
template<typename T, typename... Args>
struct is_constructible : public bool_constant<__is_constructible(T, Args...) > {};
#else
@@ -850,7 +850,7 @@ namespace eastl
// whether the __is_trivially_constructible compiler intrinsic is available.
// If the compiler has this trait built-in (which ideally all compilers would have since it's necessary for full conformance) use it.
- #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_trivially_constructible))
+ #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_trivially_constructible)) || defined(EA_COMPILER_MSVC))
template <typename T, typename Arg0 = eastl::unused>
struct is_trivially_constructible
@@ -915,7 +915,7 @@ namespace eastl
#else
// If the compiler has this trait built-in (which ideally all compilers would have since it's necessary for full conformance) use it.
- #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_trivially_constructible))
+ #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_trivially_constructible)) || defined(EA_COMPILER_MSVC))
#define EASTL_TYPE_TRAIT_is_trivially_constructible_CONFORMANCE 1
// We have a problem with clang here as of clang 3.4: __is_trivially_constructible(int[]) is false, yet I believe it should be true.
@@ -1380,7 +1380,7 @@ namespace eastl
// arrays of unknown bound
///////////////////////////////////////////////////////////////////////
- #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_trivially_assignable))
+ #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(__clang__) && EA_COMPILER_HAS_FEATURE(is_trivially_assignable))
#define EASTL_TYPE_TRAIT_is_trivially_assignable_CONFORMANCE 1
template <typename T, typename U>
@@ -1691,7 +1691,7 @@ namespace eastl
//
///////////////////////////////////////////////////////////////////////
- #if 0 // defined(_MSC_VER) && (_MSC_VER >= 1800) // VS2013+ -- Disabled due to __is_destructible being broken in VC++ versions up to at least VS2013. A ticket will be submitted for this
+ #if defined(_MSC_VER) && (_MSC_VER >= 1920)
#define EASTL_TYPE_TRAIT_is_destructible_CONFORMANCE 1
template <typename T>
@@ -1710,24 +1710,19 @@ namespace eastl
struct is_destructible
: public eastl::integral_constant<bool, !eastl::is_array_of_unknown_bounds<T>::value &&
!eastl::is_void<T>::value &&
- !eastl::is_function<T>::value &&
- !eastl::is_abstract<T>::value> {};
+ !eastl::is_function<T>::value> {};
#else
#define EASTL_TYPE_TRAIT_is_destructible_CONFORMANCE 1
- template <typename U>
- struct destructible_test_helper{ U u; };
-
template <typename>
eastl::false_type destructible_test_function(...);
- template <typename T, typename U = decltype(eastl::declval<eastl::destructible_test_helper<T> >().~destructible_test_helper<T>())>
+ template <typename T, typename U = typename eastl::remove_all_extents<T>::type, typename V = decltype(eastl::declval<U&>().~U())>
eastl::true_type destructible_test_function(int);
template <typename T, bool = eastl::is_array_of_unknown_bounds<T>::value || // Exclude these types from being considered destructible.
eastl::is_void<T>::value ||
- eastl::is_function<T>::value ||
- eastl::is_abstract<T>::value>
+ eastl::is_function<T>::value>
struct is_destructible_helper
: public eastl::identity<decltype(eastl::destructible_test_function<T>(0))>::type {}; // Need to wrap decltype with identity because some compilers otherwise don't like the bare decltype usage.
@@ -1735,6 +1730,14 @@ namespace eastl
struct is_destructible_helper<T, true>
: public eastl::false_type {};
+ template <typename T, bool Whatever>
+ struct is_destructible_helper<T&, Whatever> // Reference are trivially destructible.
+ : public eastl::true_type {};
+
+ template <typename T, bool Whatever>
+ struct is_destructible_helper<T&&, Whatever> // Reference are trivially destructible.
+ : public eastl::true_type {};
+
template <typename T>
struct is_destructible
: public is_destructible_helper<T> {};
@@ -1771,14 +1774,14 @@ namespace eastl
//
///////////////////////////////////////////////////////////////////////
- #if 0 // defined(_MSC_VER) && (_MSC_VER >= 1800) // VS2013+ -- Disabled due to __is_trivially_destructible being broken in VC++ versions up to at least VS2013. A ticket will be submitted for this
+ #if defined(_MSC_VER) && (_MSC_VER >= 1920)
#define EASTL_TYPE_TRAIT_is_trivially_destructible_CONFORMANCE 1
template <typename T>
struct is_trivially_destructible
: integral_constant<bool, __is_trivially_destructible(T)> {};
- #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG))
+ #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(__clang__))
#define EASTL_TYPE_TRAIT_is_trivially_destructible_CONFORMANCE EASTL_TYPE_TRAIT_is_destructible_CONFORMANCE
template <typename T>
@@ -1822,7 +1825,7 @@ namespace eastl
//
///////////////////////////////////////////////////////////////////////
- #if 0 // defined(_MSC_VER) && (_MSC_VER >= 1800) // VS2013+ -- Disabled due to __is_nothrow_destructible being broken in VC++ versions up to at least VS2013. A ticket will be submitted for this
+ #if defined(_MSC_VER) && (_MSC_VER >= 1920)
#define EASTL_TYPE_TRAIT_is_nothrow_destructible_CONFORMANCE ((_MSC_VER >= 1900) ? 1 : 0) // VS2013 (1800) doesn't support noexcept and so can't support all usage of this properly (in particular default exception specifications defined in [C++11 Standard, 15.4 paragraph 14].
template <typename T>
diff --git a/EASTL/include/EASTL/internal/type_properties.h b/EASTL/include/EASTL/internal/type_properties.h
index 5276f87..78bdfca 100644
--- a/EASTL/include/EASTL/internal/type_properties.h
+++ b/EASTL/include/EASTL/internal/type_properties.h
@@ -28,7 +28,7 @@ namespace eastl
//
///////////////////////////////////////////////////////////////////////
- #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(_MSC_VER) && (_MSC_VER >= 1700)) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4007)) || defined(EA_COMPILER_CLANG)) // VS2012+
+ #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(_MSC_VER) && (_MSC_VER >= 1700)) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4007)) || defined(__clang__)) // VS2012+
#define EASTL_TYPE_TRAIT_underlying_type_CONFORMANCE 1 // underlying_type is conforming.
template <typename T>
@@ -46,6 +46,25 @@ namespace eastl
using underlying_type_t = typename underlying_type<T>::type;
#endif
+ ///////////////////////////////////////////////////////////////////////
+ // to_underlying
+ //
+ // Cast a enum value to its underlying type.
+ // For example:
+ //
+ // enum class MyEnum : uint8_t { Value = 0; }
+ // auto x = MyEnum::Value;
+ // std::cout << to_underlying(x); // equivalent to sts::cout << static_cast<uint8_t>(x);
+ ///////////////////////////////////////////////////////////////////////
+
+ #if EASTL_VARIABLE_TEMPLATES_ENABLED && !defined(EA_COMPILER_NO_TEMPLATE_ALIASES)
+ template<class T>
+ constexpr underlying_type_t<T> to_underlying(T value) noexcept
+ {
+ return static_cast<underlying_type_t<T>>(value);
+ }
+ #endif
+
///////////////////////////////////////////////////////////////////////
// has_unique_object_representations
@@ -85,47 +104,31 @@ namespace eastl
///////////////////////////////////////////////////////////////////////
// is_signed
//
- // is_signed<T>::value == true if and only if T is one of the following types:
- // [const] [volatile] char (maybe)
- // [const] [volatile] signed char
- // [const] [volatile] short
- // [const] [volatile] int
- // [const] [volatile] long
- // [const] [volatile] long long
- // [const] [volatile] float
- // [const] [volatile] double
- // [const] [volatile] long double
+ // is_signed<T>::value == true if T is a (possibly cv-qualified) floating-point or signed integer type.
//
- // Used to determine if a integral type is signed or unsigned.
+ // Used to determine if a type is signed.
// Given that there are some user-made classes which emulate integral
// types, we provide the EASTL_DECLARE_SIGNED macro to allow you to
// set a given class to be identified as a signed type.
///////////////////////////////////////////////////////////////////////
#define EASTL_TYPE_TRAIT_is_signed_CONFORMANCE 1 // is_signed is conforming.
+
+#ifdef _MSC_VER
+ #pragma warning(push)
+ #pragma warning(disable: 4296) // '<': expression is always false
+#endif
+ template<typename T, bool = is_arithmetic<T>::value>
+ struct is_signed_helper : bool_constant<T(-1) < T(0)> {};
+#ifdef _MSC_VER
+ #pragma warning(pop)
+#endif
- template <typename T> struct is_signed_helper : public false_type{};
-
- template <> struct is_signed_helper<signed char> : public true_type{};
- template <> struct is_signed_helper<signed short> : public true_type{};
- template <> struct is_signed_helper<signed int> : public true_type{};
- template <> struct is_signed_helper<signed long> : public true_type{};
- template <> struct is_signed_helper<signed long long> : public true_type{};
- template <> struct is_signed_helper<float> : public true_type{};
- template <> struct is_signed_helper<double> : public true_type{};
- template <> struct is_signed_helper<long double> : public true_type{};
-
- #if (CHAR_MAX == SCHAR_MAX)
- template <> struct is_signed_helper<char> : public true_type{};
- #endif
- #ifndef EA_WCHAR_T_NON_NATIVE // If wchar_t is a native type instead of simply a define to an existing type...
- #if defined(__WCHAR_MAX__) && ((__WCHAR_MAX__ == 2147483647) || (__WCHAR_MAX__ == 32767)) // GCC defines __WCHAR_MAX__ for most platforms.
- template <> struct is_signed_helper<wchar_t> : public true_type{};
- #endif
- #endif
+ template<typename T>
+ struct is_signed_helper<T, false> : false_type {};
template <typename T>
- struct is_signed : public eastl::is_signed_helper<typename eastl::remove_cv<T>::type>{};
+ struct is_signed : public eastl::is_signed_helper<T>::type {};
#if EASTL_VARIABLE_TEMPLATES_ENABLED
template <class T>
@@ -145,41 +148,31 @@ namespace eastl
///////////////////////////////////////////////////////////////////////
// is_unsigned
//
- // is_unsigned<T>::value == true if and only if T is one of the following types:
- // [const] [volatile] char (maybe)
- // [const] [volatile] unsigned char
- // [const] [volatile] unsigned short
- // [const] [volatile] unsigned int
- // [const] [volatile] unsigned long
- // [const] [volatile] unsigned long long
+ // is_unsigned<T>::value == true if T is a (possibly cv-qualified) bool or unsigned integer type.
//
- // Used to determine if a integral type is signed or unsigned.
+ // Used to determine if a type is unsigned.
// Given that there are some user-made classes which emulate integral
// types, we provide the EASTL_DECLARE_UNSIGNED macro to allow you to
// set a given class to be identified as an unsigned type.
///////////////////////////////////////////////////////////////////////
#define EASTL_TYPE_TRAIT_is_unsigned_CONFORMANCE 1 // is_unsigned is conforming.
+
+#ifdef _MSC_VER
+ #pragma warning(push)
+ #pragma warning(disable: 4296) // '<': expression is always false
+#endif
+ template<typename T, bool = is_arithmetic<T>::value>
+ struct is_unsigned_helper : integral_constant<bool, T(0) < T(-1)> {};
+#ifdef _MSC_VER
+ #pragma warning(pop)
+#endif
- template <typename T> struct is_unsigned_helper : public false_type{};
-
- template <> struct is_unsigned_helper<unsigned char> : public true_type{};
- template <> struct is_unsigned_helper<unsigned short> : public true_type{};
- template <> struct is_unsigned_helper<unsigned int> : public true_type{};
- template <> struct is_unsigned_helper<unsigned long> : public true_type{};
- template <> struct is_unsigned_helper<unsigned long long> : public true_type{};
-
- #if (CHAR_MAX == UCHAR_MAX)
- template <> struct is_unsigned_helper<char> : public true_type{};
- #endif
- #ifndef EA_WCHAR_T_NON_NATIVE // If wchar_t is a native type instead of simply a define to an existing type...
- #if defined(_MSC_VER) || (defined(__WCHAR_MAX__) && ((__WCHAR_MAX__ == 4294967295U) || (__WCHAR_MAX__ == 65535))) // GCC defines __WCHAR_MAX__ for most platforms.
- template <> struct is_unsigned_helper<wchar_t> : public true_type{};
- #endif
- #endif
+ template<typename T>
+ struct is_unsigned_helper<T, false> : false_type {};
template <typename T>
- struct is_unsigned : public eastl::is_unsigned_helper<typename eastl::remove_cv<T>::type>{};
+ struct is_unsigned : public eastl::is_unsigned_helper<T>::type {};
#if EASTL_VARIABLE_TEMPLATES_ENABLED
template <class T>
@@ -194,7 +187,53 @@ namespace eastl
template <> struct is_unsigned<const volatile T> : public true_type{}; \
}
+ ///////////////////////////////////////////////////////////////////////
+ // is_bounded_array
+ //
+ // is_bounded_array<T>::value == true if T is an array type of known bound.
+ //
+ // is_bounded_array<int>::value is false.
+ // is_bounded_array<int[5]>::value is true.
+ // is_bounded_array<int[]>::value is false.
+ //
+ ///////////////////////////////////////////////////////////////////////
+
+ #define EASTL_TYPE_TRAIT_is_bounded_array_CONFORMANCE 1 // is_bounded_array is conforming.
+ template<class T>
+ struct is_bounded_array: eastl::false_type {};
+
+ template<class T, size_t N>
+ struct is_bounded_array<T[N]> : eastl::true_type {};
+
+ #if EASTL_VARIABLE_TEMPLATES_ENABLED
+ template <class T>
+ EA_CONSTEXPR bool is_bounded_array_v = is_bounded_array<T>::value;
+ #endif
+
+ ///////////////////////////////////////////////////////////////////////
+ // is_unbounded_array
+ //
+ // is_unbounded_array<T>::value == true if T is an array type of known bound.
+ //
+ // is_unbounded_array<int>::value is false.
+ // is_unbounded_array<int[5]>::value is false.
+ // is_unbounded_array<int[]>::value is true.
+ //
+ ///////////////////////////////////////////////////////////////////////
+
+ #define EASTL_TYPE_TRAIT_is_unbounded_array_CONFORMANCE 1 // is_unbounded_array is conforming.
+
+ template<class T>
+ struct is_unbounded_array: eastl::false_type {};
+
+ template<class T>
+ struct is_unbounded_array<T[]> : eastl::true_type {};
+
+ #if EASTL_VARIABLE_TEMPLATES_ENABLED
+ template <class T>
+ EA_CONSTEXPR bool is_unbounded_array_v = is_unbounded_array<T>::value;
+ #endif
///////////////////////////////////////////////////////////////////////
// alignment_of
@@ -222,7 +261,7 @@ namespace eastl
///////////////////////////////////////////////////////////////////////
// is_aligned
- //
+ //
// Defined as true if the type has alignment requirements greater
// than default alignment, which is taken to be 8. This allows for
// doing specialized object allocation and placement for such types.
@@ -281,7 +320,7 @@ namespace eastl
//
///////////////////////////////////////////////////////////////////////
- #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_base_of)))
+ #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || ((defined(__clang__)) && EA_COMPILER_HAS_FEATURE(is_base_of)))
#define EASTL_TYPE_TRAIT_is_base_of_CONFORMANCE 1 // is_base_of is conforming.
template <typename Base, typename Derived>
@@ -374,6 +413,44 @@ namespace eastl
EA_CONSTEXPR auto has_equality_v = has_equality<T>::value;
#endif
+ namespace internal
+ {
+ ///////////////////////////////////////////////////////////////////////
+ // is_complete_type
+ //
+ // Determines if the specified type is complete
+ //
+ // Warning: Be careful when using is_complete_type since the value is fixed at first instantiation.
+ // Consider the following:
+ //
+ // struct Foo;
+ // is_complete_type_v<Foo> // false
+ // struct Foo {};
+ // is_complete_type_v<Foo> // still false
+ ///////////////////////////////////////////////////////////////////////
+
+ template<typename T, typename = void>
+ struct is_complete_type : public false_type {};
+
+ template<typename T>
+ struct is_complete_type<T, eastl::void_t<decltype(sizeof(T) != 0)>> : public true_type {};
+
+ template<>
+ struct is_complete_type<const volatile void> : public false_type {};
+ template<>
+ struct is_complete_type<const void> : public false_type {};
+ template<>
+ struct is_complete_type<volatile void> : public false_type {};
+ template<>
+ struct is_complete_type<void> : public false_type {};
+
+ template<typename T>
+ struct is_complete_type<T, eastl::enable_if_t<eastl::is_function_v<T>>> : public true_type {};
+
+ template <typename T>
+ EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool is_complete_type_v = is_complete_type<T, void>::value;
+ }
+
} // namespace eastl
diff --git a/EASTL/include/EASTL/internal/type_transformations.h b/EASTL/include/EASTL/internal/type_transformations.h
index cffa65e..5454cfa 100644
--- a/EASTL/include/EASTL/internal/type_transformations.h
+++ b/EASTL/include/EASTL/internal/type_transformations.h
@@ -111,54 +111,148 @@ namespace eastl
// make_signed
//
// Used to convert an integral type to its signed equivalent, if not already.
- // T shall be a (possibly const and/or volatile-qualified) integral type
+ // T shall be a (possibly const and/or volatile-qualified) integral type
// or enumeration but not a bool type.;
//
- // The user can define their own make_signed overrides for their own
+ // The user can define their own make_signed overrides for their own
// types by making a template specialization like done below and adding
// it to the user's code.
///////////////////////////////////////////////////////////////////////
- // To do: This implementation needs to be updated to support C++11 conformance (recognition of enums) and
- // to support volatile-qualified types. It will probably be useful to have it fail for unsupported types.
- #define EASTL_TYPE_TRAIT_make_signed_CONFORMANCE 0 // make_signed is only partially conforming.
+ #define EASTL_TYPE_TRAIT_make_signed_CONFORMANCE 1
- template <typename T> struct make_signed { typedef T type; };
+ namespace internal
+ {
+ template <typename T, bool = eastl::is_enum_v<T> || eastl::is_integral_v<T>>
+ struct make_signed_helper_0
+ {
+ struct char_helper
+ {
+ typedef signed char type;
+ };
+
+ struct short_helper
+ {
+ typedef signed short type;
+ };
+
+ struct int_helper
+ {
+ typedef signed int type;
+ };
+
+ struct long_helper
+ {
+ typedef signed long type;
+ };
+
+ struct longlong_helper
+ {
+ typedef signed long long type;
+ };
+
+ struct int128_helper
+ {
+ #if EASTL_GCC_STYLE_INT128_SUPPORTED
+ typedef __int128_t type;
+ #endif
+ };
+
+ struct no_type_helper
+ {
+ };
+
+ typedef typename
+ eastl::conditional<sizeof(T) <= sizeof(signed char), char_helper,
+ eastl::conditional_t<sizeof(T) <= sizeof(signed short), short_helper,
+ eastl::conditional_t<sizeof(T) <= sizeof(signed int), int_helper,
+ eastl::conditional_t<sizeof(T) <= sizeof(signed long), long_helper,
+ eastl::conditional_t<sizeof(T) <= sizeof(signed long long), longlong_helper,
+ #if EASTL_GCC_STYLE_INT128_SUPPORTED
+ eastl::conditional_t<sizeof(T) <= sizeof(__int128_t), int128_helper,
+ no_type_helper
+ >
+ #else
+ no_type_helper
+ #endif
+ >
+ >
+ >
+ >
+ >::type type;
+ };
+
+ template <typename T>
+ struct make_signed_helper_0<T, false>
+ {
+ struct no_type_helper
+ {
+ };
+
+ typedef no_type_helper type;
+ };
+
+ template <typename T>
+ struct make_signed_helper_1
+ {
+ typedef typename T::type type;
+ };
+
+ template <typename T>
+ struct make_signed_helper
+ {
+ typedef typename eastl::internal::make_signed_helper_1<typename eastl::internal::make_signed_helper_0<T>::type>::type type;
+ };
+
+ } // namespace internal
+
+ template <typename T>
+ struct make_signed
+ {
+ typedef typename eastl::internal::make_signed_helper<T>::type type;
+ };
+ template <> struct make_signed<bool> {};
+ template <> struct make_signed<signed char> { typedef signed char type; };
template <> struct make_signed<unsigned char> { typedef signed char type; };
- template <> struct make_signed<const unsigned char> { typedef const signed char type; };
+ template <> struct make_signed<signed short> { typedef signed short type; };
template <> struct make_signed<unsigned short> { typedef signed short type; };
- template <> struct make_signed<const unsigned short> { typedef const signed short type; };
+ template <> struct make_signed<signed int> { typedef signed int type; };
template <> struct make_signed<unsigned int> { typedef signed int type; };
- template <> struct make_signed<const unsigned int> { typedef const signed int type; };
+ template <> struct make_signed<signed long> { typedef signed long type; };
template <> struct make_signed<unsigned long> { typedef signed long type; };
- template <> struct make_signed<const unsigned long> { typedef const signed long type; };
+ template <> struct make_signed<signed long long> { typedef signed long long type; };
template <> struct make_signed<unsigned long long> { typedef signed long long type; };
- template <> struct make_signed<const unsigned long long> { typedef const signed long long type; };
+ #if EASTL_GCC_STYLE_INT128_SUPPORTED
+ template <> struct make_signed<__int128_t> { typedef __int128_t type; };
+ template <> struct make_signed<__uint128_t> { typedef __int128_t type; };
+ #endif
+
#if (defined(CHAR_MAX) && defined(UCHAR_MAX) && (CHAR_MAX == UCHAR_MAX)) // If char is unsigned, we convert char to signed char. However, if char is signed then make_signed returns char itself and not signed char.
template <> struct make_signed<char> { typedef signed char type; };
- template <> struct make_signed<const char> { typedef signed char type; };
#endif
- #ifndef EA_WCHAR_T_NON_NATIVE // If wchar_t is a native type instead of simply a define to an existing type...
- #if (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ == 4294967295U)) // If wchar_t is a 32 bit unsigned value...
- template<>
- struct make_signed<wchar_t>
- { typedef int32_t type; };
- #elif (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ == 65535)) // If wchar_t is a 16 bit unsigned value...
- template<>
- struct make_signed<wchar_t>
- { typedef int16_t type; };
- #elif (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ == 255)) // If wchar_t is an 8 bit unsigned value...
- template<>
- struct make_signed<wchar_t>
- { typedef int8_t type; };
- #endif
- #endif
+ template <typename T>
+ struct make_signed<const T>
+ {
+ typedef eastl::add_const_t<typename eastl::make_signed<T>::type> type;
+ };
+
+ template <typename T>
+ struct make_signed<volatile T>
+ {
+ typedef eastl::add_volatile_t<typename eastl::make_signed<T>::type> type;
+ };
+
+ template <typename T>
+ struct make_signed<const volatile T>
+ {
+ typedef eastl::add_cv_t<typename eastl::make_signed<T>::type> type;
+ };
#if EASTL_VARIABLE_TEMPLATES_ENABLED
- template <class T>
+ template <typename T>
using make_signed_t = typename make_signed<T>::type;
#endif
@@ -180,55 +274,155 @@ namespace eastl
///////////////////////////////////////////////////////////////////////
// make_unsigned
//
- // Used to convert an integral type to its signed equivalent, if not already.
- // T shall be a (possibly const and/or volatile-qualified) integral type
+ // Used to convert an integral type to its unsigned equivalent, if not already.
+ // T shall be a (possibly const and/or volatile-qualified) integral type
// or enumeration but not a bool type.;
//
- // The user can define their own make_signed overrides for their own
+ // The user can define their own make_unsigned overrides for their own
// types by making a template specialization like done below and adding
// it to the user's code.
///////////////////////////////////////////////////////////////////////
- // To do: This implementation needs to be updated to support C++11 conformance (recognition of enums) and
- // to support volatile-qualified types. It will probably be useful to have it fail for unsupported types.
- #define EASTL_TYPE_TRAIT_make_unsigned_CONFORMANCE 0 // make_unsigned is only partially conforming.
+ #define EASTL_TYPE_TRAIT_make_unsigned_CONFORMANCE 1
+
+ namespace internal
+ {
+
+ template <typename T, bool = eastl::is_enum<T>::value || eastl::is_integral<T>::value>
+ struct make_unsigned_helper_0
+ {
+ struct char_helper
+ {
+ typedef unsigned char type;
+ };
- template <typename T> struct make_unsigned { typedef T type; };
+ struct short_helper
+ {
+ typedef unsigned short type;
+ };
+ struct int_helper
+ {
+ typedef unsigned int type;
+ };
+
+ struct long_helper
+ {
+ typedef unsigned long type;
+ };
+
+ struct longlong_helper
+ {
+ typedef unsigned long long type;
+ };
+
+ struct int128_helper
+ {
+ #if EASTL_GCC_STYLE_INT128_SUPPORTED
+ typedef __uint128_t type;
+ #endif
+ };
+
+ struct no_type_helper
+ {
+ };
+
+
+ typedef typename
+ eastl::conditional<sizeof(T) <= sizeof(unsigned char), char_helper,
+ eastl::conditional_t<sizeof(T) <= sizeof(unsigned short), short_helper,
+ eastl::conditional_t<sizeof(T) <= sizeof(unsigned int), int_helper,
+ eastl::conditional_t<sizeof(T) <= sizeof(unsigned long), long_helper,
+ eastl::conditional_t<sizeof(T) <= sizeof(unsigned long long), longlong_helper,
+ #if EASTL_GCC_STYLE_INT128_SUPPORTED
+ eastl::conditional_t<sizeof(T) <= sizeof(__uint128_t), int128_helper,
+ no_type_helper
+ >
+ #else
+ no_type_helper
+ #endif
+ >
+ >
+ >
+ >
+ >::type type;
+ };
+
+
+ template <typename T>
+ struct make_unsigned_helper_0<T, false>
+ {
+ struct no_type_helper
+ {
+ };
+
+ typedef no_type_helper type;
+ };
+
+ template <typename T>
+ struct make_unsigned_helper_1
+ {
+ typedef typename T::type type;
+ };
+
+ template <typename T>
+ struct make_unsigned_helper
+ {
+ typedef typename eastl::internal::make_unsigned_helper_1<typename eastl::internal::make_unsigned_helper_0<T>::type>::type type;
+ };
+
+ } // namespace internal
+
+ template <typename T>
+ struct make_unsigned
+ {
+ typedef typename eastl::internal::make_unsigned_helper<T>::type type;
+ };
+
+ template <> struct make_unsigned<bool> {};
template <> struct make_unsigned<signed char> { typedef unsigned char type; };
- template <> struct make_unsigned<const signed char> { typedef const unsigned char type; };
+ template <> struct make_unsigned<unsigned char> { typedef unsigned char type; };
template <> struct make_unsigned<signed short> { typedef unsigned short type; };
- template <> struct make_unsigned<const signed short> { typedef const unsigned short type; };
+ template <> struct make_unsigned<unsigned short> { typedef unsigned short type; };
template <> struct make_unsigned<signed int> { typedef unsigned int type; };
- template <> struct make_unsigned<const signed int> { typedef const unsigned int type; };
+ template <> struct make_unsigned<unsigned int> { typedef unsigned int type; };
template <> struct make_unsigned<signed long> { typedef unsigned long type; };
- template <> struct make_unsigned<const signed long> { typedef const unsigned long type; };
+ template <> struct make_unsigned<unsigned long> { typedef unsigned long type; };
template <> struct make_unsigned<signed long long> { typedef unsigned long long type; };
- template <> struct make_unsigned<const signed long long> { typedef const unsigned long long type; };
+ template <> struct make_unsigned<unsigned long long> { typedef unsigned long long type; };
+ #if EASTL_GCC_STYLE_INT128_SUPPORTED
+ template <> struct make_unsigned<__int128_t> { typedef __uint128_t type; };
+ template <> struct make_unsigned<__uint128_t> { typedef __uint128_t type; };
+ #endif
#if (CHAR_MIN < 0) // If char is signed, we convert char to unsigned char. However, if char is unsigned then make_unsigned returns char itself and not unsigned char.
template <> struct make_unsigned<char> { typedef unsigned char type; };
- template <> struct make_unsigned<const char> { typedef unsigned char type; };
#endif
- #ifndef EA_WCHAR_T_NON_NATIVE // If wchar_t is a native type instead of simply a define to an existing type...
- #if (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ != 4294967295U)) // If wchar_t is a 32 bit signed value...
- template<>
- struct make_unsigned<wchar_t>
- { typedef uint32_t type; };
- #elif (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ != 65535)) // If wchar_t is a 16 bit signed value...
- template<>
- struct make_unsigned<wchar_t>
- { typedef uint16_t type; };
- #elif (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ != 255)) // If wchar_t is an 8 bit signed value...
- template<>
- struct make_unsigned<wchar_t>
- { typedef uint8_t type; };
- #endif
+ #if defined(EA_CHAR8_UNIQUE) && EA_CHAR8_UNIQUE
+ template <> struct make_unsigned<char8_t> { typedef unsigned char type; };
#endif
+ template <typename T>
+ struct make_unsigned<const T>
+ {
+ typedef eastl::add_const_t<typename eastl::make_unsigned<T>::type> type;
+ };
+
+ template <typename T>
+ struct make_unsigned<volatile T>
+ {
+ typedef eastl::add_volatile_t<typename eastl::make_unsigned<T>::type> type;
+ };
+
+ template <typename T>
+ struct make_unsigned<const volatile T>
+ {
+ typedef eastl::add_cv_t<typename eastl::make_unsigned<T>::type> type;
+ };
+
#if EASTL_VARIABLE_TEMPLATES_ENABLED
- template <class T>
+ template <typename T>
using make_unsigned_t = typename make_unsigned<T>::type;
#endif
@@ -283,15 +477,33 @@ namespace eastl
// add_pointer
//
// Add pointer to a type.
- // Provides the member typedef type which is the type T*. If T is a
- // reference type, then type is a pointer to the referred type.
- //
+ // Provides the member typedef type which is the type T*.
+ //
+ // If T is a reference type,
+ // type member is a pointer to the referred type.
+ // If T is an object type, a function type that is not cv- or ref-qualified,
+ // or a (possibly cv-qualified) void type,
+ // type member is T*.
+ // Otherwise (T is a cv- or ref-qualified function type),
+ // type member is T (ie. not a pointer).
+ //
+ // cv- and ref-qualified function types are invalid, which is why there is a specific clause for it.
+ // See https://cplusplus.github.io/LWG/issue2101 for more.
+ //
///////////////////////////////////////////////////////////////////////
#define EASTL_TYPE_TRAIT_add_pointer_CONFORMANCE 1
- template<class T>
- struct add_pointer { typedef typename eastl::remove_reference<T>::type* type; };
+ namespace internal
+ {
+ template <typename T>
+ auto try_add_pointer(int) -> type_identity<typename std::remove_reference<T>::type*>;
+ template <typename T>
+ auto try_add_pointer(...) -> type_identity<T>;
+ }
+
+ template <typename T>
+ struct add_pointer : decltype(internal::try_add_pointer<T>(0)) {};
#if EASTL_VARIABLE_TEMPLATES_ENABLED
template <class T>
@@ -553,32 +765,6 @@ namespace eastl
return u.destValue;
}
-
-
- ///////////////////////////////////////////////////////////////////////
- // void_t
- //
- // Maps a sequence of any types to void. This utility class is used in
- // template meta programming to simplify compile time reflection mechanisms
- // required by the standard library.
- //
- // http://en.cppreference.com/w/cpp/types/void_t
- //
- // Example:
- // template <typename T, typename = void>
- // struct is_iterable : false_type {};
- //
- // template <typename T>
- // struct is_iterable<T, void_t<decltype(declval<T>().begin()),
- // decltype(declval<T>().end())>> : true_type {};
- //
- ///////////////////////////////////////////////////////////////////////
- #if EASTL_VARIABLE_TEMPLATES_ENABLED
- template <class...>
- using void_t = void;
- #endif
-
-
} // namespace eastl
diff --git a/EASTL/include/EASTL/internal/type_void_t.h b/EASTL/include/EASTL/internal/type_void_t.h
new file mode 100644
index 0000000..40c6818
--- /dev/null
+++ b/EASTL/include/EASTL/internal/type_void_t.h
@@ -0,0 +1,43 @@
+/////////////////////////////////////////////////////////////////////////////
+// Copyright (c) Electronic Arts Inc. All rights reserved.
+/////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef EASTL_INTERNAL_TYPE_VOID_T_H
+#define EASTL_INTERNAL_TYPE_VOID_T_H
+
+
+#include <EABase/eabase.h>
+#if defined(EA_PRAGMA_ONCE_SUPPORTED)
+ #pragma once
+#endif
+
+namespace eastl
+{
+
+ ///////////////////////////////////////////////////////////////////////
+ // void_t
+ //
+ // Maps a sequence of any types to void. This utility class is used in
+ // template meta programming to simplify compile time reflection mechanisms
+ // required by the standard library.
+ //
+ // http://en.cppreference.com/w/cpp/types/void_t
+ //
+ // Example:
+ // template <typename T, typename = void>
+ // struct is_iterable : false_type {};
+ //
+ // template <typename T>
+ // struct is_iterable<T, void_t<decltype(declval<T>().begin()),
+ // decltype(declval<T>().end())>> : true_type {};
+ //
+ ///////////////////////////////////////////////////////////////////////
+ template <class...>
+ using void_t = void;
+
+
+} // namespace eastl
+
+
+#endif // Header include guard
diff --git a/EASTL/include/EASTL/intrusive_list.h b/EASTL/include/EASTL/intrusive_list.h
index 18d7e93..dc0129f 100644
--- a/EASTL/include/EASTL/intrusive_list.h
+++ b/EASTL/include/EASTL/intrusive_list.h
@@ -146,6 +146,7 @@ namespace eastl
intrusive_list_iterator();
explicit intrusive_list_iterator(pointer pNode); // Note that you can also construct an iterator from T via this, since value_type == node_type.
intrusive_list_iterator(const iterator& x);
+ intrusive_list_iterator& operator=(const iterator& x);
reference operator*() const;
pointer operator->() const;
@@ -368,6 +369,13 @@ namespace eastl
// Empty
}
+ template <typename T, typename Pointer, typename Reference>
+ inline typename intrusive_list_iterator<T, Pointer, Reference>::this_type&
+ intrusive_list_iterator<T, Pointer, Reference>::operator=(const iterator& x)
+ {
+ mpNode = x.mpNode;
+ return *this;
+ }
template <typename T, typename Pointer, typename Reference>
inline typename intrusive_list_iterator<T, Pointer, Reference>::reference
diff --git a/EASTL/include/EASTL/iterator.h b/EASTL/include/EASTL/iterator.h
index d2dc899..6c268aa 100644
--- a/EASTL/include/EASTL/iterator.h
+++ b/EASTL/include/EASTL/iterator.h
@@ -9,6 +9,8 @@
#include <EASTL/internal/config.h>
#include <EASTL/internal/move_help.h>
+#include <EASTL/internal/type_detected.h>
+#include <EASTL/internal/type_void_t.h>
#include <EASTL/initializer_list.h>
EA_DISABLE_ALL_VC_WARNINGS();
@@ -93,16 +95,35 @@ namespace eastl
// struct iterator_traits
- template <typename Iterator>
- struct iterator_traits
+ namespace internal
{
- typedef typename Iterator::iterator_category iterator_category;
- typedef typename Iterator::value_type value_type;
- typedef typename Iterator::difference_type difference_type;
- typedef typename Iterator::pointer pointer;
- typedef typename Iterator::reference reference;
- };
+ // Helper to make iterator_traits SFINAE friendly as N3844 requires.
+ template <typename Iterator, class = void>
+ struct default_iterator_traits {};
+ template <typename Iterator>
+ struct default_iterator_traits<
+ Iterator,
+ void_t<
+ typename Iterator::iterator_category,
+ typename Iterator::value_type,
+ typename Iterator::difference_type,
+ typename Iterator::pointer,
+ typename Iterator::reference
+ >
+ >
+ {
+ typedef typename Iterator::iterator_category iterator_category;
+ typedef typename Iterator::value_type value_type;
+ typedef typename Iterator::difference_type difference_type;
+ typedef typename Iterator::pointer pointer;
+ typedef typename Iterator::reference reference;
+ };
+ }
+
+ template <typename Iterator>
+ struct iterator_traits : internal::default_iterator_traits<Iterator> {};
+
template <typename T>
struct iterator_traits<T*>
{
@@ -129,37 +150,46 @@ namespace eastl
/// is_iterator_wrapper
///
/// Tells if an Iterator type is a wrapper type as opposed to a regular type.
- /// Relies on the class declaring a typedef called wrapped_iterator_type.
+ /// Relies on the class declaring a member function called unwrap.
///
/// Examples of wrapping iterators:
- /// reverse_iterator
/// generic_iterator
/// move_iterator
+ /// reverse_iterator<T> (if T is a wrapped iterator)
/// Examples of non-wrapping iterators:
/// iterator
/// list::iterator
/// char*
///
/// Example behavior:
- /// is_iterator_wrapper(int*)::value => false
- /// is_iterator_wrapper(eastl::array<char>*)::value => false
- /// is_iterator_wrapper(eastl::vector<int>::iterator)::value => false
- /// is_iterator_wrapper(eastl::generic_iterator<int*>)::value => true
- /// is_iterator_wrapper(eastl::move_iterator<eastl::array<int>::iterator>)::value => true
+ /// is_iterator_wrapper(int*)::value => false
+ /// is_iterator_wrapper(eastl::array<char>*)::value => false
+ /// is_iterator_wrapper(eastl::vector<int>::iterator)::value => false
+ /// is_iterator_wrapper(eastl::generic_iterator<int*>)::value => true
+ /// is_iterator_wrapper(eastl::move_iterator<eastl::array<int>::iterator>)::value => true
+ /// is_iterator_wrapper(eastl::reverse_iterator<int*>)::value => false
+ /// is_iterator_wrapper(eastl::reverse_iterator<eastl::move_iterator<int*>>)::value => true
///
template<typename Iterator>
class is_iterator_wrapper
{
- template<typename>
- static eastl::no_type test(...);
-
- template<typename U>
- static eastl::yes_type test(typename U::wrapped_iterator_type*, typename eastl::enable_if<eastl::is_class<U>::value>::type* = 0);
-
+#if defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_CLANG_CL)
+ // Using a default template type parameter trick here because
+ // of a bug in clang that makes the other implementation not
+ // work when unwrap() is private and this is class is a
+ // friend.
+ // See: https://bugs.llvm.org/show_bug.cgi?id=25334
+ template<typename T, typename U = decltype(eastl::declval<T>().unwrap())>
+ using detect_has_unwrap = U;
+#else
+ // Note: the above implementation does not work on GCC when
+ // unwrap() is private and this class is a friend. So we're
+ // forced to diverge here to support both GCC and clang.
+ template<typename T>
+ using detect_has_unwrap = decltype(eastl::declval<T>().unwrap());
+#endif
public:
- EA_DISABLE_VC_WARNING(6334)
- static const bool value = (sizeof(test<Iterator>(NULL)) == sizeof(eastl::yes_type));
- EA_RESTORE_VC_WARNING()
+ static const bool value = eastl::is_detected<detect_has_unwrap, Iterator>::value;
};
@@ -180,25 +210,28 @@ namespace eastl
template <typename Iterator, bool isWrapper>
struct is_iterator_wrapper_helper
{
- typedef Iterator iterator_type;
+ using iterator_type = Iterator;
- static iterator_type get_base(Iterator it)
- { return it; }
+ static iterator_type get_unwrapped(Iterator it) { return it; }
};
template <typename Iterator>
struct is_iterator_wrapper_helper<Iterator, true>
{
- typedef typename Iterator::iterator_type iterator_type;
+ // get_unwrapped must return by value since we're returning
+ // it.unwrap(), and `it` will be out of scope as soon as
+ // get_unwrapped returns.
+ using iterator_type =
+ typename eastl::remove_cvref<decltype(eastl::declval<Iterator>().unwrap())>::type;
- static iterator_type get_base(Iterator it)
- { return it.base(); }
+ static iterator_type get_unwrapped(Iterator it) { return it.unwrap(); }
};
+
template <typename Iterator>
inline typename is_iterator_wrapper_helper<Iterator, eastl::is_iterator_wrapper<Iterator>::value>::iterator_type unwrap_iterator(Iterator it)
- { return eastl::is_iterator_wrapper_helper<Iterator, eastl::is_iterator_wrapper<Iterator>::value>::get_base(it); }
+ { return eastl::is_iterator_wrapper_helper<Iterator, eastl::is_iterator_wrapper<Iterator>::value>::get_unwrapped(it); }
@@ -222,9 +255,13 @@ namespace eastl
typename eastl::iterator_traits<Iterator>::pointer,
typename eastl::iterator_traits<Iterator>::reference>
{
+ private:
+ using base_wrapped_iterator_type =
+ typename eastl::is_iterator_wrapper_helper<Iterator,
+ eastl::is_iterator_wrapper<Iterator>::value>::iterator_type;
+
public:
typedef Iterator iterator_type;
- typedef iterator_type wrapped_iterator_type; // This is not in the C++ Standard; it's used by use to identify it as a wrapping iterator type.
typedef typename eastl::iterator_traits<Iterator>::pointer pointer;
typedef typename eastl::iterator_traits<Iterator>::reference reference;
typedef typename eastl::iterator_traits<Iterator>::difference_type difference_type;
@@ -304,6 +341,18 @@ namespace eastl
// operator[] may return something other than reference.
EA_CPP14_CONSTEXPR reference operator[](difference_type n) const
{ return mIterator[-n - 1]; }
+
+
+ private:
+ // Unwrapping interface, not part of the public API.
+ template <typename U = iterator_type>
+ EA_CPP14_CONSTEXPR typename eastl::enable_if<eastl::is_iterator_wrapper<U>::value, reverse_iterator<base_wrapped_iterator_type>>::type unwrap() const
+ { return reverse_iterator<base_wrapped_iterator_type>(unwrap_iterator(mIterator)); }
+
+ // The unwrapper helpers need access to unwrap() (when it exists).
+ using this_type = reverse_iterator<Iterator>;
+ friend is_iterator_wrapper_helper<this_type, is_iterator_wrapper<iterator_type>::value>;
+ friend is_iterator_wrapper<this_type>;
};
@@ -380,21 +429,15 @@ namespace eastl
struct is_reverse_iterator< eastl::reverse_iterator<Iterator> >
: public eastl::true_type {};
-
-
- /// unwrap_reverse_iterator
- ///
- /// Returns Iterator::get_base() if it's a reverse_iterator, else returns Iterator as-is.
- ///
- /// Example usage:
- /// vector<int> intVector;
- /// eastl::reverse_iterator<vector<int>::iterator> reverseIterator(intVector.begin());
- /// vector<int>::iterator it = unwrap_reverse_iterator(reverseIterator);
- ///
- /// Disabled until there is considered a good use for it.
- /// template <typename Iterator>
- /// inline typename eastl::is_iterator_wrapper_helper<Iterator, eastl::is_reverse_iterator<Iterator>::value>::iterator_type unwrap_reverse_iterator(Iterator it)
- /// { return eastl::is_iterator_wrapper_helper<Iterator, eastl::is_reverse_iterator<Iterator>::value>::get_base(it); }
+ /// unwrap_reverse_iterator is not implemented since there's no
+ /// good use case and there's some abiguitiy. Note that
+ /// unwrap_iterator(reverse_iterator<T>) returns
+ /// reverse_iterator<unwrap(T)>. However, given what
+ /// unwrap_generic_iterator and unwrap_move_iterator do, one might
+ /// expect unwrap_reverse_iterator(reverse_iterator<T>) to return
+ /// T, which is not the same. To avoid that confusion, and because
+ /// there's no current use case for this, we don't provide
+ /// unwrap_reverse_iterator.
@@ -409,15 +452,19 @@ namespace eastl
template<typename Iterator>
class move_iterator // Don't inherit from iterator.
{
+ private:
+ using WrappedIteratorReference = typename iterator_traits<Iterator>::reference;
+
public:
typedef Iterator iterator_type;
- typedef iterator_type wrapped_iterator_type; // This is not in the C++ Standard; it's used by use to identify it as a wrapping iterator type.
typedef iterator_traits<Iterator> 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;
+ using reference = conditional_t<is_reference<WrappedIteratorReference>::value,
+ remove_reference_t<WrappedIteratorReference>&&,
+ WrappedIteratorReference>;
protected:
iterator_type mIterator;
@@ -440,8 +487,7 @@ namespace eastl
iterator_type base() const
{ return mIterator; }
- reference operator*() const
- { return eastl::move(*mIterator); }
+ reference operator*() const { return static_cast<reference>(*mIterator); }
pointer operator->() const
{ return mIterator; }
@@ -492,6 +538,16 @@ namespace eastl
reference operator[](difference_type n) const
{ return eastl::move(mIterator[n]); }
+
+ private:
+ // Unwrapping interface, not part of the public API.
+ iterator_type unwrap() const
+ { return mIterator; }
+
+ // The unwrapper helpers need access to unwrap().
+ using this_type = move_iterator<Iterator>;
+ friend is_iterator_wrapper_helper<this_type, true>;
+ friend is_iterator_wrapper<this_type>;
};
template<typename Iterator1, typename Iterator2>
@@ -585,7 +641,7 @@ namespace eastl
/// unwrap_move_iterator
///
- /// Returns Iterator::get_base() if it's a move_iterator, else returns Iterator as-is.
+ /// Returns `it.base()` if it's a move_iterator, else returns `it` as-is.
///
/// Example usage:
/// vector<int> intVector;
@@ -594,9 +650,10 @@ namespace eastl
///
template <typename Iterator>
inline typename eastl::is_iterator_wrapper_helper<Iterator, eastl::is_move_iterator<Iterator>::value>::iterator_type unwrap_move_iterator(Iterator it)
- { return eastl::is_iterator_wrapper_helper<Iterator, eastl::is_move_iterator<Iterator>::value>::get_base(it); }
-
-
+ {
+ // get_unwrapped(it) -> it.unwrap() which is equivalent to `it.base()` for move_iterator and to `it` otherwise.
+ return eastl::is_iterator_wrapper_helper<Iterator, eastl::is_move_iterator<Iterator>::value>::get_unwrapped(it);
+ }
/// back_insert_iterator
@@ -1070,10 +1127,16 @@ namespace eastl
return container.begin();
}
+ template<typename T, size_t arraySize>
+ EA_CPP14_CONSTEXPR inline T* begin(T (&arrayObject)[arraySize]) EA_NOEXCEPT
+ {
+ return arrayObject;
+ }
+
template <typename Container>
- EA_CPP14_CONSTEXPR inline auto cbegin(const Container& container) -> decltype(container.begin())
+ EA_CPP14_CONSTEXPR inline auto cbegin(const Container& container) -> decltype(eastl::begin(container))
{
- return container.begin();
+ return eastl::begin(container);
}
template <typename Container>
@@ -1088,10 +1151,16 @@ namespace eastl
return container.end();
}
+ template<typename T, size_t arraySize>
+ EA_CPP14_CONSTEXPR inline T* end(T (&arrayObject)[arraySize]) EA_NOEXCEPT
+ {
+ return (arrayObject + arraySize);
+ }
+
template <typename Container>
- EA_CPP14_CONSTEXPR inline auto cend(const Container& container) -> decltype(container.end())
+ EA_CPP14_CONSTEXPR inline auto cend(const Container& container) -> decltype(eastl::end(container))
{
- return container.end();
+ return eastl::end(container);
}
template <typename Container>
@@ -1130,17 +1199,6 @@ namespace eastl
return container.rend();
}
- template<typename T, size_t arraySize>
- EA_CPP14_CONSTEXPR inline T* begin(T (&arrayObject)[arraySize])
- {
- return arrayObject;
- }
-
- template<typename T, size_t arraySize>
- EA_CPP14_CONSTEXPR inline T* end(T (&arrayObject)[arraySize])
- {
- return (arrayObject + arraySize);
- }
template <typename T, size_t arraySize>
EA_CPP14_CONSTEXPR inline reverse_iterator<T*> rbegin(T (&arrayObject)[arraySize])
@@ -1179,7 +1237,7 @@ namespace eastl
// Some compilers (e.g. GCC 4.6) support range-based for loops, but have a bug with
// respect to argument-dependent lookup which results on them unilaterally using std::begin/end
// with range-based for loops. To work around this we #include <iterator> for this case in
-// order to make std::begin/end visible to users of <eastl/iterator.h>, for portability.
+// order to make std::begin/end visible to users of <EASTL/iterator.h>, for portability.
#if !EASTL_BEGIN_END_ENABLED && !defined(EA_COMPILER_NO_RANGE_BASED_FOR_LOOP)
#include <iterator>
#endif
diff --git a/EASTL/include/EASTL/list.h b/EASTL/include/EASTL/list.h
index 680dcad..be99c01 100644
--- a/EASTL/include/EASTL/list.h
+++ b/EASTL/include/EASTL/list.h
@@ -403,10 +403,10 @@ namespace eastl
void clear() EA_NOEXCEPT;
void reset_lose_memory() EA_NOEXCEPT; // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
- void remove(const T& x);
+ size_type remove(const T& x);
template <typename Predicate>
- void remove_if(Predicate);
+ size_type remove_if(Predicate);
void reverse() EA_NOEXCEPT;
@@ -771,7 +771,7 @@ namespace eastl
inline typename ListBase<T, Allocator>::node_type*
ListBase<T, Allocator>::DoAllocateNode()
{
- node_type* pNode = (node_type*)allocate_memory(internalAllocator(), sizeof(node_type), EASTL_ALIGN_OF(T), 0);
+ node_type* pNode = (node_type*)allocate_memory(internalAllocator(), sizeof(node_type), EASTL_ALIGN_OF(node_type), 0);
EASTL_ASSERT(pNode != nullptr);
return pNode;
}
@@ -1457,9 +1457,10 @@ namespace eastl
template <typename T, typename Allocator>
- void list<T, Allocator>::remove(const value_type& value)
+ typename list<T, Allocator>::size_type list<T, Allocator>::remove(const value_type& value)
{
iterator current((ListNodeBase*)internalNode().mpNext);
+ size_type numRemoved = 0;
while(current.mpNode != &internalNode())
{
@@ -1469,23 +1470,30 @@ namespace eastl
{
++current;
DoErase((ListNodeBase*)current.mpNode->mpPrev);
+ ++numRemoved;
}
}
+ return numRemoved;
}
template <typename T, typename Allocator>
template <typename Predicate>
- inline void list<T, Allocator>::remove_if(Predicate predicate)
+ inline typename list<T, Allocator>::size_type list<T, Allocator>::remove_if(Predicate predicate)
{
+ size_type numRemoved = 0;
for(iterator first((ListNodeBase*)internalNode().mpNext), last((ListNodeBase*)&internalNode()); first != last; )
{
iterator temp(first);
++temp;
if(predicate(first.mpNode->mValue))
+ {
DoErase((ListNodeBase*)first.mpNode);
+ ++numRemoved;
+ }
first = temp;
}
+ return numRemoved;
}
@@ -2100,6 +2108,13 @@ namespace eastl
#endif
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T, typename Allocator>
+ inline synth_three_way_result<T> operator<=>(const list<T, Allocator>& a, const list<T, Allocator>& b)
+ {
+ return eastl::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end(), synth_three_way{});
+ }
+#else
template <typename T, typename Allocator>
bool operator<(const list<T, Allocator>& a, const list<T, Allocator>& b)
{
@@ -2129,7 +2144,7 @@ namespace eastl
{
return !(a < b);
}
-
+#endif
template <typename T, typename Allocator>
void swap(list<T, Allocator>& a, list<T, Allocator>& b)
{
@@ -2143,17 +2158,17 @@ namespace eastl
// https://en.cppreference.com/w/cpp/container/list/erase2
///////////////////////////////////////////////////////////////////////
template <class T, class Allocator, class U>
- void erase(list<T, Allocator>& c, const U& value)
+ typename list<T, Allocator>::size_type erase(list<T, Allocator>& c, const U& value)
{
// Erases all elements that compare equal to value from the container.
- c.remove_if([&](auto& elem) { return elem == value; });
+ return c.remove(value);
}
template <class T, class Allocator, class Predicate>
- void erase_if(list<T, Allocator>& c, Predicate predicate)
+ typename list<T, Allocator>::size_type erase_if(list<T, Allocator>& c, Predicate predicate)
{
// Erases all elements that satisfy the predicate pred from the container.
- c.remove_if(predicate);
+ return c.remove_if(predicate);
}
diff --git a/EASTL/include/EASTL/map.h b/EASTL/include/EASTL/map.h
index 0e6c1d0..7824250 100644
--- a/EASTL/include/EASTL/map.h
+++ b/EASTL/include/EASTL/map.h
@@ -156,6 +156,17 @@ namespace eastl
T& at(const Key& key);
const T& at(const Key& key) const;
+ template <class... Args> eastl::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
+ template <class... Args> eastl::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);
+ template <class... Args> iterator try_emplace(const_iterator position, const key_type& k, Args&&... args);
+ template <class... Args> iterator try_emplace(const_iterator position, key_type&& k, Args&&... args);
+
+ private:
+ template <class KFwd, class... Args>
+ eastl::pair<iterator, bool> try_emplace_forward(KFwd&& k, Args&&... args);
+
+ template <class KFwd, class... Args>
+ iterator try_emplace_forward(const_iterator hint, KFwd&& key, Args&&... args);
}; // map
@@ -268,7 +279,6 @@ namespace eastl
private:
// these base member functions are not included in multimaps
- using base_type::try_emplace;
using base_type::insert_or_assign;
}; // multimap
@@ -439,31 +449,28 @@ namespace eastl
//return it->second;
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename Key, typename T, typename Compare, typename Allocator>
+ inline synth_three_way_result<eastl::pair<const Key, T>> operator<=>(const map<Key, T, Compare, Allocator>& a,
+ const map<Key, T, Compare, Allocator>& b)
+ {
+ return eastl::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end(), synth_three_way{});
+ }
+#endif
template <typename Key, typename T, typename Compare, typename Allocator>
inline T& map<Key, T, Compare, Allocator>::at(const Key& key)
{
- iterator itLower(lower_bound(key)); // itLower->first is >= key.
-
- if(itLower == end())
- {
- #if EASTL_EXCEPTIONS_ENABLED
- throw std::out_of_range("map::at key does not exist");
- #else
- EASTL_FAIL_MSG("map::at key does not exist");
- #endif
- }
-
- return (*itLower).second;
+ // use the use const version of ::at to remove duplication
+ return const_cast<T&>(const_cast<map<Key, T, Compare, Allocator> const*>(this)->at(key));
}
-
template <typename Key, typename T, typename Compare, typename Allocator>
inline const T& map<Key, T, Compare, Allocator>::at(const Key& key) const
{
- const_iterator itLower(lower_bound(key)); // itLower->first is >= key.
+ const_iterator candidate = this->find(key);
- if(itLower == end())
+ if (candidate == end())
{
#if EASTL_EXCEPTIONS_ENABLED
throw std::out_of_range("map::at key does not exist");
@@ -472,7 +479,7 @@ namespace eastl
#endif
}
- return (*itLower).second;
+ return candidate->second;
}
@@ -482,8 +489,9 @@ namespace eastl
// https://en.cppreference.com/w/cpp/container/map/erase_if
///////////////////////////////////////////////////////////////////////
template <class Key, class T, class Compare, class Allocator, class Predicate>
- void erase_if(map<Key, T, Compare, Allocator>& c, Predicate predicate)
+ typename map<Key, T, Compare, Allocator>::size_type erase_if(map<Key, T, Compare, Allocator>& c, Predicate predicate)
{
+ auto oldSize = c.size();
for (auto i = c.begin(), last = c.end(); i != last;)
{
if (predicate(*i))
@@ -495,8 +503,84 @@ namespace eastl
++i;
}
}
+ return oldSize - c.size();
+ }
+
+
+ template <class Key, class T, class Compare, class Allocator>
+ template <class... Args>
+ inline eastl::pair<typename map<Key, T, Compare, Allocator>::iterator, bool>
+ map<Key, T, Compare, Allocator>::try_emplace(const key_type& key, Args&&... args)
+ {
+ return try_emplace_forward(key, eastl::forward<Args>(args)...);
+ }
+
+ template <class Key, class T, class Compare, class Allocator>
+ template <class... Args>
+ inline eastl::pair<typename map<Key, T, Compare, Allocator>::iterator, bool>
+ map<Key, T, Compare, Allocator>::try_emplace(key_type&& key, Args&&... args)
+ {
+ return try_emplace_forward(eastl::move(key), eastl::forward<Args>(args)...);
+ }
+
+ template <class Key, class T, class Compare, class Allocator>
+ template <class KFwd, class... Args>
+ inline eastl::pair<typename map<Key, T, Compare, Allocator>::iterator, bool>
+ map<Key, T, Compare, Allocator>::try_emplace_forward(KFwd&& key, Args&&... args)
+ {
+ bool canInsert;
+ node_type* const pPosition = base_type::DoGetKeyInsertionPositionUniqueKeys(canInsert, key);
+ if (!canInsert)
+ {
+ return pair<iterator, bool>(iterator(pPosition), false);
+ }
+ node_type* const pNodeNew =
+ base_type::DoCreateNode(piecewise_construct, eastl::forward_as_tuple(eastl::forward<KFwd>(key)),
+ eastl::forward_as_tuple(eastl::forward<Args>(args)...));
+ // the key might be moved above, so we can't re-use it,
+ // we need to get it back from the node's value.
+ const auto& k = extract_key{}(pNodeNew->mValue);
+ const iterator itResult(base_type::DoInsertValueImpl(pPosition, false, k, pNodeNew));
+ return pair<iterator, bool>(itResult, true);
+ }
+
+ template <class Key, class T, class Compare, class Allocator>
+ template <class... Args>
+ inline typename map<Key, T, Compare, Allocator>::iterator
+ map<Key, T, Compare, Allocator>::try_emplace(const_iterator hint, const key_type& key, Args&&... args)
+ {
+ return try_emplace_forward(hint, key, eastl::forward<Args>(args)...);
}
+ template <class Key, class T, class Compare, class Allocator>
+ template <class... Args>
+ inline typename map<Key, T, Compare, Allocator>::iterator
+ map<Key, T, Compare, Allocator>::try_emplace(const_iterator hint, key_type&& key, Args&&... args)
+ {
+ return try_emplace_forward(hint, eastl::move(key), eastl::forward<Args>(args)...);
+ }
+
+ template <class Key, class T, class Compare, class Allocator>
+ template <class KFwd, class... Args>
+ inline typename map<Key, T, Compare, Allocator>::iterator
+ map<Key, T, Compare, Allocator>::try_emplace_forward(const_iterator hint, KFwd&& key, Args&&... args)
+ {
+ bool bForceToLeft;
+ node_type* const pPosition = base_type::DoGetKeyInsertionPositionUniqueKeysHint(hint, bForceToLeft, key);
+
+ if (!pPosition)
+ {
+ // the hint didn't help, we need to do a normal insert.
+ return try_emplace_forward(eastl::forward<KFwd>(key), eastl::forward<Args>(args)...).first;
+ }
+
+ node_type* const pNodeNew =
+ base_type::DoCreateNode(piecewise_construct, eastl::forward_as_tuple(eastl::forward<KFwd>(key)),
+ eastl::forward_as_tuple(eastl::forward<Args>(args)...));
+ // the key might be moved above, so we can't re-use it,
+ // we need to get it back from the node's value.
+ return base_type::DoInsertValueImpl(pPosition, bForceToLeft, extract_key{}(pNodeNew->mValue), pNodeNew);
+ }
///////////////////////////////////////////////////////////////////////
// multimap
@@ -658,8 +742,9 @@ namespace eastl
// https://en.cppreference.com/w/cpp/container/multimap/erase_if
///////////////////////////////////////////////////////////////////////
template <class Key, class T, class Compare, class Allocator, class Predicate>
- void erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate predicate)
+ typename multimap<Key, T, Compare, Allocator>::size_type erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate predicate)
{
+ auto oldSize = c.size();
// Erases all elements that satisfy the predicate pred from the container.
for (auto i = c.begin(), last = c.end(); i != last;)
{
@@ -672,7 +757,26 @@ namespace eastl
++i;
}
}
+ return oldSize - c.size();
+ }
+
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename Key, typename T, typename Compare, typename Allocator>
+ inline synth_three_way_result<eastl::pair<const Key, T>> operator<=>(const multimap<Key, T, Compare, Allocator>& a,
+ const multimap<Key, T, Compare, Allocator>& b)
+ {
+ return eastl::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end(), synth_three_way{});
}
+#endif
+
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename Key, typename T, typename Compare, typename Allocator>
+ inline synth_three_way_result<eastl::pair<const Key, T>> operator<=>(const multimap<Key, T, Compare, Allocator>& a,
+ const multimap<Key, T, Compare, Allocator>& b)
+ {
+ return eastl::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end(), synth_three_way{});
+ }
+#endif
} // namespace eastl
diff --git a/EASTL/include/EASTL/memory.h b/EASTL/include/EASTL/memory.h
index cf24b41..ab2798f 100644
--- a/EASTL/include/EASTL/memory.h
+++ b/EASTL/include/EASTL/memory.h
@@ -439,6 +439,9 @@ namespace eastl
template <typename T>
static T* do_move_start(T* first, T* last, T* dest)
{
+ if (EASTL_UNLIKELY(first == last))
+ return dest;
+
return (T*)memcpy(dest, first, (size_t)((uintptr_t)last - (uintptr_t)first)) + (last - first);
}
@@ -882,6 +885,9 @@ namespace eastl
template <typename ForwardIterator, typename Count>
inline void uninitialized_default_fill_n_impl(ForwardIterator first, Count n, true_type)
{
+ if (EASTL_UNLIKELY(n == 0))
+ return;
+
typedef typename eastl::iterator_traits<ForwardIterator>::value_type value_type;
memset(first, 0, sizeof(value_type) * n);
}
@@ -1676,6 +1682,41 @@ namespace eastl
{ return eastl::addressof(r); } // 20.6.3.2: if element_type is (possibly cv-qualified) void, the type of r is unspecified; otherwise, it is T&.
};
+ ///////////////////////////////////////////////////////////////////////
+ // to_address
+ //
+ // Helper that call the customization point in pointer_traits<T>::to_address for retrieving the address of a pointer.
+ // This is useful if you are using fancy-pointers.
+ ///////////////////////////////////////////////////////////////////////
+
+ namespace Internal
+ {
+ template <class T>
+ using detect_pointer_traits_to_address = decltype(eastl::pointer_traits<T>::to_address(eastl::declval<const T&>()));
+
+ template <class T>
+ using result_detect_pointer_traits_to_address = eastl::is_detected<detect_pointer_traits_to_address, T>;
+ }
+
+ template<class T>
+ EA_CPP14_CONSTEXPR T* to_address(T* p) noexcept
+ {
+ static_assert(!eastl::is_function<T>::value, "Cannot call to_address with a function pointer. C++20 20.2.4.1 - Pointer conversion.");
+ return p;
+ }
+
+ template <class Ptr, typename eastl::enable_if<Internal::result_detect_pointer_traits_to_address<Ptr>::value, int>::type = 0>
+ EA_CPP14_CONSTEXPR auto to_address(const Ptr& ptr) noexcept -> decltype(eastl::pointer_traits<Ptr>::to_address(ptr))
+ {
+ return eastl::pointer_traits<Ptr>::to_address(ptr);
+ }
+
+ template <class Ptr, typename eastl::enable_if<!Internal::result_detect_pointer_traits_to_address<Ptr>::value, int>::type = 0>
+ EA_CPP14_CONSTEXPR auto to_address(const Ptr& ptr) noexcept -> decltype(to_address(ptr.operator->()))
+ {
+ return to_address(ptr.operator->());
+ }
+
} // namespace eastl
diff --git a/EASTL/include/EASTL/meta.h b/EASTL/include/EASTL/meta.h
index 09880b7..545354d 100644
--- a/EASTL/include/EASTL/meta.h
+++ b/EASTL/include/EASTL/meta.h
@@ -36,24 +36,24 @@ namespace eastl
template <int I, typename T, typename Head, typename... Types>
struct get_type_index<I, T, Head, Types...>
{
- static const int value = is_same_v<T, Head> ? I : get_type_index<I + 1, T, Types...>::value;
+ static EA_CONSTEXPR_OR_CONST int value = is_same_v<T, Head> ? I : get_type_index<I + 1, T, Types...>::value;
};
template <int I, typename T>
struct get_type_index<I, T>
{
- static const int value = -1;
+ static EA_CONSTEXPR_OR_CONST int value = -1;
};
}
template<typename T, typename... Types>
struct get_type_index
{
- static const int value = Internal::get_type_index<0, T, Types...>::value;
+ static EA_CONSTEXPR_OR_CONST int value = Internal::get_type_index<0, T, Types...>::value;
};
template <typename T, typename... Ts>
- constexpr int get_type_index_v = get_type_index<T, Ts...>::value;
+ EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR int get_type_index_v = get_type_index<T, Ts...>::value;
////////////////////////////////////////////////////////////////////////////////////////////
@@ -77,7 +77,7 @@ namespace eastl
////////////////////////////////////////////////////////////////////////////////////////////
- // type_count_v
+ // type_count_v
//
// Returns the number of occurrences of type T in a typelist.
//
@@ -87,33 +87,37 @@ namespace eastl
template <typename T, typename H, typename... Types>
struct type_count<T, H, Types...>
{
- static const int value = (is_same_v<T, H> ? 1 : 0) + type_count<T, Types...>::value;
+ static EA_CONSTEXPR_OR_CONST int value = (is_same_v<T, H> ? 1 : 0) + type_count<T, Types...>::value;
};
- template <typename T> struct type_count<T> { static const int value = 0; };
+ template <typename T>
+ struct type_count<T>
+ {
+ static EA_CONSTEXPR_OR_CONST int value = 0;
+ };
template <typename T, typename... Ts>
- constexpr int type_count_v = type_count<T, Ts...>::value;
+ EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR int type_count_v = type_count<T, Ts...>::value;
////////////////////////////////////////////////////////////////////////////////////////////
// duplicate_type_check_v
- //
+ //
// Checks if a type T occurs in a typelist more than once.
//
template <typename T, typename... Types>
struct duplicate_type_check
{
- static const bool value = (type_count<T, Types...>::value == 1);
+ static EA_CONSTEXPR_OR_CONST bool value = (type_count<T, Types...>::value == 1);
};
template <typename... Ts>
- constexpr bool duplicate_type_check_v = duplicate_type_check<Ts...>::value;
+ EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool duplicate_type_check_v = duplicate_type_check<Ts...>::value;
//////////////////////////////////////////////////////////////////////////////////
- // type_list
+ // type_list
//
// type_list is a simple struct that allows us to pass template parameter packs
// around in a single struct, and deduce parameter packs from function arguments
@@ -170,8 +174,8 @@ namespace eastl
////////////////////////////////////////////////////////////////////////////////////////////
- // overload_resolution_t
- //
+ // overload_resolution_t
+ //
// Given an input type and a typelist (which is a stand-in for alternative
// function overloads) this traits will return the same type chosen as if
// overload_resolution has selected a function to run.
@@ -215,8 +219,29 @@ namespace eastl
template <typename T, typename OverloadSet>
using overload_resolution_t = typename overload_resolution<decay_t<T>, OverloadSet>::type;
- } // namespace meta
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ // double_pack_expansion
+ //
+ // MSVC 2017 has a hard time expanding two packs of different lengths.
+ // This is a helper meant to coerce MSVC 2017 into doing the expansion by adding another level
+ // of indirection.
+ //
+
+ template <typename T, size_t I>
+ struct double_pack_expansion;
+
+ template <size_t... Is, size_t I>
+ struct double_pack_expansion<index_sequence<Is...>, I>
+ {
+ using type = index_sequence<Is..., I>;
+ };
+
+ template <typename IndexSequence, size_t I>
+ using double_pack_expansion_t = typename double_pack_expansion<IndexSequence, I>::type;
+
+
+ } // namespace meta
} // namespace eastl
#endif // EASTL_META_H
-
diff --git a/EASTL/include/EASTL/numeric.h b/EASTL/include/EASTL/numeric.h
index 4b83c94..200be6c 100644
--- a/EASTL/include/EASTL/numeric.h
+++ b/EASTL/include/EASTL/numeric.h
@@ -233,6 +233,103 @@ namespace eastl
}
+ #if defined(EA_COMPILER_CPP20_ENABLED)
+ /// midpoint
+ ///
+ /// Computes the midpoint between the LHS and RHS by adding them together, then dividing the sum by 2.
+ /// If the operands are of integer type and the sum is odd, the result will be rounded closer to the LHS.
+ /// If the operands are floating points, then at most one inexact operation occurs.
+ ///
+ template <typename T>
+ constexpr eastl::enable_if_t<eastl::is_arithmetic_v<T> && !eastl::is_same_v<eastl::remove_cv_t<T>, bool>, T> midpoint(const T lhs, const T rhs) EA_NOEXCEPT
+ {
+ // If T is an integral type...
+ if constexpr(eastl::is_integral_v<T>)
+ {
+ using U = eastl::make_unsigned_t<T>;
+
+ int sign = 1;
+ U m = lhs;
+ U M = rhs;
+
+ if (lhs > rhs)
+ {
+ sign = -1;
+ m = rhs;
+ M = lhs;
+ }
+
+ return lhs + static_cast<T>(sign * static_cast<T>((U(M - m)) / 2 ));
+ }
+
+ // otherwise if T is a floating point
+ else
+ {
+ const T LO = eastl::numeric_limits<T>::min() * 2;
+ const T HI = eastl::numeric_limits<T>::max() / 2;
+
+ const T lhs_abs = (lhs < 0) ? -lhs : lhs;
+ const T rhs_abs = (rhs < 0) ? -rhs : rhs;
+
+ if (lhs_abs <= HI && rhs_abs <= HI)
+ return (lhs + rhs) / 2;
+ if (lhs_abs < LO)
+ return lhs + (rhs / 2);
+ if (rhs_abs < LO)
+ return (lhs / 2) + rhs;
+ return (lhs / 2) + (rhs / 2);
+ }
+ }
+
+
+ /// midpoint
+ ///
+ /// Computes the midpoint address between pointers LHS and RHS.
+ /// The midpoint address closer to the LHS is chosen.
+ ///
+ template <typename T>
+ constexpr eastl::enable_if_t<eastl::is_object_v<T>, T*> midpoint(T* lhs, T* rhs)
+ {
+ return lhs + ((rhs - lhs) / 2);
+ }
+
+
+ template <class T>
+ constexpr T shared_lerp(const T a, const T b, const T t) EA_NOEXCEPT
+ {
+ if ((a <= 0 && b >= 0) || (a >= 0 && b <= 0))
+ {
+ return t * b + (1 - t) * a;
+ }
+
+ if (t == 1)
+ {
+ return b;
+ }
+
+ const T X = a + t * (b - a);
+
+ if ((t > 1) == (b > a))
+ {
+ return (b > X) ? b : X;
+ }
+ return (b < X) ? b : X;
+ }
+
+ /// lerp
+ ///
+ /// Calculates the linear interpolation of two points A and B expressed A + T * (B - A)
+ /// where T is some value in range [0, 1]. If T is outside this range, the linear extrapolation will be computed.
+ ///
+ /// https://en.cppreference.com/w/cpp/numeric/lerp
+ ///
+ /// C++ proposal paper:
+ /// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0811r3.html
+ ///
+ constexpr float lerp(float a, float b, float t) EA_NOEXCEPT { return shared_lerp(a, b, t); }
+ constexpr double lerp(double a, double b, double t) EA_NOEXCEPT { return shared_lerp(a, b, t); }
+ constexpr long double lerp(long double a, long double b, long double t) EA_NOEXCEPT { return shared_lerp(a, b, t); }
+ #endif
} // namespace eastl
diff --git a/EASTL/include/EASTL/numeric_limits.h b/EASTL/include/EASTL/numeric_limits.h
index c2770c9..0d7dc97 100644
--- a/EASTL/include/EASTL/numeric_limits.h
+++ b/EASTL/include/EASTL/numeric_limits.h
@@ -57,7 +57,7 @@ EA_DISABLE_VC_WARNING(4310 4296)
// Indicates whether we need to define our own implementations of inf, nan, snan, denorm floating point constants.
//
#if !defined(EASTL_CUSTOM_FLOAT_CONSTANTS_REQUIRED)
- #if (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG) && defined(__FLT_MIN__)) || defined(_CPPLIB_VER) // __FLT_MIN__ detects if it's really GCC/clang and not a mimic. _CPPLIB_VER (Dinkumware) covers VC++, and Microsoft platforms.
+ #if (defined(EA_COMPILER_GNUC) || defined(__clang__) && defined(__FLT_MIN__)) || defined(_CPPLIB_VER) // __FLT_MIN__ detects if it's really GCC/clang and not a mimic. _CPPLIB_VER (Dinkumware) covers VC++, and Microsoft platforms.
#define EASTL_CUSTOM_FLOAT_CONSTANTS_REQUIRED 0
#else
#define EASTL_CUSTOM_FLOAT_CONSTANTS_REQUIRED 1
@@ -614,6 +614,65 @@ namespace eastl
};
+ #if defined(EA_CHAR8_UNIQUE) && EA_CHAR8_UNIQUE
+ template<>
+ struct numeric_limits<char8_t>
+ {
+ typedef char8_t value_type;
+
+ static EA_CONSTEXPR_OR_CONST bool is_specialized = true;
+ static EA_CONSTEXPR_OR_CONST int digits = EASTL_LIMITS_DIGITS(value_type);
+ static EA_CONSTEXPR_OR_CONST int digits10 = EASTL_LIMITS_DIGITS10(value_type);
+ static EA_CONSTEXPR_OR_CONST int max_digits10 = 0;
+ static EA_CONSTEXPR_OR_CONST bool is_signed = EASTL_LIMITS_IS_SIGNED(value_type);
+ static EA_CONSTEXPR_OR_CONST bool is_integer = true;
+ static EA_CONSTEXPR_OR_CONST bool is_exact = true;
+ static EA_CONSTEXPR_OR_CONST int radix = 2;
+ static EA_CONSTEXPR_OR_CONST int min_exponent = 0;
+ static EA_CONSTEXPR_OR_CONST int min_exponent10 = 0;
+ static EA_CONSTEXPR_OR_CONST int max_exponent = 0;
+ static EA_CONSTEXPR_OR_CONST int max_exponent10 = 0;
+ static EA_CONSTEXPR_OR_CONST bool is_bounded = true;
+ static EA_CONSTEXPR_OR_CONST bool is_modulo = true;
+ static EA_CONSTEXPR_OR_CONST bool traps = true;
+ static EA_CONSTEXPR_OR_CONST bool tinyness_before = false;
+ static EA_CONSTEXPR_OR_CONST float_round_style round_style = round_toward_zero;
+ static EA_CONSTEXPR_OR_CONST bool has_infinity = false;
+ static EA_CONSTEXPR_OR_CONST bool has_quiet_NaN = false;
+ static EA_CONSTEXPR_OR_CONST bool has_signaling_NaN = false;
+ static EA_CONSTEXPR_OR_CONST float_denorm_style has_denorm = denorm_absent;
+ static EA_CONSTEXPR_OR_CONST bool has_denorm_loss = false;
+ static EA_CONSTEXPR_OR_CONST bool is_iec559 = false;
+
+ static EA_CONSTEXPR value_type min()
+ { return EASTL_LIMITS_MIN(value_type); }
+
+ static EA_CONSTEXPR value_type max()
+ { return EASTL_LIMITS_MAX(value_type); }
+
+ static EA_CONSTEXPR value_type lowest()
+ { return EASTL_LIMITS_MIN(value_type); }
+
+ static EA_CONSTEXPR value_type epsilon()
+ { return 0; }
+
+ static EA_CONSTEXPR value_type round_error()
+ { return 0; }
+
+ static EA_CONSTEXPR value_type infinity()
+ { return 0; }
+
+ static EA_CONSTEXPR value_type quiet_NaN()
+ { return 0; }
+
+ static EA_CONSTEXPR value_type signaling_NaN()
+ { return 0; }
+
+ static EA_CONSTEXPR value_type denorm_min()
+ { return (value_type)0; }
+ };
+ #endif
+
#if EA_CHAR16_NATIVE // If char16_t is a true unique type (as called for by the C++11 Standard)...
// numeric_limits<char16_t>
@@ -1213,7 +1272,7 @@ namespace eastl
};
- #if (EA_COMPILER_INTMAX_SIZE >= 16) && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) // If __int128_t/__uint128_t is supported...
+ #if (EA_COMPILER_INTMAX_SIZE >= 16) && (defined(EA_COMPILER_GNUC) || defined(__clang__)) // If __int128_t/__uint128_t is supported...
// numeric_limits<__uint128_t>
template<>
struct numeric_limits<__uint128_t>
@@ -1391,7 +1450,7 @@ namespace eastl
static value_type denorm_min()
{ return Internal::gFloatDenorm; }
- #elif (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) && defined(__FLT_MIN__)
+ #elif (defined(EA_COMPILER_GNUC) || defined(__clang__)) && defined(__FLT_MIN__)
static EA_CONSTEXPR value_type min()
{ return __FLT_MIN__; }
@@ -1435,6 +1494,19 @@ namespace eastl
static value_type round_error()
{ return 0.5f; }
+ #if defined(_MSVC_STL_UPDATE) && _MSVC_STL_UPDATE >= 202206L // If using a recent version of MSVC's STL...
+ static value_type infinity()
+ { return __builtin_huge_valf(); }
+
+ static value_type quiet_NaN()
+ { return __builtin_nanf("0"); }
+
+ static value_type signaling_NaN()
+ { return __builtin_nansf("1"); }
+
+ static value_type denorm_min()
+ { return FLT_TRUE_MIN; }
+ #else
static value_type infinity()
{ return _CSTD _FInf._Float; }
@@ -1446,6 +1518,7 @@ namespace eastl
static value_type denorm_min()
{ return _CSTD _FDenorm._Float; }
+ #endif
#endif
};
@@ -1509,7 +1582,7 @@ namespace eastl
static value_type denorm_min()
{ return Internal::gDoubleDenorm; }
- #elif (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) && defined(__DBL_MIN__)
+ #elif (defined(EA_COMPILER_GNUC) || defined(__clang__)) && defined(__DBL_MIN__)
static EA_CONSTEXPR value_type min()
{ return __DBL_MIN__; }
@@ -1553,6 +1626,19 @@ namespace eastl
static value_type round_error()
{ return 0.5f; }
+ #if defined(_MSVC_STL_UPDATE) && _MSVC_STL_UPDATE >= 202206L // If using a recent version of MSVC's STL...
+ static value_type infinity()
+ { return __builtin_huge_val(); }
+
+ static value_type quiet_NaN()
+ { return __builtin_nan("0"); }
+
+ static value_type signaling_NaN()
+ { return __builtin_nans("1"); }
+
+ static value_type denorm_min()
+ { return DBL_TRUE_MIN; }
+ #else
static value_type infinity()
{ return _CSTD _Inf._Double; }
@@ -1564,6 +1650,7 @@ namespace eastl
static value_type denorm_min()
{ return _CSTD _Denorm._Double; }
+ #endif
#endif
};
@@ -1627,7 +1714,7 @@ namespace eastl
static value_type denorm_min()
{ return Internal::gLongDoubleDenorm; }
- #elif (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) && defined(__LDBL_MIN__)
+ #elif (defined(EA_COMPILER_GNUC) || defined(__clang__)) && defined(__LDBL_MIN__)
static EA_CONSTEXPR value_type min()
{ return __LDBL_MIN__; }
@@ -1671,6 +1758,19 @@ namespace eastl
static value_type round_error()
{ return 0.5f; }
+ #if defined(_MSVC_STL_UPDATE) && _MSVC_STL_UPDATE >= 202206L // If using a recent version of MSVC's STL...
+ static value_type infinity()
+ { return __builtin_huge_val(); }
+
+ static value_type quiet_NaN()
+ { return __builtin_nan("0"); }
+
+ static value_type signaling_NaN()
+ { return __builtin_nans("1"); }
+
+ static value_type denorm_min()
+ { return LDBL_TRUE_MIN; }
+ #else
static value_type infinity()
{ return _CSTD _LInf._Long_double; }
@@ -1682,6 +1782,7 @@ namespace eastl
static value_type denorm_min()
{ return _CSTD _LDenorm._Long_double; }
+ #endif
#endif
};
diff --git a/EASTL/include/EASTL/optional.h b/EASTL/include/EASTL/optional.h
index 763bfd8..15cacd0 100644
--- a/EASTL/include/EASTL/optional.h
+++ b/EASTL/include/EASTL/optional.h
@@ -552,6 +552,17 @@ namespace eastl
inline EA_CONSTEXPR bool operator>=(const optional<T>& lhs, const optional<T>& rhs)
{ return !(lhs < rhs); }
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <class T, class U=T> requires std::three_way_comparable_with<T, U>
+ inline EA_CONSTEXPR std::compare_three_way_result_t<T, U> operator<=>(const optional<T>& lhs, const optional<U>& rhs)
+ {
+ if (lhs && rhs)
+ {
+ return *lhs <=> *rhs;
+ }
+ return lhs.has_value() <=> rhs.has_value();
+ }
+#endif
///////////////////////////////////////////////////////////////////////////////
// Compare an optional object with a nullopt
@@ -559,7 +570,11 @@ namespace eastl
template <class T>
inline EA_CONSTEXPR bool operator==(const optional<T>& opt, eastl::nullopt_t) EA_NOEXCEPT
{ return !opt; }
-
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <class T>
+ inline EA_CONSTEXPR std::strong_ordering operator<=>(const optional<T>& opt, eastl::nullopt_t) EA_NOEXCEPT
+ { return opt.has_value() <=> false; }
+#else
template <class T>
inline EA_CONSTEXPR bool operator==(eastl::nullopt_t, const optional<T>& opt) EA_NOEXCEPT
{ return !opt; }
@@ -603,7 +618,7 @@ namespace eastl
template <class T>
inline EA_CONSTEXPR bool operator>=(eastl::nullopt_t, const optional<T>& opt) EA_NOEXCEPT
{ return !opt; }
-
+#endif
///////////////////////////////////////////////////////////////////////////////
// Compare an optional object with a T
@@ -656,6 +671,11 @@ namespace eastl
inline EA_CONSTEXPR bool operator>=(const T& value, const optional<T>& opt)
{ return !(value < opt); }
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <class T, class U=T> requires std::three_way_comparable_with<T, U>
+ inline EA_CONSTEXPR std::compare_three_way_result_t<T, U> operator<=>(const optional<T>& opt, const U& value)
+ { return (opt.has_value()) ? *opt <=> value : std::strong_ordering::less; }
+#endif
///////////////////////////////////////////////////////////////////////////////
/// hash
diff --git a/EASTL/include/EASTL/queue.h b/EASTL/include/EASTL/queue.h
index 9e06e20..8b29555 100644
--- a/EASTL/include/EASTL/queue.h
+++ b/EASTL/include/EASTL/queue.h
@@ -308,6 +308,14 @@ namespace eastl
{
return (a.c == b.c);
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T, typename Container> requires std::three_way_comparable<Container>
+
+ inline synth_three_way_result<T> operator<=>(const queue<T, Container>& a, const queue<T, Container>& b)
+ {
+ return a.c <=> b.c;
+ }
+#endif
template <typename T, typename Container>
inline bool operator!=(const queue<T, Container>& a, const queue<T, Container>& b)
@@ -339,7 +347,6 @@ namespace eastl
return !(a.c < b.c);
}
-
template <typename T, typename Container>
inline void swap(queue<T, Container>& a, queue<T, Container>& b) EA_NOEXCEPT_IF((eastl::is_nothrow_swappable<typename queue<T, Container>::container_type>::value)) // EDG has a bug and won't let us use Container in this noexcept statement
{
diff --git a/EASTL/include/EASTL/set.h b/EASTL/include/EASTL/set.h
index a66a885..8256162 100644
--- a/EASTL/include/EASTL/set.h
+++ b/EASTL/include/EASTL/set.h
@@ -401,8 +401,9 @@ namespace eastl
// https://en.cppreference.com/w/cpp/container/set/erase_if
///////////////////////////////////////////////////////////////////////
template <class Key, class Compare, class Allocator, class Predicate>
- void erase_if(set<Key, Compare, Allocator>& c, Predicate predicate)
+ typename set<Key, Compare, Allocator>::size_type erase_if(set<Key, Compare, Allocator>& c, Predicate predicate)
{
+ auto oldSize = c.size();
for (auto i = c.begin(), last = c.end(); i != last;)
{
if (predicate(*i))
@@ -414,8 +415,17 @@ namespace eastl
++i;
}
}
+ return oldSize - c.size();
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <class Key, class Compare, class Allocator>
+ synth_three_way_result<Key> operator<=>(const set<Key, Compare, Allocator>& a, const set<Key, Compare, Allocator>& b)
+ {
+ return eastl::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end(), synth_three_way{});
+ }
+#endif
+
///////////////////////////////////////////////////////////////////////
// multiset
@@ -611,8 +621,9 @@ namespace eastl
// https://en.cppreference.com/w/cpp/container/multiset/erase_if
///////////////////////////////////////////////////////////////////////
template <class Key, class Compare, class Allocator, class Predicate>
- void erase_if(multiset<Key, Compare, Allocator>& c, Predicate predicate)
+ typename multiset<Key, Compare, Allocator>::size_type erase_if(multiset<Key, Compare, Allocator>& c, Predicate predicate)
{
+ auto oldSize = c.size();
// Erases all elements that satisfy the predicate pred from the container.
for (auto i = c.begin(), last = c.end(); i != last;)
{
@@ -625,8 +636,17 @@ namespace eastl
++i;
}
}
+ return oldSize - c.size();
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <class Key, class Compare, class Allocator>
+ synth_three_way_result<Key> operator<=>(const multiset<Key, Compare, Allocator>& a, const multiset<Key, Compare, Allocator>& b)
+ {
+ return eastl::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end(), synth_three_way{});
+ }
+#endif
+
} // namespace eastl
diff --git a/EASTL/include/EASTL/shared_ptr.h b/EASTL/include/EASTL/shared_ptr.h
index 5535adf..e7eb778 100644
--- a/EASTL/include/EASTL/shared_ptr.h
+++ b/EASTL/include/EASTL/shared_ptr.h
@@ -48,6 +48,7 @@
#include <EASTL/unique_ptr.h>
#include <EASTL/functional.h>
#include <EASTL/allocator.h>
+#include <EASTL/atomic.h>
#if EASTL_RTTI_ENABLED
#include <typeinfo>
#endif
@@ -117,8 +118,8 @@ namespace eastl
/// This is a small utility class used by shared_ptr and weak_ptr.
struct ref_count_sp
{
- int32_t mRefCount; /// Reference count on the contained pointer. Starts as 1 by default.
- int32_t mWeakRefCount; /// Reference count on contained pointer plus this ref_count_sp object itself. Starts as 1 by default.
+ atomic<int32_t> mRefCount; /// Reference count on the contained pointer. Starts as 1 by default.
+ atomic<int32_t> mWeakRefCount; /// Reference count on contained pointer plus this ref_count_sp object itself. Starts as 1 by default.
public:
ref_count_sp(int32_t refCount = 1, int32_t weakRefCount = 1) EA_NOEXCEPT;
@@ -147,44 +148,49 @@ namespace eastl
inline int32_t ref_count_sp::use_count() const EA_NOEXCEPT
{
- return mRefCount; // To figure out: is this right?
+ return mRefCount.load(memory_order_relaxed); // To figure out: is this right?
}
inline void ref_count_sp::addref() EA_NOEXCEPT
{
- Internal::atomic_increment(&mRefCount);
- Internal::atomic_increment(&mWeakRefCount);
+ mRefCount.fetch_add(1, memory_order_relaxed);
+ mWeakRefCount.fetch_add(1, memory_order_relaxed);
}
inline void ref_count_sp::release()
{
- EASTL_ASSERT((mRefCount > 0) && (mWeakRefCount > 0));
- if(Internal::atomic_decrement(&mRefCount) == 0)
+ EASTL_ASSERT((mRefCount.load(memory_order_relaxed) > 0));
+ if(mRefCount.fetch_sub(1, memory_order_release) == 1)
+ {
+ atomic_thread_fence(memory_order_acquire);
free_value();
+ }
- if(Internal::atomic_decrement(&mWeakRefCount) == 0)
- free_ref_count_sp();
+ weak_release();
}
inline void ref_count_sp::weak_addref() EA_NOEXCEPT
{
- Internal::atomic_increment(&mWeakRefCount);
+ mWeakRefCount.fetch_add(1, memory_order_relaxed);
}
inline void ref_count_sp::weak_release()
{
- EASTL_ASSERT(mWeakRefCount > 0);
- if(Internal::atomic_decrement(&mWeakRefCount) == 0)
+ EASTL_ASSERT(mWeakRefCount.load(memory_order_relaxed) > 0);
+ if(mWeakRefCount.fetch_sub(1, memory_order_release) == 1)
+ {
+ atomic_thread_fence(memory_order_acquire);
free_ref_count_sp();
+ }
}
inline ref_count_sp* ref_count_sp::lock() EA_NOEXCEPT
{
- for(int32_t refCountTemp = mRefCount; refCountTemp != 0; refCountTemp = mRefCount)
+ for(int32_t refCountTemp = mRefCount.load(memory_order_relaxed); refCountTemp != 0; )
{
- if(Internal::atomic_compare_and_swap(&mRefCount, refCountTemp + 1, refCountTemp))
+ if(mRefCount.compare_exchange_weak(refCountTemp, refCountTemp + 1, memory_order_relaxed))
{
- Internal::atomic_increment(&mWeakRefCount);
+ mWeakRefCount.fetch_add(1, memory_order_relaxed);
return this;
}
}
@@ -810,14 +816,14 @@ namespace eastl
/// Returns: the number of shared_ptr objects, *this included, that share ownership with *this, or 0 when *this is empty.
int use_count() const EA_NOEXCEPT
{
- return mpRefCount ? mpRefCount->mRefCount : 0;
+ return mpRefCount ? mpRefCount->use_count() : 0;
}
/// unique
/// Returns: use_count() == 1.
bool unique() const EA_NOEXCEPT
{
- return (mpRefCount && (mpRefCount->mRefCount == 1));
+ return (mpRefCount && (mpRefCount->use_count() == 1));
}
@@ -970,6 +976,13 @@ namespace eastl
return (a.get() == b.get());
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T, typename U>
+ std::strong_ordering operator<=>(const shared_ptr<T>& a, const shared_ptr<U>& b) EA_NOEXCEPT
+ {
+ return a.get() <=> b.get();
+ }
+#else
template <typename T, typename U>
inline bool operator!=(const shared_ptr<T>& a, const shared_ptr<U>& b) EA_NOEXCEPT
{
@@ -1006,6 +1019,7 @@ namespace eastl
{
return !(a < b);
}
+#endif
template <typename T>
inline bool operator==(const shared_ptr<T>& a, std::nullptr_t) EA_NOEXCEPT
@@ -1013,6 +1027,13 @@ namespace eastl
return !a;
}
+ #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T>
+ inline std::strong_ordering operator<=>(const shared_ptr<T>& a, std::nullptr_t) EA_NOEXCEPT
+ {
+ return a.get() <=> nullptr;
+ }
+ #else
template <typename T>
inline bool operator==(std::nullptr_t, const shared_ptr<T>& b) EA_NOEXCEPT
{
@@ -1078,7 +1099,7 @@ namespace eastl
{
return !(nullptr < b);
}
-
+#endif
@@ -1508,13 +1529,13 @@ namespace eastl
// Returns: 0 if *this is empty ; otherwise, the number of shared_ptr instances that share ownership with *this.
int use_count() const EA_NOEXCEPT
{
- return mpRefCount ? mpRefCount->mRefCount : 0;
+ return mpRefCount ? mpRefCount->use_count() : 0;
}
// Returns: use_count() == 0
bool expired() const EA_NOEXCEPT
{
- return (!mpRefCount || (mpRefCount->mRefCount == 0));
+ return (!mpRefCount || (mpRefCount->use_count() == 0));
}
void reset()
diff --git a/EASTL/include/EASTL/slist.h b/EASTL/include/EASTL/slist.h
index 2796692..dc3c447 100644
--- a/EASTL/include/EASTL/slist.h
+++ b/EASTL/include/EASTL/slist.h
@@ -353,10 +353,10 @@ namespace eastl
void clear() EA_NOEXCEPT;
void reset_lose_memory() EA_NOEXCEPT; // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
- void remove(const value_type& value);
+ size_type remove(const value_type& value);
template <typename Predicate>
- void remove_if(Predicate predicate);
+ size_type remove_if(Predicate predicate);
void reverse() EA_NOEXCEPT;
@@ -679,7 +679,7 @@ namespace eastl
template <typename T, typename Allocator>
inline SListNode<T>* SListBase<T, Allocator>::DoAllocateNode()
{
- return (node_type*)allocate_memory(internalAllocator(), sizeof(node_type), EASTL_ALIGN_OF(T), 0);
+ return (node_type*)allocate_memory(internalAllocator(), sizeof(node_type), EASTL_ALIGN_OF(node_type), 0);
}
@@ -1249,32 +1249,42 @@ namespace eastl
template <typename T, typename Allocator>
- void slist<T, Allocator>::remove(const value_type& value)
+ typename slist<T, Allocator>::size_type slist<T, Allocator>::remove(const value_type& value)
{
base_node_type* pNode = &internalNode();
+ size_type numErased = 0;
while(pNode && pNode->mpNext)
{
- if(static_cast<node_type*>(pNode->mpNext)->mValue == value)
+ if (static_cast<node_type*>(pNode->mpNext)->mValue == value)
+ {
DoEraseAfter((SListNodeBase*)pNode); // This will take care of modifying pNode->mpNext.
+ ++numErased;
+ }
else
pNode = pNode->mpNext;
}
+ return numErased;
}
template <typename T, typename Allocator>
template <typename Predicate>
- void slist<T, Allocator>::remove_if(Predicate predicate)
+ inline typename slist<T, Allocator>::size_type slist<T, Allocator>::remove_if(Predicate predicate)
{
base_node_type* pNode = &internalNode();
+ size_type numErased = 0;
while(pNode && pNode->mpNext)
{
- if(predicate(static_cast<node_type*>(pNode->mpNext)->mValue))
+ if (predicate(static_cast<node_type*>(pNode->mpNext)->mValue))
+ {
DoEraseAfter((SListNodeBase*)pNode); // This will take care of modifying pNode->mpNext.
+ ++numErased;
+ }
else
pNode = pNode->mpNext;
}
+ return numErased;
}
@@ -1811,7 +1821,13 @@ namespace eastl
#endif
}
-
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T, typename Allocator>
+ inline synth_three_way_result<T> operator<=>(const slist<T, Allocator>& a, const slist<T, Allocator>& b)
+ {
+ return eastl::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end(), synth_three_way{});
+ }
+#else
template <typename T, typename Allocator>
inline bool operator<(const slist<T, Allocator>& a, const slist<T, Allocator>& b)
{
@@ -1845,7 +1861,7 @@ namespace eastl
{
return !(a < b);
}
-
+#endif
template <typename T, typename Allocator>
inline void swap(slist<T, Allocator>& a, slist<T, Allocator>& b)
@@ -1858,17 +1874,17 @@ namespace eastl
///
/// https://en.cppreference.com/w/cpp/container/forward_list/erase2
template <class T, class Allocator, class U>
- void erase(slist<T, Allocator>& c, const U& value)
+ typename slist<T, Allocator>::size_type erase(slist<T, Allocator>& c, const U& value)
{
// Erases all elements that compare equal to value from the container.
- c.remove_if([&](auto& elem) { return elem == value; });
+ return c.remove(value);
}
template <class T, class Allocator, class Predicate>
- void erase_if(slist<T, Allocator>& c, Predicate predicate)
+ typename slist<T, Allocator>::size_type erase_if(slist<T, Allocator>& c, Predicate predicate)
{
// Erases all elements that satisfy the predicate pred from the container.
- c.remove_if(predicate);
+ return c.remove_if(predicate);
}
diff --git a/EASTL/include/EASTL/sort.h b/EASTL/include/EASTL/sort.h
index d089431..fb1c6e5 100644
--- a/EASTL/include/EASTL/sort.h
+++ b/EASTL/include/EASTL/sort.h
@@ -305,7 +305,7 @@ namespace eastl
{
iBack = iCurrent = iSorted;
- for(iBack -= nSpace; (iCurrent != iInsertFirst) && compare(*iCurrent, *iBack); iCurrent = iBack, iBack -= nSpace)
+ for(; (iCurrent != iInsertFirst) && compare(*iCurrent, *(iBack -= nSpace)); iCurrent = iBack)
{
EASTL_VALIDATE_COMPARE(!compare(*iBack, *iCurrent)); // Validate that the compare function is sane.
eastl::iter_swap(iCurrent, iBack);
@@ -715,18 +715,20 @@ namespace eastl
template <typename RandomAccessIterator, typename T>
inline RandomAccessIterator get_partition_impl(RandomAccessIterator first, RandomAccessIterator last, T&& pivotValue)
{
+ using PureT = decay_t<T>;
+
for(; ; ++first)
{
- while(*first < pivotValue)
+ while(eastl::less<PureT>()(*first, pivotValue))
{
- EASTL_VALIDATE_COMPARE(!(pivotValue < *first)); // Validate that the compare function is sane.
+ EASTL_VALIDATE_COMPARE(!eastl::less<PureT>()(pivotValue, *first)); // Validate that the compare function is sane.
++first;
}
--last;
- while(pivotValue < *last)
+ while(eastl::less<PureT>()(pivotValue, *last))
{
- EASTL_VALIDATE_COMPARE(!(*last < pivotValue)); // Validate that the compare function is sane.
+ EASTL_VALIDATE_COMPARE(!eastl::less<PureT>()(*last, pivotValue)); // Validate that the compare function is sane.
--last;
}
@@ -813,9 +815,9 @@ namespace eastl
RandomAccessIterator end(current), prev(current);
value_type value(eastl::forward<value_type>(*current));
- for(--prev; value < *prev; --end, --prev) // We skip checking for (prev >= first) because quick_sort (our caller) makes this unnecessary.
+ for(--prev; eastl::less<value_type>()(value, *prev); --end, --prev) // We skip checking for (prev >= first) because quick_sort (our caller) makes this unnecessary.
{
- EASTL_VALIDATE_COMPARE(!(*prev < value)); // Validate that the compare function is sane.
+ EASTL_VALIDATE_COMPARE(!eastl::less<value_type>()(*prev, value)); // Validate that the compare function is sane.
*end = eastl::forward<value_type>(*prev);
}
@@ -860,9 +862,9 @@ namespace eastl
for(RandomAccessIterator i = middle; i < last; ++i)
{
- if(*i < *first)
+ if(eastl::less<value_type>()(*i, *first))
{
- EASTL_VALIDATE_COMPARE(!(*first < *i)); // Validate that the compare function is sane.
+ EASTL_VALIDATE_COMPARE(!eastl::less<value_type>()(*first, *i)); // Validate that the compare function is sane.
value_type temp(eastl::forward<value_type>(*i));
*i = eastl::forward<value_type>(*first);
eastl::adjust_heap<RandomAccessIterator, difference_type, value_type>
@@ -1653,8 +1655,8 @@ namespace eastl
IntegerType)
{
RandomAccessIterator srcFirst = first;
- constexpr size_t numBuckets = 1 << DigitBits;
- constexpr IntegerType bucketMask = numBuckets - 1;
+ EA_CONSTEXPR_OR_CONST size_t numBuckets = 1 << DigitBits;
+ EA_CONSTEXPR_OR_CONST IntegerType bucketMask = numBuckets - 1;
// The alignment of this variable isn't required; it merely allows the code below to be faster on some platforms.
uint32_t EA_PREFIX_ALIGN(EASTL_PLATFORM_PREFERRED_ALIGNMENT) bucketSize[numBuckets];
@@ -1712,6 +1714,7 @@ namespace eastl
bucketPosition[i + 1] = bucketPosition[i] + bucketSize[i];
bucketSize[i] = 0; // Clear the bucket for the next pass
}
+ bucketSize[numBuckets - 1] = 0;
uint32_t jNext = j + DigitBits;
for (temp = srcFirst; temp != last; ++temp)
diff --git a/EASTL/include/EASTL/span.h b/EASTL/include/EASTL/span.h
index 1f3b9b4..9c47f5b 100644
--- a/EASTL/include/EASTL/span.h
+++ b/EASTL/include/EASTL/span.h
@@ -76,7 +76,7 @@ namespace eastl
static EA_CONSTEXPR size_t extent = Extent;
// constructors / destructor
- EA_CONSTEXPR span() EA_NOEXCEPT = default;
+ EA_CONSTEXPR span() EA_NOEXCEPT;
EA_CONSTEXPR span(const span& other) EA_NOEXCEPT = default;
EA_CONSTEXPR span(pointer ptr, index_type count);
EA_CONSTEXPR span(pointer pBegin, pointer pEnd);
@@ -86,9 +86,14 @@ namespace eastl
EA_CPP14_CONSTEXPR span& operator=(const span& other) EA_NOEXCEPT = default;
// conversion constructors for c-array and eastl::array
- template <size_t N> EA_CONSTEXPR span(element_type (&arr)[N]) EA_NOEXCEPT;
- template <size_t N> EA_CONSTEXPR span(eastl::array<value_type, N>& arr) EA_NOEXCEPT;
- template <size_t N> EA_CONSTEXPR span(const eastl::array<value_type, N>& arr) EA_NOEXCEPT;
+ template <size_t N, typename = enable_if_t<(Extent == eastl::dynamic_extent || N == Extent)>>
+ EA_CONSTEXPR span(element_type (&arr)[N]) EA_NOEXCEPT;
+
+ template <size_t N, typename = enable_if_t<(Extent == eastl::dynamic_extent || N == Extent)>>
+ EA_CONSTEXPR span(eastl::array<value_type, N>& arr) EA_NOEXCEPT;
+
+ template <size_t N, typename = enable_if_t<(Extent == eastl::dynamic_extent || N == Extent)>>
+ EA_CONSTEXPR span(const eastl::array<value_type, N>& arr) EA_NOEXCEPT;
// SfinaeForGenericContainers
//
@@ -198,34 +203,43 @@ namespace eastl
// ctor implementations
///////////////////////////////////////////////////////////////////////////
+
+ template <typename T, size_t Extent>
+ EA_CONSTEXPR span<T, Extent>::span() EA_NOEXCEPT
+ {
+ static_assert(Extent == dynamic_extent || Extent == 0, "impossible to default construct a span with a fixed Extent different than 0");
+ }
+
template <typename T, size_t Extent>
EA_CONSTEXPR span<T, Extent>::span(pointer ptr, index_type size)
: mpData(ptr), mnSize(size)
{
+ EASTL_ASSERT_MSG(Extent == dynamic_extent || Extent == mnSize, "impossible to create a span with a fixed Extent different than the size of the supplied buffer");
}
template <typename T, size_t Extent>
EA_CONSTEXPR span<T, Extent>::span(pointer pBegin, pointer pEnd)
: mpData(pBegin), mnSize(static_cast<index_type>(pEnd - pBegin))
{
+ EASTL_ASSERT_MSG(Extent == dynamic_extent || Extent == mnSize, "impossible to create a span with a fixed Extent different than the size of the supplied buffer");
}
template <typename T, size_t Extent>
- template <size_t N>
+ template <size_t N, typename>
EA_CONSTEXPR span<T, Extent>::span(element_type(&arr)[N]) EA_NOEXCEPT
: span(arr, static_cast<index_type>(N))
{
}
template <typename T, size_t Extent>
- template <size_t N>
+ template <size_t N, typename>
EA_CONSTEXPR span<T, Extent>::span(eastl::array<value_type, N> &arr) EA_NOEXCEPT
: span(arr.data(), arr.size())
{
}
template <typename T, size_t Extent>
- template <size_t N>
+ template <size_t N, typename>
EA_CONSTEXPR span<T, Extent>::span(const eastl::array<value_type, N>& arr) EA_NOEXCEPT
: span(arr.data(), arr.size())
{
@@ -368,7 +382,7 @@ namespace eastl
template <size_t Count>
EA_CPP14_CONSTEXPR span<typename span<T, Extent>::element_type, Count> span<T, Extent>::first() const
{
- EASTL_ASSERT_MSG(bounds_check(Count), "undefined behavior accessing out of bounds");
+ EASTL_ASSERT_MSG(Count <= size(), "undefined behavior accessing out of bounds");
return {data(), static_cast<index_type>(Count)};
}
@@ -376,7 +390,7 @@ namespace eastl
EA_CPP14_CONSTEXPR span<typename span<T, Extent>::element_type, dynamic_extent>
span<T, Extent>::first(size_t sz) const
{
- EASTL_ASSERT_MSG(bounds_check(sz), "undefined behavior accessing out of bounds");
+ EASTL_ASSERT_MSG(sz <= size(), "undefined behavior accessing out of bounds");
return {data(), static_cast<index_type>(sz)};
}
@@ -384,7 +398,7 @@ namespace eastl
template <size_t Count>
EA_CPP14_CONSTEXPR span<typename span<T, Extent>::element_type, Count> span<T, Extent>::last() const
{
- EASTL_ASSERT_MSG(bounds_check(Count), "undefined behavior accessing out of bounds");
+ EASTL_ASSERT_MSG(Count <= size(), "undefined behavior accessing out of bounds");
return {data() + size() - Count, static_cast<index_type>(Count)};
}
@@ -392,7 +406,7 @@ namespace eastl
EA_CPP14_CONSTEXPR span<typename span<T, Extent>::element_type, dynamic_extent>
span<T, Extent>::last(size_t sz) const
{
- EASTL_ASSERT_MSG(bounds_check(sz), "undefined behavior accessing out of bounds");
+ EASTL_ASSERT_MSG(sz <= size(), "undefined behavior accessing out of bounds");
return {data() + size() - sz, static_cast<index_type>(sz)};
}
@@ -401,7 +415,7 @@ namespace eastl
EA_CONSTEXPR span<typename span<T, Extent>::element_type, Internal::SubspanExtent<Extent, Offset, Count>::value>
span<T, Extent>::subspan() const
{
- EASTL_ASSERT_MSG(bounds_check(Offset), "undefined behaviour accessing out of bounds");
+ EASTL_ASSERT_MSG(Offset <= size(), "undefined behaviour accessing out of bounds");
EASTL_ASSERT_MSG(Count == dynamic_extent || Count <= (size() - Offset), "undefined behaviour exceeding size of span");
return {data() + Offset, eastl_size_t(Count == dynamic_extent ? size() - Offset : Count)};
@@ -411,16 +425,16 @@ namespace eastl
EA_CONSTEXPR span<typename span<T, Extent>::element_type, dynamic_extent>
span<T, Extent>::subspan(size_t offset, size_t count) const
{
- EASTL_ASSERT_MSG(bounds_check(offset), "undefined behaviour accessing out of bounds");
+ EASTL_ASSERT_MSG(offset <= size(), "undefined behaviour accessing out of bounds");
EASTL_ASSERT_MSG(count == dynamic_extent || count <= (size() - offset), "undefined behaviour exceeding size of span");
return {data() + offset, eastl_size_t(count == dynamic_extent ? size() - offset : count)};
}
template <typename T, size_t Extent>
- EA_CONSTEXPR bool span<T, Extent>::bounds_check(size_t sz) const
+ EA_CONSTEXPR bool span<T, Extent>::bounds_check(size_t offset) const
{
- return (sz >= 0 && sz < size());
+ return offset < size();
}
}
diff --git a/EASTL/include/EASTL/stack.h b/EASTL/include/EASTL/stack.h
index 3edd5f5..f060b60 100644
--- a/EASTL/include/EASTL/stack.h
+++ b/EASTL/include/EASTL/stack.h
@@ -284,6 +284,13 @@ namespace eastl
return (a.c == b.c);
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T, typename Container> requires std::three_way_comparable<Container>
+ inline synth_three_way_result<T> operator<=>(const stack<T, Container>& a, const stack<T, Container>& b)
+ {
+ return a.c <=> b.c;
+ }
+#endif
template <typename T, typename Container>
inline bool operator!=(const stack<T, Container>& a, const stack<T, Container>& b)
@@ -319,7 +326,6 @@ namespace eastl
return !(a.c < b.c);
}
-
template <typename T, typename Container>
inline void swap(stack<T, Container>& a, stack<T, Container>& b) EA_NOEXCEPT_IF((eastl::is_nothrow_swappable<typename stack<T, Container>::container_type>::value))
{
diff --git a/EASTL/include/EASTL/string.h b/EASTL/include/EASTL/string.h
index 82816a4..3a70b79 100644
--- a/EASTL/include/EASTL/string.h
+++ b/EASTL/include/EASTL/string.h
@@ -294,7 +294,7 @@ namespace eastl
typedef ptrdiff_t difference_type;
typedef Allocator allocator_type;
- static const size_type npos = (size_type)-1; /// 'npos' means non-valid position or simply non-position.
+ static const EA_CONSTEXPR size_type npos = (size_type)-1; /// 'npos' means non-valid position or simply non-position.
public:
// CtorDoNotInitialize exists so that we can create a constructor that allocates but doesn't
@@ -303,7 +303,12 @@ namespace eastl
// CtorSprintf exists so that we can create a constructor that accepts printf-style
// arguments but also doesn't collide with any other constructor declaration.
- struct CtorSprintf{};
+ #ifdef EA_PLATFORM_MINGW
+ // Workaround for MinGW compiler bug: variadic arguments are corrupted if empty object is passed before it
+ struct CtorSprintf{ int dummy; };
+ #else
+ struct CtorSprintf{};
+ #endif
// CtorConvert exists so that we can have a constructor that implements string encoding
// conversion, such as between UCS2 char16_t and UTF8 char8_t.
@@ -313,19 +318,19 @@ namespace eastl
// Masks used to determine if we are in SSO or Heap
#ifdef EA_SYSTEM_BIG_ENDIAN
// Big Endian use LSB, unless we want to reorder struct layouts on endianness, Bit is set when we are in Heap
- static constexpr size_type kHeapMask = 0x1;
- static constexpr size_type kSSOMask = 0x1;
+ static EA_CONSTEXPR_OR_CONST size_type kHeapMask = 0x1;
+ static EA_CONSTEXPR_OR_CONST size_type kSSOMask = 0x1;
#else
// Little Endian use MSB
- static constexpr size_type kHeapMask = ~(size_type(~size_type(0)) >> 1);
- static constexpr size_type kSSOMask = 0x80;
+ static EA_CONSTEXPR_OR_CONST size_type kHeapMask = ~(size_type(~size_type(0)) >> 1);
+ static EA_CONSTEXPR_OR_CONST size_type kSSOMask = 0x80;
#endif
public:
#ifdef EA_SYSTEM_BIG_ENDIAN
- static constexpr size_type kMaxSize = (~kHeapMask) >> 1;
+ static EA_CONSTEXPR_OR_CONST size_type kMaxSize = (~kHeapMask) >> 1;
#else
- static constexpr size_type kMaxSize = ~kHeapMask;
+ static EA_CONSTEXPR_OR_CONST size_type kMaxSize = ~kHeapMask;
#endif
protected:
@@ -353,7 +358,7 @@ namespace eastl
// The view of memory when the string data is able to store the string data locally (without a heap allocation).
struct SSOLayout
{
- static constexpr size_type SSO_CAPACITY = (sizeof(HeapLayout) - sizeof(char)) / sizeof(value_type);
+ static EA_CONSTEXPR_OR_CONST size_type SSO_CAPACITY = (sizeof(HeapLayout) - sizeof(char)) / sizeof(value_type);
// mnSize must correspond to the last byte of HeapLayout.mnCapacity, so we don't want the compiler to insert
// padding after mnSize if sizeof(value_type) != 1; Also ensures both layouts are the same size.
@@ -1793,7 +1798,9 @@ namespace eastl
}
if (nReturnValue >= 0)
+ {
internalLayout().SetSize(nInitialSize + nReturnValue);
+ }
#if EASTL_VA_COPY_ENABLED
// va_end for arguments will be called by the caller.
@@ -1849,7 +1856,9 @@ namespace eastl
}
if(nReturnValue >= 0)
+ {
internalLayout().SetSize(nInitialSize + nReturnValue);
+ }
#if EASTL_VA_COPY_ENABLED
// va_end for arguments will be called by the caller.
@@ -3759,7 +3768,7 @@ namespace eastl
return ((a.size() == b.size()) && (memcmp(a.data(), b.data(), (size_t)a.size() * sizeof(typename basic_string<T, Allocator>::value_type)) == 0));
}
-
+#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <typename T, typename Allocator>
inline bool operator==(const typename basic_string<T, Allocator>::value_type* p, const basic_string<T, Allocator>& b)
{
@@ -3767,7 +3776,7 @@ namespace eastl
const size_type n = (size_type)CharStrlen(p);
return ((n == b.size()) && (memcmp(p, b.data(), (size_t)n * sizeof(*p)) == 0));
}
-
+#endif
template <typename T, typename Allocator>
inline bool operator==(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::value_type* p)
@@ -3776,6 +3785,52 @@ namespace eastl
const size_type n = (size_type)CharStrlen(p);
return ((a.size() == n) && (memcmp(a.data(), p, (size_t)n * sizeof(*p)) == 0));
}
+
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T, typename Allocator>
+ inline auto operator<=>(const basic_string<T, Allocator>& a, const basic_string<T, Allocator>& b)
+ {
+ return basic_string<T, Allocator>::compare(a.begin(), a.end(), b.begin(), b.end()) <=> 0;
+ }
+
+ template <typename T, typename Allocator>
+ inline auto operator<=>(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::value_type* p)
+ {
+ typedef typename basic_string<T, Allocator>::size_type size_type;
+ const size_type n = (size_type)CharStrlen(p);
+ return basic_string<T, Allocator>::compare(a.begin(), a.end(), p, p + n) <=> 0;
+ }
+
+ template <typename T, typename Allocator>
+ inline auto operator<=>(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::view_type v)
+ {
+ typedef typename basic_string<T, Allocator>::view_type view_type;
+ return static_cast<view_type>(a) <=> v;
+ }
+
+#else
+
+ template <typename T, typename Allocator>
+ inline bool operator==(const typename basic_string<T, Allocator>::view_type v, const basic_string<T, Allocator>& b)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ typedef typename basic_string<T, Allocator>::view_type view_type;
+ return v == static_cast<view_type>(b);
+ }
+
+ template <typename T, typename Allocator>
+ inline bool operator==(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::view_type v)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ typedef typename basic_string<T, Allocator>::view_type view_type;
+ return static_cast<view_type>(a) == v;
+ }
template <typename T, typename Allocator>
@@ -3784,7 +3839,6 @@ namespace eastl
return !(a == b);
}
-
template <typename T, typename Allocator>
inline bool operator!=(const typename basic_string<T, Allocator>::value_type* p, const basic_string<T, Allocator>& b)
{
@@ -3797,6 +3851,28 @@ namespace eastl
{
return !(a == p);
}
+
+
+ template <typename T, typename Allocator>
+ inline bool operator!=(const typename basic_string<T, Allocator>::view_type v, const basic_string<T, Allocator>& b)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ return !(v == b);
+ }
+
+
+ template <typename T, typename Allocator>
+ inline bool operator!=(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::view_type v)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ return !(a == v);
+ }
// Operator< (and also >, <=, and >=).
@@ -3822,6 +3898,30 @@ namespace eastl
const size_type n = (size_type)CharStrlen(p);
return basic_string<T, Allocator>::compare(a.begin(), a.end(), p, p + n) < 0;
}
+
+
+ template <typename T, typename Allocator>
+ inline bool operator<(const typename basic_string<T, Allocator>::view_type v, const basic_string<T, Allocator>& b)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ typedef typename basic_string<T, Allocator>::view_type view_type;
+ return v < static_cast<view_type>(b);
+ }
+
+
+ template <typename T, typename Allocator>
+ inline bool operator<(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::view_type v)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ typedef typename basic_string<T, Allocator>::view_type view_type;
+ return static_cast<view_type>(a) < v;
+ }
template <typename T, typename Allocator>
@@ -3843,6 +3943,28 @@ namespace eastl
{
return p < a;
}
+
+
+ template <typename T, typename Allocator>
+ inline bool operator>(const typename basic_string<T, Allocator>::view_type v, const basic_string<T, Allocator>& b)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ return b < v;
+ }
+
+
+ template <typename T, typename Allocator>
+ inline bool operator>(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::view_type v)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ return v < a;
+ }
template <typename T, typename Allocator>
@@ -3864,6 +3986,28 @@ namespace eastl
{
return !(p < a);
}
+
+
+ template <typename T, typename Allocator>
+ inline bool operator<=(const typename basic_string<T, Allocator>::view_type v, const basic_string<T, Allocator>& b)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ return !(b < v);
+ }
+
+
+ template <typename T, typename Allocator>
+ inline bool operator<=(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::view_type v)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ return !(v < a);
+ }
template <typename T, typename Allocator>
@@ -3885,7 +4029,29 @@ namespace eastl
{
return !(a < p);
}
+
+
+ template <typename T, typename Allocator>
+ inline bool operator>=(const typename basic_string<T, Allocator>::view_type v, const basic_string<T, Allocator>& b)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ return !(v < b);
+ }
+
+
+ template <typename T, typename Allocator>
+ inline bool operator>=(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::view_type v)
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+ return !(a < v);
+ }
+#endif
template <typename T, typename Allocator>
inline void swap(basic_string<T, Allocator>& a, basic_string<T, Allocator>& b)
@@ -4055,7 +4221,12 @@ namespace eastl
/// http://en.cppreference.com/w/cpp/string/basic_string/operator%22%22s
///
#if EASTL_USER_LITERALS_ENABLED && EASTL_INLINE_NAMESPACES_ENABLED
- EA_DISABLE_VC_WARNING(4455) // disable warning C4455: literal suffix identifiers that do not start with an underscore are reserved
+ // Disabling the Clang/GCC/MSVC warning about using user
+ // defined literals without a leading '_' as they are reserved
+ // for standard libary usage.
+ EA_DISABLE_VC_WARNING(4455)
+ EA_DISABLE_CLANG_WARNING(-Wuser-defined-literals)
+ EA_DISABLE_GCC_WARNING(-Wliteral-suffix)
inline namespace literals
{
inline namespace string_literals
@@ -4071,7 +4242,9 @@ namespace eastl
#endif
}
}
- EA_RESTORE_VC_WARNING() // warning: 4455
+ EA_RESTORE_GCC_WARNING() // -Wliteral-suffix
+ EA_RESTORE_CLANG_WARNING() // -Wuser-defined-literals
+ EA_RESTORE_VC_WARNING() // warning: 4455
#endif
@@ -4079,17 +4252,40 @@ namespace eastl
///
/// https://en.cppreference.com/w/cpp/string/basic_string/erase2
template <class CharT, class Allocator, class U>
- void erase(basic_string<CharT, Allocator>& c, const U& value)
+ typename basic_string<CharT, Allocator>::size_type erase(basic_string<CharT, Allocator>& c, const U& value)
{
// Erases all elements that compare equal to value from the container.
- c.erase(eastl::remove(c.begin(), c.end(), value), c.end());
+ auto origEnd = c.end();
+ auto newEnd = eastl::remove(c.begin(), origEnd, value);
+ auto numRemoved = eastl::distance(newEnd, origEnd);
+ c.erase(newEnd, origEnd);
+
+ // Note: This is technically a lossy conversion when size_type
+ // is 32bits and ptrdiff_t is 64bits (could happen on 64bit
+ // systems when EASTL_SIZE_T_32BIT is set). In practice this
+ // is fine because if EASTL_SIZE_T_32BIT is set then the
+ // string should not have more characters than fit in a
+ // uint32_t and so the distance here should fit in a
+ // size_type.
+ return static_cast<typename basic_string<CharT, Allocator>::size_type>(numRemoved);
}
template <class CharT, class Allocator, class Predicate>
- void erase_if(basic_string<CharT, Allocator>& c, Predicate predicate)
+ typename basic_string<CharT, Allocator>::size_type erase_if(basic_string<CharT, Allocator>& c, Predicate predicate)
{
// Erases all elements that satisfy the predicate pred from the container.
- c.erase(eastl::remove_if(c.begin(), c.end(), predicate), c.end());
+ auto origEnd = c.end();
+ auto newEnd = eastl::remove_if(c.begin(), origEnd, predicate);
+ auto numRemoved = eastl::distance(newEnd, origEnd);
+ c.erase(newEnd, origEnd);
+ // Note: This is technically a lossy conversion when size_type
+ // is 32bits and ptrdiff_t is 64bits (could happen on 64bit
+ // systems when EASTL_SIZE_T_32BIT is set). In practice this
+ // is fine because if EASTL_SIZE_T_32BIT is set then the
+ // string should not have more characters than fit in a
+ // uint32_t and so the distance here should fit in a
+ // size_type.
+ return static_cast<typename basic_string<CharT, Allocator>::size_type>(numRemoved);
}
} // namespace eastl
diff --git a/EASTL/include/EASTL/string_view.h b/EASTL/include/EASTL/string_view.h
index 54452a3..f600e50 100644
--- a/EASTL/include/EASTL/string_view.h
+++ b/EASTL/include/EASTL/string_view.h
@@ -451,64 +451,268 @@ namespace eastl
// global operators
+ // Disabling symmetric comparisons that require conversions, since they are causing an internal compiler error
+ // when compiled using MSVC when certain flags are enabled (/Zi /O2 /Zc:inline)
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator==(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return (lhs.size() == rhs.size()) && (lhs.compare(rhs) == 0);
+ // }
+ //
+ // // type_identity_t is used in this context to forcefully trigger conversion operators towards basic_string_view.
+ // // Mostly we want basic_string::operator basic_string_view() to kick-in to be able to compare strings and string_views.
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator==(type_identity_t<basic_string_view<CharT>> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return (lhs.size() == rhs.size()) && (lhs.compare(rhs) == 0);
+ // }
+
template <class CharT>
- inline EA_CONSTEXPR bool operator==(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ inline EA_CONSTEXPR bool operator==(basic_string_view<CharT> lhs, type_identity_t<basic_string_view<CharT>> rhs) EA_NOEXCEPT
{
return (lhs.size() == rhs.size()) && (lhs.compare(rhs) == 0);
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <class CharT>
- inline EA_CONSTEXPR bool operator==(decay_t<basic_string_view<CharT>> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ inline EA_CONSTEXPR auto operator<=>(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
{
- return (lhs.size() == rhs.size()) && (lhs.compare(rhs) == 0);
+ return static_cast<std::weak_ordering>(lhs.compare(rhs) <=> 0);
}
template <class CharT>
- inline EA_CONSTEXPR bool operator==(basic_string_view<CharT> lhs, decay_t<basic_string_view<CharT>> rhs) EA_NOEXCEPT
+ inline EA_CONSTEXPR auto operator<=>(basic_string_view<CharT> lhs, typename basic_string_view<CharT>::const_pointer rhs) EA_NOEXCEPT
{
- return (lhs.size() == rhs.size()) && (lhs.compare(rhs) == 0);
+ typedef basic_string_view<CharT> view_type;
+ return static_cast<std::weak_ordering>(lhs <=> static_cast<view_type>(rhs));
}
+#else
template <class CharT>
- inline EA_CONSTEXPR bool operator==(decay_t<basic_string_view<CharT>> lhs, decay_t<basic_string_view<CharT>> rhs) EA_NOEXCEPT
+ inline EA_CONSTEXPR bool operator==(typename basic_string_view<CharT>::const_pointer lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
{
- return (lhs.size() == rhs.size()) && (lhs.compare(rhs) == 0);
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ typedef basic_string_view<CharT> view_type;
+ return static_cast<view_type>(lhs) == rhs;
+ }
+
+ template <class CharT>
+ inline EA_CONSTEXPR bool operator==(basic_string_view<CharT> lhs, typename basic_string_view<CharT>::const_pointer rhs) EA_NOEXCEPT
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ typedef basic_string_view<CharT> view_type;
+ return lhs == static_cast<view_type>(rhs);
}
+ // Disabling symmetric comparisons that require conversions, since they are causing an internal compiler error
+ // when compiled using MSVC when certain flags are enabled (/Zi /O2 /Zc:inline)
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator!=(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return !(lhs == rhs);
+ // }
+ //
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator!=(type_identity_t<basic_string_view<CharT>> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return !(lhs == rhs);
+ // }
+ template <class CharT>
+ inline EA_CONSTEXPR bool operator!=(basic_string_view<CharT> lhs, type_identity_t<basic_string_view<CharT>> rhs) EA_NOEXCEPT
+ {
+ return !(lhs == rhs);
+ }
+ template <class CharT>
+ inline EA_CONSTEXPR bool operator!=(typename basic_string_view<CharT>::const_pointer lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ return !(lhs == rhs);
+ }
template <class CharT>
- inline EA_CONSTEXPR bool operator!=(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ inline EA_CONSTEXPR bool operator!=(basic_string_view<CharT> lhs, typename basic_string_view<CharT>::const_pointer rhs) EA_NOEXCEPT
{
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
return !(lhs == rhs);
}
+ // Disabling symmetric comparisons that require conversions, since they are causing an internal compiler error
+ // when compiled using MSVC when certain flags are enabled (/Zi /O2 /Zc:inline)
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator<(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return lhs.compare(rhs) < 0;
+ // }
+ //
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator<(type_identity_t<basic_string_view<CharT>> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return lhs.compare(rhs) < 0;
+ // }
+
template <class CharT>
- inline EA_CONSTEXPR bool operator<(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ inline EA_CONSTEXPR bool operator<(basic_string_view<CharT> lhs, type_identity_t<basic_string_view<CharT>> rhs) EA_NOEXCEPT
{
return lhs.compare(rhs) < 0;
}
template <class CharT>
- inline EA_CONSTEXPR bool operator<=(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ inline EA_CONSTEXPR bool operator<(typename basic_string_view<CharT>::const_pointer lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ typedef basic_string_view<CharT> view_type;
+ return static_cast<view_type>(lhs) < rhs;
+ }
+
+ template <class CharT>
+ inline EA_CONSTEXPR bool operator<(basic_string_view<CharT> lhs, typename basic_string_view<CharT>::const_pointer rhs) EA_NOEXCEPT
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ typedef basic_string_view<CharT> view_type;
+ return lhs < static_cast<view_type>(rhs);
+ }
+
+ // Disabling symmetric comparisons that require conversions, since they are causing an internal compiler error
+ // when compiled using MSVC when certain flags are enabled (/Zi /O2 /Zc:inline)
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator<=(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return !(rhs < lhs);
+ // }
+ //
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator<=(type_identity_t<basic_string_view<CharT>> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return !(rhs < lhs);
+ // }
+
+ template <class CharT>
+ inline EA_CONSTEXPR bool operator<=(basic_string_view<CharT> lhs, type_identity_t<basic_string_view<CharT>> rhs) EA_NOEXCEPT
+ {
+ return !(rhs < lhs);
+ }
+
+ template <class CharT>
+ inline EA_CONSTEXPR bool operator<=(typename basic_string_view<CharT>::const_pointer lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
{
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
return !(rhs < lhs);
}
template <class CharT>
- inline EA_CONSTEXPR bool operator>(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ inline EA_CONSTEXPR bool operator<=(basic_string_view<CharT> lhs, typename basic_string_view<CharT>::const_pointer rhs) EA_NOEXCEPT
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ return !(rhs < lhs);
+ }
+
+ // Disabling symmetric comparisons that require conversions, since they are causing an internal compiler error
+ // when compiled using MSVC when certain flags are enabled (/Zi /O2 /Zc:inline)
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator>(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return rhs < lhs;
+ // }
+ //
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator>(type_identity_t<basic_string_view<CharT>> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return rhs < lhs;
+ // }
+
+ template <class CharT>
+ inline EA_CONSTEXPR bool operator>(basic_string_view<CharT> lhs, type_identity_t<basic_string_view<CharT>> rhs) EA_NOEXCEPT
+ {
+ return rhs < lhs;
+ }
+
+ template <class CharT>
+ inline EA_CONSTEXPR bool operator>(typename basic_string_view<CharT>::const_pointer lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ return rhs < lhs;
+ }
+
+ template <class CharT>
+ inline EA_CONSTEXPR bool operator>(basic_string_view<CharT> lhs, typename basic_string_view<CharT>::const_pointer rhs) EA_NOEXCEPT
{
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
return rhs < lhs;
}
+ // Disabling symmetric comparisons that require conversions, since they are causing an internal compiler error
+ // when compiled using MSVC when certain flags are enabled (/Zi /O2 /Zc:inline)
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator>=(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return !(lhs < rhs);
+ // }
+ //
+ // template <class CharT>
+ // inline EA_CONSTEXPR bool operator>=(type_identity_t<basic_string_view<CharT>> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ // {
+ // return !(lhs < rhs);
+ // }
+
+ template <class CharT>
+ inline EA_CONSTEXPR bool operator>=(basic_string_view<CharT> lhs, type_identity_t<basic_string_view<CharT>> rhs) EA_NOEXCEPT
+ {
+ return !(lhs < rhs);
+ }
+
template <class CharT>
- inline EA_CONSTEXPR bool operator>=(basic_string_view<CharT> lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
+ inline EA_CONSTEXPR bool operator>=(typename basic_string_view<CharT>::const_pointer lhs, basic_string_view<CharT> rhs) EA_NOEXCEPT
{
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
return !(lhs < rhs);
}
- // string_view / wstring_view
+ template <class CharT>
+ inline EA_CONSTEXPR bool operator>=(basic_string_view<CharT> lhs, typename basic_string_view<CharT>::const_pointer rhs) EA_NOEXCEPT
+ {
+ // Workaround for basic_string_view comparisons that require conversions,
+ // since they are causing an internal compiler error when compiled using
+ // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline).
+
+ return !(lhs < rhs);
+ }
+#endif
+ // string_view / wstring_view
typedef basic_string_view<char> string_view;
typedef basic_string_view<wchar_t> wstring_view;
@@ -599,7 +803,13 @@ namespace eastl
#if EASTL_USER_LITERALS_ENABLED && EASTL_INLINE_NAMESPACES_ENABLED
- EA_DISABLE_VC_WARNING(4455) // disable warning C4455: literal suffix identifiers that do not start with an underscore are reserved
+ // Disabling the Clang/GCC/MSVC warning about using user
+ // defined literals without a leading '_' as they are reserved
+ // for standard libary usage.
+ EA_DISABLE_VC_WARNING(4455)
+ EA_DISABLE_CLANG_WARNING(-Wuser-defined-literals)
+ EA_DISABLE_GCC_WARNING(-Wliteral-suffix)
+
inline namespace literals
{
inline namespace string_view_literals
@@ -609,11 +819,16 @@ namespace eastl
EA_CONSTEXPR inline u32string_view operator "" sv(const char32_t* str, size_t len) EA_NOEXCEPT { return {str, len}; }
EA_CONSTEXPR inline wstring_view operator "" sv(const wchar_t* str, size_t len) EA_NOEXCEPT { return {str, len}; }
+ // We've seen _sv trigger the following warning on clang:
+ // identifier '_sv' is reserved because it starts with '_' at global scope [-Wreserved-identifier]
+ // Temporarily disable the warning until we figure out why it thinks _sv is "at global scope".
+ EA_DISABLE_CLANG_WARNING(-Wreserved-identifier)
// Backwards compatibility.
EA_CONSTEXPR inline string_view operator "" _sv(const char* str, size_t len) EA_NOEXCEPT { return {str, len}; }
EA_CONSTEXPR inline u16string_view operator "" _sv(const char16_t* str, size_t len) EA_NOEXCEPT { return {str, len}; }
EA_CONSTEXPR inline u32string_view operator "" _sv(const char32_t* str, size_t len) EA_NOEXCEPT { return {str, len}; }
EA_CONSTEXPR inline wstring_view operator "" _sv(const wchar_t* str, size_t len) EA_NOEXCEPT { return {str, len}; }
+ EA_RESTORE_CLANG_WARNING() // -Wreserved-identifier
// C++20 char8_t support.
#if EA_CHAR8_UNIQUE
@@ -622,7 +837,10 @@ namespace eastl
#endif
}
}
- EA_RESTORE_VC_WARNING() // warning: 4455
+
+ EA_RESTORE_GCC_WARNING() // -Wliteral-suffix
+ EA_RESTORE_CLANG_WARNING() // -Wuser-defined-literals
+ EA_RESTORE_VC_WARNING() // warning: 4455
#endif
} // namespace eastl
diff --git a/EASTL/include/EASTL/tuple.h b/EASTL/include/EASTL/tuple.h
index cec5115..12460c6 100644
--- a/EASTL/include/EASTL/tuple.h
+++ b/EASTL/include/EASTL/tuple.h
@@ -6,6 +6,7 @@
#define EASTL_TUPLE_H
#include <EASTL/internal/config.h>
+#include <EASTL/compare.h>
#include <EASTL/functional.h>
#include <EASTL/type_traits.h>
#include <EASTL/utility.h>
@@ -199,7 +200,7 @@ namespace Internal
// We shouldn't need this explicit constructor as it should be handled by the template below but OSX clang
// is_constructible type trait incorrectly gives false for is_constructible<T&&, T&&>::value
- explicit TupleLeaf(ValueType&& v) : mValue(eastl::move(v)) {}
+ explicit TupleLeaf(ValueType&& v) : mValue(eastl::forward<ValueType>(v)) {}
template <typename T, typename = typename enable_if<is_constructible<ValueType, T&&>::value>::type>
explicit TupleLeaf(T&& t)
@@ -233,50 +234,6 @@ namespace Internal
ValueType mValue;
};
- // TupleLeaf: Specialize for when ValueType is a reference
- template <size_t I, typename ValueType, bool IsEmpty>
- class TupleLeaf<I, ValueType&, IsEmpty>
- {
- public:
- TupleLeaf(const TupleLeaf&) = default;
- TupleLeaf& operator=(const TupleLeaf&) = delete;
-
- template <typename T, typename = typename enable_if<is_constructible<ValueType, T&&>::value>::type>
- explicit TupleLeaf(T&& t)
- : mValue(eastl::forward<T>(t))
- {
- }
-
- explicit TupleLeaf(ValueType& t) : mValue(t)
- {
- }
-
- template <typename T>
- explicit TupleLeaf(const TupleLeaf<I, T>& t)
- : mValue(t.getInternal())
- {
- }
-
- template <typename T>
- TupleLeaf& operator=(T&& t)
- {
- mValue = eastl::forward<T>(t);
- return *this;
- }
-
- int swap(TupleLeaf& t)
- {
- eastl::Internal::swap(*this, t);
- return 0;
- }
-
- ValueType& getInternal() { return mValue; }
- const ValueType& getInternal() const { return mValue; }
-
- private:
- ValueType& mValue;
- };
-
// TupleLeaf: partial specialization for when we can use the Empty Base Class Optimization
template <size_t I, typename ValueType>
class TupleLeaf<I, ValueType, true> : private ValueType
@@ -609,7 +566,6 @@ namespace Internal
}
};
-
// TupleLess
//
//
@@ -718,6 +674,16 @@ namespace Internal
return TC2::DoCat2(eastl::forward<TupleArg1>(t1), eastl::forward<TupleArg2>(t2));
}
};
+
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename... T1s, typename... T2s, size_t... Is>
+ constexpr auto TupleThreeWay(const tuple<T1s...>& t1, const tuple<T2s...>& t2, index_sequence<Is...> is)
+ {
+ std::common_comparison_category_t<synth_three_way_result<T1s, T2s>...> result = std::strong_ordering::equal;
+ ((result = synth_three_way{}(get<Is>(t1), get<Is>(t2)), result != 0) || ...);
+ return result;
+ }
+#endif
} // namespace Internal
@@ -868,6 +834,13 @@ inline bool operator==(const tuple<T1s...>& t1, const tuple<T2s...>& t2)
return Internal::TupleEqual<sizeof...(T1s)>()(t1, t2);
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+template <typename... T1s, typename... T2s>
+inline constexpr std::common_comparison_category_t<synth_three_way_result<T1s, T2s>...> operator<=>(const tuple<T1s...>& t1, const tuple<T2s...>& t2)
+{
+ return Internal::TupleThreeWay(t1, t2, make_index_sequence<sizeof...(T1s)>{});
+}
+#else
template <typename... T1s, typename... T2s>
inline bool operator<(const tuple<T1s...>& t1, const tuple<T2s...>& t2)
{
@@ -878,7 +851,7 @@ template <typename... T1s, typename... T2s> inline bool operator!=(const tuple<T
template <typename... T1s, typename... T2s> inline bool operator> (const tuple<T1s...>& t1, const tuple<T2s...>& t2) { return t2 < t1; }
template <typename... T1s, typename... T2s> inline bool operator<=(const tuple<T1s...>& t1, const tuple<T2s...>& t2) { return !(t2 < t1); }
template <typename... T1s, typename... T2s> inline bool operator>=(const tuple<T1s...>& t1, const tuple<T2s...>& t2) { return !(t1 < t2); }
-
+#endif
// tuple_cat
//
diff --git a/EASTL/include/EASTL/type_traits.h b/EASTL/include/EASTL/type_traits.h
index 68a388d..73d2216 100644
--- a/EASTL/include/EASTL/type_traits.h
+++ b/EASTL/include/EASTL/type_traits.h
@@ -93,6 +93,8 @@
// is_abstract T is an abstract class.
// is_signed T is a signed integral type.
// is_unsigned T is an unsigned integral type.
+// is_bounded_array T is a type is an array type of known bound
+// is_unbounded_array T is a type is an array type of unknown bound
//
// is_constructible
// is_trivially_constructible
@@ -131,6 +133,7 @@
// remove_cv
// remove_const The member typedef type shall be the same as T except that any top level const-qualifier has been removed. remove_const<const volatile int>::type evaluates to volatile int, whereas remove_const<const int*> is const int*.
// remove_volatile
+// remove_cvref
// add_cv
// add_const
// add_volatile
@@ -177,6 +180,12 @@
// is_nothrow_swappable "
// is_reference_wrapper Found in <EASTL/functional.h>
// remove_reference_wrapper "
+// is_detected Checks if some supplied arguments (Args) respect a constraint (Op).
+// detected_t Check which type we obtain after expanding some arguments (Args) over a constraint (Op).
+// detected_or Checks if some supplied arguments (Args) respect a constraint (Op) and allow to overwrite return type.
+// detected_or_t Equivalent to detected_or<Default, Op, Args...>::type.
+// is_detected_exact Check that the type we obtain after expanding some arguments (Args) over a constraint (Op) is equivalent to Expected.
+// is_detected_convertible Check that the type we obtain after expanding some arguments (Args) over a constraint (Op) is convertible to Expected.
//
// Deprecated pre-C++11 type traits
// has_trivial_constructor The default constructor for T is trivial.
@@ -500,13 +509,8 @@ namespace eastl
struct conjunction<B, Bn...> : conditional<bool(B::value), conjunction<Bn...>, B>::type {};
#if EASTL_VARIABLE_TEMPLATES_ENABLED
- #if EASTL_INLINE_VARIABLE_ENABLED
- template<class... Bn>
- inline constexpr bool conjunction_v = conjunction<Bn...>::value;
- #else
- template<class... Bn>
- static const constexpr bool conjunction_v = conjunction<Bn...>::value;
- #endif
+ template <typename... Bn>
+ EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool conjunction_v = conjunction<Bn...>::value;
#endif
@@ -529,13 +533,8 @@ namespace eastl
struct disjunction<B, Bn...> : conditional<bool(B::value), B, disjunction<Bn...>>::type {};
#if EASTL_VARIABLE_TEMPLATES_ENABLED
- #if EASTL_INLINE_VARIABLE_ENABLED
- template<class... B>
- inline constexpr bool disjunction_v = disjunction<B...>::value;
- #else
- template<class... B>
- static const constexpr bool disjunction_v = disjunction<B...>::value;
- #endif
+ template <typename... B>
+ EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool disjunction_v = disjunction<B...>::value;
#endif
@@ -552,13 +551,8 @@ namespace eastl
struct negation : eastl::bool_constant<!bool(B::value)> {};
#if EASTL_VARIABLE_TEMPLATES_ENABLED
- #if EASTL_INLINE_VARIABLE_ENABLED
- template<class B>
- inline constexpr bool negation_v = negation<B>::value;
- #else
- template<class B>
- static const constexpr bool negation_v = negation<B>::value;
- #endif
+ template <typename B>
+ EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR bool negation_v = negation<B>::value;
#endif
@@ -636,12 +630,8 @@ namespace eastl
#define EASTL_TYPE_TRAIT_is_const_CONFORMANCE 1 // is_const is conforming.
- template <typename T> struct is_const_value : public eastl::false_type{};
- template <typename T> struct is_const_value<const T*> : public eastl::true_type{};
- template <typename T> struct is_const_value<const volatile T*> : public eastl::true_type{};
-
- template <typename T> struct is_const : public eastl::is_const_value<T*>{};
- template <typename T> struct is_const<T&> : public eastl::false_type{}; // Note here that T is const, not the reference to T. So is_const is false. See section 8.3.2p1 of the C++ standard.
+ template <typename T> struct is_const : public eastl::false_type {};
+ template <typename T> struct is_const<const T> : public eastl::true_type {};
#if EASTL_VARIABLE_TEMPLATES_ENABLED
template <class T>
@@ -658,12 +648,8 @@ namespace eastl
#define EASTL_TYPE_TRAIT_is_volatile_CONFORMANCE 1 // is_volatile is conforming.
- template <typename T> struct is_volatile_value : public eastl::false_type{};
- template <typename T> struct is_volatile_value<volatile T*> : public eastl::true_type{};
- template <typename T> struct is_volatile_value<const volatile T*> : public eastl::true_type{};
-
- template <typename T> struct is_volatile : public eastl::is_volatile_value<T*>{};
- template <typename T> struct is_volatile<T&> : public eastl::false_type{}; // Note here that T is volatile, not the reference to T. So is_const is false. See section 8.3.2p1 of the C++ standard.
+ template <typename T> struct is_volatile : public eastl::false_type {};
+ template <typename T> struct is_volatile<volatile T> : public eastl::true_type {};
#if EASTL_VARIABLE_TEMPLATES_ENABLED
template <class T>
@@ -674,15 +660,16 @@ namespace eastl
///////////////////////////////////////////////////////////////////////
// is_reference
//
- // is_reference<T>::value == true if and only if T is a reference type.
+ // is_reference<T>::value == true if and only if T is a reference type (l-value reference or r-value reference).
// This category includes reference to function types.
//
///////////////////////////////////////////////////////////////////////
#define EASTL_TYPE_TRAIT_is_reference_CONFORMANCE 1 // is_reference is conforming; doesn't make mistakes.
- template <typename T> struct is_reference : public eastl::false_type{};
- template <typename T> struct is_reference<T&> : public eastl::true_type{};
+ template <typename T> struct is_reference : public eastl::false_type{};
+ template <typename T> struct is_reference<T&> : public eastl::true_type{};
+ template <typename T> struct is_reference<T&&> : public eastl::true_type{};
#if EASTL_VARIABLE_TEMPLATES_ENABLED
template<typename T>
@@ -700,39 +687,21 @@ namespace eastl
#define EASTL_TYPE_TRAIT_is_function_CONFORMANCE 1 // is_function is conforming.
- template <typename>
+ // afaik, original credit is to Walter Brown who described this implementation at CppCon 2019.
+ // libc++, libstdc++ and MS STL all use similar implementations.
+ // This relies on the fact that only function and reference types can't be const qualified.
+ // Rather than listing an obscene number of specializations for const, volatile, l- and r-value reference,
+ // noexcept and all relevant combinations we take advantage of this fact.
+#ifdef _MSC_VER
+ #pragma warning(push)
+ #pragma warning(disable: 4180) // qualifier applied to function type has no meaning; ignored
+#endif
+ template <typename T>
struct is_function
- : public eastl::false_type {};
-
- #if EA_PLATFORM_PTR_SIZE == 4 && defined(EA_PLATFORM_MICROSOFT) && defined(_MSC_EXTENSIONS)
- // __cdecl specialization
- template <typename ReturnValue, typename... ArgPack>
- struct is_function<ReturnValue __cdecl (ArgPack...)>
- : public eastl::true_type {};
-
- template <typename ReturnValue, typename... ArgPack>
- struct is_function<ReturnValue __cdecl (ArgPack..., ...)> // The second ellipsis handles the case of a function that takes ellipsis, like printf.
- : public eastl::true_type {};
-
- // __stdcall specialization
- template <typename ReturnValue, typename... ArgPack>
- struct is_function<ReturnValue __stdcall (ArgPack...)>
- : public eastl::true_type {};
-
- // When functions use a variable number of arguments, it is the caller that cleans the stack (cf. cdecl).
- //
- // template <typename ReturnValue, typename... ArgPack>
- // struct is_function<ReturnValue __stdcall (ArgPack..., ...)> // The second ellipsis handles the case of a function that takes ellipsis, like printf.
- // : public eastl::true_type {};
- #else
- template <typename ReturnValue, typename... ArgPack>
- struct is_function<ReturnValue (ArgPack...)>
- : public eastl::true_type {};
-
- template <typename ReturnValue, typename... ArgPack>
- struct is_function<ReturnValue (ArgPack..., ...)> // The second ellipsis handles the case of a function that takes ellipsis, like printf.
- : public eastl::true_type {};
- #endif
+ : public eastl::bool_constant<!eastl::is_reference<T>::value && !eastl::is_const<const T>::value>::type {};
+#ifdef _MSC_VER
+ #pragma warning(pop)
+#endif
#if EASTL_VARIABLE_TEMPLATES_ENABLED
template<typename T>
@@ -831,9 +800,11 @@ namespace eastl
//
// The add_reference transformation trait adds a level of indirection
// by reference to the type to which it is applied. For a given type T,
- // add_reference<T>::type is equivalent to T& if is_reference<T>::value == false,
+ // add_reference<T>::type is equivalent to T& if is_lvalue_reference<T>::value == false,
// and T otherwise.
//
+ // Note: due to the reference collapsing rules, if you supply an r-value reference such as T&&, it will collapse to T&.
+ //
///////////////////////////////////////////////////////////////////////
#define EASTL_TYPE_TRAIT_add_reference_CONFORMANCE 1 // add_reference is conforming.
@@ -912,12 +883,16 @@ namespace eastl
#define EASTL_TYPE_TRAIT_add_lvalue_reference_CONFORMANCE 1 // add_lvalue_reference is conforming.
- template <typename T> struct add_lvalue_reference { typedef T& type; }; // If T is an && type then T&& & will be equivalent to T&.
- template <typename T> struct add_lvalue_reference<T&> { typedef T& type; }; // This shouldn't be required for modern compilers, as they recognize that a reference to a reference is still a reference.
- template <> struct add_lvalue_reference<void> { typedef void type; };
- template <> struct add_lvalue_reference<const void> { typedef const void type; };
- template <> struct add_lvalue_reference<volatile void> { typedef volatile void type; };
- template <> struct add_lvalue_reference<const volatile void> { typedef const volatile void type; };
+ namespace internal
+ {
+ template <typename T>
+ auto try_add_lvalue_reference(int)->type_identity<T&>;
+
+ template <typename T>
+ auto try_add_lvalue_reference(...)->type_identity<T>;
+ }
+
+ template <typename T> struct add_lvalue_reference : decltype(internal::try_add_lvalue_reference<T>(0)) {};
#if defined(EA_COMPILER_NO_TEMPLATE_ALIASES)
// To do: define macro.
@@ -947,12 +922,16 @@ namespace eastl
#define EASTL_TYPE_TRAIT_add_rvalue_reference_CONFORMANCE 1
- template <typename T> struct add_rvalue_reference { typedef T&& type; }; // Dinkumware has this as { typedef typename eastl::remove_reference<T>::type&& type; }, but that doesn't seem right to me.
- template <typename T> struct add_rvalue_reference<T&> { typedef T& type; }; // The Standard section 20.7.9.2 specifies that we do this, though it seems like the compiler ought to not require this, as C++11 stipulates that & + && -> &.
- template <> struct add_rvalue_reference<void> { typedef void type; };
- template <> struct add_rvalue_reference<const void> { typedef const void type; };
- template <> struct add_rvalue_reference<volatile void> { typedef volatile void type; };
- template <> struct add_rvalue_reference<const volatile void> { typedef const volatile void type; };
+ namespace internal
+ {
+ template <typename T>
+ auto try_add_rvalue_reference(int)->type_identity<T&&>;
+
+ template <typename T>
+ auto try_add_rvalue_reference(...)->type_identity<T>;
+ }
+
+ template <typename T> struct add_rvalue_reference : decltype(internal::try_add_rvalue_reference<T>(0)) {};
#if defined(EA_COMPILER_NO_TEMPLATE_ALIASES)
// To do: define macro.
@@ -1052,9 +1031,11 @@ namespace eastl
// The following files implement the type traits themselves.
#include <EASTL/internal/type_fundamental.h>
#include <EASTL/internal/type_transformations.h>
+#include <EASTL/internal/type_void_t.h>
#include <EASTL/internal/type_properties.h>
#include <EASTL/internal/type_compound.h>
#include <EASTL/internal/type_pod.h>
+#include <EASTL/internal/type_detected.h>
#endif // Header include guard
diff --git a/EASTL/include/EASTL/unique_ptr.h b/EASTL/include/EASTL/unique_ptr.h
index 562e2c4..195cc42 100644
--- a/EASTL/include/EASTL/unique_ptr.h
+++ b/EASTL/include/EASTL/unique_ptr.h
@@ -88,6 +88,7 @@ namespace eastl
template <typename T, typename Deleter = eastl::default_delete<T> >
class unique_ptr
{
+ static_assert(!is_rvalue_reference<Deleter>::value, "The supplied Deleter cannot be a r-value reference.");
public:
typedef Deleter deleter_type;
typedef T element_type;
@@ -130,7 +131,7 @@ namespace eastl
/// Example usage:
/// eastl::smart_ptr_deleter<int> del;
/// unique_ptr<int> ptr(new int(3), del);
- unique_ptr(pointer pValue, typename eastl::conditional<eastl::is_reference<deleter_type>::value, deleter_type, typename eastl::add_lvalue_reference<const deleter_type>::type>::type deleter) EA_NOEXCEPT
+ unique_ptr(pointer pValue, typename eastl::conditional<eastl::is_lvalue_reference<deleter_type>::value, deleter_type, typename eastl::add_lvalue_reference<const deleter_type>::type>::type deleter) EA_NOEXCEPT
: mPair(pValue, deleter) {}
/// unique_ptr
@@ -140,7 +141,7 @@ namespace eastl
unique_ptr(pointer pValue, typename eastl::remove_reference<deleter_type>::type&& deleter) EA_NOEXCEPT
: mPair(pValue, eastl::move(deleter))
{
- static_assert(!eastl::is_reference<deleter_type>::value, "deleter_type reference refers to an rvalue deleter. The reference will probably become invalid before used. Change the deleter_type to not be a reference or construct with permanent deleter.");
+ static_assert(!eastl::is_lvalue_reference<deleter_type>::value, "deleter_type reference refers to an rvalue deleter. The reference will probably become invalid before used. Change the deleter_type to not be a reference or construct with permanent deleter.");
}
/// unique_ptr
@@ -157,7 +158,7 @@ namespace eastl
/// unique_ptr<int> ptr(new int(3));
/// unique_ptr<int> newPtr = eastl::move(ptr);
template <typename U, typename E>
- unique_ptr(unique_ptr<U, E>&& u, typename enable_if<!is_array<U>::value && is_convertible<typename unique_ptr<U, E>::pointer, pointer>::value && is_convertible<E, deleter_type>::value && (is_same<deleter_type, E>::value || !is_reference<deleter_type>::value)>::type* = 0) EA_NOEXCEPT
+ unique_ptr(unique_ptr<U, E>&& u, typename enable_if<!is_array<U>::value && is_convertible<typename unique_ptr<U, E>::pointer, pointer>::value && is_convertible<E, deleter_type>::value && (is_same<deleter_type, E>::value || !is_lvalue_reference<deleter_type>::value)>::type* = 0) EA_NOEXCEPT
: mPair(u.release(), eastl::forward<E>(u.get_deleter())) {}
/// unique_ptr
@@ -383,7 +384,7 @@ namespace eastl
}
template <typename P>
- unique_ptr(P pArray, typename eastl::conditional<eastl::is_reference<deleter_type>::value, deleter_type,
+ unique_ptr(P pArray, typename eastl::conditional<eastl::is_lvalue_reference<deleter_type>::value, deleter_type,
typename eastl::add_lvalue_reference<const deleter_type>::type>::type deleter,
typename eastl::enable_if<Internal::is_array_cv_convertible<P, pointer>::value>::type* = 0) EA_NOEXCEPT
: mPair(pArray, deleter) {}
@@ -392,7 +393,7 @@ namespace eastl
unique_ptr(P pArray, typename eastl::remove_reference<deleter_type>::type&& deleter, eastl::enable_if_t<Internal::is_array_cv_convertible<P, pointer>::value>* = 0) EA_NOEXCEPT
: mPair(pArray, eastl::move(deleter))
{
- static_assert(!eastl::is_reference<deleter_type>::value, "deleter_type reference refers to an rvalue deleter. The reference will probably become invalid before used. Change the deleter_type to not be a reference or construct with permanent deleter.");
+ static_assert(!eastl::is_lvalue_reference<deleter_type>::value, "deleter_type reference refers to an rvalue deleter. The reference will probably become invalid before used. Change the deleter_type to not be a reference or construct with permanent deleter.");
}
unique_ptr(this_type&& x) EA_NOEXCEPT
@@ -401,7 +402,7 @@ namespace eastl
template <typename U, typename E>
unique_ptr(unique_ptr<U, E>&& u, typename enable_if<Internal::is_safe_array_conversion<T, pointer, U, typename unique_ptr<U, E>::pointer>::value &&
eastl::is_convertible<E, deleter_type>::value &&
- (!eastl::is_reference<deleter_type>::value || eastl::is_same<E, deleter_type>::value)>::type* = 0) EA_NOEXCEPT
+ (!eastl::is_lvalue_reference<deleter_type>::value || eastl::is_same<E, deleter_type>::value)>::type* = 0) EA_NOEXCEPT
: mPair(u.release(), eastl::forward<E>(u.get_deleter())) {}
this_type& operator=(this_type&& x) EA_NOEXCEPT
@@ -535,27 +536,12 @@ namespace eastl
///
/// auto pArray = make_unique<Test[]>(4);
///
- namespace Internal
- {
- template <typename T>
- struct unique_type
- { typedef unique_ptr<T> unique_type_single; };
-
- template <typename T>
- struct unique_type<T[]>
- { typedef unique_ptr<T[]> unique_type_unbounded_array; };
-
- template <typename T, size_t N>
- struct unique_type<T[N]>
- { typedef void unique_type_bounded_array; };
- }
-
template <typename T, typename... Args>
- inline typename Internal::unique_type<T>::unique_type_single make_unique(Args&&... args)
+ inline typename eastl::enable_if<!eastl::is_array<T>::value, eastl::unique_ptr<T>>::type make_unique(Args&&... args)
{ return unique_ptr<T>(new T(eastl::forward<Args>(args)...)); }
template <typename T>
- inline typename Internal::unique_type<T>::unique_type_unbounded_array make_unique(size_t n)
+ inline typename eastl::enable_if<eastl::is_unbounded_array<T>::value, eastl::unique_ptr<T>>::type make_unique(size_t n)
{
typedef typename eastl::remove_extent<T>::type TBase;
return unique_ptr<T>(new TBase[n]);
@@ -563,7 +549,7 @@ namespace eastl
// It's not possible to create a unique_ptr for arrays of a known bound (e.g. int[4] as opposed to int[]).
template <typename T, typename... Args>
- typename Internal::unique_type<T>::unique_type_bounded_array
+ typename eastl::enable_if<eastl::is_bounded_array<T>::value>::type
make_unique(Args&&...) = delete;
@@ -595,12 +581,20 @@ namespace eastl
{
return (a.get() == b.get());
}
-
+ #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T1, typename D1, typename T2, typename D2>
+ requires std::three_way_comparable_with<typename unique_ptr<T1, D1>::pointer, typename unique_ptr<T2, D2>::pointer>
+ inline std::compare_three_way_result_t<typename unique_ptr<T1, D1>::pointer, typename unique_ptr<T2, D2>::pointer> operator<=>(const unique_ptr<T1, D1>& a, const unique_ptr<T2, D2>& b)
+ {
+ return a.get() <=> b.get();
+ }
+ #else
template <typename T1, typename D1, typename T2, typename D2>
inline bool operator!=(const unique_ptr<T1, D1>& a, const unique_ptr<T2, D2>& b)
{
return !(a.get() == b.get());
}
+ #endif
/// Returns which unique_ptr is 'less' than the other. Useful when storing
/// sorted containers of unique_ptr objects.
@@ -645,6 +639,14 @@ namespace eastl
return !a;
}
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T, typename D>
+ requires std::three_way_comparable_with<typename unique_ptr<T, D>::pointer, std::nullptr_t>
+ inline std::compare_three_way_result_t<typename unique_ptr<T, D>::pointer, std::nullptr_t> operator<=>(const unique_ptr<T, D>& a, std::nullptr_t)
+ {
+ return a.get() <=> nullptr;
+ }
+#else
template <typename T, typename D>
inline bool operator==(std::nullptr_t, const unique_ptr<T, D>& a) EA_NOEXCEPT
{
@@ -662,6 +664,7 @@ namespace eastl
{
return static_cast<bool>(a);
}
+#endif
template <typename T, typename D>
inline bool operator<(const unique_ptr<T, D>& a, std::nullptr_t)
diff --git a/EASTL/include/EASTL/utility.h b/EASTL/include/EASTL/utility.h
index cc546fb..1e6b922 100644
--- a/EASTL/include/EASTL/utility.h
+++ b/EASTL/include/EASTL/utility.h
@@ -10,6 +10,8 @@
#include <EASTL/internal/config.h>
#include <EASTL/type_traits.h>
#include <EASTL/iterator.h>
+#include <EASTL/numeric_limits.h>
+#include <EASTL/compare.h>
#include <EASTL/internal/functional_base.h>
#include <EASTL/internal/move_help.h>
#include <EABase/eahave.h>
@@ -352,6 +354,90 @@ namespace eastl
}
+ #if defined(EA_COMPILER_CPP20_ENABLED)
+ ///////////////////////////////////////////////////////////////////////
+ /// Safe Integral Comparisons
+ ///
+ template <typename T, typename U>
+ EA_CONSTEXPR bool cmp_equal(const T x, const U y) EA_NOEXCEPT
+ {
+ // Assert types are not chars, bools, etc.
+ static_assert(eastl::is_integral_v<T> && !eastl::is_same_v<eastl::remove_cv_t<T>, bool> && !eastl::is_same_v<eastl::remove_cv_t<T>, char>);
+ static_assert(eastl::is_integral_v<U> && !eastl::is_same_v<eastl::remove_cv_t<U>, bool> && !eastl::is_same_v<eastl::remove_cv_t<U>, char>);
+
+ using UT = eastl::make_unsigned_t<T>;
+ using UU = eastl::make_unsigned_t<U>;
+
+ if constexpr (eastl::is_signed_v<T> == eastl::is_signed_v<U>)
+ {
+ return x == y;
+ }
+ else if (eastl::is_signed_v<T>)
+ {
+ return (x < 0) ? false : UT(x) == y;
+ }
+ else
+ {
+ return (y < 0) ? false : x == UU(y);
+ }
+ }
+
+
+ template <typename T, typename U>
+ EA_CONSTEXPR bool cmp_not_equal(const T x, const U y) EA_NOEXCEPT
+ { return !eastl::cmp_equal(x, y); }
+
+
+ template <typename T, typename U>
+ EA_CONSTEXPR bool cmp_less(const T x, const U y) EA_NOEXCEPT
+ {
+ static_assert(eastl::is_integral_v<T> && !eastl::is_same_v<eastl::remove_cv_t<T>, bool> && !eastl::is_same_v<eastl::remove_cv_t<T>, char>);
+ static_assert(eastl::is_integral_v<U> && !eastl::is_same_v<eastl::remove_cv_t<U>, bool> && !eastl::is_same_v<eastl::remove_cv_t<U>, char>);
+
+ using UT = eastl::make_unsigned_t<T>;
+ using UU = eastl::make_unsigned_t<U>;
+
+ if constexpr (eastl::is_signed_v<T> == eastl::is_signed_v<U>)
+ {
+ return x < y;
+ }
+ else if (eastl::is_signed_v<T>)
+ {
+ return (x < 0) ? true : UT(x) < y;
+ }
+ else
+ {
+ return (y < 0) ? false : x < UU(y);
+ }
+ }
+
+
+ template <typename T, typename U>
+ EA_CONSTEXPR bool cmp_greater(const T x, const U y) EA_NOEXCEPT
+ { return eastl::cmp_less(y, x); }
+
+
+ template <typename T, typename U>
+ EA_CONSTEXPR bool cmp_less_equal(const T x, const U y) EA_NOEXCEPT
+ { return !eastl::cmp_greater(x, y); }
+
+
+ template <typename T, typename U>
+ EA_CONSTEXPR bool cmp_greater_equal(const T x, const U y) EA_NOEXCEPT
+ { return !eastl::cmp_less(x, y); }
+
+
+ template <typename T, typename U>
+ EA_CONSTEXPR bool in_range(const U x) EA_NOEXCEPT
+ {
+ static_assert(eastl::is_integral_v<T> && !eastl::is_same_v<eastl::remove_cv_t<T>, bool> && !eastl::is_same_v<eastl::remove_cv_t<T>, char>);
+ static_assert(eastl::is_integral_v<U> && !eastl::is_same_v<eastl::remove_cv_t<U>, bool> && !eastl::is_same_v<eastl::remove_cv_t<U>, char>);
+
+ return eastl::cmp_greater_equal(x, eastl::numeric_limits<T>::min()) && eastl::cmp_less_equal(x, eastl::numeric_limits<T>::max());
+ }
+ #endif
+
+
///////////////////////////////////////////////////////////////////////
/// pair_first_construct
///
@@ -360,7 +446,7 @@ namespace eastl
struct pair_first_construct_t {};
EA_CONSTEXPR pair_first_construct_t pair_first_construct = pair_first_construct_t();
-
+
///////////////////////////////////////////////////////////////////////
/// pair
///
@@ -413,7 +499,7 @@ namespace eastl
//
// See bug submitted to LLVM for more details.
// https://bugs.llvm.org/show_bug.cgi?id=38374
- #if !defined(EA_COMPILER_CLANG)
+ #if !defined(__clang__)
template<typename T>
using single_pair_ctor_sfinae = eastl::enable_if_t<eastl::is_default_constructible_v<T>>;
#else
@@ -630,7 +716,17 @@ namespace eastl
return ((a.first == b.first) && (a.second == b.second));
}
-
+ #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T1, typename T2>
+ EA_CONSTEXPR inline std::common_comparison_category_t<synth_three_way_result<T1>, synth_three_way_result<T2>> operator<=>(const pair<T1, T2>& a, const pair<T1, T2>& b)
+ {
+ if (auto result = synth_three_way{}(a.first, b.first); result != 0)
+ {
+ return result;
+ }
+ return synth_three_way{}(a.second, b.second);
+ }
+ #else
template <typename T1, typename T2>
EA_CPP14_CONSTEXPR inline bool operator<(const pair<T1, T2>& a, const pair<T1, T2>& b)
{
@@ -668,7 +764,7 @@ namespace eastl
{
return !(b < a);
}
-
+ #endif
diff --git a/EASTL/include/EASTL/variant.h b/EASTL/include/EASTL/variant.h
index e59c300..a7af97b 100644
--- a/EASTL/include/EASTL/variant.h
+++ b/EASTL/include/EASTL/variant.h
@@ -10,12 +10,12 @@
//
// As with unions, if a variant holds a value of some object type T, the object
// representation of T is allocated directly within the object representation of
-// the variant itself.
+// the variant itself.
//
// Variant is not allowed to allocate additional (dynamic) memory.
//
// A variant is not permitted to hold references, arrays, or the type void.
-// Empty variants are also ill-formed (variant<monostate> can be used instead).
+// Empty variants are also ill-formed (variant<monostate> can be used instead).
//
// A variant is permitted to hold the same type more than once, and to hold
// differently cv-qualified versions of the same type. As with unions, the
@@ -48,7 +48,7 @@
// * strong exception guarantees as specified (we punted on the assignment problem).
// if an exception is thrown during assignment its undefined behaviour in our implementation.
//
-// Reference:
+// Reference:
// * http://en.cppreference.com/w/cpp/utility/variant
// * https://thenewcpp.wordpress.com/2012/02/15/variadic-templates-part-3-or-how-i-wrote-a-variant-class/
///////////////////////////////////////////////////////////////////////////
@@ -65,6 +65,13 @@
#include <EASTL/initializer_list.h>
#include <EASTL/tuple.h>
#include <EASTL/type_traits.h>
+#include <EASTL/array.h>
+
+#if EASTL_EXCEPTIONS_ENABLED
+ #include <stdexcept>
+ #include <exception>
+#endif
+
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
@@ -83,7 +90,7 @@ namespace eastl
///////////////////////////////////////////////////////////////////////////
// default_construct_if_supported<T>
//
- // Utility class to remove default constructor calls for types that
+ // Utility class to remove default constructor calls for types that
// do not support default construction.
//
// We can remove these utilities when C++17 'constexpr if' is available.
@@ -106,7 +113,7 @@ namespace eastl
///////////////////////////////////////////////////////////////////////////
// destroy_if_supported<T>
//
- // Utility class to remove default constructor calls for types that
+ // Utility class to remove default constructor calls for types that
// do not support default construction.
//
// We can remove these utilities when C++17 'constexpr if' is available.
@@ -129,7 +136,7 @@ namespace eastl
///////////////////////////////////////////////////////////////////////////
// copy_if_supported<T>
//
- // Utility class to remove copy constructor calls for types that
+ // Utility class to remove copy constructor calls for types that
// do not support copying.
//
// We can remove these utilities when C++17 'constexpr if' is available.
@@ -152,7 +159,7 @@ namespace eastl
///////////////////////////////////////////////////////////////////////////
// move_if_supported<T>
//
- // Utility class to remove move constructor calls for types that
+ // Utility class to remove move constructor calls for types that
// do not support moves.
//
// We can remove these utilities when C++17 'constexpr if' is available.
@@ -171,7 +178,7 @@ namespace eastl
{
static void call(T* pThis, T* pOther) {} // intentionally blank
};
- } // namespace internal
+ } // namespace internal
///////////////////////////////////////////////////////////////////////////
@@ -217,11 +224,15 @@ namespace eastl
struct monostate {};
// 20.7.8, monostate relational operators
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ EA_CONSTEXPR std::strong_ordering operator<=>(monostate, monostate) EA_NOEXCEPT { return std::strong_ordering::equal; }
+#else
EA_CONSTEXPR bool operator> (monostate, monostate) EA_NOEXCEPT { return false; }
EA_CONSTEXPR bool operator< (monostate, monostate) EA_NOEXCEPT { return false; }
EA_CONSTEXPR bool operator!=(monostate, monostate) EA_NOEXCEPT { return false; }
EA_CONSTEXPR bool operator<=(monostate, monostate) EA_NOEXCEPT { return true; }
EA_CONSTEXPR bool operator>=(monostate, monostate) EA_NOEXCEPT { return true; }
+#endif
EA_CONSTEXPR bool operator==(monostate, monostate) EA_NOEXCEPT { return true; }
// 20.7.11, hash support
@@ -229,10 +240,10 @@ namespace eastl
template <> struct hash<monostate>
{ size_t operator()(monostate) const { return static_cast<size_t>(-0x42); } };
-
+
///////////////////////////////////////////////////////////////////////////
// variant_storage
- //
+ //
// This is a utility class to simplify the implementation of a storage type
// for a distriminted union. This utility handles the alignment, size
// requirements, and data access required by the variant type.
@@ -318,33 +329,33 @@ namespace eastl
public:
variant_storage()
{
- DoOp(StorageOp::DEFAULT_CONSTRUCT);
+ DoOp(StorageOp::DEFAULT_CONSTRUCT);
}
~variant_storage()
{
- DoOp(StorageOp::DESTROY);
+ DoOp(StorageOp::DESTROY);
}
variant_storage(const variant_storage& other)
{
- DoOp(StorageOp::COPY, other);
+ DoOp(StorageOp::COPY, other);
}
variant_storage(variant_storage&& other)
{
- DoOp(StorageOp::MOVE, other);
+ DoOp(StorageOp::MOVE, other);
}
variant_storage& operator=(const variant_storage& other)
{
- DoOp(StorageOp::COPY, other);
+ DoOp(StorageOp::COPY, other);
return *this;
}
variant_storage& operator=(variant_storage&& other)
{
- DoOp(StorageOp::MOVE, eastl::move(other));
+ DoOp(StorageOp::MOVE, eastl::move(other));
return *this;
}
@@ -353,7 +364,7 @@ namespace eastl
{
// NOTE(rparolin): If this assert fires there is an EASTL problem picking the size of the local buffer which
// variant_storage used to store types. The size selected should be large enough to hold the largest type in
- // the user provided variant type-list.
+ // the user provided variant type-list.
static_assert(sizeof(aligned_storage_impl_t) >= sizeof(T), "T is larger than local buffer size");
using RT = remove_reference_t<T>;
@@ -368,7 +379,7 @@ namespace eastl
{
// NOTE(rparolin): If this assert fires there is an EASTL problem picking the size of the local buffer which
// variant_storage used to store types. The size selected should be large enough to hold the largest type in
- // the user provided variant type-list.
+ // the user provided variant type-list.
static_assert(sizeof(aligned_storage_impl_t) >= sizeof(T), "T is larger than local buffer size");
using RT = remove_reference_t<T>;
@@ -394,7 +405,7 @@ namespace eastl
void destroy()
{
- DoOp(StorageOp::DESTROY);
+ DoOp(StorageOp::DESTROY);
}
};
@@ -426,7 +437,7 @@ namespace eastl
{
// NOTE(rparolin): If this assert fires there is an EASTL problem picking the size of the local buffer which
// variant_storage used to store types. The size selected should be large enough to hold the largest type in
- // the user provided variant type-list.
+ // the user provided variant type-list.
static_assert(sizeof(aligned_storage_impl_t) >= sizeof(T), "T is larger than local buffer size");
new (&mBuffer) remove_reference_t<T>(eastl::forward<Args>(args)...);
@@ -438,7 +449,7 @@ namespace eastl
{
// NOTE(rparolin): If this assert fires there is an EASTL problem picking the size of the local buffer which
// variant_storage used to store types. The size selected should be large enough to hold the largest type in
- // the user provided variant type-list.
+ // the user provided variant type-list.
static_assert(sizeof(aligned_storage_impl_t) >= sizeof(T), "T is larger than local buffer size");
new (&mBuffer) remove_reference_t<T>(il, eastl::forward<Args>(args)...);
@@ -464,7 +475,7 @@ namespace eastl
///////////////////////////////////////////////////////////////////////////
- // 20.7.2, forward-declaration for types that depend on the variant
+ // 20.7.2, forward-declaration for types that depend on the variant
//
template <class... Types>
class variant;
@@ -473,18 +484,19 @@ namespace eastl
///////////////////////////////////////////////////////////////////////////
// 20.7.3, variant_size, variant_size_v helper classes
//
- template <class T> struct variant_size;
+ template <class T> struct variant_size;
template <class T> struct variant_size<const T> : integral_constant<size_t, variant_size<T>::value> {};
template <class T> struct variant_size<volatile T> : integral_constant<size_t, variant_size<T>::value> {};
template <class T> struct variant_size<const volatile T> : integral_constant<size_t, variant_size<T>::value> {};
template <class... Types> struct variant_size<variant<Types...>> : integral_constant<size_t, sizeof...(Types)> {};
// variant_size_v template alias
- template <class T> EA_CONSTEXPR size_t variant_size_v = variant_size<T>::value;
+ template <typename T>
+ EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR size_t variant_size_v = variant_size<T>::value;
///////////////////////////////////////////////////////////////////////////
- // variant_alternative_helper
+ // variant_alternative_helper
//
// This helper does the heavy lifting of traversing the variadic type list
// and retrieving the type at the user provided index.
@@ -508,9 +520,9 @@ namespace eastl
template <size_t I, class... Types> struct variant_alternative<I, variant<Types...>> : variant_alternative_helper<I, Types...> {};
// ISO required cv-qualifer specializations
- template <size_t I, class T> struct variant_alternative<I, const T> : add_cv_t<variant_alternative<I, T>> {};
- template <size_t I, class T> struct variant_alternative<I, volatile T> : add_volatile_t<variant_alternative<I, T>> {};
- template <size_t I, class T> struct variant_alternative<I, const volatile T> : add_cv_t<variant_alternative<I, T>> {};
+ template <size_t I, class T> struct variant_alternative<I, const T> : add_const<typename variant_alternative<I, T>::type> {};
+ template <size_t I, class T> struct variant_alternative<I, volatile T> : add_volatile<typename variant_alternative<I, T>::type> {};
+ template <size_t I, class T> struct variant_alternative<I, const volatile T> : add_cv<typename variant_alternative<I, T>::type> {};
// variant_alternative_t template alias
template <size_t I, class T> using variant_alternative_t = typename variant_alternative<I, T>::type;
@@ -525,7 +537,7 @@ namespace eastl
///////////////////////////////////////////////////////////////////////////
- // get_if
+ // get_if
//
template <size_t I, class... Types>
EA_CONSTEXPR add_pointer_t<variant_alternative_t<I, variant<Types...>>> get_if(variant<Types...>* pv) EA_NOEXCEPT
@@ -559,15 +571,14 @@ namespace eastl
///////////////////////////////////////////////////////////////////////////
- // get
+ // get
//
template <size_t I, class... Types>
EA_CONSTEXPR variant_alternative_t<I, variant<Types...>>& get(variant<Types...>& v)
{
static_assert(I < sizeof...(Types), "get is ill-formed if I is not a valid index in the variant typelist");
using return_type = add_pointer_t<variant_alternative_t<I, variant<Types...>>>;
-
- EASTL_ASSERT(v.index() == I);
+
return *v.mStorage.template get_as<return_type>();
}
@@ -576,8 +587,7 @@ namespace eastl
{
static_assert(I < sizeof...(Types), "get is ill-formed if I is not a valid index in the variant typelist");
using return_type = add_pointer_t<variant_alternative_t<I, variant<Types...>>>;
-
- EASTL_ASSERT(v.index() == I);
+
return eastl::move(*v.mStorage.template get_as<return_type>());
}
@@ -586,8 +596,7 @@ namespace eastl
{
static_assert(I < sizeof...(Types), "get is ill-formed if I is not a valid index in the variant typelist");
using return_type = add_pointer_t<variant_alternative_t<I, variant<Types...>>>;
-
- EASTL_ASSERT(v.index() == I);
+
return *v.mStorage.template get_as<return_type>();
}
@@ -596,8 +605,7 @@ namespace eastl
{
static_assert(I < sizeof...(Types), "get is ill-formed if I is not a valid index in the variant typelist");
using return_type = add_pointer_t<variant_alternative_t<I, variant<Types...>>>;
-
- EASTL_ASSERT(v.index() == I);
+
return eastl::move(*v.mStorage.template get_as<return_type>());
}
@@ -645,7 +653,7 @@ namespace eastl
// 20.7.2, variant
//
template <class... Types>
- class variant
+ class variant
{
static_assert(sizeof...(Types) > 0, "variant must have at least 1 type (empty variants are ill-formed)");
static_assert(disjunction_v<is_void<Types>...> == false, "variant does not allow void as an alternative type");
@@ -661,7 +669,7 @@ namespace eastl
//
variant_index_t mIndex;
variant_storage_t mStorage;
-
+
public:
///////////////////////////////////////////////////////////////////////////
// 20.7.2.1, constructors
@@ -808,10 +816,16 @@ namespace eastl
variant_alternative_t<I, variant>& emplace(Args&&... args)
{
if (!valueless_by_exception())
+ {
mStorage.destroy();
- mIndex = static_cast<variant_index_t>(I);
+ #if EASTL_EXCEPTIONS_ENABLED
+ mIndex = static_cast<variant_index_t>(variant_npos);
+ #endif
+ }
+
mStorage.template set_as<T>(eastl::forward<Args>(args)...);
+ mIndex = static_cast<variant_index_t>(I);
return *reinterpret_cast<T*>(&mStorage.mBuffer);
}
@@ -829,10 +843,16 @@ namespace eastl
variant_alternative_t<I, variant>& emplace(std::initializer_list<U> il, Args&&... args)
{
if (!valueless_by_exception())
+ {
mStorage.destroy();
- mIndex = static_cast<variant_index_t>(I);
+ #if EASTL_EXCEPTIONS_ENABLED
+ mIndex = static_cast<variant_index_t>(variant_npos);
+ #endif
+ }
+
mStorage.template set_as<T>(il, eastl::forward<Args>(args)...);
+ mIndex = static_cast<variant_index_t>(I);
return *reinterpret_cast<T*>(&mStorage.mBuffer);
}
@@ -896,14 +916,29 @@ namespace eastl
///////////////////////////////////////////////////////////////////////////
// 20.7.2.5, value status
//
- EA_CONSTEXPR size_t index() const EA_NOEXCEPT { return valueless_by_exception() ? variant_npos : mIndex; }
- EA_CONSTEXPR bool valueless_by_exception() const EA_NOEXCEPT { return mIndex == variant_npos; }
+ EA_CONSTEXPR size_t index() const EA_NOEXCEPT
+ {
+ #if EASTL_EXCEPTIONS_ENABLED
+ return valueless_by_exception() ? variant_npos : mIndex;
+ #else
+ return mIndex;
+ #endif
+ }
+
+ EA_CONSTEXPR bool valueless_by_exception() const EA_NOEXCEPT
+ {
+ #if EASTL_EXCEPTIONS_ENABLED
+ return mIndex == variant_npos;
+ #else
+ return false;
+ #endif
+ }
///////////////////////////////////////////////////////////////////////////
// 20.7.2.6, swap
//
- void swap(variant& other)
+ void swap(variant& other)
EA_NOEXCEPT(conjunction_v<is_nothrow_move_constructible<Types>..., is_nothrow_swappable<Types>...>)
{
eastl::swap(mIndex, other.mIndex);
@@ -926,12 +961,13 @@ namespace eastl
// 20.7.9, swap
//
template <class... Types>
- void swap(variant<Types...>& lhs, variant<Types...>& rhs)
+ void swap(variant<Types...>& lhs, variant<Types...>& rhs)
EA_NOEXCEPT(EA_NOEXCEPT(lhs.swap(rhs)))
{
lhs.swap(rhs);
}
+
// visit is a bit convoluted, in order to fulfill a few requirements:
// - It must support visiting multiple variants using a single visitor and a single function call. The
// visitor in this case should have one function for each possible combination of types:
@@ -949,149 +985,355 @@ namespace eastl
//
// - It must be declared constexpr
// - It must be constant-time for the case of visiting a single variant
- // - It must allow different return types in the visitor, as long as they are all convertible
//
- // visitor_caller is responsible for the mechanics of visit. Each visitor_caller creates an array of
- // functions which call get<I>() on the variant (where I is the array index), then add the returned reference
- // to a tuple of arguments. The final visitor_caller calls invoke() with the visitor and the unpacked
- // arguments.
+ // - 20.7.7 states that variant visitation requires all combinations of visitors to return the same type.
//
- // This allows us to look up each appropriate get() function in constant time using the variant's index.
- template <typename Visitor, typename Variant, typename... Variants>
- struct visitor_caller
+ // NOTE(mwinkler):
+ // Visit creates an N-Dimensional matrix whereby each dimension is M wide.
+ // Where N == sizeof...(Variants) and M == variant_size_v<Variant>
+ //
+ // variant<int, bool, float> v;
+ // visit(Visitor{}, v, v);
+ //
+ // This creates a 3x3 matrix of potential visitors.
+ // The argument indices into the variants are as follows.
+ // [0, 0], [0, 1], [0, 2]
+ // [1, 0], [1, 1], [1, 2]
+ // [2, 0], [2, 1], [2, 2]
+ //
+ // These indices are compile-time constants but the variants have a runtime index.
+ // Therefore we must instantiate an NxNxN... matrix of function pointers who are
+ // templated on the indices based on their position in the matrix and then
+ // at runtime index into the array to call the correct function pointer that can
+ // get the correct alternatives in the variants.
+ //
+ // There are a couple of ways to do this. We can construct the matrix bottom up or top down.
+ //
+ // Constructing a matrix bottom up would look something as follows.
+ //
+ // make_visitor_matrix_recurse(eastl::index_sequence<>{}, eastl::make_index_sequence<eastl::variant_size_v<eastl::decay_t<Variants>>>{}...);
+ //
+ // make_visitor_matrix_recurse(eastl::index_sequence<Is...>) { return templated function pointer on Is... }
+ //
+ // make_visitor_matrix_recurse(eastl::index_sequence<Is...>, eastl::index_sequence<Js...>, RestIndex... rest)
+ // return make_array(make_visitor_matrix_recurse(eastl::index_sequence<Is..., Js>{}, rest...)...);
+ //
+ // Essentially we construct the matrix bottom up, row by row of indices and return an array of function pointers.
+ // The end result is a NxNxN... array on the stack which can be indexed by each variant in order as follows,
+ // array[v0.index()][v1.index()][vn.index()]();
+ //
+ // The downside with this approach is the massive NxNxN... array that is created on the stack.
+ //
+ // The other approach is to build the matrix top down and use tail recursion to ensure there is only one
+ // N sized array on the stack. The downside here is the extra function calls, but we feel this approach provides
+ // a good balance between performance and memory usage.
+ //
+ // We construct the matrix top down by first creating an N sized array that is indexed by the first variant.
+ // This calls a function that recursively creates another N sized array that is indexed by the second variant.
+ // The recursion continues until we reach the base case which is the last variant. At this point we know
+ // the compile-time value of the N indices needed to get each alternative from each variant to invoke the visitor upon.
+ // Essentially we create a tree of function pointers like so.
+ //
+ //
+ // +------------------------------------------------------------------+
+ // | |
+ // | 0 1 N |
+ // | |
+ // | |
+ // +----+---------------------------+---------------------------------+
+ // | |
+ // | |
+ // | |
+ // | |
+ // | |
+ // +--------------------------+-----------------+ +----+------------------------------------+
+ // | | | |
+ // |0,0 0,1 0,N| |1,0 1,1 1,N|
+ // | | | |
+ // | | | |
+ // +--------------------------------------------+ +-----------------------------------------+
+ //
+ // Essentially each call creates a N sized array of function pointers that is the concatention of the indices known so far
+ // and the index of itself in the array whereby the leaf function pointer does the final invoke of the visitor.
+ //
+
+ // Since decltype() is not one of the contexts where an overloaded function can be used without arguments;
+ // We use this function to deduce the function pointer types.
+ // We also return an eastl::array<> since we cannot return C-style arrays as value types.
+ template <typename T>
+ static EA_CONSTEXPR array<decay_t<T>, 1> make_visitor_array(T&& t)
{
- // @visitor, @variant and @variants are all the arguments to the initial visit() function.
- // @args is the tuple of arguments which have been retrieved by any previous visitor_callers.
- //
- // The two unnamed index_sequence parameters let us deduce two different sets of indices
- // as parameter packs - one for the arguments and one for the array of call_next functions.
- // This is necessary so we can create the constexpr array of functions which call
- // get<I>(variant) based on the array index, and so we can unpack the final of arguments by
- // calling get<I>(args) for each index in args.
- template <size_t I, typename ArgsTuple, size_t... ArgsIndices, size_t... ArrayIndices>
- static decltype(auto) EA_CONSTEXPR call_next(Visitor&& visitor,
- index_sequence<ArgsIndices...>,
- index_sequence<ArrayIndices...>,
- ArgsTuple&& args,
- Variant&& variant,
- Variants&&... variants)
- {
- // Call the appropriate get() function on the variant, and pack the result into a new tuple along with
- // all of the previous arguments. Then call the next visitor_caller with the new argument added,
- // and the current variant removed.
- return visitor_caller<Visitor, Variants...>::call(
- eastl::forward<Visitor>(visitor),
- index_sequence<ArgsIndices..., sizeof...(ArgsIndices)>(),
- index_sequence<ArrayIndices...>(),
- eastl::make_tuple(get<ArgsIndices>(eastl::forward<ArgsTuple>(args))..., get<I>(eastl::forward<Variant>(variant))),
- eastl::forward<Variants>(variants)...
- );
+ return { { eastl::forward<T>(t) } };
+ }
+
+ template <typename T, typename... Ts>
+ static EA_CONSTEXPR array<decay_t<T>, sizeof...(Ts) + 1> make_visitor_array(T&& t, Ts&&... ts)
+ {
+ static_assert(conjunction_v<is_same<decay_t<T>, decay_t<Ts>>...>, "`visit` variant visitation requires that all visitors have the same return type!");
+
+ return { { eastl::forward<T>(t), eastl::forward<Ts>(ts)... } };
+ }
+
+
+ template <size_t N, typename Variant, typename... Variants, eastl::enable_if_t<N == 0, int> = 0>
+ static EA_CONSTEXPR decltype(auto) get_variant_n(Variant&& variant, Variants&&... variants)
+ {
+ return eastl::forward<Variant>(variant);
+ }
+
+ template <size_t N, typename Variant, typename... Variants, eastl::enable_if_t<N != 0, int> = 0>
+ static EA_CONSTEXPR decltype(auto) get_variant_n(Variant&& variant, Variants&&... variants)
+ {
+ return get_variant_n<N - 1>(eastl::forward<Variants>(variants)...);
+ }
+
+
+ template <typename Visitor, typename Index, typename Array, typename... Variants>
+ static EA_CONSTEXPR decltype(auto) call_visitor_at_index(Array&& array, Index index, Visitor&& visitor, Variants&&... variants)
+ {
+ return array[static_cast<typename Array::size_type>(index)](eastl::forward<Visitor>(visitor), eastl::forward<Variants>(variants)...);
+ }
+
+ template <size_t VariantsIndex, typename Visitor, typename Array, typename... Variants>
+ static EA_CONSTEXPR decltype(auto) call_visitor_at(Array&& array, Visitor&& visitor, Variants&&... variants)
+ {
+ return call_visitor_at_index(eastl::forward<Array>(array),
+ get_variant_n<VariantsIndex>(eastl::forward<Variants>(variants)...).index(),
+ eastl::forward<Visitor>(visitor),
+ eastl::forward<Variants>(variants)...);
+ }
+
+
+ // abstracts calling visit on 2 or more variants
+ template <typename VariantIndexSequence, typename Visitor, typename... Variants>
+ struct visitor_caller_n;
+
+ template <typename Visitor, typename... Variants, size_t... VariantIndices>
+ struct visitor_caller_n<index_sequence<VariantIndices...>, Visitor, Variants...>
+ {
+ using return_type = invoke_result_t<Visitor, variant_alternative_t<0, remove_reference_t<Variants>>...>;
+
+ template <size_t... VariantArgIndices>
+ static EA_CONSTEXPR return_type invoke_visitor_leaf(Visitor&& visitor, Variants&&... variants)
+ {
+ return eastl::invoke(eastl::forward<Visitor>(visitor),
+ eastl::get<VariantArgIndices>(eastl::forward<Variants>(variants))...);
+ }
+
+ template <size_t... VariantArgIndices>
+ static EA_CONSTEXPR auto make_invoke_visitor_leaf(index_sequence<VariantArgIndices...>)
+ {
+ return &invoke_visitor_leaf<VariantArgIndices...>;
}
- // Arguments are the same as for call_next (see above).
- template <typename ArgsTuple, size_t... ArgsIndices, size_t... ArrayIndices>
- static decltype(auto) EA_CPP14_CONSTEXPR call(Visitor&& visitor,
- index_sequence<ArgsIndices...>,
- index_sequence<ArrayIndices...>,
- ArgsTuple&& args,
- Variant&& variant,
- Variants&&... variants)
- {
- // Deduce the type of the inner array of call_next functions
- using return_type = decltype(call_next<0>(
- eastl::forward<Visitor>(visitor),
- index_sequence<ArgsIndices...>(),
- index_sequence<ArrayIndices...>(),
- eastl::forward<ArgsTuple>(args),
- eastl::forward<Variant>(variant),
- eastl::forward<Variants>(variants)...)
- );
-
- using next_type = return_type (*)(
- Visitor&&,
- index_sequence<ArgsIndices...>,
- index_sequence<ArrayIndices...>,
- ArgsTuple&&,
- Variant&&,
- Variants&&...
- );
-
- // Create an array of call_next<0>, call_next<1>, ... , call_next<N - 1>
- // where N = variant_size<Variant>.
- EA_CPP14_CONSTEXPR next_type next[] = { static_cast<next_type>(call_next<ArrayIndices>)... };
-
- // call_next() with the correct index for the variant.
- return next[variant.index()](
- eastl::forward<Visitor>(visitor),
- index_sequence<ArgsIndices...>(),
- index_sequence<ArrayIndices...>(),
- eastl::forward<ArgsTuple>(args),
- eastl::forward<Variant>(variant),
- eastl::forward<Variants>(variants)...
- );
+
+ template <size_t... VariantArgIndices>
+ static EA_CONSTEXPR return_type invoke_visitor_recurse(Visitor&& visitor, Variants&&... variants)
+ {
+ return call(index_sequence<VariantArgIndices...>{},
+ eastl::forward<Visitor>(visitor),
+ eastl::forward<Variants>(variants)...);
}
+
+ template <size_t... VariantArgIndices>
+ static EA_CONSTEXPR auto make_invoke_visitor_recurse(index_sequence<VariantArgIndices...>)
+ {
+ return &invoke_visitor_recurse<VariantArgIndices...>;
+ }
+
+
+ template <typename VariantArgIndexSequence, enable_if_t<internal::index_sequence_size_v<VariantArgIndexSequence> + 1 == sizeof...(Variants), int> = 0>
+ static EA_CPP14_CONSTEXPR decltype(auto) call(VariantArgIndexSequence, Visitor&& visitor, Variants&&... variants)
+ {
+ EA_CPP14_CONSTEXPR auto callers = make_visitor_array(make_invoke_visitor_leaf(meta::double_pack_expansion_t<VariantArgIndexSequence, VariantIndices>{})...);
+
+ return call_visitor_at<internal::index_sequence_size_v<VariantArgIndexSequence>>(eastl::move(callers),
+ eastl::forward<Visitor>(visitor),
+ eastl::forward<Variants>(variants)...);
+ }
+
+ template <typename VariantArgIndexSequence, enable_if_t<internal::index_sequence_size_v<VariantArgIndexSequence> + 1 != sizeof...(Variants), int> = 0>
+ static EA_CPP14_CONSTEXPR decltype(auto) call(VariantArgIndexSequence, Visitor&& visitor, Variants&&... variants)
+ {
+ EA_CPP14_CONSTEXPR auto callers = make_visitor_array(make_invoke_visitor_recurse(meta::double_pack_expansion_t<VariantArgIndexSequence, VariantIndices>{})...);
+
+ return call_visitor_at<internal::index_sequence_size_v<VariantArgIndexSequence>>(eastl::move(callers),
+ eastl::forward<Visitor>(visitor),
+ eastl::forward<Variants>(variants)...);
+ }
+
};
- template <typename Visitor, typename Variant>
- struct visitor_caller<Visitor, Variant>
+ template <typename VariantIndexSequence, typename Visitor, typename... Variants>
+ static EA_CONSTEXPR decltype(auto) call_initial_n(VariantIndexSequence, Visitor&& visitor, Variants&&... variants)
{
- // Invoke the correct visitor for a given variant index, and call the correct get() function to retrieve
- // the argument. Unpack any additional arguments from earlier visitor_callers (see above).
- template <typename R, size_t I, typename ArgsTuple, size_t... ArgsIndices>
- static decltype(auto) EA_CONSTEXPR invoke_visitor(Visitor&& visitor, index_sequence<ArgsIndices...>, ArgsTuple&& args, Variant&& variant)
- {
- return static_cast<R>(invoke(
- eastl::forward<Visitor>(visitor),
- get<ArgsIndices>(eastl::forward<ArgsTuple>(args))...,
- get<I>(eastl::forward<Variant>(variant))
- ));
+ return visitor_caller_n<VariantIndexSequence, Visitor, Variants...>::call(index_sequence<>{}, eastl::forward<Visitor>(visitor), eastl::forward<Variants>(variants)...);
+ }
+
+
+ // abstracts calling visit on 2 or more variants with return types convertible to R
+ template <typename R, typename VariantIndexSequence, typename Visitor, typename... Variants>
+ struct visitor_caller_n_r;
+
+ template <typename R, size_t... VariantIndices, typename Visitor, typename... Variants>
+ struct visitor_caller_n_r<R, index_sequence<VariantIndices...>, Visitor, Variants...>
+ {
+ template <typename R_, size_t... VariantArgIndices>
+ struct visitor_leaf_r
+ {
+ static EA_CONSTEXPR R_ invoke_visitor_leaf_r(Visitor&& visitor, Variants&&... variants)
+ {
+ return eastl::invoke(eastl::forward<Visitor>(visitor),
+ eastl::get<VariantArgIndices>(eastl::forward<Variants>(variants))...);
+ }
+ };
+
+ // void return type must discard the return values of the visitor even if the visitor returns a value.
+ template <size_t... VariantArgIndices>
+ struct visitor_leaf_r<void, VariantArgIndices...>
+ {
+ static EA_CONSTEXPR void invoke_visitor_leaf_r(Visitor&& visitor, Variants&&... variants)
+ {
+ eastl::invoke(eastl::forward<Visitor>(visitor),
+ eastl::get<VariantArgIndices>(eastl::forward<Variants>(variants))...);
+ }
+ };
+ template <size_t... VariantArgIndices> struct visitor_leaf_r<const void, VariantArgIndices...> : public visitor_leaf_r<void, VariantArgIndices...> {};
+ template <size_t... VariantArgIndices> struct visitor_leaf_r<volatile void, VariantArgIndices...> : public visitor_leaf_r<void, VariantArgIndices...> {};
+ template <size_t... VariantArgIndices> struct visitor_leaf_r<const volatile void, VariantArgIndices...> : public visitor_leaf_r<void, VariantArgIndices...> {};
+
+ template <typename R_, size_t... VariantArgIndices>
+ static EA_CONSTEXPR auto make_invoke_visitor_leaf_r(index_sequence<VariantArgIndices...>)
+ {
+ return &visitor_leaf_r<R_, VariantArgIndices...>::invoke_visitor_leaf_r;
}
- // The final call() in the recursion.
- //
- // By this point, <ArgsIndices...> expands to <0 .. N - 2> where N is the number of arguments to the
- // final invoke() call. This corresponds to each element in @args, so `get<ArgsIndices>(args)...`
- // expands to `get<0>(args), get<1>(args), ... , get<N - 2>(args)`. The final argument is selected
- // based on the final array index, leaving us with a sequence of arguments from 0 .. N - 1.
- //
- // <ArrayIndices...> is the same as in earlier calls - it expands to <0 .. I - 1> where I is the
- // number of alternatives in the variant. This lets us call the correct `get<I>` based on the
- // final variant index, as we did for all earlier calls.
- template <typename ArgsTuple, size_t... ArgsIndices, size_t... ArrayIndices>
- static decltype(auto) EA_CPP14_CONSTEXPR call(Visitor&& visitor, index_sequence<ArgsIndices...>, index_sequence<ArrayIndices...>, ArgsTuple&& args, Variant&& variant)
- {
- // MSVC isn't able to handle the nested pack expansion required here, so we have to just use the
- // return type of the first visitor function instead of the common_type of all possible visitor
- // functions. This means we can't handle the case where visitor functions return different (but
- // compatible) types. This is unlikely to be a common case, but we might be able to get around it
- // if it's a big issue.
- //
- // TODO: we should reevaluate this on future compiler releases
- #if defined(EA_COMPILER_MSVC)
- using return_type = invoke_result_t<Visitor, decltype(get<ArgsIndices>(args))..., decltype(get<0>(variant))>;
- #else
- // If we're on a compiler that can take it, determine the common_type between all possible visitor
- // invocations.
- using return_type = common_type_t<
- invoke_result_t<Visitor, decltype(get<ArgsIndices>(args))..., decltype(get<ArrayIndices>(variant))>...
- >;
- #endif
- using caller_type = return_type (*)(Visitor&&, index_sequence<ArgsIndices...>, ArgsTuple&&, Variant&&);
+ template <typename R_, size_t... VariantArgIndices>
+ struct visitor_recurse_r
+ {
+ static EA_CONSTEXPR R_ invoke_visitor_recurse_r(Visitor&& visitor, Variants&&... variants)
+ {
+ return call_r(index_sequence<VariantArgIndices...>{},
+ eastl::forward<Visitor>(visitor),
+ eastl::forward<Variants>(variants)...);
+ }
+ };
+
+ template <typename R_, size_t... VariantArgIndices>
+ static EA_CONSTEXPR auto make_invoke_visitor_recurse_r(index_sequence<VariantArgIndices...>)
+ {
+ return &visitor_recurse_r<R_, VariantArgIndices...>::invoke_visitor_recurse_r;
+ }
+
+
+ template <typename VariantArgIndexSequence, enable_if_t<internal::index_sequence_size_v<VariantArgIndexSequence> + 1 == sizeof...(Variants), int> = 0>
+ static EA_CPP14_CONSTEXPR decltype(auto) call_r(VariantArgIndexSequence, Visitor&& visitor, Variants&&... variants)
+ {
+ EA_CPP14_CONSTEXPR auto callers = make_visitor_array(make_invoke_visitor_leaf_r<R>(meta::double_pack_expansion_t<VariantArgIndexSequence, VariantIndices>{})...);
+
+ return call_visitor_at<internal::index_sequence_size_v<VariantArgIndexSequence>>(eastl::move(callers),
+ eastl::forward<Visitor>(visitor),
+ eastl::forward<Variants>(variants)...);
+ }
+
+ template <typename VariantArgIndexSequence, enable_if_t<internal::index_sequence_size_v<VariantArgIndexSequence> + 1 != sizeof...(Variants), int> = 0>
+ static EA_CPP14_CONSTEXPR decltype(auto) call_r(VariantArgIndexSequence, Visitor&& visitor, Variants&&... variants)
+ {
+ EA_CPP14_CONSTEXPR auto callers = make_visitor_array(make_invoke_visitor_recurse_r<R>(meta::double_pack_expansion_t<VariantArgIndexSequence, VariantIndices>{})...);
+
+ return call_visitor_at<internal::index_sequence_size_v<VariantArgIndexSequence>>(eastl::move(callers),
+ eastl::forward<Visitor>(visitor),
+ eastl::forward<Variants>(variants)...);
+ }
+
+ };
+
+ template <typename R, typename VariantIndexSequence, typename Visitor, typename... Variants>
+ static EA_CONSTEXPR decltype(auto) call_initial_n_r(VariantIndexSequence, Visitor&& visitor, Variants&&... variants)
+ {
+ return visitor_caller_n_r<R, VariantIndexSequence, Visitor, Variants...>::call_r(index_sequence<>{}, eastl::forward<Visitor>(visitor), eastl::forward<Variants>(variants)...);
+ }
+
+
+ // abstracts calling visit on a single variant
+ struct visitor_caller_one
+ {
+
+ template <typename Visitor, typename Variant, size_t I>
+ static EA_CONSTEXPR decltype(auto) invoke_visitor(Visitor&& visitor, Variant&& variant)
+ {
+ return eastl::invoke(eastl::forward<Visitor>(visitor),
+ eastl::get<I>(eastl::forward<Variant>(variant)));
+ }
+
+ template <typename Visitor, typename Variant, size_t... VariantArgIndices>
+ static EA_CPP14_CONSTEXPR decltype(auto) call_index(Visitor&& visitor, Variant&& variant, index_sequence<VariantArgIndices...>)
+ {
+ EA_CPP14_CONSTEXPR auto callers = make_visitor_array((&invoke_visitor<Visitor, Variant, VariantArgIndices>)...);
+
+ return call_visitor_at_index(eastl::move(callers), eastl::forward<Variant>(variant).index(),
+ eastl::forward<Visitor>(visitor), eastl::forward<Variant>(variant));
+ }
+
+ template <typename Visitor, typename Variant>
+ static EA_CONSTEXPR decltype(auto) call(Visitor&& visitor, Variant&& variant)
+ {
+ return call_index(eastl::forward<Visitor>(visitor),
+ eastl::forward<Variant>(variant),
+ make_index_sequence<variant_size_v<decay_t<Variant>>>{});
+ }
+
+ };
+
+ template <typename R>
+ struct visitor_r
+ {
+ template <typename Visitor, typename Variant, size_t I>
+ static EA_CONSTEXPR R invoke_visitor_r(Visitor&& visitor, Variant&& variant)
+ {
+ return eastl::invoke(eastl::forward<Visitor>(visitor),
+ eastl::get<I>(eastl::forward<Variant>(variant)));
+ }
+ };
+
+ // void return type must discard the return values of the visitor even if the visitor returns a value.
+ template <>
+ struct visitor_r<void>
+ {
+ template <typename Visitor, typename Variant, size_t I>
+ static EA_CONSTEXPR void invoke_visitor_r(Visitor&& visitor, Variant&& variant)
+ {
+ eastl::invoke(eastl::forward<Visitor>(visitor),
+ eastl::get<I>(eastl::forward<Variant>(variant)));
+ }
+ };
+
+ template<> struct visitor_r<const void> : public visitor_r<void> {};
+ template<> struct visitor_r<volatile void> : public visitor_r<void> {};
+ template<> struct visitor_r<const volatile void> : public visitor_r<void> {};
+
+ // abstracts calling visit on a single variant with return types convertible to R
+ struct visitor_caller_one_r
+ {
+ template <typename R, typename Visitor, typename Variant, size_t... VariantArgIndices>
+ static EA_CPP14_CONSTEXPR decltype(auto) call_index_r(Visitor&& visitor, Variant&& variant, eastl::index_sequence<VariantArgIndices...>)
+ {
+ EA_CPP14_CONSTEXPR auto callers = make_visitor_array(&visitor_r<R>::template invoke_visitor_r<Visitor, Variant, VariantArgIndices>...);
- // Create the final array of invoke_visitor<0>, invoke_visitor<1>, ... , invoke_visitor<N - 1>
- // where N = variant_size<Variant>
- EA_CPP14_CONSTEXPR caller_type callers[] = { invoke_visitor<return_type, ArrayIndices>... };
+ return callers[static_cast<typename decltype(callers)::size_type>(eastl::forward<Variant>(variant).index())](eastl::forward<Visitor>(visitor),
+ eastl::forward<Variant>(variant));
+ }
- return callers[eastl::forward<Variant>(variant).index()](
- eastl::forward<Visitor>(visitor),
- index_sequence<ArgsIndices...>(),
- eastl::forward<ArgsTuple>(args),
- eastl::forward<Variant>(variant)
- );
+ template <typename R, typename Visitor, typename Variant>
+ static EA_CONSTEXPR decltype(auto) call_r(Visitor&& visitor, Variant&& variant)
+ {
+ return call_index_r<R>(eastl::forward<Visitor>(visitor), eastl::forward<Variant>(variant), eastl::make_index_sequence<eastl::variant_size_v<eastl::decay_t<Variant>>>());
}
+
};
+
///////////////////////////////////////////////////////////////////////////
// 20.7.6, visitation
//
@@ -1107,24 +1349,80 @@ namespace eastl
// visit(MyVisitor{}, v); // calls MyVisitor::operator()(string) {}
//
+ template <typename... Variants>
+ static EA_CPP14_CONSTEXPR void visit_throw_bad_variant_access(Variants&&... variants)
+ {
+ #if EASTL_EXCEPTIONS_ENABLED
+ using bool_array_type = bool[];
+ bool badAccess = false;
+
+ (void)bool_array_type{ (badAccess |= eastl::forward<Variants>(variants).valueless_by_exception(), false)... };
+
+ if (badAccess)
+ {
+ throw bad_variant_access();
+ }
+ #endif
+ }
+
+ template <typename... Variants>
+ static EA_CONSTEXPR void visit_static_assert_check(Variants&&... variants)
+ {
+ static_assert(sizeof...(Variants) > 0, "`visit` at least one variant instance must be passed as an argument to the visit function");
+
+ using variant_type = decay_t<meta::get_type_at_t<0, Variants...>>;
+ static_assert(conjunction_v<is_same<variant_type, decay_t<Variants>>...>,
+ "`visit` all variants passed to eastl::visit() must have the same type");
+ }
+
+
// visit
//
- template <class Visitor, class... Variants>
- EA_CONSTEXPR decltype(auto) visit(Visitor&& visitor, Variants&&... variants)
+ template <typename Visitor, typename Variant>
+ EA_CPP14_CONSTEXPR decltype(auto) visit(Visitor&& visitor, Variant&& variant)
+ {
+ visit_static_assert_check(eastl::forward<Variant>(variant));
+
+ visit_throw_bad_variant_access(eastl::forward<Variant>(variant));
+
+ return visitor_caller_one::call(eastl::forward<Visitor>(visitor),
+ eastl::forward<Variant>(variant));
+ }
+
+ template <typename Visitor, typename... Variants>
+ EA_CPP14_CONSTEXPR decltype(auto) visit(Visitor&& visitor, Variants&&... variants)
{
- static_assert(sizeof...(Variants) > 0, "at least one variant instance must be passed as an argument to the visit function");
-
- using variant_type = remove_reference_t<meta::get_type_at_t<0, Variants...>>;
- static_assert(conjunction_v<is_same<variant_type, remove_reference_t<Variants>>...>,
- "all variants passed to eastl::visit() must have the same type");
-
- return visitor_caller<Visitor, Variants...>::call(
- eastl::forward<Visitor>(visitor),
- index_sequence<>(),
- make_index_sequence<variant_size_v<variant_type>>(),
- tuple<>(),
- eastl::forward<Variants>(variants)...
- );
+ visit_static_assert_check(eastl::forward<Variants>(variants)...);
+
+ visit_throw_bad_variant_access(eastl::forward<Variants>(variants)...);
+
+ return call_initial_n(make_index_sequence<variant_size_v<decay_t<meta::get_type_at_t<0, Variants...>>>>{},
+ eastl::forward<Visitor>(visitor),
+ eastl::forward<Variants>(variants)...);
+
+ }
+
+ template <typename R, typename Visitor, typename Variant, eastl::enable_if_t<!eastl::is_same_v<R, Visitor>, int> = 0>
+ EA_CPP14_CONSTEXPR R visit(Visitor&& visitor, Variant&& variant)
+ {
+ visit_static_assert_check(eastl::forward<Variant>(variant));
+
+ visit_throw_bad_variant_access(eastl::forward<Variant>(variant));
+
+ return visitor_caller_one_r::call_r<R>(eastl::forward<Visitor>(visitor),
+ eastl::forward<Variant>(variant));
+ }
+
+ template <typename R, typename Visitor, typename... Variants, eastl::enable_if_t<!eastl::is_same_v<R, Visitor>, int> = 0>
+ EA_CPP14_CONSTEXPR R visit(Visitor&& visitor, Variants&&... variants)
+ {
+ visit_static_assert_check(eastl::forward<Variants>(variants)...);
+
+ visit_throw_bad_variant_access(eastl::forward<Variants>(variants)...);
+
+ return call_initial_n_r<R>(make_index_sequence<variant_size_v<decay_t<meta::get_type_at_t<0, Variants...>>>>{},
+ eastl::forward<Visitor>(visitor),
+ eastl::forward<Variants>(variants)...);
}
@@ -1134,42 +1432,76 @@ namespace eastl
namespace internal
{
- template <class... Types, class Predicate>
- EA_CPP14_CONSTEXPR bool Compare(const variant<Types...>& lhs, const variant<Types...>& rhs, Predicate predicate)
+ // For relational operators we do not need to create the NxN matrix of comparisons since we know already
+ // that both the lhs and rhs variants have the same index. We just need to compare the value of the types at that
+ // index for equality. Therefore the visitation is simpler than visit() for relational operators.
+ //
+ struct variant_relational_comparison
{
- return visit(predicate, lhs, rhs);
- }
+ template <typename Compare, size_t I, typename Variant>
+ static EA_CONSTEXPR bool invoke_relational_visitor(const Variant& lhs, const Variant& rhs)
+ {
+ return eastl::invoke(Compare{}, eastl::get<I>(lhs), eastl::get<I>(rhs));
+ }
- // For variant visitation, we need to have a comparison function for all possible combinations of types,
- // eg. for variant<int, string>, our comparator needs:
- //
- // bool operator()(int, int);
- // bool operator()(int, string);
- // bool operator()(string, int);
- // bool operator()(string, string);
- //
- // Even though we never call the mixed-type versions of these functions when comparing variants, we
- // need them in order to compile visit(). So this struct forwards the good comparisons to the appropriate
- // comparison, and asserts that we never call the bad comparisons.
- template <typename C>
- struct variant_comparison : public C
- {
- template <typename A, typename B, typename = eastl::enable_if_t<eastl::is_same_v<eastl::decay_t<A>, eastl::decay_t<B>>>>
- auto operator()(const A& a, const B& b)
+ template <typename Compare, typename Variant, size_t... VariantArgIndices>
+ static EA_CPP14_CONSTEXPR bool call_index(const Variant& lhs, const Variant& rhs, eastl::index_sequence<VariantArgIndices...>)
{
- return C::operator()(a, b);
+ using invoke_relational_visitor_func_ptr = bool (*)(const Variant&, const Variant&);
+
+ EA_CPP14_CONSTEXPR invoke_relational_visitor_func_ptr visitors[] = { static_cast<invoke_relational_visitor_func_ptr>(&invoke_relational_visitor<Compare, VariantArgIndices, Variant>)... };
+
+ return visitors[lhs.index()](lhs, rhs);
}
- template <typename A, typename B, typename = eastl::enable_if_t<!eastl::is_same_v<eastl::decay_t<A>, eastl::decay_t<B>>>>
- bool operator()(const A&, const B&)
+ template <typename Compare, typename Variant>
+ static EA_CONSTEXPR bool call(const Variant& lhs, const Variant& rhs)
{
- EASTL_ASSERT_MSG(false, "eastl::variant<> comparison function called on two different types at different indices! This is a library bug! Please file bug report.");
- return false;
+ return call_index<Compare>(lhs, rhs, eastl::make_index_sequence<eastl::variant_size_v<eastl::decay_t<Variant>>>());
}
+
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename Compare, size_t I, typename Variant>
+ static EA_CONSTEXPR std::compare_three_way_result_t<Variant> invoke_relational_visitor_three_way(const Variant& lhs, const Variant& rhs)
+ {
+ return eastl::invoke(Compare{}, eastl::get<I>(lhs), eastl::get<I>(rhs));
+ }
+
+ template <typename Compare, typename Variant, size_t... VariantArgIndices>
+ static EA_CONSTEXPR std::compare_three_way_result_t<Variant> call_index_three_way(const Variant& lhs, const Variant& rhs, eastl::index_sequence<VariantArgIndices...>)
+ {
+ using invoke_relational_visitor_func_ptr = std::compare_three_way_result_t<Variant> (*)(const Variant&, const Variant&);
+
+ EA_CONSTEXPR invoke_relational_visitor_func_ptr visitors[] = {static_cast<invoke_relational_visitor_func_ptr>(&invoke_relational_visitor_three_way<Compare, VariantArgIndices, Variant>)...};
+
+ return visitors[lhs.index()](lhs, rhs);
+ }
+
+ template <typename Compare, typename Variant>
+ static EA_CONSTEXPR std::compare_three_way_result_t<Variant> call_three_way(const Variant& lhs, const Variant& rhs)
+ {
+ return call_index_three_way<Compare>(lhs, rhs, eastl::make_index_sequence<eastl::variant_size_v<eastl::decay_t<Variant>>>());
+ }
+#endif
};
+ template <typename Compare, typename Variant>
+ static EA_CONSTEXPR bool CompareVariantRelational(const Variant& lhs, const Variant& rhs)
+ {
+ return variant_relational_comparison::call<Compare>(lhs, rhs);
+ }
+
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename Compare, typename Variant>
+ static EA_CONSTEXPR std::compare_three_way_result_t<Variant> CompareVariantRelationalThreeWay(const Variant& lhs, const Variant& rhs)
+ {
+ return variant_relational_comparison::call_three_way<Compare>(lhs, rhs);
+ }
+#endif
+
} // namespace internal
+
///////////////////////////////////////////////////////////////////////////
// 20.7.5, relational operators
//
@@ -1178,7 +1510,17 @@ namespace eastl
{
if (lhs.index() != rhs.index()) return false;
if (lhs.valueless_by_exception()) return true;
- return internal::Compare(lhs, rhs, internal::variant_comparison<equal_to<>>{});
+
+ return internal::CompareVariantRelational<eastl::equal_to<>>(lhs, rhs);
+ }
+
+ template <class... Types>
+ EA_CPP14_CONSTEXPR bool operator!=(const variant<Types...>& lhs, const variant<Types...>& rhs)
+ {
+ if (lhs.index() != rhs.index()) return true;
+ if (lhs.valueless_by_exception()) return false;
+
+ return internal::CompareVariantRelational<eastl::not_equal_to<>>(lhs, rhs);
}
template <class... Types>
@@ -1188,15 +1530,8 @@ namespace eastl
if (lhs.valueless_by_exception()) return true;
if (lhs.index() < rhs.index()) return true;
if (lhs.index() > rhs.index()) return false;
- return internal::Compare(lhs, rhs, internal::variant_comparison<less<>>{});
- }
- template <class... Types>
- EA_CPP14_CONSTEXPR bool operator!=(const variant<Types...>& lhs, const variant<Types...>& rhs)
- {
- if (lhs.index() != rhs.index()) return true;
- if (lhs.valueless_by_exception()) return false;
- return internal::Compare(lhs, rhs, internal::variant_comparison<not_equal_to<>>{});
+ return internal::CompareVariantRelational<eastl::less<>>(lhs, rhs);
}
template <class... Types>
@@ -1206,17 +1541,19 @@ namespace eastl
if (rhs.valueless_by_exception()) return true;
if (lhs.index() > rhs.index()) return true;
if (lhs.index() < rhs.index()) return false;
- return internal::Compare(lhs, rhs, internal::variant_comparison<greater<>>{});
+
+ return internal::CompareVariantRelational<eastl::greater<>>(lhs, rhs);
}
template <class... Types>
EA_CPP14_CONSTEXPR bool operator<=(const variant<Types...>& lhs, const variant<Types...>& rhs)
{
- if (rhs.valueless_by_exception()) return true;
- if (lhs.valueless_by_exception()) return false;
+ if (lhs.valueless_by_exception()) return true;
+ if (rhs.valueless_by_exception()) return false;
if (lhs.index() < rhs.index()) return true;
if (lhs.index() > rhs.index()) return false;
- return internal::Compare(lhs, rhs, internal::variant_comparison<less_equal<>>{});
+
+ return internal::CompareVariantRelational<eastl::less_equal<>>(lhs, rhs);
}
template <class... Types>
@@ -1226,11 +1563,26 @@ namespace eastl
if (lhs.valueless_by_exception()) return false;
if (lhs.index() > rhs.index()) return true;
if (lhs.index() < rhs.index()) return false;
- return internal::Compare(lhs, rhs, internal::variant_comparison<greater_equal<>>{});
+
+ return internal::CompareVariantRelational<eastl::greater_equal<>>(lhs, rhs);
}
+
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <class... Types> requires (std::three_way_comparable<Types> && ...)
+ EA_CONSTEXPR std::common_comparison_category_t<std::compare_three_way_result_t<Types>...> operator<=>(const variant<Types...>& lhs, const variant<Types...>& rhs)
+ {
+ if (lhs.valueless_by_exception() && rhs.valueless_by_exception()) return std::strong_ordering::equal;
+ if (lhs.valueless_by_exception()) return std::strong_ordering::less;
+ if (rhs.valueless_by_exception()) return std::strong_ordering::greater;
+ if (auto result = (lhs.index() <=> rhs.index()); result != 0) return result;
+
+ return internal::CompareVariantRelationalThreeWay<std::compare_three_way>(lhs, rhs);
+
+ }
+#endif
+
} // namespace eastl
EA_RESTORE_VC_WARNING()
#endif // EASTL_VARIANT_H
-
diff --git a/EASTL/include/EASTL/vector.h b/EASTL/include/EASTL/vector.h
index 1736a78..b6ca8dc 100644
--- a/EASTL/include/EASTL/vector.h
+++ b/EASTL/include/EASTL/vector.h
@@ -1058,8 +1058,9 @@ namespace eastl
{
if(mpEnd == internalCapacityPtr())
{
- const size_type newSize = (size_type)(mpEnd - mpBegin) + 1;
- reserve(newSize);
+ const size_type nPrevSize = size_type(mpEnd - mpBegin);
+ const size_type nNewSize = GetNewCapacity(nPrevSize);
+ DoGrow(nNewSize);
}
return mpEnd++;
@@ -1982,7 +1983,13 @@ namespace eastl
return ((a.size() == b.size()) && eastl::equal(a.begin(), a.end(), b.begin()));
}
-
+#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
+ template <typename T, typename Allocator>
+ inline synth_three_way_result<T> operator<=>(const vector<T, Allocator>& a, const vector<T, Allocator>& b)
+ {
+ return eastl::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end(), synth_three_way{});
+ }
+#else
template <typename T, typename Allocator>
inline bool operator!=(const vector<T, Allocator>& a, const vector<T, Allocator>& b)
{
@@ -2016,7 +2023,7 @@ namespace eastl
{
return !(a < b);
}
-
+#endif
template <typename T, typename Allocator>
inline void swap(vector<T, Allocator>& a, vector<T, Allocator>& b) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(a.swap(b)))
@@ -2032,17 +2039,39 @@ namespace eastl
// https://en.cppreference.com/w/cpp/container/vector/erase2
///////////////////////////////////////////////////////////////////////
template <class T, class Allocator, class U>
- void erase(vector<T, Allocator>& c, const U& value)
+ typename vector<T, Allocator>::size_type erase(vector<T, Allocator>& c, const U& value)
{
// Erases all elements that compare equal to value from the container.
- c.erase(eastl::remove(c.begin(), c.end(), value), c.end());
+ auto origEnd = c.end();
+ auto newEnd = eastl::remove(c.begin(), origEnd, value);
+ auto numRemoved = eastl::distance(newEnd, origEnd);
+ c.erase(newEnd, origEnd);
+
+ // Note: This is technically a lossy conversion when size_type
+ // is 32bits and ptrdiff_t is 64bits (could happen on 64bit
+ // systems when EASTL_SIZE_T_32BIT is set). In practice this
+ // is fine because if EASTL_SIZE_T_32BIT is set then the vector
+ // should not have more elements than fit in a uint32_t and so
+ // the distance here should fit in a size_type.
+ return static_cast<typename vector<T, Allocator>::size_type>(numRemoved);
}
template <class T, class Allocator, class Predicate>
- void erase_if(vector<T, Allocator>& c, Predicate predicate)
+ typename vector<T, Allocator>::size_type erase_if(vector<T, Allocator>& c, Predicate predicate)
{
// Erases all elements that satisfy the predicate pred from the container.
- c.erase(eastl::remove_if(c.begin(), c.end(), predicate), c.end());
+ auto origEnd = c.end();
+ auto newEnd = eastl::remove_if(c.begin(), origEnd, predicate);
+ auto numRemoved = eastl::distance(newEnd, origEnd);
+ c.erase(newEnd, origEnd);
+
+ // Note: This is technically a lossy conversion when size_type
+ // is 32bits and ptrdiff_t is 64bits (could happen on 64bit
+ // systems when EASTL_SIZE_T_32BIT is set). In practice this
+ // is fine because if EASTL_SIZE_T_32BIT is set then the vector
+ // should not have more elements than fit in a uint32_t and so
+ // the distance here should fit in a size_type.
+ return static_cast<typename vector<T, Allocator>::size_type>(numRemoved);
}
} // namespace eastl