diff --git a/README.md b/README.md index 7cc400ab..07b8ea35 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,11 @@ Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on compiling and testi EASTL was created by Paul Pedriana and he maintained the project for roughly 10 years. -Roberto Parolin is the current EASTL owner and primary maintainer within EA and is responsible for the open source repository. -Max Winkler is the secondary maintainer for EASTL within EA and on the open source repository. +EASTL was subsequently maintained by Roberto Parolin for more than 8 years. +He was the driver and proponent for getting EASTL opensourced. +Rob was a mentor to all members of the team and taught us everything we ever wanted to know about C++ spookyness. + +Max Winkler is the current EASTL owner and primary maintainer within EA and is responsible for the open source repository. Significant EASTL contributions were made by (in alphabetical order): diff --git a/doc/EASTL-n2271.pdf b/doc/EASTL-n2271.pdf new file mode 100644 index 00000000..8a1b0b9e Binary files /dev/null and b/doc/EASTL-n2271.pdf differ diff --git a/include/EASTL/algorithm.h b/include/EASTL/algorithm.h index 147ff471..da35c2e2 100644 --- a/include/EASTL/algorithm.h +++ b/include/EASTL/algorithm.h @@ -3,8 +3,8 @@ ///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// -// This file implements some of the primary algorithms from the C++ STL -// algorithm library. These versions are just like that STL versions and so +// This file implements some of the primary algorithms from the C++ STL +// algorithm library. These versions are just like that STL versions and so // are redundant. They are provided solely for the purpose of projects that // either cannot use standard C++ STL or want algorithms that have guaranteed // identical behaviour across platforms. @@ -13,11 +13,11 @@ /////////////////////////////////////////////////////////////////////////////// // Definitions -// +// // You will notice that we are very particular about the templated typenames -// we use here. You will notice that we follow the C++ standard closely in -// these respects. Each of these typenames have a specific meaning; -// this is why we don't just label templated arguments with just letters +// we use here. You will notice that we follow the C++ standard closely in +// these respects. Each of these typenames have a specific meaning; +// this is why we don't just label templated arguments with just letters // such as T, U, V, A, B. Here we provide a quick reference for the typenames // we use. See the C++ standard, section 25-8 for more details. // -------------------------------------------------------------- @@ -39,9 +39,9 @@ // RandomAccessIterator An input iterator which can be addressed like an array. It is a superset of all other input iterators. // OutputIterator An output iterator (iterator you write to) which allows writing each element only once in only in a forward direction. // -// Note that with iterators that a function which takes an InputIterator will +// Note that with iterators that a function which takes an InputIterator will // also work with a ForwardIterator, BidirectionalIterator, or RandomAccessIterator. -// The given iterator type is merely the -minimum- supported functionality the +// The given iterator type is merely the -minimum- supported functionality the // iterator must support. /////////////////////////////////////////////////////////////////////////////// @@ -51,15 +51,15 @@ // // There are a number of opportunities for opptimizations that we take here // in this library. The most obvious kinds are those that subsitute memcpy -// in the place of a conventional loop for data types with which this is +// in the place of a conventional loop for data types with which this is // possible. The algorithms here are optimized to a higher level than currently // available C++ STL algorithms from vendors such as Microsoft. This is especially -// so for game programming on console devices, as we do things such as reduce -// branching relative to other STL algorithm implementations. However, the +// so for game programming on console devices, as we do things such as reduce +// branching relative to other STL algorithm implementations. However, the // proper implementation of these algorithm optimizations is a fairly tricky -// thing. +// thing. // -// The various things we look to take advantage of in order to implement +// The various things we look to take advantage of in order to implement // optimizations include: // - Taking advantage of random access iterators. // - Taking advantage of POD (plain old data) data types. @@ -76,9 +76,9 @@ // Supported Algorithms // // Algorithms that we implement are listed here. Note that these items are not -// all within this header file, as we split up the header files in order to +// all within this header file, as we split up the header files in order to // improve compilation performance. Items marked with '+' are items that are -// extensions which don't exist in the C++ standard. +// extensions which don't exist in the C++ standard. // // ------------------------------------------------------------------------------- // Algorithm Notes @@ -94,6 +94,7 @@ // +binary_search_i // +change_heap Found in heap.h // +change_heap Found in heap.h +// clamp // copy // copy_if C++11 // copy_n C++11 @@ -159,7 +160,7 @@ // push_heap Found in heap.h // pop_heap Found in heap.h // pop_heap Found in heap.h -// random_shuffle +// random_shuffle // remove // remove_if // remove_copy @@ -172,6 +173,7 @@ // replace_copy_if // reverse_copy // reverse +// random_shuffle // rotate // rotate_copy // search @@ -179,10 +181,16 @@ // search_n // set_difference // set_difference +// set_difference_2 +// set_difference_2 +// set_decomposition +// set_decomposition // set_intersection // set_intersection // set_symmetric_difference // set_symmetric_difference +// set_union +// set_union // sort Found in sort.h // sort Found in sort.h // sort_heap Found in heap.h @@ -205,8 +213,8 @@ // Algorithms from the C++ standard that we don't implement are listed here. // Most of these items are absent because they aren't used very often. // They also happen to be the more complicated than other algorithms. -// However, we can implement any of these functions for users that might -// need them. +// However, we can implement any of these functions for users that might +// need them. // includes // includes // inplace_merge @@ -216,10 +224,7 @@ // paritition // prev_permutation // prev_permutation -// random_shuffle // search_n -// set_union -// set_union // stable_partition // unique_copy // unique_copy @@ -284,16 +289,16 @@ namespace eastl { /// min_element /// - /// min_element finds the smallest element in the range [first, last). - /// It returns the first iterator i in [first, last) such that no other - /// iterator in [first, last) points to a value smaller than *i. + /// min_element finds the smallest element in the range [first, last). + /// It returns the first iterator i in [first, last) such that no other + /// iterator in [first, last) points to a value smaller than *i. /// The return value is last if and only if [first, last) is an empty range. /// - /// Returns: The first iterator i in the range [first, last) such that - /// for any iterator j in the range [first, last) the following corresponding + /// Returns: The first iterator i in the range [first, last) such that + /// for any iterator j in the range [first, last) the following corresponding /// condition holds: !(*j < *i). /// - /// Complexity: Exactly 'max((last - first) - 1, 0)' applications of the + /// Complexity: Exactly 'max((last - first) - 1, 0)' applications of the /// corresponding comparisons. /// template @@ -316,16 +321,16 @@ namespace eastl /// min_element /// - /// min_element finds the smallest element in the range [first, last). - /// It returns the first iterator i in [first, last) such that no other - /// iterator in [first, last) points to a value smaller than *i. + /// min_element finds the smallest element in the range [first, last). + /// It returns the first iterator i in [first, last) such that no other + /// iterator in [first, last) points to a value smaller than *i. /// The return value is last if and only if [first, last) is an empty range. /// - /// Returns: The first iterator i in the range [first, last) such that - /// for any iterator j in the range [first, last) the following corresponding + /// Returns: The first iterator i in the range [first, last) such that + /// for any iterator j in the range [first, last) the following corresponding /// conditions hold: compare(*j, *i) == false. /// - /// Complexity: Exactly 'max((last - first) - 1, 0)' applications of the + /// Complexity: Exactly 'max((last - first) - 1, 0)' applications of the /// corresponding comparisons. /// template @@ -348,16 +353,16 @@ namespace eastl /// max_element /// - /// max_element finds the largest element in the range [first, last). - /// It returns the first iterator i in [first, last) such that no other - /// iterator in [first, last) points to a value greater than *i. + /// max_element finds the largest element in the range [first, last). + /// It returns the first iterator i in [first, last) such that no other + /// iterator in [first, last) points to a value greater than *i. /// The return value is last if and only if [first, last) is an empty range. /// - /// Returns: The first iterator i in the range [first, last) such that - /// for any iterator j in the range [first, last) the following corresponding + /// Returns: The first iterator i in the range [first, last) such that + /// for any iterator j in the range [first, last) the following corresponding /// condition holds: !(*i < *j). /// - /// Complexity: Exactly 'max((last - first) - 1, 0)' applications of the + /// Complexity: Exactly 'max((last - first) - 1, 0)' applications of the /// corresponding comparisons. /// template @@ -380,16 +385,16 @@ namespace eastl /// max_element /// - /// max_element finds the largest element in the range [first, last). - /// It returns the first iterator i in [first, last) such that no other - /// iterator in [first, last) points to a value greater than *i. + /// max_element finds the largest element in the range [first, last). + /// It returns the first iterator i in [first, last) such that no other + /// iterator in [first, last) points to a value greater than *i. /// The return value is last if and only if [first, last) is an empty range. /// - /// Returns: The first iterator i in the range [first, last) such that - /// for any iterator j in the range [first, last) the following corresponding + /// Returns: The first iterator i in the range [first, last) such that + /// for any iterator j in the range [first, last) the following corresponding /// condition holds: compare(*i, *j) == false. /// - /// Complexity: Exactly 'max((last - first) - 1, 0)' applications of the + /// Complexity: Exactly 'max((last - first) - 1, 0)' applications of the /// corresponding comparisons. /// template @@ -414,7 +419,7 @@ namespace eastl /// min /// - /// Min returns the lesser of its two arguments; it returns the first + /// Min returns the lesser of its two arguments; it returns the first /// argument if neither is less than the other. The two arguments are /// compared with operator <. /// @@ -423,15 +428,15 @@ namespace eastl /// which for example may in practice result in something different than: /// b <= a ? b : a /// in the case where b is different from a (though they compare as equal). - /// We choose the specific ordering here because that's the ordering + /// We choose the specific ordering here because that's the ordering /// done by other STL implementations. /// - /// Some compilers (e.g. VS20003 - VS2013) generate poor code for the case of + /// Some compilers (e.g. VS20003 - VS2013) generate poor code for the case of /// scalars returned by reference, so we provide a specialization for those cases. - /// The specialization returns T by value instead of reference, which is + /// The specialization returns T by value instead of reference, which is /// not that the Standard specifies. The Standard allows you to use /// an expression like &max(x, y), which would be impossible in this case. - /// However, we have found no actual code that uses min or max like this and + /// However, we have found no actual code that uses min or max like this and /// this specialization causes no problems in practice. Microsoft has acknowledged /// the problem and may fix it for a future VS version. /// @@ -441,7 +446,7 @@ namespace eastl { return b < a ? b : a; } - + template inline EA_CONSTEXPR typename eastl::enable_if::value, const T&>::type min(const T& a, const T& b) @@ -458,7 +463,7 @@ namespace eastl /// min_alt /// - /// This is an alternative version of min that avoids any possible + /// This is an alternative version of min that avoids any possible /// collisions with Microsoft #defines of min and max. /// /// See min(a, b) for detailed specifications. @@ -486,10 +491,10 @@ namespace eastl /// min /// - /// Min returns the lesser of its two arguments; it returns the first + /// Min returns the lesser of its two arguments; it returns the first /// argument if neither is less than the other. The two arguments are - /// compared with the Compare function (or function object), which - /// takes two arguments and returns true if the first is less than + /// compared with the Compare function (or function object), which + /// takes two arguments and returns true if the first is less than /// the second. /// /// See min(a, b) for detailed specifications. @@ -520,7 +525,7 @@ namespace eastl /// min_alt /// - /// This is an alternative version of min that avoids any possible + /// This is an alternative version of min that avoids any possible /// collisions with Microsoft #defines of min and max. /// /// See min(a, b) for detailed specifications. @@ -537,7 +542,7 @@ namespace eastl /// max /// - /// Max returns the greater of its two arguments; it returns the first + /// Max returns the greater of its two arguments; it returns the first /// argument if neither is greater than the other. The two arguments are /// compared with operator < (and not operator >). /// @@ -546,7 +551,7 @@ namespace eastl /// which for example may in practice result in something different than: /// a <= b ? b : a /// in the case where b is different from a (though they compare as equal). - /// We choose the specific ordering here because that's the ordering + /// We choose the specific ordering here because that's the ordering /// done by other STL implementations. /// template @@ -572,7 +577,7 @@ namespace eastl /// max_alt /// - /// This is an alternative version of max that avoids any possible + /// This is an alternative version of max that avoids any possible /// collisions with Microsoft #defines of min and max. /// template @@ -597,10 +602,10 @@ namespace eastl #if EASTL_MINMAX_ENABLED /// max /// - /// Min returns the lesser of its two arguments; it returns the first + /// Min returns the lesser of its two arguments; it returns the first /// argument if neither is less than the other. The two arguments are - /// compared with the Compare function (or function object), which - /// takes two arguments and returns true if the first is less than + /// compared with the Compare function (or function object), which + /// takes two arguments and returns true if the first is less than /// the second. /// template @@ -610,11 +615,11 @@ namespace eastl return compare(a, b) ? b : a; } #endif - + /// max_alt /// - /// This is an alternative version of max that avoids any possible + /// This is an alternative version of max that avoids any possible /// collisions with Microsoft #defines of min and max. /// template @@ -661,22 +666,22 @@ namespace eastl /// minmax_element /// - /// Returns: make_pair(first, first) if [first, last) is empty, otherwise make_pair(m, M), - /// where m is the first iterator in [first,last) such that no iterator in the range - /// refers to a smaller element, and where M is the last iterator in [first,last) such + /// Returns: make_pair(first, first) if [first, last) is empty, otherwise make_pair(m, M), + /// where m is the first iterator in [first,last) such that no iterator in the range + /// refers to a smaller element, and where M is the last iterator in [first,last) such /// that no iterator in the range refers to a larger element. /// - /// Complexity: At most max([(3/2)*(N - 1)], 0) applications of the corresponding predicate, + /// Complexity: At most max([(3/2)*(N - 1)], 0) applications of the corresponding predicate, /// where N is distance(first, last). /// template - eastl::pair + eastl::pair minmax_element(ForwardIterator first, ForwardIterator last, Compare compare) { eastl::pair result(first, first); - + if(!(first == last) && !(++first == last)) - { + { if(compare(*first, *result.first)) { result.second = result.first; @@ -691,22 +696,22 @@ namespace eastl if(++first == last) { - if(compare(*i, *result.first)) + if(compare(*i, *result.first)) result.first = i; - else if(!compare(*i, *result.second)) + else if(!compare(*i, *result.second)) result.second = i; break; - } + } else { if(compare(*first, *i)) { - if(compare(*first, *result.first)) + if(compare(*first, *result.first)) result.first = first; - if(!compare(*i, *result.second)) + if(!compare(*i, *result.second)) result.second = i; - } + } else { if(compare(*i, *result.first)) @@ -724,7 +729,7 @@ namespace eastl template - eastl::pair + eastl::pair minmax_element(ForwardIterator first, ForwardIterator last) { typedef typename eastl::iterator_traits::value_type value_type; @@ -745,14 +750,14 @@ namespace eastl // The following optimization is a problem because it changes the return value in a way that would break // users unless they used auto (e.g. auto result = minmax(17, 33); ) // - // template + // template // inline EA_CONSTEXPR typename eastl::enable_if::value, eastl::pair >::type // minmax(T a, T b) // { // return (b < a) ? eastl::make_pair(b, a) : eastl::make_pair(a, b); // } // - // template + // template // inline typename eastl::enable_if::value, eastl::pair >::type // minmax(const T& a, const T& b) // { @@ -761,9 +766,9 @@ namespace eastl // It turns out that the following conforming definition of minmax generates a warning when used with VC++ up // to at least VS2012. The VS2012 version of minmax is a broken and non-conforming definition, and we don't - // want to do that. We could do it for scalars alone, though we'd have to decide if we are going to do that + // want to do that. We could do it for scalars alone, though we'd have to decide if we are going to do that // for all compilers, because it changes the return value from a pair of references to a pair of values. - template + template inline eastl::pair minmax(const T& a, const T& b) { @@ -771,7 +776,7 @@ namespace eastl } - template + template eastl::pair minmax(const T& a, const T& b, Compare compare) { @@ -822,7 +827,7 @@ namespace eastl /// median finds which element of three (a, b, d) is in-between the other two. /// If two or more elements are equal, the first (e.g. a before b) is chosen. /// - /// Complexity: Either two or three comparisons will be required, depending + /// Complexity: Either two or three comparisons will be required, depending /// on the values. /// template @@ -836,7 +841,7 @@ namespace eastl /// median finds which element of three (a, b, d) is in-between the other two. /// If two or more elements are equal, the first (e.g. a before b) is chosen. /// - /// Complexity: Either two or three comparisons will be required, depending + /// Complexity: Either two or three comparisons will be required, depending /// on the values. /// template @@ -871,7 +876,7 @@ namespace eastl /// median finds which element of three (a, b, d) is in-between the other two. /// If two or more elements are equal, the first (e.g. a before b) is chosen. /// - /// Complexity: Either two or three comparisons will be required, depending + /// Complexity: Either two or three comparisons will be required, depending /// on the values. /// template @@ -885,7 +890,7 @@ namespace eastl /// median finds which element of three (a, b, d) is in-between the other two. /// If two or more elements are equal, the first (e.g. a before b) is chosen. /// - /// Complexity: Either two or three comparisons will be required, depending + /// Complexity: Either two or three comparisons will be required, depending /// on the values. /// template @@ -938,7 +943,7 @@ namespace eastl { for(; first != last; ++first) { - if(p(*first)) + if(p(*first)) return false; } return true; @@ -947,14 +952,14 @@ namespace eastl /// adjacent_find /// - /// Returns: The first iterator i such that both i and i + 1 are in the range - /// [first, last) for which the following corresponding conditions hold: *i == *(i + 1). + /// Returns: The first iterator i such that both i and i + 1 are in the range + /// [first, last) for which the following corresponding conditions hold: *i == *(i + 1). /// Returns last if no such iterator is found. /// /// Complexity: Exactly 'find(first, last, value) - first' applications of the corresponding predicate. /// template - inline ForwardIterator + inline ForwardIterator adjacent_find(ForwardIterator first, ForwardIterator last) { if(first != last) @@ -975,14 +980,14 @@ namespace eastl /// adjacent_find /// - /// Returns: The first iterator i such that both i and i + 1 are in the range - /// [first, last) for which the following corresponding conditions hold: predicate(*i, *(i + 1)) != false. + /// Returns: The first iterator i such that both i and i + 1 are in the range + /// [first, last) for which the following corresponding conditions hold: predicate(*i, *(i + 1)) != false. /// Returns last if no such iterator is found. /// /// Complexity: Exactly 'find(first, last, value) - first' applications of the corresponding predicate. /// template - inline ForwardIterator + inline ForwardIterator adjacent_find(ForwardIterator first, ForwardIterator last, BinaryPredicate predicate) { if(first != last) @@ -1005,7 +1010,7 @@ namespace eastl /// New for C++11 /// Randomizes a sequence of values via a user-supplied UniformRandomNumberGenerator. /// The difference between this and the original random_shuffle function is that this uses the more - /// advanced and flexible UniformRandomNumberGenerator interface as opposed to the more + /// advanced and flexible UniformRandomNumberGenerator interface as opposed to the more /// limited RandomNumberGenerator interface of random_shuffle. /// /// Effects: Shuffles the elements in the range [first, last) with uniform distribution. @@ -1065,7 +1070,7 @@ namespace eastl // as it turns out that the latter results in unequal distribution probabilities. // http://www.cigital.com/papers/download/developer_gambling.php - for(RandomAccessIterator i = first + 1; i < last; ++i) + for(RandomAccessIterator i = first + 1; i < last; ++i) iter_swap(i, first + (difference_type)rng((eastl_size_t)((i - first) + 1))); } @@ -1087,7 +1092,7 @@ namespace eastl /// inline void random_shuffle(RandomAccessIterator first, RandomAccessIterator last) /// { /// for(RandomAccessIterator i = first + 1; i < last; ++i) - /// iter_swap(i, first + SomeRangedRandomNumberGenerator((i - first) + 1)); + /// iter_swap(i, first + SomeRangedRandomNumberGenerator((i - first) + 1)); /// } @@ -1111,13 +1116,13 @@ namespace eastl template inline OutputIterator move_n_impl(RandomAccessIterator first, Size n, OutputIterator result, EASTL_ITC_NS::random_access_iterator_tag) - { + { return eastl::move(first, first + n, result); // Take advantage of the optimizations present in the move algorithm. } template - inline OutputIterator + inline OutputIterator move_n(InputIterator first, Size n, OutputIterator result) { typedef typename eastl::iterator_traits::iterator_category IC; @@ -1129,9 +1134,9 @@ namespace eastl /// copy_n /// /// Same as copy(InputIterator, InputIterator, OutputIterator) except based on count instead of iterator range. - /// Effects: Copies exactly count values from the range beginning at first to the range beginning at result, if count > 0. Does nothing otherwise. - /// Returns: Iterator in the destination range, pointing past the last element copied if count>0 or first otherwise. - /// Complexity: Exactly count assignments, if count > 0. + /// Effects: Copies exactly count values from the range beginning at first to the range beginning at result, if count > 0. Does nothing otherwise. + /// Returns: Iterator in the destination range, pointing past the last element copied if count>0 or first otherwise. + /// Complexity: Exactly count assignments, if count > 0. /// template inline OutputIterator @@ -1145,13 +1150,13 @@ namespace eastl template inline OutputIterator copy_n_impl(RandomAccessIterator first, Size n, OutputIterator result, EASTL_ITC_NS::random_access_iterator_tag) - { + { return eastl::copy(first, first + n, result); // Take advantage of the optimizations present in the copy algorithm. } template - inline OutputIterator + inline OutputIterator copy_n(InputIterator first, Size n, OutputIterator result) { typedef typename eastl::iterator_traits::iterator_category IC; @@ -1162,7 +1167,7 @@ namespace eastl /// copy_if /// /// Effects: Assigns to the result iterator only if the predicate is true. - /// + /// template inline OutputIterator copy_if(InputIterator first, InputIterator last, OutputIterator result, Predicate predicate) @@ -1224,7 +1229,7 @@ namespace eastl // Specialization for copying non-trivial data via a random-access iterator. It's theoretically faster because the compiler can see the count when its a compile-time const. // This specialization converts the random access BidirectionalIterator1 last-first to an integral type. There's simple way for us to take advantage of a random access output iterator, // as the range is specified by the input instead of the output, and distance(first, last) for a non-random-access iterator is potentially slow. - template <> + template <> struct move_and_copy_backward_helper { template @@ -1258,9 +1263,9 @@ namespace eastl typedef typename eastl::iterator_traits::value_type value_type_input; typedef typename eastl::iterator_traits::value_type value_type_output; - const bool canBeMemmoved = eastl::is_trivially_copyable::value && - eastl::is_same::value && - (eastl::is_pointer::value || eastl::is_same::value) && + const bool canBeMemmoved = eastl::is_trivially_copyable::value && + eastl::is_same::value && + (eastl::is_pointer::value || eastl::is_same::value) && (eastl::is_pointer::value || eastl::is_same::value); return eastl::move_and_copy_backward_helper::move_or_copy_backward(first, last, resultEnd); // Need to chose based on the input iterator tag and not the output iterator tag, because containers accept input ranges of iterator types different than self. @@ -1277,16 +1282,16 @@ namespace eastl /// move_backward /// - /// The elements are moved in reverse order (the last element is moved first), but their relative order is preserved. - /// After this operation the elements in the moved-from range will still contain valid values of the - /// appropriate type, but not necessarily the same values as before the move. + /// The elements are moved in reverse order (the last element is moved first), but their relative order is preserved. + /// After this operation the elements in the moved-from range will still contain valid values of the + /// appropriate type, but not necessarily the same values as before the move. /// Returns the beginning of the result range. /// Note: When moving between containers, the dest range must be valid; this function doesn't resize containers. - /// Note: If result is within [first, last), move must be used instead of move_backward. + /// Note: If result is within [first, last), move must be used instead of move_backward. /// /// Example usage: - /// eastl::move_backward(myArray.begin(), myArray.end(), myDestArray.end()); - /// + /// eastl::move_backward(myArray.begin(), myArray.end(), myDestArray.end()); + /// /// Reference implementation: /// template /// BidirectionalIterator2 move_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 resultEnd) @@ -1295,7 +1300,7 @@ namespace eastl /// *--resultEnd = eastl::move(*--last); /// return resultEnd; /// } - /// + /// template inline BidirectionalIterator2 move_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 resultEnd) { @@ -1306,9 +1311,9 @@ namespace eastl /// copy_backward /// /// copies memory in the range of [first, last) to the range *ending* with result. - /// - /// Effects: Copies elements in the range [first, last) into the range - /// [result - (last - first), result) starting from last 1 and proceeding to first. + /// + /// Effects: Copies elements in the range [first, last) into the range + /// [result - (last - first), result) starting from last 1 and proceeding to first. /// For each positive integer n <= (last - first), performs *(result n) = *(last - n). /// /// Requires: result shall not be in the range [first, last). @@ -1316,7 +1321,7 @@ namespace eastl /// Returns: result - (last - first). That is, returns the beginning of the result range. /// /// Complexity: Exactly 'last - first' assignments. - /// + /// template inline BidirectionalIterator2 copy_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 resultEnd) { @@ -1330,7 +1335,7 @@ namespace eastl /// /// Counts the number of items in the range of [first, last) which equal the input value. /// - /// Effects: Returns the number of iterators i in the range [first, last) for which the + /// Effects: Returns the number of iterators i in the range [first, last) for which the /// following corresponding conditions hold: *i == value. /// /// Complexity: At most 'last - first' applications of the corresponding predicate. @@ -1372,10 +1377,10 @@ namespace eastl /// count_if /// - /// Counts the number of items in the range of [first, last) which match + /// Counts the number of items in the range of [first, last) which match /// the input value as defined by the input predicate function. /// - /// Effects: Returns the number of iterators i in the range [first, last) for which the + /// Effects: Returns the number of iterators i in the range [first, last) for which the /// following corresponding conditions hold: predicate(*i) != false. /// /// Complexity: At most 'last - first' applications of the corresponding predicate. @@ -1400,14 +1405,14 @@ namespace eastl /// find /// - /// finds the value within the unsorted range of [first, last). + /// finds the value within the unsorted range of [first, last). /// - /// Returns: The first iterator i in the range [first, last) for which - /// the following corresponding conditions hold: *i == value. + /// Returns: The first iterator i in the range [first, last) for which + /// the following corresponding conditions hold: *i == value. /// Returns last if no such iterator is found. /// /// Complexity: At most 'last - first' applications of the corresponding predicate. - /// This is a linear search and not a binary one. + /// This is a linear search and not a binary one. /// /// Note: The predicate version of find is find_if and not another variation of find. /// This is because both versions would have three parameters and there could be ambiguity. @@ -1437,10 +1442,10 @@ namespace eastl /// find_if /// - /// finds the value within the unsorted range of [first, last). + /// finds the value within the unsorted range of [first, last). /// - /// Returns: The first iterator i in the range [first, last) for which - /// the following corresponding conditions hold: pred(*i) != false. + /// Returns: The first iterator i in the range [first, last) for which + /// the following corresponding conditions hold: pred(*i) != false. /// Returns last if no such iterator is found. /// If the sequence of elements to search for (i.e. first2 - last2) is empty, /// the find always fails and last1 will be returned. @@ -1467,7 +1472,7 @@ namespace eastl /// returns false for the elements instead of true. /// template - inline InputIterator + inline InputIterator find_if_not(InputIterator first, InputIterator last, Predicate predicate) { for(; first != last; ++first) @@ -1483,27 +1488,27 @@ namespace eastl /// find_first_of /// - /// find_first_of is similar to find in that it performs linear search through - /// a range of ForwardIterators. The difference is that while find searches - /// for one particular value, find_first_of searches for any of several values. - /// Specifically, find_first_of searches for the first occurrance in the - /// range [first1, last1) of any of the elements in [first2, last2). + /// find_first_of is similar to find in that it performs linear search through + /// a range of ForwardIterators. The difference is that while find searches + /// for one particular value, find_first_of searches for any of several values. + /// Specifically, find_first_of searches for the first occurrance in the + /// range [first1, last1) of any of the elements in [first2, last2). /// This function is thus similar to the strpbrk standard C string function. /// If the sequence of elements to search for (i.e. first2-last2) is empty, /// the find always fails and last1 will be returned. /// /// Effects: Finds an element that matches one of a set of values. /// - /// Returns: The first iterator i in the range [first1, last1) such that for some + /// Returns: The first iterator i in the range [first1, last1) such that for some /// integer j in the range [first2, last2) the following conditions hold: *i == *j. /// Returns last1 if no such iterator is found. /// - /// Complexity: At most '(last1 - first1) * (last2 - first2)' applications of the + /// Complexity: At most '(last1 - first1) * (last2 - first2)' applications of the /// corresponding predicate. /// template ForwardIterator1 - find_first_of(ForwardIterator1 first1, ForwardIterator1 last1, + find_first_of(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2) { for(; first1 != last1; ++first1) @@ -1520,25 +1525,25 @@ namespace eastl /// find_first_of /// - /// find_first_of is similar to find in that it performs linear search through - /// a range of ForwardIterators. The difference is that while find searches - /// for one particular value, find_first_of searches for any of several values. - /// Specifically, find_first_of searches for the first occurrance in the - /// range [first1, last1) of any of the elements in [first2, last2). + /// find_first_of is similar to find in that it performs linear search through + /// a range of ForwardIterators. The difference is that while find searches + /// for one particular value, find_first_of searches for any of several values. + /// Specifically, find_first_of searches for the first occurrance in the + /// range [first1, last1) of any of the elements in [first2, last2). /// This function is thus similar to the strpbrk standard C string function. /// /// Effects: Finds an element that matches one of a set of values. /// - /// Returns: The first iterator i in the range [first1, last1) such that for some + /// Returns: The first iterator i in the range [first1, last1) such that for some /// integer j in the range [first2, last2) the following conditions hold: pred(*i, *j) != false. /// Returns last1 if no such iterator is found. /// - /// Complexity: At most '(last1 - first1) * (last2 - first2)' applications of the + /// Complexity: At most '(last1 - first1) * (last2 - first2)' applications of the /// corresponding predicate. /// template ForwardIterator1 - find_first_of(ForwardIterator1 first1, ForwardIterator1 last1, + find_first_of(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate predicate) { @@ -1559,16 +1564,16 @@ namespace eastl /// Searches through first range for the first element that does not belong the second input range. /// This is very much like the C++ string find_first_not_of function. /// - /// Returns: The first iterator i in the range [first1, last1) such that for some + /// Returns: The first iterator i in the range [first1, last1) such that for some /// integer j in the range [first2, last2) the following conditions hold: !(*i == *j). /// Returns last1 if no such iterator is found. /// - /// Complexity: At most '(last1 - first1) * (last2 - first2)' applications of the + /// Complexity: At most '(last1 - first1) * (last2 - first2)' applications of the /// corresponding predicate. /// template ForwardIterator1 - find_first_not_of(ForwardIterator1 first1, ForwardIterator1 last1, + find_first_not_of(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2) { for(; first1 != last1; ++first1) @@ -1587,17 +1592,17 @@ namespace eastl /// Searches through first range for the first element that does not belong the second input range. /// This is very much like the C++ string find_first_not_of function. /// - /// Returns: The first iterator i in the range [first1, last1) such that for some + /// Returns: The first iterator i in the range [first1, last1) such that for some /// integer j in the range [first2, last2) the following conditions hold: pred(*i, *j) == false. /// Returns last1 if no such iterator is found. /// - /// Complexity: At most '(last1 - first1) * (last2 - first2)' applications of the + /// Complexity: At most '(last1 - first1) * (last2 - first2)' applications of the /// corresponding predicate. /// template inline ForwardIterator1 - find_first_not_of(ForwardIterator1 first1, ForwardIterator1 last1, - ForwardIterator2 first2, ForwardIterator2 last2, + find_first_not_of(ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate predicate) { typedef typename eastl::iterator_traits::value_type value_type; @@ -1614,7 +1619,7 @@ namespace eastl template inline BidirectionalIterator1 - find_last_of(BidirectionalIterator1 first1, BidirectionalIterator1 last1, + find_last_of(BidirectionalIterator1 first1, BidirectionalIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2) { if((first1 != last1) && (first2 != last2)) @@ -1634,8 +1639,8 @@ namespace eastl template BidirectionalIterator1 - find_last_of(BidirectionalIterator1 first1, BidirectionalIterator1 last1, - ForwardIterator2 first2, ForwardIterator2 last2, + find_last_of(BidirectionalIterator1 first1, BidirectionalIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate predicate) { typedef typename eastl::iterator_traits::value_type value_type; @@ -1657,7 +1662,7 @@ namespace eastl template inline BidirectionalIterator1 - find_last_not_of(BidirectionalIterator1 first1, BidirectionalIterator1 last1, + find_last_not_of(BidirectionalIterator1 first1, BidirectionalIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2) { if((first1 != last1) && (first2 != last2)) @@ -1677,8 +1682,8 @@ namespace eastl template inline BidirectionalIterator1 - find_last_not_of(BidirectionalIterator1 first1, BidirectionalIterator1 last1, - ForwardIterator2 first2, ForwardIterator2 last2, + find_last_not_of(BidirectionalIterator1 first1, BidirectionalIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate predicate) { typedef typename eastl::iterator_traits::value_type value_type; @@ -1704,8 +1709,8 @@ namespace eastl /// /// Calls the Function function for each value in the range [first, last). /// Function takes a single parameter: the current value. - /// - /// Effects: Applies function to the result of dereferencing every iterator in + /// + /// Effects: Applies function to the result of dereferencing every iterator in /// the range [first, last), starting from first and proceeding to last 1. /// /// Returns: function. @@ -1713,7 +1718,7 @@ namespace eastl /// Complexity: Applies function exactly 'last - first' times. /// /// Note: If function returns a result, the result is ignored. - /// + /// template inline Function for_each(InputIterator first, InputIterator last, Function function) @@ -1727,20 +1732,20 @@ namespace eastl /// /// Calls the Function function for each value in the range [first, first + n). /// Function takes a single parameter: the current value. - /// - /// Effects: Applies function to the result of dereferencing every iterator in + /// + /// Effects: Applies function to the result of dereferencing every iterator in /// the range [first, first + n), starting from first and proceeding to last 1. /// /// Returns: first + n. /// /// Complexity: Applies function exactly 'first + n' times. /// - /// Note: + /// Note: //// * If function returns a result, the result is ignored. //// * If n < 0, behaviour is undefined. /// template - EA_CPP14_CONSTEXPR inline InputIterator + EA_CPP14_CONSTEXPR inline InputIterator for_each_n(InputIterator first, Size n, Function function) { for (Size i = 0; i < n; ++first, i++) @@ -1754,15 +1759,15 @@ namespace eastl /// Iterates the range of [first, last) and assigns to each element the /// result of the function generator. Generator is a function which takes /// no arguments. - /// + /// /// Complexity: Exactly 'last - first' invocations of generator and assignments. /// template inline void generate(ForwardIterator first, ForwardIterator last, Generator generator) { - for(; first != last; ++first) // We cannot call generate_n(first, last-first, generator) - *first = generator(); // because the 'last-first' might not be supported by the + for(; first != last; ++first) // We cannot call generate_n(first, last-first, generator) + *first = generator(); // because the 'last-first' might not be supported by the } // given iterator. @@ -1771,7 +1776,7 @@ namespace eastl /// Iterates an interator n times and assigns the result of generator /// to each succeeding element. Generator is a function which takes /// no arguments. - /// + /// /// Complexity: Exactly n invocations of generator and assignments. /// template @@ -1788,7 +1793,7 @@ namespace eastl /// /// Iterates the input range of [first, last) and the output iterator result /// and assigns the result of unaryOperation(input) to result. - /// + /// /// Effects: Assigns through every iterator i in the range [result, result + (last1 - first1)) /// a new corresponding value equal to unaryOperation(*(first1 + (i - result)). /// @@ -1814,7 +1819,7 @@ namespace eastl /// /// Iterates the input range of [first, last) and the output iterator result /// and assigns the result of binaryOperation(input1, input2) to result. - /// + /// /// Effects: Assigns through every iterator i in the range [result, result + (last1 - first1)) /// a new corresponding value equal to binaryOperation(*(first1 + (i - result), *(first2 + (i - result))). /// @@ -1838,14 +1843,14 @@ namespace eastl /// equal /// - /// Returns: true if for every iterator i in the range [first1, last1) the - /// following corresponding conditions hold: predicate(*i, *(first2 + (i - first1))) != false. + /// Returns: true if for every iterator i in the range [first1, last1) the + /// following corresponding conditions hold: predicate(*i, *(first2 + (i - first1))) != false. /// Otherwise, returns false. /// /// Complexity: At most last1 first1 applications of the corresponding predicate. /// /// To consider: Make specializations of this for scalar types and random access - /// iterators that uses memcmp or some trick memory comparison function. + /// iterators that uses memcmp or some trick memory comparison function. /// We should verify that such a thing results in an improvement. /// template @@ -1902,8 +1907,8 @@ namespace eastl /// equal /// - /// Returns: true if for every iterator i in the range [first1, last1) the - /// following corresponding conditions hold: pred(*i, *(first2 + (i first1))) != false. + /// Returns: true if for every iterator i in the range [first1, last1) the + /// following corresponding conditions hold: pred(*i, *(first2 + (i first1))) != false. /// Otherwise, returns false. /// /// Complexity: At most last1 first1 applications of the corresponding predicate. @@ -1925,20 +1930,20 @@ namespace eastl /// identical /// /// Returns true if the two input ranges are equivalent. - /// There is a subtle difference between this algorithm and - /// the 'equal' algorithm. The equal algorithm assumes the + /// There is a subtle difference between this algorithm and + /// the 'equal' algorithm. The equal algorithm assumes the /// two ranges are of equal length. This algorithm efficiently - /// compares two ranges for both length equality and for + /// compares two ranges for both length equality and for /// element equality. There is no other standard algorithm /// that can do this. /// - /// Returns: true if the sequence of elements defined by the range + /// Returns: true if the sequence of elements defined by the range /// [first1, last1) is of the same length as the sequence of /// elements defined by the range of [first2, last2) and if - /// the elements in these ranges are equal as per the + /// the elements in these ranges are equal as per the /// equal algorithm. /// - /// Complexity: At most 'min((last1 - first1), (last2 - first2))' applications + /// Complexity: At most 'min((last1 - first1), (last2 - first2))' applications /// of the corresponding comparison. /// template @@ -1972,19 +1977,19 @@ namespace eastl /// lexicographical_compare /// - /// Returns: true if the sequence of elements defined by the range - /// [first1, last1) is lexicographically less than the sequence of + /// Returns: true if the sequence of elements defined by the range + /// [first1, last1) is lexicographically less than the sequence of /// elements defined by the range [first2, last2). Returns false otherwise. /// - /// Complexity: At most 'min((last1 - first1), (last2 - first2))' applications + /// Complexity: At most 'min((last1 - first1), (last2 - first2))' applications /// of the corresponding comparison. /// - /// Note: If two sequences have the same number of elements and their - /// corresponding elements are equivalent, then neither sequence is - /// lexicographically less than the other. If one sequence is a prefix - /// of the other, then the shorter sequence is lexicographically less - /// than the longer sequence. Otherwise, the lexicographical comparison - /// of the sequences yields the same result as the comparison of the first + /// Note: If two sequences have the same number of elements and their + /// corresponding elements are equivalent, then neither sequence is + /// lexicographically less than the other. If one sequence is a prefix + /// of the other, then the shorter sequence is lexicographically less + /// than the longer sequence. Otherwise, the lexicographical comparison + /// of the sequences yields the same result as the comparison of the first /// corresponding pair of elements that are not equivalent. /// template @@ -2072,30 +2077,30 @@ namespace eastl /// lexicographical_compare /// - /// Returns: true if the sequence of elements defined by the range - /// [first1, last1) is lexicographically less than the sequence of + /// Returns: true if the sequence of elements defined by the range + /// [first1, last1) is lexicographically less than the sequence of /// elements defined by the range [first2, last2). Returns false otherwise. /// - /// Complexity: At most 'min((last1 -first1), (last2 - first2))' applications + /// Complexity: At most 'min((last1 -first1), (last2 - first2))' applications /// of the corresponding comparison. /// - /// Note: If two sequences have the same number of elements and their - /// corresponding elements are equivalent, then neither sequence is - /// lexicographically less than the other. If one sequence is a prefix - /// of the other, then the shorter sequence is lexicographically less - /// than the longer sequence. Otherwise, the lexicographical comparison - /// of the sequences yields the same result as the comparison of the first + /// Note: If two sequences have the same number of elements and their + /// corresponding elements are equivalent, then neither sequence is + /// lexicographically less than the other. If one sequence is a prefix + /// of the other, then the shorter sequence is lexicographically less + /// than the longer sequence. Otherwise, the lexicographical comparison + /// of the sequences yields the same result as the comparison of the first /// corresponding pair of elements that are not equivalent. /// /// Note: False is always returned if range 1 is exhausted before range 2. /// The result of this is that you can't do a successful reverse compare - /// (e.g. use greater<> as the comparison instead of less<>) unless the + /// (e.g. use greater<> as the comparison instead of less<>) unless the /// two sequences are of identical length. What you want to do is reverse /// the order of the arguments in order to get the desired effect. /// template inline bool - lexicographical_compare(InputIterator1 first1, InputIterator1 last1, + lexicographical_compare(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, Compare compare) { for(; (first1 != last1) && (first2 != last2); ++first1, ++first2) @@ -2111,14 +2116,14 @@ namespace eastl /// mismatch /// - /// Finds the first position where the two ranges [first1, last1) and - /// [first2, first2 + (last1 - first1)) differ. The two versions of + /// Finds the first position where the two ranges [first1, last1) and + /// [first2, first2 + (last1 - first1)) differ. The two versions of /// mismatch use different tests for whether elements differ. /// /// Returns: A pair of iterators i and j such that j == first2 + (i - first1) - /// and i is the first iterator in the range [first1, last1) for which the + /// and i is the first iterator in the range [first1, last1) for which the /// following corresponding condition holds: !(*i == *(first2 + (i - first1))). - /// Returns the pair last1 and first2 + (last1 - first1) if such an iterator + /// Returns the pair last1 and first2 + (last1 - first1) if such an iterator /// i is not found. /// /// Complexity: At most last1 first1 applications of the corresponding predicate. @@ -2140,14 +2145,14 @@ namespace eastl /// mismatch /// - /// Finds the first position where the two ranges [first1, last1) and - /// [first2, first2 + (last1 - first1)) differ. The two versions of + /// Finds the first position where the two ranges [first1, last1) and + /// [first2, first2 + (last1 - first1)) differ. The two versions of /// mismatch use different tests for whether elements differ. /// /// Returns: A pair of iterators i and j such that j == first2 + (i - first1) - /// and i is the first iterator in the range [first1, last1) for which the + /// and i is the first iterator in the range [first1, last1) for which the /// following corresponding condition holds: pred(*i, *(first2 + (i - first1))) == false. - /// Returns the pair last1 and first2 + (last1 - first1) if such an iterator + /// Returns the pair last1 and first2 + (last1 - first1) if such an iterator /// i is not found. /// /// Complexity: At most last1 first1 applications of the corresponding predicate. @@ -2170,20 +2175,20 @@ namespace eastl /// lower_bound /// - /// Finds the position of the first element in a sorted range that has a value + /// Finds the position of the first element in a sorted range that has a value /// greater than or equivalent to a specified value. /// - /// Effects: Finds the first position into which value can be inserted without + /// Effects: Finds the first position into which value can be inserted without /// violating the ordering. - /// - /// Returns: The furthermost iterator i in the range [first, last) such that - /// for any iterator j in the range [first, i) the following corresponding + /// + /// Returns: The furthermost iterator i in the range [first, last) such that + /// for any iterator j in the range [first, i) the following corresponding /// condition holds: *j < value. /// /// Complexity: At most 'log(last - first) + 1' comparisons. /// - /// Optimizations: We have no need to specialize this implementation for random - /// access iterators (e.g. contiguous array), as the code below will already + /// Optimizations: We have no need to specialize this implementation for random + /// access iterators (e.g. contiguous array), as the code below will already /// take advantage of them. /// template @@ -2216,22 +2221,22 @@ namespace eastl /// lower_bound /// - /// Finds the position of the first element in a sorted range that has a value + /// Finds the position of the first element in a sorted range that has a value /// greater than or equivalent to a specified value. The input Compare function /// takes two arguments and returns true if the first argument is less than /// the second argument. /// - /// Effects: Finds the first position into which value can be inserted without + /// Effects: Finds the first position into which value can be inserted without /// violating the ordering. - /// - /// Returns: The furthermost iterator i in the range [first, last) such that - /// for any iterator j in the range [first, i) the following corresponding + /// + /// Returns: The furthermost iterator i in the range [first, last) such that + /// for any iterator j in the range [first, i) the following corresponding /// condition holds: compare(*j, value) != false. /// /// Complexity: At most 'log(last - first) + 1' comparisons. /// - /// Optimizations: We have no need to specialize this implementation for random - /// access iterators (e.g. contiguous array), as the code below will already + /// Optimizations: We have no need to specialize this implementation for random + /// access iterators (e.g. contiguous array), as the code below will already /// take advantage of them. /// template @@ -2265,14 +2270,14 @@ namespace eastl /// upper_bound /// - /// Finds the position of the first element in a sorted range that has a + /// Finds the position of the first element in a sorted range that has a /// value that is greater than a specified value. /// - /// Effects: Finds the furthermost position into which value can be inserted + /// Effects: Finds the furthermost position into which value can be inserted /// without violating the ordering. /// - /// Returns: The furthermost iterator i in the range [first, last) such that - /// for any iterator j in the range [first, i) the following corresponding + /// Returns: The furthermost iterator i in the range [first, last) such that + /// for any iterator j in the range [first, i) the following corresponding /// condition holds: !(value < *j). /// /// Complexity: At most 'log(last - first) + 1' comparisons. @@ -2309,16 +2314,16 @@ namespace eastl /// upper_bound /// - /// Finds the position of the first element in a sorted range that has a + /// Finds the position of the first element in a sorted range that has a /// value that is greater than a specified value. The input Compare function /// takes two arguments and returns true if the first argument is less than /// the second argument. /// - /// Effects: Finds the furthermost position into which value can be inserted + /// Effects: Finds the furthermost position into which value can be inserted /// without violating the ordering. /// - /// Returns: The furthermost iterator i in the range [first, last) such that - /// for any iterator j in the range [first, i) the following corresponding + /// Returns: The furthermost iterator i in the range [first, last) such that + /// for any iterator j in the range [first, i) the following corresponding /// condition holds: compare(value, *j) == false. /// /// Complexity: At most 'log(last - first) + 1' comparisons. @@ -2355,10 +2360,10 @@ namespace eastl /// equal_range /// - /// Effects: Finds the largest subrange [i, j) such that the value can be inserted - /// at any iterator k in it without violating the ordering. k satisfies the + /// Effects: Finds the largest subrange [i, j) such that the value can be inserted + /// at any iterator k in it without violating the ordering. k satisfies the /// corresponding conditions: !(*k < value) && !(value < *k). - /// + /// /// Complexity: At most '2 * log(last - first) + 1' comparisons. /// template @@ -2393,7 +2398,7 @@ namespace eastl { ForwardIterator j(i); - return ResultType(eastl::lower_bound(first, i, value), + return ResultType(eastl::lower_bound(first, i, value), eastl::upper_bound(++j, last, value)); } } @@ -2403,10 +2408,10 @@ namespace eastl /// equal_range /// - /// Effects: Finds the largest subrange [i, j) such that the value can be inserted - /// at any iterator k in it without violating the ordering. k satisfies the + /// Effects: Finds the largest subrange [i, j) such that the value can be inserted + /// at any iterator k in it without violating the ordering. k satisfies the /// corresponding conditions: compare(*k, value) == false && compare(value, *k) == false. - /// + /// /// Complexity: At most '2 * log(last - first) + 1' comparisons. /// template @@ -2441,7 +2446,7 @@ namespace eastl { ForwardIterator j(i); - return ResultType(eastl::lower_bound(first, i, value, compare), + return ResultType(eastl::lower_bound(first, i, value, compare), eastl::upper_bound(++j, last, value, compare)); } } @@ -2451,9 +2456,9 @@ namespace eastl /// replace /// - /// Effects: Substitutes elements referred by the iterator i in the range [first, last) + /// Effects: Substitutes elements referred by the iterator i in the range [first, last) /// with new_value, when the following corresponding conditions hold: *i == old_value. - /// + /// /// Complexity: Exactly 'last - first' applications of the corresponding predicate. /// /// Note: The predicate version of replace is replace_if and not another variation of replace. @@ -2473,9 +2478,9 @@ namespace eastl /// replace_if /// - /// Effects: Substitutes elements referred by the iterator i in the range [first, last) + /// Effects: Substitutes elements referred by the iterator i in the range [first, last) /// with new_value, when the following corresponding conditions hold: predicate(*i) != false. - /// + /// /// Complexity: Exactly 'last - first' applications of the corresponding predicate. /// /// Note: The predicate version of replace_if is replace and not another variation of replace_if. @@ -2495,8 +2500,8 @@ namespace eastl /// remove_copy /// - /// Effects: Copies all the elements referred to by the iterator i in the range - /// [first, last) for which the following corresponding condition does not hold: + /// Effects: Copies all the elements referred to by the iterator i in the range + /// [first, last) for which the following corresponding condition does not hold: /// *i == value. /// /// Requires: The ranges [first, last) and [result, result + (last - first)) shall not overlap. @@ -2513,7 +2518,7 @@ namespace eastl { if(!(*first == value)) // Note that we always express value comparisons in terms of < or ==. { - *result = move(*first); + *result = eastl::move(*first); ++result; } } @@ -2523,8 +2528,8 @@ namespace eastl /// remove_copy_if /// - /// Effects: Copies all the elements referred to by the iterator i in the range - /// [first, last) for which the following corresponding condition does not hold: + /// Effects: Copies all the elements referred to by the iterator i in the range + /// [first, last) for which the following corresponding condition does not hold: /// predicate(*i) != false. /// /// Requires: The ranges [first, last) and [result, result + (last - first)) shall not overlap. @@ -2551,7 +2556,7 @@ namespace eastl /// remove /// - /// Effects: Eliminates all the elements referred to by iterator i in the + /// Effects: Eliminates all the elements referred to by iterator i in the /// range [first, last) for which the following corresponding condition /// holds: *i == value. /// @@ -2562,9 +2567,9 @@ namespace eastl /// Note: The predicate version of remove is remove_if and not another variation of remove. /// This is because both versions would have the same parameter count and there could be ambiguity. /// - /// Note: Since this function moves the element to the back of the heap and + /// Note: Since this function moves the element to the back of the heap and /// doesn't actually remove it from the given container, the user must call - /// the container erase function if the user wants to erase the element + /// the container erase function if the user wants to erase the element /// from the container. /// /// Example usage: @@ -2588,8 +2593,8 @@ namespace eastl /// remove_if /// - /// Effects: Eliminates all the elements referred to by iterator i in the - /// range [first, last) for which the following corresponding condition + /// Effects: Eliminates all the elements referred to by iterator i in the + /// range [first, last) for which the following corresponding condition /// holds: predicate(*i) != false. /// /// Returns: The end of the resulting range. @@ -2599,9 +2604,9 @@ namespace eastl /// Note: The predicate version of remove_if is remove and not another variation of remove_if. /// This is because both versions would have the same parameter count and there could be ambiguity. /// - /// Note: Since this function moves the element to the back of the heap and + /// Note: Since this function moves the element to the back of the heap and /// doesn't actually remove it from the given container, the user must call - /// the container erase function if the user wants to erase the element + /// the container erase function if the user wants to erase the element /// from the container. /// /// Example usage: @@ -2626,7 +2631,7 @@ namespace eastl /// replace_copy /// /// Effects: Assigns to every iterator i in the range [result, result + (last - first)) - /// either new_value or *(first + (i - result)) depending on whether the following + /// either new_value or *(first + (i - result)) depending on whether the following /// corresponding conditions hold: *(first + (i - result)) == old_value. /// /// Requires: The ranges [first, last) and [result, result + (last - first)) shall not overlap. @@ -2651,7 +2656,7 @@ namespace eastl /// replace_copy_if /// /// Effects: Assigns to every iterator i in the range [result, result + (last - first)) - /// either new_value or *(first + (i - result)) depending on whether the following + /// either new_value or *(first + (i - result)) depending on whether the following /// corresponding conditions hold: predicate(*(first + (i - result))) != false. /// /// Requires: The ranges [first, last) and [result, result+(lastfirst)) shall not overlap. @@ -2677,7 +2682,7 @@ namespace eastl // reverse // - // We provide helper functions which allow reverse to be implemented more + // We provide helper functions which allow reverse to be implemented more // efficiently for some types of iterators and types. // template @@ -2701,7 +2706,7 @@ namespace eastl /// /// Reverses the values within the range [first, last). /// - /// Effects: For each nonnegative integer i <= (last - first) / 2, + /// Effects: For each nonnegative integer i <= (last - first) / 2, /// applies swap to all pairs of iterators first + i, (last i) - 1. /// /// Complexity: Exactly '(last - first) / 2' swaps. @@ -2719,7 +2724,7 @@ namespace eastl /// /// Copies the range [first, last) in reverse order to the result. /// - /// Effects: Copies the range [first, last) to the range + /// Effects: Copies the range [first, last) to the range /// [result, result + (last - first)) such that for any nonnegative /// integer i < (last - first) the following assignment takes place: /// *(result + (last - first) - i) = *(first + i) @@ -2744,9 +2749,9 @@ namespace eastl /// search /// - /// Search finds a subsequence within the range [first1, last1) that is identical to [first2, last2) - /// when compared element-by-element. It returns an iterator pointing to the beginning of that - /// subsequence, or else last1 if no such subsequence exists. As such, it is very much like + /// Search finds a subsequence within the range [first1, last1) that is identical to [first2, last2) + /// when compared element-by-element. It returns an iterator pointing to the beginning of that + /// subsequence, or else last1 if no such subsequence exists. As such, it is very much like /// the C strstr function, with the primary difference being that strstr uses 0-terminated strings /// whereas search uses an end iterator to specify the end of a string. /// @@ -2758,7 +2763,7 @@ namespace eastl /// template ForwardIterator1 - search(ForwardIterator1 first1, ForwardIterator1 last1, + search(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2) { if(first2 != last2) // If there is anything to search for... @@ -2839,9 +2844,9 @@ namespace eastl /// search /// - /// Search finds a subsequence within the range [first1, last1) that is identical to [first2, last2) - /// when compared element-by-element. It returns an iterator pointing to the beginning of that - /// subsequence, or else last1 if no such subsequence exists. As such, it is very much like + /// Search finds a subsequence within the range [first1, last1) that is identical to [first2, last2) + /// when compared element-by-element. It returns an iterator pointing to the beginning of that + /// subsequence, or else last1 if no such subsequence exists. As such, it is very much like /// the C strstr function, with the only difference being that strstr uses 0-terminated strings /// whereas search uses an end iterator to specify the end of a string. /// @@ -2853,7 +2858,7 @@ namespace eastl /// template ForwardIterator1 - search(ForwardIterator1 first1, ForwardIterator1 last1, + search(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate predicate) { @@ -2894,7 +2899,7 @@ namespace eastl return first; Size d1 = (Size)eastl::distance(first, last); // Should d1 be of type Size, ptrdiff_t, or iterator_traits::difference_type? - // The problem with using iterator_traits::difference_type is that + // The problem with using iterator_traits::difference_type is that if(count > d1) // ForwardIterator may not be a true iterator but instead something like a pointer. return last; @@ -2972,9 +2977,9 @@ namespace eastl /// search_n /// - /// Returns: The first iterator i in the range [first, last count) such that - /// for any nonnegative integer n less than count the following corresponding - /// conditions hold: *(i + n) == value, pred(*(i + n),value) != false. + /// Returns: The first iterator i in the range [first, last count) such that + /// for any nonnegative integer n less than count the following corresponding + /// conditions hold: *(i + n) == value, pred(*(i + n),value) != false. /// Returns last if no such iterator is found. /// /// Complexity: At most '(last1 - first1) * count' applications of the corresponding predicate. @@ -2990,13 +2995,13 @@ namespace eastl /// binary_search /// - /// Returns: true if there is an iterator i in the range [first last) that + /// Returns: true if there is an iterator i in the range [first last) that /// satisfies the corresponding conditions: !(*i < value) && !(value < *i). /// /// Complexity: At most 'log(last - first) + 2' comparisons. /// /// Note: The reason binary_search returns bool instead of an iterator is - /// that search_n, lower_bound, or equal_range already return an iterator. + /// that search_n, lower_bound, or equal_range already return an iterator. /// However, there are arguments that binary_search should return an iterator. /// Note that we provide binary_search_i (STL extension) to return an iterator. /// @@ -3021,8 +3026,8 @@ namespace eastl /// binary_search /// - /// Returns: true if there is an iterator i in the range [first last) that - /// satisfies the corresponding conditions: compare(*i, value) == false && + /// Returns: true if there is an iterator i in the range [first last) that + /// satisfies the corresponding conditions: compare(*i, value) == false && /// compare(value, *i) == false. /// /// Complexity: At most 'log(last - first) + 2' comparisons. @@ -3041,7 +3046,7 @@ namespace eastl /// binary_search_i /// - /// Returns: iterator if there is an iterator i in the range [first last) that + /// Returns: iterator if there is an iterator i in the range [first last) that /// satisfies the corresponding conditions: !(*i < value) && !(value < *i). /// Returns last if the value is not found. /// @@ -3061,7 +3066,7 @@ namespace eastl /// binary_search_i /// - /// Returns: iterator if there is an iterator i in the range [first last) that + /// Returns: iterator if there is an iterator i in the range [first last) that /// satisfies the corresponding conditions: !(*i < value) && !(value < *i). /// Returns last if the value is not found. /// @@ -3082,12 +3087,12 @@ namespace eastl /// unique /// /// Given a sorted range, this function removes duplicated items. - /// Note that if you have a container then you will probably want - /// to call erase on the container with the return value if your + /// Note that if you have a container then you will probably want + /// to call erase on the container with the return value if your /// goal is to remove the duplicated items from the container. /// - /// Effects: Eliminates all but the first element from every consecutive - /// group of equal elements referred to by the iterator i in the range + /// Effects: Eliminates all but the first element from every consecutive + /// group of equal elements referred to by the iterator i in the range /// [first, last) for which the following corresponding condition holds: /// *i == *(i - 1). /// @@ -3109,7 +3114,7 @@ namespace eastl if(first != last) // We expect that there are duplicated items, else the user wouldn't be calling this function. { ForwardIterator dest(first); - + for(++first; first != last; ++first) { if(!(*dest == *first)) // Note that we always express value comparisons in terms of < or ==. @@ -3124,12 +3129,12 @@ namespace eastl /// unique /// /// Given a sorted range, this function removes duplicated items. - /// Note that if you have a container then you will probably want - /// to call erase on the container with the return value if your + /// Note that if you have a container then you will probably want + /// to call erase on the container with the return value if your /// goal is to remove the duplicated items from the container. /// - /// Effects: Eliminates all but the first element from every consecutive - /// group of equal elements referred to by the iterator i in the range + /// Effects: Eliminates all but the first element from every consecutive + /// group of equal elements referred to by the iterator i in the range /// [first, last) for which the following corresponding condition holds: /// predicate(*i, *(i - 1)) != false. /// @@ -3146,7 +3151,7 @@ namespace eastl if(first != last) // We expect that there are duplicated items, else the user wouldn't be calling this function. { ForwardIterator dest(first); - + for(++first; first != last; ++first) { if(!predicate(*dest, *first)) @@ -3162,8 +3167,8 @@ namespace eastl // find_end // // We provide two versions here, one for a bidirectional iterators and one for - // regular forward iterators. Given that we are searching backward, it's a bit - // more efficient if we can use backwards iteration to implement our search, + // regular forward iterators. Given that we are searching backward, it's a bit + // more efficient if we can use backwards iteration to implement our search, // though this requires an iterator that can be reversed. // template @@ -3199,13 +3204,13 @@ namespace eastl typedef eastl::reverse_iterator reverse_iterator1; typedef eastl::reverse_iterator reverse_iterator2; - reverse_iterator1 rresult(eastl::search(reverse_iterator1(last1), reverse_iterator1(first1), + reverse_iterator1 rresult(eastl::search(reverse_iterator1(last1), reverse_iterator1(first1), reverse_iterator2(last2), reverse_iterator2(first2))); if(rresult.base() != first1) // If we found something... { BidirectionalIterator1 result(rresult.base()); - eastl::advance(result, -eastl::distance(first2, last2)); // We have an opportunity to optimize this, as the + eastl::advance(result, -eastl::distance(first2, last2)); // We have an opportunity to optimize this, as the return result; // search function already calculates this distance. } return last1; @@ -3214,7 +3219,7 @@ namespace eastl /// find_end /// /// Finds the last occurrence of the second sequence in the first sequence. - /// As such, this function is much like the C string function strrstr and it + /// As such, this function is much like the C string function strrstr and it /// is also the same as a reversed version of 'search'. It is called find_end /// instead of the possibly more consistent search_end simply because the C++ /// standard algorithms have such naming. @@ -3236,7 +3241,7 @@ namespace eastl - // To consider: Fold the predicate and non-predicate versions of + // To consider: Fold the predicate and non-predicate versions of // this algorithm into a single function. template ForwardIterator1 @@ -3267,14 +3272,14 @@ namespace eastl BidirectionalIterator1 find_end_impl(BidirectionalIterator1 first1, BidirectionalIterator1 last1, BidirectionalIterator2 first2, BidirectionalIterator2 last2, - BinaryPredicate predicate, + BinaryPredicate predicate, EASTL_ITC_NS::bidirectional_iterator_tag, EASTL_ITC_NS::bidirectional_iterator_tag) { typedef eastl::reverse_iterator reverse_iterator1; typedef eastl::reverse_iterator reverse_iterator2; reverse_iterator1 rresult(eastl::search - (reverse_iterator1(last1), reverse_iterator1(first1), + (reverse_iterator1(last1), reverse_iterator1(first1), reverse_iterator2(last2), reverse_iterator2(first2), predicate)); if(rresult.base() != first1) // If we found something... @@ -3292,8 +3297,8 @@ namespace eastl /// Effects: Finds a subsequence of equal values in a sequence. /// /// Returns: The last iterator i in the range [first1, last1 - (last2 - first2)) - /// such that for any nonnegative integer n < (last2 - first2), the following - /// corresponding conditions hold: pred(*(i+n),*(first2+n)) != false. Returns + /// such that for any nonnegative integer n < (last2 - first2), the following + /// corresponding conditions hold: pred(*(i+n),*(first2+n)) != false. Returns /// last1 if no such iterator is found. /// /// Complexity: At most (last2 - first2) * (last1 - first1 - (last2 - first2) + 1) @@ -3313,31 +3318,30 @@ namespace eastl } - /// set_difference /// - /// set_difference iterates over both input ranges and copies elements present + /// set_difference iterates over both input ranges and copies elements present /// in the first range but not the second to the output range. /// - /// Effects: Copies the elements of the range [first1, last1) which are not - /// present in the range [first2, last2) to the range beginning at result. + /// Effects: Copies the elements of the range [first1, last1) which are not + /// present in the range [first2, last2) to the range beginning at result. /// The elements in the constructed range are sorted. - /// + /// /// Requires: The input ranges must be sorted. /// Requires: The output range shall not overlap with either of the original ranges. - /// + /// /// Returns: The end of the output range. - /// + /// /// Complexity: At most (2 * ((last1 - first1) + (last2 - first2)) - 1) comparisons. /// template OutputIterator set_difference(InputIterator1 first1, InputIterator1 last1, - InputIterator2 first2, InputIterator2 last2, - OutputIterator result) + InputIterator2 first2, InputIterator2 last2, + OutputIterator result) { while((first1 != last1) && (first2 != last2)) { - if(*first1 < *first2) + if(*first1 < *first2) { *result = *first1; ++first1; @@ -3345,7 +3349,7 @@ namespace eastl } else if(*first2 < *first1) ++first2; - else + else { ++first1; ++first2; @@ -3358,12 +3362,12 @@ namespace eastl template OutputIterator set_difference(InputIterator1 first1, InputIterator1 last1, - InputIterator2 first2, InputIterator2 last2, - OutputIterator result, Compare compare) + InputIterator2 first2, InputIterator2 last2, + OutputIterator result, Compare compare) { while((first1 != last1) && (first2 != last2)) { - if(compare(*first1, *first2)) + if(compare(*first1, *first2)) { EASTL_VALIDATE_COMPARE(!compare(*first2, *first1)); // Validate that the compare function is sane. *result = *first1; @@ -3375,7 +3379,7 @@ namespace eastl EASTL_VALIDATE_COMPARE(!compare(*first1, *first2)); // Validate that the compare function is sane. ++first2; } - else + else { ++first1; ++first2; @@ -3386,15 +3390,75 @@ namespace eastl } + /// set_difference_2 + /// + /// set_difference_2 iterates over both input ranges and copies elements present + /// in the first range but not the second to the first output range and copies + /// elements present in the second range but not in the first to the second output + /// range. + /// + /// Effects: Copies the elements of the range [first1, last1) which are not + /// present in the range [first2, last2) to the first output range beginning at + /// result1 AND copies the element of range [first2, last2) which are not present + /// in the range [first1, last) to the second output range beginning at result2. + /// The elements in the constructed range are sorted. + /// + /// Requires: The input ranges must be sorted. + /// Requires: The output ranges shall not overlap with either of the original ranges. + /// + /// Returns: Nothing. + /// + /// Complexity: At most (2 * ((last1 - first1) + (last2 - first2)) - 1) comparisons. + /// + template + void set_difference_2(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, + OutputIterator result1, OutputIterator result2, Compare compare) + { + while ((first1 != last1) && (first2 != last2)) + { + if (compare(*first1, *first2)) + { + EASTL_VALIDATE_COMPARE(!compare(*first2, *first1)); // Validate that the compare function is sane. + *result1++ = *first1++; + } + else if (compare(*first2, *first1)) + { + EASTL_VALIDATE_COMPARE(!compare(*first1, *first2)); // Validate that the compare function is sane. + *result2++ = *first2++; + } + else + { + ++first1; + ++first2; + } + } + + eastl::copy(first2, last2, result2); + eastl::copy(first1, last1, result1); + } + + /// set_difference_2 + /// + /// set_difference_2 with the default comparison object is eastl::less<>. + /// + template + void set_difference_2(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, + OutputIterator result1, OutputIterator result2) + { + eastl::set_difference_2(first1, last1, first2, last2, result1, result2, eastl::less<>{}); + } + /// set_symmetric_difference /// - /// set_difference iterates over both input ranges and copies elements present + /// set_difference iterates over both input ranges and copies elements present /// in the either range but not the other to the output range. /// - /// Effects: Copies the elements of the range [first1, last1) which are not - /// present in the range [first2, last2), and the elements of the range [first2, last2) - /// which are not present in the range [first1, last1) to the range beginning at result. + /// Effects: Copies the elements of the range [first1, last1) which are not + /// present in the range [first2, last2), and the elements of the range [first2, last2) + /// which are not present in the range [first1, last1) to the range beginning at result. /// The elements in the constructed range are sorted. /// /// Requires: The input ranges must be sorted. @@ -3403,7 +3467,7 @@ namespace eastl /// Returns: The end of the constructed range. /// /// Complexity: At most (2 * ((last1 - first1) + (last2 - first2)) - 1) comparisons. - /// + /// template OutputIterator set_symmetric_difference(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, @@ -3429,7 +3493,7 @@ namespace eastl ++first2; } } - + return eastl::copy(first2, last2, eastl::copy(first1, last1, result)); } @@ -3461,31 +3525,29 @@ namespace eastl ++first2; } } - + return eastl::copy(first2, last2, eastl::copy(first1, last1, result)); } - - /// set_intersection /// /// set_intersection over both ranges and copies elements present in - /// both ranges to the output range. + /// both ranges to the output range. /// - /// Effects: Constructs a sorted intersection of the elements from the + /// Effects: Constructs a sorted intersection of the elements from the /// two ranges; that is, the set of elements that are present in both of the ranges. /// /// Requires: The input ranges must be sorted. /// Requires: The resulting range shall not overlap with either of the original ranges. - /// + /// /// Returns: The end of the constructed range. - /// + /// /// Complexity: At most 2 * ((last1 - first1) + (last2 - first2)) - 1) comparisons. - /// - /// Note: The copying operation is stable; if an element is present in both ranges, + /// + /// Note: The copying operation is stable; if an element is present in both ranges, /// the one from the first range is copied. - /// + /// template OutputIterator set_intersection(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, @@ -3543,10 +3605,10 @@ namespace eastl /// set_union /// - /// set_union iterators over both ranges and copies elements present in + /// set_union iterates over both ranges and copies elements present in /// both ranges to the output range. /// - /// Effects: Constructs a sorted union of the elements from the two ranges; + /// Effects: Constructs a sorted union of the elements from the two ranges; /// that is, the set of elements that are present in one or both of the ranges. /// /// Requires: The input ranges must be sorted. @@ -3556,7 +3618,7 @@ namespace eastl /// /// Complexity: At most (2 * ((last1 - first1) + (last2 - first2)) - 1) comparisons. /// - /// Note: The copying operation is stable; if an element is present in both ranges, + /// Note: The copying operation is stable; if an element is present in both ranges, /// the one from the first range is copied. /// template @@ -3621,6 +3683,67 @@ namespace eastl } + /// set_decomposition + /// + /// set_decomposition iterates over both ranges and copies elements to one of the three + /// categories of output ranges. + /// + /// Effects: Constructs three sorted containers of the elements from the two ranges. + /// * OutputIterator1 is elements only in Container1. + /// * OutputIterator2 is elements only in Container2. + /// * OutputIterator3 is elements that are in both Container1 and Container2. + /// + /// Requires: The input ranges must be sorted. + /// Requires: The resulting ranges shall not overlap with either of the original ranges. + /// + /// Returns: The end of the constructed range of elements in both Container1 and Container2. + /// + /// Complexity: At most (2 * ((last1 - first1) + (last2 - first2)) - 1) comparisons. + /// + template + OutputIterator3 set_decomposition(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, + OutputIterator1 result1, OutputIterator2 result2, OutputIterator3 result3, Compare compare) + { + while ((first1 != last1) && (first2 != last2)) + { + if (compare(*first1, *first2)) + { + EASTL_VALIDATE_COMPARE(!compare(*first2, *first1)); // Validate that the compare function is sane. + *result1++ = *first1++; + } + else if (compare(*first2, *first1)) + { + EASTL_VALIDATE_COMPARE(!compare(*first1, *first2)); // Validate that the compare function is sane. + *result2++ = *first2++; + } + else + { + *result3++ = *first1++; + ++first2; + } + } + + eastl::copy(first1, last1, result1); + eastl::copy(first2, last2, result2); + + return result3; + } + + /// set_decomposition + /// + /// set_decomposition with the default comparison object is eastl::less<>. + /// + template + OutputIterator3 set_decomposition(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, + OutputIterator1 result1, OutputIterator2 result2, OutputIterator3 result3) + { + return eastl::set_decomposition(first1, last1, first2, last2, result1, result2, result3, eastl::less<>{}); + } + + /// is_permutation /// template @@ -3643,7 +3766,7 @@ namespace eastl for(ForwardIterator1 i = first1; i != last1; ++i) { - if(i == eastl::find(first1, i, *i)) + if(i == eastl::find(first1, i, *i)) { const difference_type c = eastl::count(first2, last2, *i); @@ -3678,7 +3801,7 @@ namespace eastl for(ForwardIterator1 i = first1; i != last1; ++i) { - if(i == eastl::find(first1, i, *i, predicate)) + if(i == eastl::find(first1, i, *i, predicate)) { const difference_type c = eastl::count(first2, last2, *i, predicate); @@ -3694,7 +3817,7 @@ namespace eastl /// next_permutation /// - /// mutates the range [first, last) to the next permutation. Returns true if the + /// mutates the range [first, last) to the next permutation. Returns true if the /// new range is not the final permutation (sorted like the starting permutation). /// Permutations start with a sorted range, and false is returned when next_permutation /// results in the initial sorted range, or if the range has <= 1 element. @@ -3703,10 +3826,10 @@ namespace eastl /// /// http://marknelson.us/2002/03/01/next-permutation/ /// Basically we start with an ordered range and reverse it's order one specifically - /// chosen swap and reverse at a time. It happens that this require going through every + /// chosen swap and reverse at a time. It happens that this require going through every /// permutation of the range. We use the same variable names as the document above. /// - /// To consider: Significantly improved permutation/combination functionality: + /// To consider: Significantly improved permutation/combination functionality: /// http://home.roadrunner.com/~hinnant/combinations.html /// /// Example usage: @@ -3730,14 +3853,14 @@ namespace eastl for(;;) { BidirectionalIterator ii(i), j; - + if(compare(*--i, *ii)) // Find two consecutive values where the first is less than the second. { j = last; while(!compare(*i, *--j)) // Find the final value that's greater than the first (it may be equal to the second). {} eastl::iter_swap(i, j); // Swap the first and the final. - eastl::reverse(ii, last); // Reverse the ranget from second to last. + eastl::reverse(ii, last); // Reverse the ranget from second to last. return true; } @@ -3765,22 +3888,22 @@ namespace eastl /// rotate /// - /// Effects: For each non-negative integer i < (last - first), places the element from the + /// Effects: For each non-negative integer i < (last - first), places the element from the /// position first + i into position first + (i + (last - middle)) % (last - first). /// /// Returns: first + (last - middle). That is, returns where first went to. - /// + /// /// Remarks: This is a left rotate. - /// - /// Requires: [first,middle) and [middle,last) shall be valid ranges. ForwardIterator shall - /// satisfy the requirements of ValueSwappable (17.6.3.2). The type of *first shall satisfy + /// + /// Requires: [first,middle) and [middle,last) shall be valid ranges. ForwardIterator shall + /// satisfy the requirements of ValueSwappable (17.6.3.2). The type of *first shall satisfy /// the requirements of MoveConstructible (Table 20) and the requirements of MoveAssignable. /// /// Complexity: At most last - first swaps. /// - /// Note: While rotate works on ForwardIterators (e.g. slist) and BidirectionalIterators (e.g. list), - /// you can get much better performance (O(1) instead of O(n)) with slist and list rotation by - /// doing splice operations on those lists instead of calling this rotate function. + /// Note: While rotate works on ForwardIterators (e.g. slist) and BidirectionalIterators (e.g. list), + /// you can get much better performance (O(1) instead of O(n)) with slist and list rotation by + /// doing splice operations on those lists instead of calling this rotate function. /// /// http://www.cs.bell-labs.com/cm/cs/pearls/s02b.pdf / http://books.google.com/books?id=kse_7qbWbjsC&pg=PA14&lpg=PA14&dq=Programming+Pearls+flipping+hands /// http://books.google.com/books?id=tjOlkl7ecVQC&pg=PA189&lpg=PA189&dq=stepanov+Elements+of+Programming+rotate @@ -3789,7 +3912,7 @@ namespace eastl /// Strategy: /// - We handle the special case of (middle == first) and (middle == last) no-ops /// up front in the main rotate entry point. - /// - There's a basic ForwardIterator implementation (rotate_general_impl) which is + /// - There's a basic ForwardIterator implementation (rotate_general_impl) which is /// a fallback implementation that's not as fast as others but works for all cases. /// - There's a slightly better BidirectionalIterator implementation. /// - We have specialized versions for rotating elements that are is_trivially_move_assignable. @@ -3798,7 +3921,7 @@ namespace eastl /// (with any iterator type) to avoid a lot of logic involved with algorithms like "flipping hands" /// and achieve near optimal O(n) behavior. it turns out that rotate-by-one is a common use /// case in practice. - /// + /// namespace Internal { template @@ -3866,7 +3989,7 @@ namespace eastl { return Internal::rotate_general_impl(first, middle, last); } }; - template <> + template <> struct rotate_helper { template @@ -3878,18 +4001,18 @@ namespace eastl } }; - template <> + template <> struct rotate_helper { template static BidirectionalIterator rotate_impl(BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last) { return Internal::rotate_general_impl(first, middle, last); } // rotate_general_impl outperforms the flipping hands algorithm. - /* + /* // Simplest "flipping hands" implementation. Disabled because it's slower on average than rotate_general_impl. template static BidirectionalIterator rotate_impl(BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last) - { + { eastl::reverse(first, middle); eastl::reverse(middle, last); eastl::reverse(first, last); @@ -3905,7 +4028,7 @@ namespace eastl eastl::reverse_impl(middle, last, EASTL_ITC_NS::bidirectional_iterator_tag()); // Reverse the right side. // Reverse the entire range. - while((first != middle) && (middle != last)) + while((first != middle) && (middle != last)) { eastl::iter_swap(first, --last); ++first; @@ -3925,13 +4048,13 @@ namespace eastl */ }; - template <> + template <> struct rotate_helper { template static BidirectionalIterator rotate_impl(BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last) { - if(eastl::next(first) == middle) // If moving trivial types by a single element, memcpy is fast for that case. + if(eastl::next(first) == middle) // If moving trivial types by a single element, memcpy is fast for that case. return Internal::move_rotate_left_by_one(first, last); if(eastl::next(middle) == last) return Internal::move_rotate_right_by_one(first, last); @@ -3951,11 +4074,11 @@ namespace eastl return x; } - template <> + template <> struct rotate_helper { // This is the juggling algorithm, using move operations. - // In practice this implementation is about 25% faster than rotate_general_impl. We may want to + // In practice this implementation is about 25% faster than rotate_general_impl. We may want to // consider sticking with just rotate_general_impl and avoid the code generation of this function. template static RandomAccessIterator rotate_impl(RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last) @@ -3992,19 +4115,19 @@ namespace eastl } }; - template <> + template <> struct rotate_helper { // Experiments were done which tested the performance of using an intermediate buffer - // to do memcpy's to as opposed to executing a swapping algorithm. It turns out this is + // to do memcpy's to as opposed to executing a swapping algorithm. It turns out this is // actually slower than even rotate_general_impl, partly because the average case involves - // memcpy'ing a quarter of the element range twice. Experiments were done with various kinds + // memcpy'ing a quarter of the element range twice. Experiments were done with various kinds // of PODs with various element counts. template static RandomAccessIterator rotate_impl(RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last) { - if(eastl::next(first) == middle) // If moving trivial types by a single element, memcpy is fast for that case. + if(eastl::next(first) == middle) // If moving trivial types by a single element, memcpy is fast for that case. return Internal::move_rotate_left_by_one(first, last); if(eastl::next(middle) == last) return Internal::move_rotate_right_by_one(first, last); @@ -4043,7 +4166,7 @@ namespace eastl /// rotate_copy /// - /// Similar to rotate except writes the output to the OutputIterator and + /// Similar to rotate except writes the output to the OutputIterator and /// returns an OutputIterator to the element past the last element copied /// (i.e. result + (last - first)) /// @@ -4075,6 +4198,8 @@ namespace eastl return eastl::clamp(v, lo, hi, eastl::less<>()); } + + } // namespace eastl diff --git a/include/EASTL/atomic.h b/include/EASTL/atomic.h index f27a72dc..27117e9c 100644 --- a/include/EASTL/atomic.h +++ b/include/EASTL/atomic.h @@ -243,36 +243,27 @@ // Deviations from the standard. This does not include new features added: // // 1. -// Description: Atomic class constructors are not and will not be constexpr. -// Reasoning : We assert in the constructor that the this pointer is properly aligned. -// There are no other constexpr functions that can be called in a constexpr -// context. The only use for constexpr here is const-init time or ensuring -// that the object's value is placed in the executable at compile-time instead -// of having to call the ctor at static-init time. If you are using constexpr -// to solve static-init order fiasco, there are other solutions for that. -// -// 2. // Description: Atomics are always lock free // Reasoning : We don't want people to fall into performance traps where implicit locking // is done. If your user defined type is large enough to not support atomic // instructions then your user code should do the locking. // -// 3. +// 2. // Description: Atomic objects can not be volatile // Reasoning : Volatile objects do not make sense in the context of eastl::atomic. // Use the given memory orders to get the ordering you need. // Atomic objects have to become visible on the bus. See below for details. // -// 4. +// 3. // Description: Consume memory order is not supported // Reasoning : See below for the reasoning. // -// 5. +// 4. // Description: ATOMIC_INIT() macros and the ATOMIC_LOCK_FREE macros are not implemented // Reasoning : Use the is_lock_free() method instead of the macros. // ATOMIC_INIT() macros aren't needed since the default constructor value initializes. // -// 6. +// 5. // Description: compare_exchange failure memory order cannot be stronger than success memory order // Reasoning : Besides the argument that it ideologically does not make sense that a failure // of the atomic operation shouldn't have a stricter ordering guarantee than the @@ -284,7 +275,7 @@ // that versions of compilers that say they support C++17 do not properly adhere to this // new requirement in their intrinsics. Thus we will not support this. // -// 7. +// 6. // Description: All memory orders are distinct types instead of enum values // Reasoning : This will not affect how the API is used in user code. // It allows us to statically assert on invalid memory orders since they are compile-time types @@ -1384,13 +1375,62 @@ // The read_depends operation can be used on loads from only an eastl::atomic type. The return pointer of the load must and can only be used to then further load values. And that is it. // If you are unsure, upgrade this load to an acquire operation. // -// MyStruct* ptr = gAtomicPtr.load(read_depends); +// MyStruct* ptr = gAtomicPtr.load(memory_order_read_depends); // int a = ptr->a; // int b = ptr->b; // return a + b; // // The loads from ptr after the gAtomicPtr load ensure that the correct values of a and b are observed. This pairs with a Release operation on the writer side by releasing gAtomicPtr. // +// +// As said above the returned pointer from a .load(memory_order_read_depends) can only be used to then further load values. +// Dereferencing(*) and Arrow Dereferencing(->) are valid operations on return values from .load(memory_order_read_depends). +// +// MyStruct* ptr = gAtomicPtr.load(memory_order_read_depends); +// int a = ptr->a; - VALID +// int a = *ptr; - VALID +// +// Since dereferencing is just indexing via some offset from some base address, this also means addition and subtraction of constants is ok. +// +// int* ptr = gAtomicPtr.load(memory_order_read_depends); +// int a = *(ptr + 1) - VALID +// int a = *(ptr - 1) - VALID +// +// Casts also work correctly since casting is just offsetting a pointer depending on the inheritance hierarchy or if using intrusive containers. +// +// ReadDependsIntrusive** intrusivePtr = gAtomicPtr.load(memory_order_read_depends); +// ReadDependsIntrusive* ptr = ((ReadDependsIntrusive*)(((char*)intrusivePtr) - offsetof(ReadDependsIntrusive, next))); +// +// Base* basePtr = gAtomicPtr.load(memory_order_read_depends); +// Dervied* derivedPtr = static_cast(basePtr); +// +// Both of the above castings from the result of the load are valid for this memory order. +// +// You can reinterpret_cast the returned pointer value to a uintptr_t to set bits, clear bits, or xor bits but the pointer must be casted back before doing anything else. +// +// int* ptr = gAtomicPtr.load(memory_order_read_depends); +// ptr = reinterpret_cast(reinterpret_cast(ptr) & ~3); +// +// Do not use any equality or relational operator (==, !=, >, <, >=, <=) results in the computation of offsets before dereferencing. +// As we learned above in the Control Dependencies section, CPUs will not order Load-Load Control Dependencies. Relational and equality operators are often compiled using branches. +// It doesn't have to be compiled to branched, condition instructions could be used. Or some architectures provide comparison instructions such as set less than which do not need +// branches when using the result of the relational operator in arithmetic statements. Then again short circuiting may need to introduct branches since C++ guarantees the +// rest of the expression must not be evaluated. +// The following odd code is forbidden. +// +// int* ptr = gAtomicPtr.load(memory_order_read_depends); +// int* ptr2 = ptr + (ptr >= 0); +// int a = *ptr2; +// +// Only equality comparisons against nullptr are allowed. This is becase the compiler cannot assume that the address of the loaded value is some known address and substitute our loaded value. +// int* ptr = gAtomicPtr.load(memory_order_read_depends); +// if (ptr == nullptr); - VALID +// if (ptr != nullptr); - VALID +// +// Thus the above sentence that states: +// The return pointer of the load must and can only be used to then further load values. And that is it. +// must be respected by the programmer. This memory order is an optimization added for efficient read heavy pointer swapping data structures. IF you are unsure, use memory_order_acquire. +// // ******** Relaxed && eastl::atomic guarantees ******** // // We saw various ways that compiler barriers do not help us and that we need something more granular to make sure accesses are not mangled by the compiler to be considered atomic. @@ -1586,7 +1626,7 @@ // ---------------------------------------------------------------------------------------- // // In this example it is entirely possible that we observe r0 = 1 && r1 = 0 even though we have source code causality and sequentially consistent operations. -// Observability is tied to the atomic object on which the operation was performed and the thread fence doesn't synchronize-with the fetch_add because there is no +// Observability is tied to the atomic object on which the operation was performed and the thread fence doesn't synchronize-with the fetch_add because // there is no load above the fence that reads the value from the fetch_add. // // ******** Sequential Consistency Semantics ******** diff --git a/include/EASTL/bonus/adaptors.h b/include/EASTL/bonus/adaptors.h index 4d3e6223..423cacdd 100644 --- a/include/EASTL/bonus/adaptors.h +++ b/include/EASTL/bonus/adaptors.h @@ -13,6 +13,7 @@ #include #include #include +#include #if defined(EA_PRAGMA_ONCE_SUPPORTED) #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. diff --git a/include/EASTL/fixed_vector.h b/include/EASTL/fixed_vector.h index 633eaa86..1dc482bd 100644 --- a/include/EASTL/fixed_vector.h +++ b/include/EASTL/fixed_vector.h @@ -356,7 +356,7 @@ namespace eastl get_allocator() = x.get_allocator(); // The primary effect of this is to copy the overflow allocator. #endif - base_type::template DoAssign, true>(make_move_iterator(x.begin()), make_move_iterator(x.end()), false_type()); // Shorter route. + base_type::template DoAssign, true>(eastl::make_move_iterator(x.begin()), eastl::make_move_iterator(x.end()), false_type()); // Shorter route. } return *this; } diff --git a/include/EASTL/internal/atomic/atomic.h b/include/EASTL/internal/atomic/atomic.h index 12486f84..e1c5286e 100644 --- a/include/EASTL/internal/atomic/atomic.h +++ b/include/EASTL/internal/atomic/atomic.h @@ -127,12 +127,12 @@ namespace internal \ public: /* ctors */ \ \ - atomic(type desired) EA_NOEXCEPT \ + EA_CONSTEXPR atomic(type desired) EA_NOEXCEPT \ : Base{ desired } \ { \ } \ \ - atomic() EA_NOEXCEPT_IF(eastl::is_nothrow_default_constructible_v) = default; \ + EA_CONSTEXPR atomic() EA_NOEXCEPT_IF(eastl::is_nothrow_default_constructible_v) = default; \ \ public: \ \ @@ -148,7 +148,6 @@ namespace internal } - #define EASTL_ATOMIC_USING_ATOMIC_BASE(type) \ public: \ \ diff --git a/include/EASTL/internal/atomic/atomic_base_width.h b/include/EASTL/internal/atomic/atomic_base_width.h index 3b32e561..ca476182 100644 --- a/include/EASTL/internal/atomic/atomic_base_width.h +++ b/include/EASTL/internal/atomic/atomic_base_width.h @@ -198,12 +198,12 @@ namespace internal \ public: /* ctors */ \ \ - atomic_base_width(T desired) EA_NOEXCEPT \ + EA_CONSTEXPR atomic_base_width(T desired) EA_NOEXCEPT \ : Base{ desired } \ { \ } \ \ - atomic_base_width() EA_NOEXCEPT_IF(eastl::is_nothrow_default_constructible_v) = default; \ + EA_CONSTEXPR atomic_base_width() EA_NOEXCEPT_IF(eastl::is_nothrow_default_constructible_v) = default; \ \ atomic_base_width(const atomic_base_width&) EA_NOEXCEPT = delete; \ \ diff --git a/include/EASTL/internal/atomic/atomic_casts.h b/include/EASTL/internal/atomic/atomic_casts.h index 84c1fac8..54b9ed27 100644 --- a/include/EASTL/internal/atomic/atomic_casts.h +++ b/include/EASTL/internal/atomic/atomic_casts.h @@ -126,7 +126,7 @@ EASTL_FORCE_INLINE Pun AtomicTypePunCast(const T& fromType) EA_NOEXCEPT * aligned_storage ensures we can TypePun objects that aren't trivially default constructible * but still trivially copyable. */ - typename eastl::aligned_storage::type ret; + typename eastl::aligned_storage::type ret; memcpy(eastl::addressof(ret), eastl::addressof(fromType), sizeof(Pun)); return reinterpret_cast(ret); } diff --git a/include/EASTL/internal/atomic/atomic_flag.h b/include/EASTL/internal/atomic/atomic_flag.h index 52b2b1c0..e135d612 100644 --- a/include/EASTL/internal/atomic/atomic_flag.h +++ b/include/EASTL/internal/atomic/atomic_flag.h @@ -22,12 +22,12 @@ class atomic_flag { public: /* ctors */ - atomic_flag(bool desired) + EA_CONSTEXPR atomic_flag(bool desired) EA_NOEXCEPT : mFlag{ desired } { } - atomic_flag() EA_NOEXCEPT + EA_CONSTEXPR atomic_flag() EA_NOEXCEPT : mFlag{ false } { } diff --git a/include/EASTL/internal/atomic/atomic_integral.h b/include/EASTL/internal/atomic/atomic_integral.h index 060b5b87..7c94db32 100644 --- a/include/EASTL/internal/atomic/atomic_integral.h +++ b/include/EASTL/internal/atomic/atomic_integral.h @@ -69,12 +69,12 @@ namespace internal public: /* ctors */ - atomic_integral_base(T desired) EA_NOEXCEPT + EA_CONSTEXPR atomic_integral_base(T desired) EA_NOEXCEPT : Base{ desired } { } - atomic_integral_base() EA_NOEXCEPT = default; + EA_CONSTEXPR atomic_integral_base() EA_NOEXCEPT = default; atomic_integral_base(const atomic_integral_base&) EA_NOEXCEPT = delete; @@ -227,12 +227,12 @@ namespace internal \ public: /* ctors */ \ \ - atomic_integral_width(T desired) EA_NOEXCEPT \ + EA_CONSTEXPR atomic_integral_width(T desired) EA_NOEXCEPT \ : Base{ desired } \ { \ } \ \ - atomic_integral_width() EA_NOEXCEPT = default; \ + EA_CONSTEXPR atomic_integral_width() EA_NOEXCEPT = default; \ \ atomic_integral_width(const atomic_integral_width&) EA_NOEXCEPT = delete; \ \ diff --git a/include/EASTL/internal/atomic/atomic_pointer.h b/include/EASTL/internal/atomic/atomic_pointer.h index 38a4647a..18f6691c 100644 --- a/include/EASTL/internal/atomic/atomic_pointer.h +++ b/include/EASTL/internal/atomic/atomic_pointer.h @@ -70,12 +70,12 @@ namespace internal public: /* ctors */ - atomic_pointer_base(T* desired) EA_NOEXCEPT + EA_CONSTEXPR atomic_pointer_base(T* desired) EA_NOEXCEPT : Base{ desired } { } - atomic_pointer_base() EA_NOEXCEPT = default; + EA_CONSTEXPR atomic_pointer_base() EA_NOEXCEPT = default; atomic_pointer_base(const atomic_pointer_base&) EA_NOEXCEPT = delete; @@ -203,12 +203,12 @@ namespace internal \ public: /* ctors */ \ \ - atomic_pointer_width(T* desired) EA_NOEXCEPT \ + EA_CONSTEXPR atomic_pointer_width(T* desired) EA_NOEXCEPT \ : Base{ desired } \ { \ } \ \ - atomic_pointer_width() EA_NOEXCEPT = default; \ + EA_CONSTEXPR atomic_pointer_width() EA_NOEXCEPT = default; \ \ atomic_pointer_width(const atomic_pointer_width&) EA_NOEXCEPT = delete; \ \ diff --git a/include/EASTL/internal/atomic/atomic_size_aligned.h b/include/EASTL/internal/atomic/atomic_size_aligned.h index 2043ae22..db23e478 100644 --- a/include/EASTL/internal/atomic/atomic_size_aligned.h +++ b/include/EASTL/internal/atomic/atomic_size_aligned.h @@ -75,16 +75,14 @@ namespace internal { public: /* ctors */ - atomic_size_aligned(T desired) EA_NOEXCEPT + EA_CONSTEXPR atomic_size_aligned(T desired) EA_NOEXCEPT : mAtomic{ desired } { - EASTL_ATOMIC_ASSERT_ALIGNED(sizeof(T)); } - atomic_size_aligned() EA_NOEXCEPT_IF(eastl::is_nothrow_default_constructible_v) + EA_CONSTEXPR atomic_size_aligned() EA_NOEXCEPT_IF(eastl::is_nothrow_default_constructible_v) : mAtomic{} /* Value-Initialize which will Zero-Initialize Trivial Constructible types */ { - EASTL_ATOMIC_ASSERT_ALIGNED(sizeof(T)); } atomic_size_aligned(const atomic_size_aligned&) EA_NOEXCEPT = delete; diff --git a/include/EASTL/internal/atomic/atomic_standalone.h b/include/EASTL/internal/atomic/atomic_standalone.h index ec0fb331..011d5fb3 100644 --- a/include/EASTL/internal/atomic/atomic_standalone.h +++ b/include/EASTL/internal/atomic/atomic_standalone.h @@ -303,41 +303,33 @@ EASTL_FORCE_INLINE typename eastl::atomic::value_type atomic_load_explicit(co template EASTL_FORCE_INLINE typename eastl::atomic::value_type atomic_load_cond(const eastl::atomic* atomicObj, Predicate pred) EA_NOEXCEPT { - typename eastl::atomic::value_type ret; - for (;;) { - ret = atomicObj->load(); + typename eastl::atomic::value_type ret = atomicObj->load(); if (pred(ret)) { - break; + return ret; } EASTL_ATOMIC_CPU_PAUSE(); } - - return ret; } template EASTL_FORCE_INLINE typename eastl::atomic::value_type atomic_load_cond_explicit(const eastl::atomic* atomicObj, Predicate pred, Order order) EA_NOEXCEPT { - typename eastl::atomic::value_type ret; - for (;;) { - ret = atomicObj->load(order); + typename eastl::atomic::value_type ret = atomicObj->load(order); if (pred(ret)) { - break; + return ret; } EASTL_ATOMIC_CPU_PAUSE(); } - - return ret; } diff --git a/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc.h b/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc.h index 90b1ff5a..6df8c05f 100644 --- a/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc.h +++ b/include/EASTL/internal/atomic/compiler/msvc/compiler_msvc.h @@ -173,6 +173,16 @@ struct FixedWidth128 } \ } +/** + * In my own opinion, I found the wording on Microsoft docs a little confusing. + * ExchangeHigh means the top 8 bytes so (ptr + 8). + * ExchangeLow means the low 8 butes so (ptr). + * Endianness does not matter since we are just loading data and comparing data. + * Thought of as memcpy() and memcmp() function calls whereby the layout of the + * data itself is irrelevant. + * Only after we type pun back to the original type, and load from memory does + * the layout of the data matter again. + */ #define EASTL_MSVC_ATOMIC_CMPXCHG_STRONG_INTRIN_128(type, ret, ptr, expected, desired, MemoryOrder) \ { \ union TypePun \ @@ -181,9 +191,7 @@ struct FixedWidth128 \ struct exchange128 \ { \ - EASTL_SYSTEM_BIG_ENDIAN_STATEMENT(__int64 hi, lo); \ - \ - EASTL_SYSTEM_LITTLE_ENDIAN_STATEMENT(__int64 lo, hi); \ + __int64 value[2]; \ }; \ \ struct exchange128 exchangePun; \ @@ -194,7 +202,7 @@ struct FixedWidth128 unsigned char cmpxchgRetChar; \ cmpxchgRetChar = EASTL_MSVC_ATOMIC_CMPXCHG_STRONG_128_OP(cmpxchgRetChar, EASTL_ATOMIC_VOLATILE_TYPE_CAST(__int64, (ptr)), \ EASTL_ATOMIC_TYPE_CAST(__int64, (expected)), \ - typePun.exchangePun.hi, typePun.exchangePun.lo, \ + typePun.exchangePun.value[1], typePun.exchangePun.value[0], \ MemoryOrder); \ \ ret = static_cast(cmpxchgRetChar); \ diff --git a/include/EASTL/internal/config.h b/include/EASTL/internal/config.h index 11538337..530bbc87 100644 --- a/include/EASTL/internal/config.h +++ b/include/EASTL/internal/config.h @@ -89,8 +89,8 @@ /////////////////////////////////////////////////////////////////////////////// #ifndef EASTL_VERSION - #define EASTL_VERSION "3.17.03" - #define EASTL_VERSION_N 31703 + #define EASTL_VERSION "3.17.06" + #define EASTL_VERSION_N 31706 #endif diff --git a/include/EASTL/internal/function_detail.h b/include/EASTL/internal/function_detail.h index 58790bc1..dc18b631 100644 --- a/include/EASTL/internal/function_detail.h +++ b/include/EASTL/internal/function_detail.h @@ -649,7 +649,7 @@ namespace eastl // We cannot assume that R is default constructible. // This function is called only when the function object CANNOT be called because it is empty, // it will always throw or assert so we never use the return value anyways and neither should the caller. - static R DefaultInvoker(Args..., const FunctorStorageType&) + static R DefaultInvoker(Args... /*args*/, const FunctorStorageType& /*functor*/) { #if EASTL_EXCEPTIONS_ENABLED throw eastl::bad_function_call(); diff --git a/include/EASTL/iterator.h b/include/EASTL/iterator.h index 6fffd5da..d2dc8993 100644 --- a/include/EASTL/iterator.h +++ b/include/EASTL/iterator.h @@ -41,10 +41,10 @@ EA_DISABLE_VC_WARNING(4217); // Member template functions cannot be used for cop namespace eastl { /// iterator_status_flag - /// - /// Defines the validity status of an iterator. This is primarily used for - /// iterator validation in debug builds. These are implemented as OR-able - /// flags (as opposed to mutually exclusive values) in order to deal with + /// + /// Defines the validity status of an iterator. This is primarily used for + /// iterator validation in debug builds. These are implemented as OR-able + /// flags (as opposed to mutually exclusive values) in order to deal with /// the nature of iterator status. In particular, an iterator may be valid /// but not dereferencable, as in the case with an iterator to container end(). /// An iterator may be valid but also dereferencable, as in the case with an @@ -80,7 +80,7 @@ namespace eastl // struct iterator - template struct iterator { @@ -106,7 +106,7 @@ namespace eastl template struct iterator_traits { - typedef EASTL_ITC_NS::random_access_iterator_tag iterator_category; // To consider: Change this to contiguous_iterator_tag for the case that + typedef EASTL_ITC_NS::random_access_iterator_tag iterator_category; // To consider: Change this to contiguous_iterator_tag for the case that typedef T value_type; // EASTL_ITC_NS is "eastl" instead of "std". typedef ptrdiff_t difference_type; typedef T* pointer; @@ -132,14 +132,14 @@ namespace eastl /// Relies on the class declaring a typedef called wrapped_iterator_type. /// /// Examples of wrapping iterators: - /// reverse_iterator - /// generic_iterator - /// move_iterator + /// reverse_iterator + /// generic_iterator + /// move_iterator /// Examples of non-wrapping iterators: /// iterator /// list::iterator /// char* - /// + /// /// Example behavior: /// is_iterator_wrapper(int*)::value => false /// is_iterator_wrapper(eastl::array*)::value => false @@ -155,7 +155,7 @@ namespace eastl template static eastl::yes_type test(typename U::wrapped_iterator_type*, typename eastl::enable_if::value>::type* = 0); - + public: EA_DISABLE_VC_WARNING(6334) static const bool value = (sizeof(test(NULL)) == sizeof(eastl::yes_type)); @@ -165,11 +165,11 @@ namespace eastl /// unwrap_iterator /// - /// Takes a wrapper Iterator (e.g. move_iterator, reverse_iterator, generic_iterator) instance + /// Takes a wrapper Iterator (e.g. move_iterator, reverse_iterator, generic_iterator) instance /// and returns the wrapped iterator type. If Iterator is not a wrapper (including being a pointer), /// or is not an iterator, then this function returns it as-is. - /// unwrap_iterator unwraps only a single layer of iterator at a time. You need to call it twice, - /// for example, to unwrap two layers of iterators. + /// unwrap_iterator unwraps only a single layer of iterator at a time. You need to call it twice, + /// for example, to unwrap two layers of iterators. /// /// Example usage: /// int* pInt = unwrap_iterator(&pIntArray[15]); @@ -205,13 +205,13 @@ namespace eastl /// reverse_iterator /// /// From the C++ standard: - /// Bidirectional and random access iterators have corresponding reverse - /// iterator adaptors that iterate through the data structure in the - /// opposite direction. They have the same signatures as the corresponding - /// iterators. The fundamental relation between a reverse iterator and its + /// Bidirectional and random access iterators have corresponding reverse + /// iterator adaptors that iterate through the data structure in the + /// opposite direction. They have the same signatures as the corresponding + /// iterators. The fundamental relation between a reverse iterator and its /// corresponding iterator i is established by the identity: /// &*(reverse_iterator(i)) == &*(i - 1). - /// This mapping is dictated by the fact that while there is always a pointer + /// This mapping is dictated by the fact that while there is always a pointer /// past the end of an array, there might not be a valid pointer before the /// beginning of an array. /// @@ -233,7 +233,7 @@ namespace eastl Iterator mIterator; public: - EA_CPP14_CONSTEXPR reverse_iterator() // It's important that we construct mIterator, because if Iterator + EA_CPP14_CONSTEXPR reverse_iterator() // It's important that we construct mIterator, because if Iterator : mIterator() { } // is a pointer, there's a difference between doing it and not. EA_CPP14_CONSTEXPR explicit reverse_iterator(iterator_type i) @@ -246,7 +246,7 @@ namespace eastl EA_CPP14_CONSTEXPR reverse_iterator(const reverse_iterator& ri) : mIterator(ri.base()) { } - // This operator= isn't in the standard, but the the C++ + // This operator= isn't in the standard, but the the C++ // library working group has tentatively approved it, as it // allows const and non-const reverse_iterators to interoperate. template @@ -297,10 +297,10 @@ namespace eastl EA_CPP14_CONSTEXPR reverse_iterator& operator-=(difference_type n) { mIterator += n; return *this; } - // http://cplusplus.github.io/LWG/lwg-defects.html#386, - // http://llvm.org/bugs/show_bug.cgi?id=17883 - // random_access_iterator operator[] is merely required to return something convertible to reference. - // reverse_iterator operator[] can't necessarily know what to return as the underlying iterator + // http://cplusplus.github.io/LWG/lwg-defects.html#386, + // http://llvm.org/bugs/show_bug.cgi?id=17883 + // random_access_iterator operator[] is merely required to return something convertible to reference. + // reverse_iterator operator[] can't necessarily know what to return as the underlying iterator // operator[] may return something other than reference. EA_CPP14_CONSTEXPR reference operator[](difference_type n) const { return mIterator[-n - 1]; } @@ -309,12 +309,12 @@ namespace eastl // The C++ library working group has tentatively approved the usage of two // template parameters (Iterator1 and Iterator2) in order to allow reverse_iterators - // and const_reverse iterators to be comparable. This is a similar issue to the + // and const_reverse iterators to be comparable. This is a similar issue to the // C++ defect report #179 regarding comparison of container iterators and const_iterators. // - // libstdc++ reports that std::relops breaks the usage of two iterator types and if we + // libstdc++ reports that std::relops breaks the usage of two iterator types and if we // want to support relops then we need to also make versions of each of below with - // a single template parameter to placate std::relops. But relops is hardly used due to + // a single template parameter to placate std::relops. But relops is hardly used due to // the troubles it causes and so we are avoiding support here until somebody complains about it. template EA_CPP14_CONSTEXPR inline bool @@ -369,9 +369,9 @@ namespace eastl /// This is a type traits extension utility. /// Given an iterator, tells if it's a reverse_iterator vs anything else. /// If it's a reverse iterator wrapped by another iterator then value is false. - /// To consider: Detect that if it's a move_iterator and unwrap + /// To consider: Detect that if it's a move_iterator and unwrap /// move_iterator so we can detect that underneath it's reverse_iterator. - /// + /// template struct is_reverse_iterator : public eastl::false_type {}; @@ -485,7 +485,7 @@ namespace eastl { return move_iterator(mIterator - n); } move_iterator& operator-=(difference_type n) - { + { mIterator -= n; return *this; } @@ -548,12 +548,12 @@ namespace eastl // make_move_if_noexcept_iterator returns move_iterator if the Iterator is of a noexcept type; - // otherwise returns Iterator as-is. The point of this is to be able to avoid moves that can generate exceptions and instead + // otherwise returns Iterator as-is. The point of this is to be able to avoid moves that can generate exceptions and instead // fall back to copies or whatever the default IteratorType::operator* returns for use by copy/move algorithms. // To consider: merge the conditional expression usage here with the one used by move_if_noexcept, as they are the same condition. #if EASTL_EXCEPTIONS_ENABLED - template ::value_type>::value || - !eastl::is_copy_constructible::value_type>::value, + template ::value_type>::value || + !eastl::is_copy_constructible::value_type>::value, eastl::move_iterator, Iterator>::type> inline IteratorType make_move_if_noexcept_iterator(Iterator i) { return IteratorType(i); } @@ -573,7 +573,7 @@ namespace eastl /// Example usage (though somewhat useless): /// template /// bool IsMoveIterator() { return typename eastl::is_move_iterator::value; } - /// + /// template struct is_move_iterator : public eastl::false_type {}; @@ -601,7 +601,7 @@ namespace eastl /// back_insert_iterator /// - /// A back_insert_iterator is simply a class that acts like an iterator but when you + /// A back_insert_iterator is simply a class that acts like an iterator but when you /// assign a value to it, it calls push_back on the container with the value. /// template @@ -658,7 +658,7 @@ namespace eastl /// front_insert_iterator /// - /// A front_insert_iterator is simply a class that acts like an iterator but when you + /// A front_insert_iterator is simply a class that acts like an iterator but when you /// assign a value to it, it calls push_front on the container with the value. /// template @@ -712,18 +712,18 @@ namespace eastl /// insert_iterator /// - /// An insert_iterator is like an iterator except that when you assign a value to it, + /// An insert_iterator is like an iterator except that when you assign a value to it, /// the insert_iterator inserts the value into the container and increments the iterator. /// - /// insert_iterator is an iterator adaptor that functions as an OutputIterator: - /// assignment through an insert_iterator inserts an object into a container. - /// Specifically, if ii is an insert_iterator, then ii keeps track of a container c and + /// insert_iterator is an iterator adaptor that functions as an OutputIterator: + /// assignment through an insert_iterator inserts an object into a container. + /// Specifically, if ii is an insert_iterator, then ii keeps track of a container c and /// an insertion point p; the expression *ii = x performs the insertion container.insert(p, x). /// - /// If you assign through an insert_iterator several times, then you will be inserting - /// several elements into the underlying container. In the case of a sequence, they will - /// appear at a particular location in the underlying sequence, in the order in which - /// they were inserted: one of the arguments to insert_iterator's constructor is an + /// If you assign through an insert_iterator several times, then you will be inserting + /// several elements into the underlying container. In the case of a sequence, they will + /// appear at a particular location in the underlying sequence, in the order in which + /// they were inserted: one of the arguments to insert_iterator's constructor is an /// iterator p, and the new range will be inserted immediately before p. /// template @@ -736,11 +736,11 @@ namespace eastl protected: Container& container; - iterator_type it; + iterator_type it; public: // This assignment operator is defined more to stop compiler warnings (e.g. VC++ C4512) - // than to be useful. However, it does allow an insert_iterator to be assigned to another + // than to be useful. However, it does allow an insert_iterator to be assigned to another // insert iterator provided that they point to the same container. insert_iterator& operator=(const insert_iterator& x) { @@ -768,7 +768,7 @@ namespace eastl insert_iterator& operator++(int) { return *this; } // This is by design. - }; // insert_iterator + }; // insert_iterator /// inserter @@ -789,7 +789,7 @@ namespace eastl /// This is a type traits extension utility. /// Given an iterator, tells if it's an insert_iterator vs anything else. /// If it's a insert_iterator wrapped by another iterator then value is false. - /// + /// template struct is_insert_iterator : public eastl::false_type {}; @@ -809,6 +809,7 @@ namespace eastl /// iterators (e.g. with list). The former is more efficient. /// template + EA_CONSTEXPR inline typename eastl::iterator_traits::difference_type distance_impl(InputIterator first, InputIterator last, EASTL_ITC_NS::input_iterator_tag) { @@ -823,13 +824,14 @@ namespace eastl } template + EA_CONSTEXPR inline typename eastl::iterator_traits::difference_type distance_impl(RandomAccessIterator first, RandomAccessIterator last, EASTL_ITC_NS::random_access_iterator_tag) { return last - first; } - // Special version defined so that std C++ iterators can be recognized by + // Special version defined so that std C++ iterators can be recognized by // this function. Unfortunately, this function treats all foreign iterators // as InputIterators and thus can seriously hamper performance in the case // of large ranges of bidirectional_iterator_tag iterators. @@ -848,6 +850,7 @@ namespace eastl //} template + EA_CONSTEXPR inline typename eastl::iterator_traits::difference_type distance(InputIterator first, InputIterator last) { @@ -863,8 +866,8 @@ namespace eastl /// advance /// /// Implements the advance() function. There are three versions, one for - /// random access iterators (e.g. with vector), one for bidirectional - /// iterators (list) and one for regular input iterators (e.g. with slist). + /// random access iterators (e.g. with vector), one for bidirectional + /// iterators (list) and one for regular input iterators (e.g. with slist). /// template inline void @@ -918,7 +921,7 @@ namespace eastl i += n; } - // Special version defined so that std C++ iterators can be recognized by + // Special version defined so that std C++ iterators can be recognized by // this function. Unfortunately, this function treats all foreign iterators // as InputIterators and thus can seriously hamper performance in the case // of large ranges of bidirectional_iterator_tag iterators. @@ -946,7 +949,7 @@ namespace eastl // http://en.cppreference.com/w/cpp/iterator/next // template - inline InputIterator + inline InputIterator next(InputIterator it, typename eastl::iterator_traits::difference_type n = 1) { eastl::advance(it, n); @@ -963,7 +966,7 @@ namespace eastl #if defined(EA_COMPILER_CPP11_ENABLED) && EA_COMPILER_CPP11_ENABLED - + // eastl::data // // http://en.cppreference.com/w/cpp/iterator/data @@ -977,7 +980,7 @@ namespace eastl { return c.data(); } template - EA_CPP14_CONSTEXPR T* data(T(&array)[N]) EA_NOEXCEPT + EA_CPP14_CONSTEXPR T* data(T(&array)[N]) EA_NOEXCEPT { return array; } template @@ -989,7 +992,7 @@ namespace eastl // // http://en.cppreference.com/w/cpp/iterator/size // - template + template EA_CPP14_CONSTEXPR auto size(const C& c) -> decltype(c.size()) { return c.size(); } @@ -1016,10 +1019,10 @@ namespace eastl // eastl::empty - // + // // http://en.cppreference.com/w/cpp/iterator/empty // - template + template EA_CPP14_CONSTEXPR auto empty(const Container& c) -> decltype(c.empty()) { return c.empty(); } @@ -1027,7 +1030,7 @@ namespace eastl EA_CPP14_CONSTEXPR bool empty(const T (&)[N]) EA_NOEXCEPT { return false; } - template + template EA_CPP14_CONSTEXPR bool empty(std::initializer_list il) EA_NOEXCEPT { return il.size() == 0; } @@ -1039,13 +1042,13 @@ namespace eastl // // In order to enable eastl::begin and eastl::end, the compiler needs to have conforming support // for argument-dependent lookup if it supports C++11 range-based for loops. The reason for this is - // that in C++11 range-based for loops result in usage of std::begin/std::end, but allow that to + // that in C++11 range-based for loops result in usage of std::begin/std::end, but allow that to // be overridden by argument-dependent lookup: // C++11 Standard, section 6.5.4, paragraph 1. - // "otherwise, begin-expr and end-expr are begin(__range) and end(__range), respectively, - // where begin and end are looked up with argument-dependent lookup (3.4.2). For the + // "otherwise, begin-expr and end-expr are begin(__range) and end(__range), respectively, + // where begin and end are looked up with argument-dependent lookup (3.4.2). For the // purposes of this name lookup, namespace std is an associated namespace." - // It turns out that one compiler has a problem: GCC 4.6. That version added support for + // It turns out that one compiler has a problem: GCC 4.6. That version added support for // range-based for loops but has broken argument-dependent lookup which was fixed in GCC 4.7. // #if (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION == 4006)) @@ -1057,19 +1060,19 @@ namespace eastl #if EASTL_BEGIN_END_ENABLED template EA_CPP14_CONSTEXPR inline auto begin(Container& container) -> decltype(container.begin()) - { + { return container.begin(); } template EA_CPP14_CONSTEXPR inline auto begin(const Container& container) -> decltype(container.begin()) - { + { return container.begin(); } template EA_CPP14_CONSTEXPR inline auto cbegin(const Container& container) -> decltype(container.begin()) - { + { return container.begin(); } @@ -1133,7 +1136,7 @@ namespace eastl return arrayObject; } - template + template EA_CPP14_CONSTEXPR inline T* end(T (&arrayObject)[arraySize]) { return (arrayObject + arraySize); @@ -1173,9 +1176,9 @@ namespace eastl -// Some compilers (e.g. GCC 4.6) support range-based for loops, but have a bug with +// Some compilers (e.g. GCC 4.6) support range-based for loops, but have a bug with // respect to argument-dependent lookup which results on them unilaterally using std::begin/end -// with range-based for loops. To work around this we #include for this case in +// with range-based for loops. To work around this we #include for this case in // order to make std::begin/end visible to users of , for portability. #if !EASTL_BEGIN_END_ENABLED && !defined(EA_COMPILER_NO_RANGE_BASED_FOR_LOOP) #include diff --git a/include/EASTL/shared_ptr.h b/include/EASTL/shared_ptr.h index 69f918f1..5535adfc 100644 --- a/include/EASTL/shared_ptr.h +++ b/include/EASTL/shared_ptr.h @@ -593,8 +593,10 @@ namespace eastl /// the shared reference count is deleted. ~shared_ptr() { - if(mpRefCount) + if (mpRefCount) + { mpRefCount->release(); + } // else if mpValue is non-NULL then we just lose it because it wasn't actually shared (can happen with // shared_ptr(const shared_ptr& sharedPtr, element_type* pValue) constructor). diff --git a/include/EASTL/sort.h b/include/EASTL/sort.h index 475489d5..d0894311 100644 --- a/include/EASTL/sort.h +++ b/include/EASTL/sort.h @@ -1178,7 +1178,7 @@ namespace eastl { for(;; ++curr) { - if(curr == (size - 1)) // If we are at the end of the data... this run is done. + if(curr >= (size - 1)) // If we are at the end of the data... this run is done. break; if(compare(*(first + curr), *(first + curr - 1))) // If this item is not in order... this run is done. @@ -1189,7 +1189,7 @@ namespace eastl { for(;; ++curr) { - if(curr == (size - 1)) // If we are at the end of the data... this run is done. + if(curr >= (size - 1)) // If we are at the end of the data... this run is done. break; if(!compare(*(first + curr), *(first + curr - 1))) // If this item is not in order... this run is done. diff --git a/include/EASTL/tuple.h b/include/EASTL/tuple.h index 09f1d633..9d27bffc 100644 --- a/include/EASTL/tuple.h +++ b/include/EASTL/tuple.h @@ -395,7 +395,7 @@ namespace Internal TupleImpl& operator=(OtherTuple&& t) { swallow(TupleLeaf::operator=( - eastl::forward>>(get(t)))...); + eastl::forward>>(get(t)))...); return *this; } @@ -755,16 +755,16 @@ class tuple template = 0> EA_CONSTEXPR tuple(U&& u, Us&&... us) - : mImpl(make_index_sequence{}, Internal::MakeTupleTypes_t{}, eastl::forward(u), - eastl::forward(us)...) + : mImpl(make_index_sequence{}, Internal::MakeTupleTypes_t{}, eastl::forward(u), + eastl::forward(us)...) { } template = 0> explicit EA_CONSTEXPR tuple(U&& u, Us&&... us) - : mImpl(make_index_sequence{}, Internal::MakeTupleTypes_t{}, eastl::forward(u), - eastl::forward(us)...) + : mImpl(make_index_sequence{}, Internal::MakeTupleTypes_t{}, eastl::forward(u), + eastl::forward(us)...) { } @@ -831,7 +831,7 @@ inline const_tuple_element_t>& get(const tuple& t) template inline tuple_element_t>&& get(tuple&& t) { - return get(move(t.mImpl)); + return get(eastl::move(t.mImpl)); } template @@ -849,7 +849,7 @@ inline const T& get(const tuple& t) template inline T&& get(tuple&& t) { - return get(move(t.mImpl)); + return get(eastl::move(t.mImpl)); } template diff --git a/include/EASTL/variant.h b/include/EASTL/variant.h index ed7fc8e3..e59c3007 100644 --- a/include/EASTL/variant.h +++ b/include/EASTL/variant.h @@ -177,11 +177,7 @@ namespace eastl /////////////////////////////////////////////////////////////////////////// // 20.7.3, variant_npos // - #ifdef EA_COMPILER_NO_INLINE_VARIABLES - static EA_CONSTEXPR const size_t variant_npos = size_t(-1); - #else - inline EA_CONSTEXPR size_t variant_npos = -1; - #endif + EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR size_t variant_npos = size_t(-1); /////////////////////////////////////////////////////////////////////////// @@ -1048,7 +1044,7 @@ namespace eastl eastl::forward(visitor), get(eastl::forward(args))..., get(eastl::forward(variant)) - )); + )); } // The final call() in the recursion. diff --git a/test/source/TestAlgorithm.cpp b/test/source/TestAlgorithm.cpp index 1e0a3bb7..142d45e1 100644 --- a/test/source/TestAlgorithm.cpp +++ b/test/source/TestAlgorithm.cpp @@ -79,8 +79,8 @@ namespace enum TestMinMaxEnum { - teX = 0, - teY = 3 + teX = 0, + teY = 3 }; @@ -593,11 +593,11 @@ static int TestMinMax() { // template - // eastl::pair + // eastl::pair // minmax_element(ForwardIterator first, ForwardIterator last) // // template - // eastl::pair + // eastl::pair // minmax_element(ForwardIterator first, ForwardIterator last, Compare compare) int intArray[] = { 5, -2, 1, 5, 6, 5 }; @@ -606,15 +606,15 @@ static int TestMinMax() EATEST_VERIFY((*result.first == -2) && (*result.second == 6)); - // template + // template // eastl::pair // minmax(const T& a, const T& b) // - // template + // template // eastl::pair // minmax(const T& a, const T& b, Compare comp) - // The VC++ compiler is broken in such a way that it can't compile the following without generating a warning: + // The VC++ compiler is broken in such a way that it can't compile the following without generating a warning: // warning C4413: 'eastl::pair::first' : reference member is initialized to a temporary that doesn't persist after the constructor exits. // The Microsoft standard library definition of minmax doesn't generate this warning... because that minmax is broken and non-conforming. I think they // made it the way they did because of the aforementioned compiler bug. @@ -883,7 +883,7 @@ int TestAlgorithm() eastl::string in = "123456"; eastl::string out; - + eastl::copy_n(in.begin(), 4, eastl::back_inserter(out)); EATEST_VERIFY(out == "1234"); } @@ -913,7 +913,7 @@ int TestAlgorithm() for(eastl_size_t i = 0; i < 4; i++) src.push_back(eastl::string(1, (char8_t)('0' + i))); eastl::vector dest(src.size()); - + eastl::move(src.begin(), src.end(), dest.begin()); EATEST_VERIFY((dest[0] == "0") && (dest[3] == "3")); EATEST_VERIFY(src[0].empty() && src[3].empty()); @@ -925,7 +925,7 @@ int TestAlgorithm() for(eastl_size_t i = 0; i < 4; i++) src.push_back(eastl::string(1, (char8_t)('0' + i))); eastl::vector dest(src.size()); - + eastl::move_backward(src.begin(), src.end(), dest.end()); EATEST_VERIFY((dest[0] == "0") && (dest[3] == "3")); EATEST_VERIFY(src[0].empty() && src[3].empty()); @@ -954,7 +954,7 @@ int TestAlgorithm() // Count all items whose value is less than three. ptrdiff_t n = count_if(intArray, intArray, bind2nd(less(), (int)3)); // No-op EATEST_VERIFY(n == 0); - n = count_if(intArray, intArray + 12, bind2nd(less(), (int)3)); + n = count_if(intArray, intArray + 12, bind2nd(less(), (int)3)); EATEST_VERIFY(n == 5); @@ -963,7 +963,7 @@ int TestAlgorithm() n = count_if(toArray, toArray, bind2nd(less(), TestObject(3))); // No-op EATEST_VERIFY(n == 0); - n = count_if(toArray, toArray + 6, bind2nd(less(), TestObject(3))); + n = count_if(toArray, toArray + 6, bind2nd(less(), TestObject(3))); EATEST_VERIFY(n == 3); @@ -978,7 +978,7 @@ int TestAlgorithm() n = count_if(intList.begin(), intList.begin(), bind2nd(less(), (int)3)); // No-op EATEST_VERIFY(n == 0); - n = count_if(intList.begin(), intList.end(), bind2nd(less(), (int)3)); + n = count_if(intList.begin(), intList.end(), bind2nd(less(), (int)3)); EATEST_VERIFY(n == 3); } @@ -1181,12 +1181,12 @@ int TestAlgorithm() // The list is now: { 5, 2, 1, 2, 3, 4 } slist::iterator it = find_if(intList.begin(), intList.begin(), bind2nd(equal_to(), (int)1)); // No-op EATEST_VERIFY(it == intList.begin()); - it = find_if(intList.begin(), intList.end(), bind2nd(equal_to(), (int)1)); + it = find_if(intList.begin(), intList.end(), bind2nd(equal_to(), (int)1)); EATEST_VERIFY(*it == 1); - it = find_if(intList.begin(), intList.end(), bind2nd(equal_to(), (int)99)); + it = find_if(intList.begin(), intList.end(), bind2nd(equal_to(), (int)99)); EATEST_VERIFY(it == intList.end()); - it = find_if_not(intList.begin(), intList.end(), bind2nd(equal_to(), (int)5)); + it = find_if_not(intList.begin(), intList.end(), bind2nd(equal_to(), (int)5)); EATEST_VERIFY(*it == 2); } @@ -2162,7 +2162,98 @@ int TestAlgorithm() } + // set_difference_2 { + // template + // void set_difference_2(InputIterator1 first1, InputIterator1 last1, + // InputIterator2 first2, InputIterator2 last2, + // OutputIterator result1, OutputIterator result2) + { + const eastl::vector v1 = {1, 2, 4, 5, 7, 7, 9}; + const eastl::vector v2 = { 2, 6, 9}; + eastl::vector only_v1, only_v2; + + eastl::set_difference_2(v1.begin(), v1.end(), v2.begin(), v2.end(), + eastl::inserter(only_v1, only_v1.begin()), + eastl::inserter(only_v2, only_v2.begin())); + + EATEST_VERIFY((only_v1 == eastl::vector{1, 4, 5, 7, 7})); + EATEST_VERIFY((only_v2 == eastl::vector{6})); + } + + // template + // void set_difference_2(InputIterator1 first1, InputIterator1 last1, + // InputIterator2 first2, InputIterator2 last2, + // OutputIterator result1, OutputIterator result2, Compare compare) + { + struct local + { + int data = -1; + bool operator==(const local& other) const + { return data == other.data; } + }; + + const eastl::vector v1 = {{1}, {2}, {4}, {5}, {7}, {7}, {9}}; + const eastl::vector v2 = { {2}, {6}, {9}}; + eastl::vector only_v1, only_v2; + + eastl::set_difference_2(v1.begin(), v1.end(), v2.begin(), v2.end(), + eastl::inserter(only_v1, only_v1.begin()), + eastl::inserter(only_v2, only_v2.begin()), + [](const local& lhs, const local& rhs) { return lhs.data < rhs.data; }); + + EATEST_VERIFY((only_v1 == eastl::vector{{1}, {4}, {5}, {7}, {7}})); + EATEST_VERIFY((only_v2 == eastl::vector{{6}})); + } + } + + + // set_decomposition + { + // OutputIterator3 set_decomposition(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, + // OutputIterator1 result1, OutputIterator2 result2, OutputIterator3 result3) + { + const eastl::vector v1 = {1, 2, 4, 5, 7, 7, 9}; + const eastl::vector v2 = { 2, 6, 9}; + eastl::vector only_v1, only_v2, intersection; + + eastl::set_decomposition(v1.begin(), v1.end(), v2.begin(), v2.end(), + eastl::inserter(only_v1, only_v1.begin()), + eastl::inserter(only_v2, only_v2.begin()), + eastl::inserter(intersection, intersection.begin())); + + EATEST_VERIFY((only_v1 == eastl::vector{1, 4, 5, 7, 7})); + EATEST_VERIFY((only_v2 == eastl::vector{6})); + EATEST_VERIFY((intersection == eastl::vector{2, 9})); + } + + // OutputIterator3 set_decomposition(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, + // OutputIterator1 result1, OutputIterator2 result2, OutputIterator3 result3, Compare compare) + { + struct local + { + int data = -1; + bool operator==(const local& other) const + { return data == other.data; } + }; + + const eastl::vector v1 = {{1}, {2}, {4}, {5}, {7}, {7}, {9}}; + const eastl::vector v2 = { {2}, {6}, {9}}; + eastl::vector only_v1, only_v2, intersection; + + eastl::set_decomposition(v1.begin(), v1.end(), v2.begin(), v2.end(), + eastl::inserter(only_v1, only_v1.begin()), + eastl::inserter(only_v2, only_v2.begin()), + eastl::inserter(intersection, intersection.begin()), + [](const local& lhs, const local& rhs) { return lhs.data < rhs.data; }); + + EATEST_VERIFY((only_v1 == eastl::vector{{1}, {4}, {5}, {7}, {7}})); + EATEST_VERIFY((only_v2 == eastl::vector{{6}})); + EATEST_VERIFY((intersection == eastl::vector{{2}, {9}})); + } + } + + { // template // bool is_permutation(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2) diff --git a/test/source/TestAtomicBasic.cpp b/test/source/TestAtomicBasic.cpp index d082e35f..166b030f 100644 --- a/test/source/TestAtomicBasic.cpp +++ b/test/source/TestAtomicBasic.cpp @@ -1,3985 +1,4083 @@ -///////////////////////////////////////////////////////////////////////////// -// Copyright (c) Electronic Arts Inc. All rights reserved. -///////////////////////////////////////////////////////////////////////////// - - -#include "EASTLTest.h" - -#include - - -/** - * This is a basic test suite that tests all functionality is implemented - * and that all operations do as expected. - * I.E. fetch_add returns the previous value and add_fetch returns the current value - */ - -class AtomicStandaloneBasicTest -{ -public: - - int RunTest() - { - AtomicSignalFence(); - - AtomicThreadFence(); - - AtomicCpuPause(); - - AtomicCompilerBarrier(); - - return nErrorCount; - } - -private: - - void AtomicSignalFence(); - - void AtomicThreadFence(); - - void AtomicCpuPause(); - - void AtomicCompilerBarrier(); - -private: - - int nErrorCount = 0; -}; - -void AtomicStandaloneBasicTest::AtomicSignalFence() -{ - eastl::atomic_signal_fence(eastl::memory_order_relaxed); - - eastl::atomic_signal_fence(eastl::memory_order_acquire); - - eastl::atomic_signal_fence(eastl::memory_order_release); - - eastl::atomic_signal_fence(eastl::memory_order_acq_rel); - - eastl::atomic_signal_fence(eastl::memory_order_seq_cst); -} - -void AtomicStandaloneBasicTest::AtomicThreadFence() -{ - eastl::atomic_thread_fence(eastl::memory_order_relaxed); - - eastl::atomic_thread_fence(eastl::memory_order_acquire); - - eastl::atomic_thread_fence(eastl::memory_order_release); - - eastl::atomic_thread_fence(eastl::memory_order_acq_rel); - - eastl::atomic_thread_fence(eastl::memory_order_seq_cst); -} - -void AtomicStandaloneBasicTest::AtomicCpuPause() -{ - eastl::cpu_pause(); -} - -void AtomicStandaloneBasicTest::AtomicCompilerBarrier() -{ - eastl::compiler_barrier(); - - { - bool ret = false; - eastl::compiler_barrier_data_dependency(ret); - } -} - -class AtomicFlagBasicTest -{ -public: - - using AtomicType = eastl::atomic_flag; - using BoolType = bool; - - int RunTest() - { - TestAtomicFlagCtor(); - - TestAtomicFlagClear(); - - TestAtomicFlagTestAndSet(); - - TestAtomicFlagTest(); - - TestAllMemoryOrders(); - - TestAtomicFlagStandalone(); - - return nErrorCount; - } - -private: - - void TestAtomicFlagCtor(); - - void TestAtomicFlagClear(); - - void TestAtomicFlagTestAndSet(); - - void TestAtomicFlagTest(); - - void TestAllMemoryOrders(); - - void TestAtomicFlagStandalone(); - -private: - - int nErrorCount = 0; -}; - -void AtomicFlagBasicTest::TestAtomicFlagCtor() -{ - { - AtomicType atomic; - - VERIFY(atomic.test(eastl::memory_order_relaxed) == false); - } - - { - AtomicType atomic{ false }; - - VERIFY(atomic.test(eastl::memory_order_relaxed) == false); - } - - { - AtomicType atomic{ true }; - - VERIFY(atomic.test(eastl::memory_order_relaxed) == true); - } -} - -void AtomicFlagBasicTest::TestAtomicFlagClear() -{ - { - AtomicType atomic; - - atomic.clear(eastl::memory_order_relaxed); - - VERIFY(atomic.test(eastl::memory_order_relaxed) == false); - } - - { - AtomicType atomic{ true }; - - atomic.clear(eastl::memory_order_relaxed); - - VERIFY(atomic.test(eastl::memory_order_relaxed) == false); - } -} - -void AtomicFlagBasicTest::TestAtomicFlagTestAndSet() -{ - { - AtomicType atomic; - - BoolType ret = atomic.test_and_set(eastl::memory_order_relaxed); - - VERIFY(ret == false); - - VERIFY(atomic.test(eastl::memory_order_relaxed) == true); - } - - { - AtomicType atomic{ true }; - - BoolType ret = atomic.test_and_set(eastl::memory_order_relaxed); - - VERIFY(ret == true); - - VERIFY(atomic.test(eastl::memory_order_relaxed) == true); - } -} - -void AtomicFlagBasicTest::TestAtomicFlagTest() -{ - { - AtomicType atomic; - - VERIFY(atomic.test(eastl::memory_order_relaxed) == false); - } - - { - AtomicType atomic{ true }; - - VERIFY(atomic.test(eastl::memory_order_relaxed) == true); - } -} - -void AtomicFlagBasicTest::TestAllMemoryOrders() -{ - { - AtomicType atomic; - - atomic.clear(); - - atomic.clear(eastl::memory_order_relaxed); - - atomic.clear(eastl::memory_order_release); - - atomic.clear(eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - atomic.test_and_set(); - - atomic.test_and_set(eastl::memory_order_relaxed); - - atomic.test_and_set(eastl::memory_order_acquire); - - atomic.test_and_set(eastl::memory_order_release); - - atomic.test_and_set(eastl::memory_order_acq_rel); - - atomic.test_and_set(eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - BoolType ret = atomic.test(); - - ret = atomic.test(eastl::memory_order_relaxed); - - ret = atomic.test(eastl::memory_order_acquire); - - ret = atomic.test(eastl::memory_order_seq_cst); - } -} - -void AtomicFlagBasicTest::TestAtomicFlagStandalone() -{ - { - AtomicType atomic; - - BoolType ret = atomic_flag_test_and_set(&atomic); - - ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_relaxed); - - ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_acquire); - - ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_release); - - ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_acq_rel); - - ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - atomic_flag_clear(&atomic); - - atomic_flag_clear_explicit(&atomic, eastl::memory_order_relaxed); - - atomic_flag_clear_explicit(&atomic, eastl::memory_order_release); - - atomic_flag_clear_explicit(&atomic, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - BoolType ret = atomic_flag_test(&atomic); - - ret = atomic_flag_test_explicit(&atomic, eastl::memory_order_relaxed); - - ret = atomic_flag_test_explicit(&atomic, eastl::memory_order_acquire); - - ret = atomic_flag_test_explicit(&atomic, eastl::memory_order_seq_cst); - } -} - -class AtomicVoidPointerBasicTest -{ -public: - - using AtomicType = eastl::atomic; - using PtrType = void*; - - int RunTest() - { - TestAtomicCtor(); - - TestAssignmentOperators(); - - TestIsLockFree(); - - TestStore(); - - TestLoad(); - - TestExchange(); - - TestCompareExchangeWeak(); - - TestCompareExchangeStrong(); - - TestAllMemoryOrders(); - - return nErrorCount; - } - -private: - - void TestAtomicCtor(); - - void TestAssignmentOperators(); - - void TestIsLockFree(); - - void TestStore(); - - void TestLoad(); - - void TestExchange(); - - void TestCompareExchangeWeak(); - - void TestCompareExchangeStrong(); - - void TestAllMemoryOrders(); - -private: - - int nErrorCount = 0; -}; - -void AtomicVoidPointerBasicTest::TestAtomicCtor() -{ - { - AtomicType atomic; - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } - - { - AtomicType atomic{ (PtrType)0x04 }; - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x04); - } -} - -void AtomicVoidPointerBasicTest::TestAssignmentOperators() -{ - { - AtomicType atomic; - - PtrType ret = atomic = (PtrType)0x04; - - VERIFY(ret == (PtrType)0x04); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x04); - } - - { - AtomicType atomic; - - PtrType ret = atomic = (PtrType)0x0; - - VERIFY(ret == (PtrType)0x0); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } -} - -void AtomicVoidPointerBasicTest::TestIsLockFree() -{ - { - AtomicType atomic; - - VERIFY(atomic.is_lock_free() == true); - - VERIFY(atomic.is_always_lock_free == true); - } -} - -void AtomicVoidPointerBasicTest::TestStore() -{ - { - PtrType val = (PtrType)0x0; - AtomicType atomic; - - atomic.store(val, eastl::memory_order_relaxed); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == val); - } - - { - PtrType val = (PtrType)0x4; - AtomicType atomic; - - atomic.store(val, eastl::memory_order_relaxed); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == val); - } -} - -void AtomicVoidPointerBasicTest::TestLoad() -{ - { - AtomicType atomic{ (PtrType)0x4 }; - - PtrType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic == (PtrType)0x4); - } -} - -void AtomicVoidPointerBasicTest::TestExchange() -{ - { - AtomicType atomic; - - PtrType ret = atomic.exchange((PtrType)0x4, eastl::memory_order_release); - - VERIFY(ret == (PtrType)0x0); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } -} - -void AtomicVoidPointerBasicTest::TestCompareExchangeWeak() -{ - { - AtomicType atomic; - - PtrType observed = (PtrType)0x0; - bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - if (ret) - { - VERIFY(ret == true); - VERIFY(observed == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - } - - { - AtomicType atomic; - - PtrType observed = (PtrType)0x4; - bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - VERIFY(ret == false); - VERIFY(observed == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } -} - -void AtomicVoidPointerBasicTest::TestCompareExchangeStrong() -{ - { - AtomicType atomic; - - PtrType observed = (PtrType)0x0; - bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - VERIFY(ret == true); - VERIFY(observed == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - - { - AtomicType atomic; - - PtrType observed = (PtrType)0x4; - bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - VERIFY(ret == false); - VERIFY(observed == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } -} - -void AtomicVoidPointerBasicTest::TestAllMemoryOrders() -{ - { - AtomicType atomic; - PtrType val = (PtrType)0x4; - - atomic.store(val); - - atomic.store(val, eastl::memory_order_relaxed); - - atomic.store(val, eastl::memory_order_release); - - atomic.store(val, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - PtrType ret = atomic.load(); - - ret = atomic.load(eastl::memory_order_relaxed); - - ret = atomic.load(eastl::memory_order_acquire); - - ret = atomic.load(eastl::memory_order_seq_cst); - - ret = atomic.load(eastl::memory_order_read_depends); - } - - { - AtomicType atomic; - - PtrType ret = atomic.exchange((PtrType)0x4); - - ret = atomic.exchange((PtrType)0x4, eastl::memory_order_relaxed); - - ret = atomic.exchange((PtrType)0x4, eastl::memory_order_acquire); - - ret = atomic.exchange((PtrType)0x4, eastl::memory_order_release); - - ret = atomic.exchange((PtrType)0x4, eastl::memory_order_acq_rel); - - ret = atomic.exchange((PtrType)0x4, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - PtrType observed = (PtrType)0x0; - - bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_release); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - PtrType observed = (PtrType)0x0; - - bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_release); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - PtrType observed = (PtrType)0x0; - bool ret; - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_release, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - PtrType observed = (PtrType)0x0; - bool ret; - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_release, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); - } -} - -class AtomicPointerBasicTest -{ -public: - - using AtomicType = eastl::atomic; - using PtrType = uint32_t*; - - int RunTest() - { - TestAtomicCtor(); - - TestAssignmentOperators(); - - TestIsLockFree(); - - TestStore(); - - TestLoad(); - - TestExchange(); - - TestCompareExchangeWeak(); - - TestCompareExchangeStrong(); - - TestAllMemoryOrders(); - - TestFetchAdd(); - TestAddFetch(); - - TestFetchSub(); - TestSubFetch(); - - TestAtomicPointerStandalone(); - - return nErrorCount; - } - -private: - - void TestAtomicCtor(); - - void TestAssignmentOperators(); - - void TestIsLockFree(); - - void TestStore(); - - void TestLoad(); - - void TestExchange(); - - void TestCompareExchangeWeak(); - - void TestCompareExchangeStrong(); - - void TestAllMemoryOrders(); - - void TestFetchAdd(); - void TestAddFetch(); - - void TestFetchSub(); - void TestSubFetch(); - - void TestAtomicPointerStandalone(); - -private: - - int nErrorCount = 0; -}; - -void AtomicPointerBasicTest::TestAtomicCtor() -{ - { - AtomicType atomic{}; - - PtrType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == nullptr); - } - - { - AtomicType atomic{ (PtrType)0x4 }; - - PtrType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x4); - } -} - -void AtomicPointerBasicTest::TestAssignmentOperators() -{ - { - PtrType val = (PtrType)0x4; - AtomicType atomic{val}; - - PtrType expected = (PtrType)0x8; - - PtrType ret = atomic = expected; - - VERIFY(ret == expected); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } - - { - PtrType val = (PtrType)0x0; - AtomicType atomic{val}; - - PtrType ret = atomic = val; - - VERIFY(ret == val); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == val); - } - - { - PtrType val = (PtrType)0x4; - AtomicType atomic{val}; - - PtrType expected = (PtrType)0x8; - PtrType ret = ++atomic; - - VERIFY(ret == expected); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } - - { - PtrType val = (PtrType)0x4; - - - AtomicType atomic{val}; - - PtrType expected = (PtrType)0x8; - PtrType ret = atomic++; - - VERIFY(ret == val); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } - - { - PtrType val = (PtrType)0x4; - AtomicType atomic{val}; - - PtrType expected = (PtrType)0x10; - PtrType ret = atomic += 3; - - VERIFY(ret == expected); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } - - { - PtrType val = (PtrType)0x4; - AtomicType atomic{val}; - - PtrType expected = (PtrType)0x4; - PtrType ret = atomic += 0; - - VERIFY(ret == expected); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } - - { - PtrType val = (PtrType)0x4; - AtomicType atomic{val}; - - PtrType expected = (PtrType)0x0; - PtrType ret = atomic -= 1; - - VERIFY(ret == expected); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } - - { - PtrType val = (PtrType)0x4; - AtomicType atomic{val}; - - PtrType expected = (PtrType)0x4; - PtrType ret = atomic -= 0; - - VERIFY(ret == expected); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } -} - -void AtomicPointerBasicTest::TestIsLockFree() -{ - { - AtomicType atomic; - - VERIFY(atomic.is_lock_free() == true); - - VERIFY(atomic.is_always_lock_free == true); - } -} - -void AtomicPointerBasicTest::TestStore() -{ - { - PtrType val = (PtrType)0x0; - AtomicType atomic; - - atomic.store(val, eastl::memory_order_relaxed); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == val); - } - - { - PtrType val = (PtrType)0x4; - AtomicType atomic; - - atomic.store(val, eastl::memory_order_relaxed); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == val); - } -} - -void AtomicPointerBasicTest::TestLoad() -{ - { - AtomicType atomic{ (PtrType)0x4 }; - - PtrType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic == (PtrType)0x4); - } -} - -void AtomicPointerBasicTest::TestCompareExchangeWeak() -{ - { - AtomicType atomic; - - PtrType observed = (PtrType)0x0; - bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - if (ret) - { - VERIFY(ret == true); - VERIFY(observed == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - } - - { - AtomicType atomic; - - PtrType observed = (PtrType)0x4; - bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - VERIFY(ret == false); - VERIFY(observed == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } -} - -void AtomicPointerBasicTest::TestCompareExchangeStrong() -{ - { - AtomicType atomic; - - PtrType observed = (PtrType)0x0; - bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - VERIFY(ret == true); - VERIFY(observed == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - - { - AtomicType atomic; - - PtrType observed = (PtrType)0x4; - bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - VERIFY(ret == false); - VERIFY(observed == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } -} - -void AtomicPointerBasicTest::TestExchange() -{ - { - AtomicType atomic; - - PtrType ret = atomic.exchange((PtrType)0x4, eastl::memory_order_release); - - VERIFY(ret == (PtrType)0x0); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } -} - -void AtomicPointerBasicTest::TestAllMemoryOrders() -{ - { - AtomicType atomic; - PtrType val = (PtrType)0x4; - - atomic.store(val); - - atomic.store(val, eastl::memory_order_relaxed); - - atomic.store(val, eastl::memory_order_release); - - atomic.store(val, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - PtrType ret = atomic.load(); - - ret = atomic.load(eastl::memory_order_relaxed); - - ret = atomic.load(eastl::memory_order_acquire); - - ret = atomic.load(eastl::memory_order_seq_cst); - - ret = atomic.load(eastl::memory_order_read_depends); - } - - { - AtomicType atomic; - - PtrType ret = atomic.fetch_add(0); - - ret = atomic.fetch_add(0, eastl::memory_order_relaxed); - - ret = atomic.fetch_add(0, eastl::memory_order_acquire); - - ret = atomic.fetch_add(0, eastl::memory_order_release); - - ret = atomic.fetch_add(0, eastl::memory_order_acq_rel); - - ret = atomic.fetch_add(0, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - PtrType ret = atomic.fetch_sub(0); - - ret = atomic.fetch_sub(0, eastl::memory_order_relaxed); - - ret = atomic.fetch_sub(0, eastl::memory_order_acquire); - - ret = atomic.fetch_sub(0, eastl::memory_order_release); - - ret = atomic.fetch_sub(0, eastl::memory_order_acq_rel); - - ret = atomic.fetch_sub(0, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - PtrType ret = atomic.add_fetch(0); - - ret = atomic.add_fetch(0, eastl::memory_order_relaxed); - - ret = atomic.add_fetch(0, eastl::memory_order_acquire); - - ret = atomic.add_fetch(0, eastl::memory_order_release); - - ret = atomic.add_fetch(0, eastl::memory_order_acq_rel); - - ret = atomic.add_fetch(0, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - PtrType ret = atomic.sub_fetch(0); - - ret = atomic.sub_fetch(0, eastl::memory_order_relaxed); - - ret = atomic.sub_fetch(0, eastl::memory_order_acquire); - - ret = atomic.sub_fetch(0, eastl::memory_order_release); - - ret = atomic.sub_fetch(0, eastl::memory_order_acq_rel); - - ret = atomic.sub_fetch(0, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - PtrType ret = atomic.exchange((PtrType)0x4); - - ret = atomic.exchange((PtrType)0x4, eastl::memory_order_relaxed); - - ret = atomic.exchange((PtrType)0x4, eastl::memory_order_acquire); - - ret = atomic.exchange((PtrType)0x4, eastl::memory_order_release); - - ret = atomic.exchange((PtrType)0x4, eastl::memory_order_acq_rel); - - ret = atomic.exchange((PtrType)0x4, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - PtrType observed = (PtrType)0x0; - - bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_release); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - PtrType observed = (PtrType)0x0; - - bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_release); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - PtrType observed = (PtrType)0x0; - bool ret; - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_release, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - PtrType observed = (PtrType)0x0; - bool ret; - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_release, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); - } -} - -void AtomicPointerBasicTest::TestFetchAdd() -{ - { - PtrType val = (PtrType)0x4; - AtomicType atomic{ val }; - - PtrType ret = atomic.fetch_add(1, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x8); - } - - { - PtrType val = (PtrType)0x4; - AtomicType atomic{ val }; - - PtrType ret = atomic.fetch_add(0, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } -} - -void AtomicPointerBasicTest::TestAddFetch() -{ - { - PtrType val = (PtrType)0x4; - AtomicType atomic{ val }; - - PtrType ret = atomic.add_fetch(1, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x8); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x8); - } - - { - PtrType val = (PtrType)0x4; - AtomicType atomic{ val }; - - PtrType ret = atomic.add_fetch(0, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } -} - -void AtomicPointerBasicTest::TestFetchSub() -{ - { - PtrType val = (PtrType)0x4; - AtomicType atomic{ val }; - - PtrType ret = atomic.fetch_sub(1, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } - - { - PtrType val = (PtrType)0x4; - AtomicType atomic{ val }; - - PtrType ret = atomic.fetch_sub(0, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } -} - -void AtomicPointerBasicTest::TestSubFetch() -{ - { - PtrType val = (PtrType)0x4; - AtomicType atomic{ val }; - - PtrType ret = atomic.sub_fetch(1, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x0); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } - - { - PtrType val = (PtrType)0x4; - AtomicType atomic{ val }; - - PtrType ret = atomic.sub_fetch(0, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } -} - -void AtomicPointerBasicTest::TestAtomicPointerStandalone() -{ - { - AtomicType atomic; - - VERIFY(atomic_is_lock_free(&atomic) == true); - } - - { - AtomicType atomic; - PtrType val = (PtrType)0x4; - - atomic_store(&atomic, val); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == val); - } - - { - AtomicType atomic; - PtrType val = (PtrType)0x4; - - atomic_store_explicit(&atomic, val, eastl::memory_order_relaxed); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == val); - } - - { - AtomicType atomic; - - PtrType ret = atomic_load(&atomic); - - VERIFY(ret == (PtrType)0x0); - } - - { - AtomicType atomic; - - PtrType ret = atomic_load_explicit(&atomic, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x0); - } - - { - AtomicType atomic; - - PtrType ret = atomic_load_cond(&atomic, [](PtrType val) { return true; }); - - VERIFY(ret == (PtrType)0x0); - } - - { - AtomicType atomic; - - PtrType ret = atomic_load_cond_explicit(&atomic, [](PtrType val) { return true; }, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x0); - } - - { - AtomicType atomic; - - PtrType ret = atomic_exchange(&atomic, (PtrType)0x4); - - VERIFY(ret == (PtrType)0x0); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - - { - AtomicType atomic; - - PtrType ret = atomic_exchange_explicit(&atomic, (PtrType)0x4, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x0); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - - { - AtomicType atomic; - - PtrType ret = atomic_add_fetch(&atomic, 1); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - - { - AtomicType atomic; - - PtrType ret = atomic_add_fetch_explicit(&atomic, 1, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - - { - AtomicType atomic; - - PtrType ret = atomic_fetch_add(&atomic, 1); - - VERIFY(ret == (PtrType)0x0); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - - { - AtomicType atomic; - - PtrType ret = atomic_fetch_add_explicit(&atomic, 1, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x0); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - - { - AtomicType atomic{ (PtrType)0x4 }; - - PtrType ret = atomic_fetch_sub(&atomic, 1); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } - - { - AtomicType atomic{ (PtrType)0x4 }; - - PtrType ret = atomic_fetch_sub_explicit(&atomic, 1, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x4); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } - - { - AtomicType atomic{ (PtrType)0x4 }; - - PtrType ret = atomic_sub_fetch(&atomic, 1); - - VERIFY(ret == (PtrType)0x0); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } - - { - AtomicType atomic{ (PtrType)0x4 }; - - PtrType ret = atomic_sub_fetch_explicit(&atomic, 1, eastl::memory_order_relaxed); - - VERIFY(ret == (PtrType)0x0); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); - } - - { - AtomicType atomic; - - PtrType expected = (PtrType)0x0; - bool ret = atomic_compare_exchange_strong(&atomic, &expected, (PtrType)0x4); - - VERIFY(ret == true); - - VERIFY(expected == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - - { - AtomicType atomic; - - PtrType expected = (PtrType)0x0; - bool ret = atomic_compare_exchange_strong_explicit(&atomic, &expected, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - VERIFY(ret == true); - - VERIFY(expected == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - - { - AtomicType atomic; - - PtrType expected = (PtrType)0x0; - bool ret = atomic_compare_exchange_weak(&atomic, &expected, (PtrType)0x4); - - if (ret) - { - VERIFY(ret == true); - - VERIFY(expected == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - } - - { - AtomicType atomic; - - PtrType expected = (PtrType)0x0; - bool ret = atomic_compare_exchange_weak_explicit(&atomic, &expected, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - if (ret) - { - VERIFY(ret == true); - - VERIFY(expected == (PtrType)0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); - } - } -} - -struct AtomicNonTriviallyConstructible -{ - AtomicNonTriviallyConstructible() - : a(0) - , b(0) - { - } - - AtomicNonTriviallyConstructible(uint16_t a, uint16_t b) - : a(a) - , b(b) - { - } - - friend bool operator==(const AtomicNonTriviallyConstructible& a, const AtomicNonTriviallyConstructible& b) - { - return a.a == b.a && a.b == b.b; - } - - uint16_t a; - uint16_t b; -}; - -struct AtomicNonTriviallyConstructibleNoExcept -{ - AtomicNonTriviallyConstructibleNoExcept() noexcept - : a(0) - , b(0) - { - } - - AtomicNonTriviallyConstructibleNoExcept(uint16_t a, uint16_t b) noexcept - : a(a) - , b(b) - { - } - - friend bool operator==(const AtomicNonTriviallyConstructibleNoExcept& a, const AtomicNonTriviallyConstructibleNoExcept& b) - { - return a.a == b.a && a.b == b.b; - } - - uint16_t a; - uint16_t b; -}; - -struct AtomicUserType16 -{ - uint8_t a; - uint8_t b; - - friend bool operator==(const AtomicUserType16& a, const AtomicUserType16& b) - { - return (a.a == b.a) && (a.b == b.b); - } -}; - -struct AtomicUserType128 -{ - uint32_t a; - uint32_t b; - uint32_t c; - uint32_t d; - - AtomicUserType128() = default; - - AtomicUserType128(const AtomicUserType128&) = default; - - AtomicUserType128(uint32_t a, uint32_t b) - : a(a) - , b(b) - , c(0) - , d(0) - { - } - - AtomicUserType128& operator=(const AtomicUserType128&) = default; - - friend bool operator==(const AtomicUserType128& a, const AtomicUserType128& b) - { - return (a.a == b.a) && (a.b == b.b) && (a.c == b.c) && (a.d == b.d); - } -}; - -template -class AtomicUserTypeBasicTest -{ -public: - - using AtomicType = eastl::atomic; - using UserType = T; - - int RunTest() - { - TestAtomicCtor(); - - TestAssignmentOperators(); - - TestIsLockFree(); - - TestStore(); - - TestLoad(); - - TestExchange(); - - TestCompareExchangeWeak(); - - TestCompareExchangeStrong(); - - TestAllMemoryOrders(); - - return nErrorCount; - } - -private: - - void TestAtomicCtor(); - - void TestAssignmentOperators(); - - void TestIsLockFree(); - - void TestStore(); - - void TestLoad(); - - void TestExchange(); - - void TestCompareExchangeWeak(); - - void TestCompareExchangeStrong(); - - void TestAllMemoryOrders(); - -private: - - int nErrorCount = 0; -}; - -template -void AtomicUserTypeBasicTest::TestAtomicCtor() -{ - { - AtomicType atomic; - UserType expected{0, 0}; - - UserType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == expected); - } - - { - AtomicType atomic{ {5, 8} }; - UserType expected{5, 8}; - - UserType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == expected); - } -} - -template -void AtomicUserTypeBasicTest::TestAssignmentOperators() -{ - { - AtomicType atomic; - UserType expected{5, 6}; - - atomic = {5, 6}; - - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } - - { - AtomicType atomic; - UserType expected{0, 0}; - - atomic = {0, 0}; - - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } -} - -template -void AtomicUserTypeBasicTest::TestIsLockFree() -{ - { - AtomicType atomic; - - VERIFY(atomic.is_lock_free() == true); - - VERIFY(AtomicType::is_always_lock_free == true); - } -} - -template -void AtomicUserTypeBasicTest::TestStore() -{ - { - AtomicType atomic; - UserType expected{5, 6}; - - atomic.store(expected, eastl::memory_order_relaxed); - - UserType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == expected); - } - - { - AtomicType atomic; - UserType expected{5, 6}; - - atomic.store({5, 6}, eastl::memory_order_relaxed); - - UserType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == expected); - } -} - -template -void AtomicUserTypeBasicTest::TestLoad() -{ - { - AtomicType atomic; - UserType expected{0, 0}; - - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - - VERIFY(atomic == expected); - } - - { - AtomicType atomic{ {5, 6} }; - UserType expected{5, 6}; - - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - - VERIFY(atomic == expected); - } -} - -template -void AtomicUserTypeBasicTest::TestExchange() -{ - { - AtomicType atomic; - UserType expected{0, 0}; - - UserType ret = atomic.exchange({0, 0}, eastl::memory_order_relaxed); - - VERIFY(ret == expected); - } - - { - AtomicType atomic; - UserType expected{0, 0}; - UserType expected2{0, 1}; - - UserType ret = atomic.exchange({0, 1}, eastl::memory_order_relaxed); - - VERIFY(ret == expected); - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected2); - } -} - -template -void AtomicUserTypeBasicTest::TestCompareExchangeWeak() -{ - { - AtomicType atomic; - - UserType observed{0, 0}; - bool ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_relaxed); - - UserType expected{0, 0}; - if (ret) - { - VERIFY(ret == true); - VERIFY(observed == expected); - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } - } - - { - AtomicType atomic; - - UserType observed{0, 0}; - bool ret = atomic.compare_exchange_weak(observed, {0, 1}, eastl::memory_order_relaxed); - - UserType expected{0, 1}; - UserType expected2{0, 0}; - if (ret) - { - VERIFY(ret == true); - VERIFY(observed == expected2); - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } - } - - { - AtomicType atomic; - - UserType observed{0, 1}; - bool ret = atomic.compare_exchange_weak(observed, {0, 1}, eastl::memory_order_relaxed); - - UserType expected{0, 0}; - - VERIFY(ret == false); - VERIFY(observed == expected); - } -} - -template -void AtomicUserTypeBasicTest::TestCompareExchangeStrong() -{ - { - AtomicType atomic; - - UserType observed{0, 0}; - bool ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_relaxed); - - UserType expected{0, 0}; - - VERIFY(ret == true); - VERIFY(observed == expected); - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } - - { - AtomicType atomic; - - UserType observed{0, 0}; - bool ret = atomic.compare_exchange_strong(observed, {0, 1}, eastl::memory_order_relaxed); - - UserType expected{0, 1}; - UserType expected2{0, 0}; - - VERIFY(ret == true); - VERIFY(observed == expected2); - VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); - } - - { - AtomicType atomic; - - UserType observed{0, 1}; - bool ret = atomic.compare_exchange_strong(observed, {0, 1}, eastl::memory_order_relaxed); - - UserType expected{0, 0}; - - VERIFY(ret == false); - VERIFY(observed == expected); - } -} - -template -void AtomicUserTypeBasicTest::TestAllMemoryOrders() -{ - { - AtomicType atomic; - UserType val{0, 1}; - - atomic.store(val); - - atomic.store(val, eastl::memory_order_relaxed); - - atomic.store(val, eastl::memory_order_release); - - atomic.store(val, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - UserType ret = atomic.load(); - - ret = atomic.load(eastl::memory_order_relaxed); - - ret = atomic.load(eastl::memory_order_acquire); - - ret = atomic.load(eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - UserType ret = atomic.exchange({0, 1}); - - ret = atomic.exchange({0, 0}, eastl::memory_order_relaxed); - - ret = atomic.exchange({0, 0}, eastl::memory_order_acquire); - - ret = atomic.exchange({0, 0}, eastl::memory_order_release); - - ret = atomic.exchange({0, 0}, eastl::memory_order_acq_rel); - - ret = atomic.exchange({0, 0}, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - UserType observed{0, 0}; - - bool ret = atomic.compare_exchange_weak(observed, {0, 0}); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_release); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acq_rel); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - UserType observed{0, 0}; - - bool ret = atomic.compare_exchange_strong(observed, {0, 0}); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_release); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acq_rel); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - UserType observed{0, 0}; - bool ret; - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acquire, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acquire, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_release, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acq_rel, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - UserType observed{0, 0}; - bool ret; - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acquire, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acquire, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_release, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acq_rel, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); - } -} - - -class AtomicBoolBasicTest -{ -public: - - using AtomicType = eastl::atomic; - using BoolType = bool; - - int RunTest() - { - TestAtomicCtor(); - - TestAssignmentOperators(); - - TestIsLockFree(); - - TestStore(); - - TestLoad(); - - TestExchange(); - - TestCompareExchangeWeak(); - - TestCompareExchangeStrong(); - - TestAllMemoryOrders(); - - return nErrorCount; - } - -private: - - void TestAtomicCtor(); - - void TestAssignmentOperators(); - - void TestIsLockFree(); - - void TestStore(); - - void TestLoad(); - - void TestExchange(); - - void TestCompareExchangeWeak(); - - void TestCompareExchangeStrong(); - - void TestAllMemoryOrders(); - -private: - - int nErrorCount = 0; -}; - -void AtomicBoolBasicTest::TestAtomicCtor() -{ - { - AtomicType atomic{ false }; - - BoolType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == false); - } - - { - AtomicType atomic{ true }; - - BoolType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == true); - } - - { - AtomicType atomic; - - BoolType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == false); - } - - { - AtomicType atomic{}; - - BoolType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == false); - } -} - -void AtomicBoolBasicTest::TestAssignmentOperators() -{ - { - AtomicType atomic; - - BoolType ret = atomic = true; - - VERIFY(ret == true); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == true); - } -} - -void AtomicBoolBasicTest::TestIsLockFree() -{ - { - AtomicType atomic; - - bool ret = atomic.is_lock_free(); - - VERIFY(ret == true); - - VERIFY(AtomicType::is_always_lock_free == true); - } -} - -void AtomicBoolBasicTest::TestStore() -{ - { - AtomicType atomic; - - atomic.store(true, eastl::memory_order_relaxed); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == true); - } -} - -void AtomicBoolBasicTest::TestLoad() -{ - { - AtomicType atomic; - - VERIFY(atomic.load(eastl::memory_order_relaxed) == false); - - VERIFY(atomic == false); - } - - { - AtomicType atomic{ true }; - - VERIFY(atomic.load(eastl::memory_order_relaxed) == true); - - VERIFY(atomic == true); - } -} - -void AtomicBoolBasicTest::TestExchange() -{ - { - AtomicType atomic; - - BoolType ret = atomic.exchange(false, eastl::memory_order_relaxed); - - VERIFY(ret == false); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == false); - } - - { - AtomicType atomic; - - BoolType ret = atomic.exchange(true, eastl::memory_order_relaxed); - - VERIFY(ret == false); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == true); - } -} - -void AtomicBoolBasicTest::TestCompareExchangeWeak() -{ - { - AtomicType atomic{ false }; - - BoolType observed = false; - bool ret = atomic.compare_exchange_weak(observed, false, eastl::memory_order_relaxed); - - if (ret) - { - VERIFY(ret == true); - VERIFY(observed == false); - VERIFY(atomic.load(eastl::memory_order_relaxed) == false); - } - } - - { - AtomicType atomic{ false }; - - BoolType observed = false; - bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); - - if (ret) - { - VERIFY(ret == true); - VERIFY(observed == false); - VERIFY(atomic.load(eastl::memory_order_relaxed) == true); - } - } - - { - AtomicType atomic{ false }; - - BoolType observed = true; - bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); - - VERIFY(ret == false); - VERIFY(observed == false); - } -} - -void AtomicBoolBasicTest::TestCompareExchangeStrong() -{ - { - AtomicType atomic{ false }; - - BoolType observed = false; - bool ret = atomic.compare_exchange_weak(observed, false, eastl::memory_order_relaxed); - - VERIFY(ret == true); - VERIFY(observed == false); - VERIFY(atomic.load(eastl::memory_order_relaxed) == false); - } - - { - AtomicType atomic{ false }; - - BoolType observed = false; - bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); - - VERIFY(ret == true); - VERIFY(observed == false); - VERIFY(atomic.load(eastl::memory_order_relaxed) == true); - } - - { - AtomicType atomic{ false }; - - BoolType observed = true; - bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); - - VERIFY(ret == false); - VERIFY(observed == false); - } -} - -void AtomicBoolBasicTest::TestAllMemoryOrders() -{ - { - AtomicType atomic; - - atomic.store(true); - - atomic.store(true, eastl::memory_order_relaxed); - - atomic.store(true, eastl::memory_order_release); - - atomic.store(true, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - BoolType ret = atomic.load(); - - ret = atomic.load(eastl::memory_order_relaxed); - - ret = atomic.load(eastl::memory_order_acquire); - - ret = atomic.load(eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - BoolType ret = atomic.exchange(true); - - ret = atomic.exchange(true, eastl::memory_order_relaxed); - - ret = atomic.exchange(true, eastl::memory_order_acquire); - - ret = atomic.exchange(true, eastl::memory_order_release); - - ret = atomic.exchange(true, eastl::memory_order_acq_rel); - - ret = atomic.exchange(true, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - BoolType observed = false; - bool ret = atomic.compare_exchange_weak(observed, true); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_release); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acq_rel); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - BoolType observed = false; - bool ret = atomic.compare_exchange_strong(observed, true); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_release); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acq_rel); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - BoolType observed = false; - bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acquire, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acquire, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_release, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acq_rel, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic; - - BoolType observed = false; - bool ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acquire, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acquire, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_release, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acq_rel, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); - } -} - - -template -class AtomicIntegralBasicTest -{ -public: - - using AtomicType = eastl::atomic; - using IntegralType = T; - - int RunTest() - { - TestAtomicCtor(); - - TestAtomicFetchAdd(); - TestAtomicAddFetch(); - - TestAtomicFetchSub(); - TestAtomicSubFetch(); - - TestAtomicFetchAnd(); - TestAtomicAndFetch(); - - TestAtomicFetchOr(); - TestAtomicOrFetch(); - - TestAtomicFetchXor(); - TestAtomicXorFetch(); - - TestAssignmentOperators(); - - TestIsLockFree(); - - TestStore(); - - TestLoad(); - - TestExchange(); - - TestCompareExchangeWeak(); - - TestCompareExchangeStrong(); - - TestAllMemoryOrders(); - - TestAtomicStandalone(); - - return nErrorCount; - } - -private: - - void TestAtomicCtor(); - - void TestAtomicFetchAdd(); - void TestAtomicAddFetch(); - - void TestAtomicFetchSub(); - void TestAtomicSubFetch(); - - void TestAtomicFetchAnd(); - void TestAtomicAndFetch(); - - void TestAtomicFetchOr(); - void TestAtomicOrFetch(); - - void TestAtomicFetchXor(); - void TestAtomicXorFetch(); - - void TestAssignmentOperators(); - - void TestIsLockFree(); - - void TestStore(); - - void TestLoad(); - - void TestExchange(); - - void TestCompareExchangeWeak(); - - void TestCompareExchangeStrong(); - - void TestAllMemoryOrders(); - - void TestAtomicStandalone(); - -private: - - int nErrorCount = 0; -}; - -template -void AtomicIntegralBasicTest::TestAtomicCtor() -{ - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 1 }; - - IntegralType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 1); - } - - { - AtomicType atomic{ 20 }; - - IntegralType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 20); - } - - { - AtomicType atomic; - - IntegralType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } -} - -template -void AtomicIntegralBasicTest::TestAtomicFetchAdd() -{ - { - AtomicType atomic; - - IntegralType ret = atomic.fetch_add(1, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic.fetch_add(0, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 5 }; - - IntegralType ret = atomic.fetch_add(0, eastl::memory_order_relaxed); - - VERIFY(ret == 5); - - ret = atomic.fetch_add(4, eastl::memory_order_relaxed); - - VERIFY(ret == 5); - - ret = atomic.fetch_add(1, eastl::memory_order_relaxed); - - VERIFY(ret == 9); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 10); - } -} - -template -void AtomicIntegralBasicTest::TestAtomicAddFetch() -{ - { - AtomicType atomic; - - IntegralType ret = atomic.add_fetch(1, eastl::memory_order_relaxed); - - VERIFY(ret == 1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic.add_fetch(0, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 5 }; - - IntegralType ret = atomic.add_fetch(0, eastl::memory_order_relaxed); - - VERIFY(ret == 5); - - ret = atomic.add_fetch(4, eastl::memory_order_relaxed); - - VERIFY(ret == 9); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 9); - } -} - -template -void AtomicIntegralBasicTest::TestAtomicFetchSub() -{ - { - AtomicType atomic{ 1 }; - - IntegralType ret = atomic.fetch_sub(1, eastl::memory_order_relaxed); - - VERIFY(ret == 1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 1 }; - - IntegralType ret = atomic.fetch_sub(0, eastl::memory_order_relaxed); - - VERIFY(ret == 1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 1); - } - - { - AtomicType atomic{ 5 }; - - IntegralType ret = atomic.fetch_sub(2, eastl::memory_order_relaxed); - - VERIFY(ret == 5); - - ret = atomic.fetch_sub(1, eastl::memory_order_relaxed); - - VERIFY(ret == 3); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 2); - } -} - -template -void AtomicIntegralBasicTest::TestAtomicSubFetch() -{ - { - AtomicType atomic{ 1 }; - - IntegralType ret = atomic.sub_fetch(1, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 1 }; - - IntegralType ret = atomic.sub_fetch(0, eastl::memory_order_relaxed); - - VERIFY(ret == 1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 1); - } - - { - AtomicType atomic{ 5 }; - - IntegralType ret = atomic.sub_fetch(2, eastl::memory_order_relaxed); - - VERIFY(ret == 3); - - ret = atomic.sub_fetch(1, eastl::memory_order_relaxed); - - VERIFY(ret == 2); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 2); - } -} - -template -void AtomicIntegralBasicTest::TestAtomicFetchAnd() -{ - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic.fetch_and(0x0, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic.fetch_and(0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 0xF }; - - IntegralType ret = atomic.fetch_and(0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0xF); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0X1); - } - - { - AtomicType atomic{ 0xF }; - - IntegralType ret = atomic.fetch_and(0xF0, eastl::memory_order_relaxed); - - VERIFY(ret == 0xF); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - } -} - -template -void AtomicIntegralBasicTest::TestAtomicAndFetch() -{ - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic.and_fetch(0x0, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic.and_fetch(0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 0xF }; - - IntegralType ret = atomic.and_fetch(0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - } - - { - AtomicType atomic{ 0xF }; - - IntegralType ret = atomic.and_fetch(0xF0, eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - } -} - -template -void AtomicIntegralBasicTest::TestAtomicFetchOr() -{ - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic.fetch_or(0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic.fetch_or(0x0, eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic.fetch_or(0x2, eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x3); - } -} - -template -void AtomicIntegralBasicTest::TestAtomicOrFetch() -{ - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic.or_fetch(0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic.or_fetch(0x0, eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic.or_fetch(0x2, eastl::memory_order_relaxed); - - VERIFY(ret == 0x3); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x3); - } -} - -template -void AtomicIntegralBasicTest::TestAtomicFetchXor() -{ - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic.fetch_xor(0x0, eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic.fetch_xor(0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - } - - { - AtomicType atomic{ 0x0 }; - - IntegralType ret = atomic.fetch_xor(0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - } -} - -template -void AtomicIntegralBasicTest::TestAtomicXorFetch() -{ - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic.xor_fetch(0x0, eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic.xor_fetch(0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - } - - { - AtomicType atomic{ 0x0 }; - - IntegralType ret = atomic.xor_fetch(0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - } -} - -template -void AtomicIntegralBasicTest::TestAssignmentOperators() -{ - { - AtomicType atomic{ 0 }; - - IntegralType ret = (atomic = 5); - - VERIFY(ret == 5); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 5); - } - - { - AtomicType atomic{ 0 }; - - IntegralType ret = ++atomic; - - VERIFY(ret == 1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 1); - } - - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic++; - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 1); - } - - { - AtomicType atomic{ 1 }; - - IntegralType ret = --atomic; - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 1 }; - - IntegralType ret = atomic--; - - VERIFY(ret == 1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic += 5; - - VERIFY(ret == 5); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 5); - } - - { - AtomicType atomic{ 5 }; - - IntegralType ret = atomic -= 3; - - VERIFY(ret == 2); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 2); - } - - { - AtomicType atomic{ 0x0 }; - - IntegralType ret = atomic |= 0x1; - - VERIFY(ret == 0x1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic &= 0x1; - - VERIFY(ret == 0x1); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic ^= 0x1; - - VERIFY(ret == 0x0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - } -} - -template -void AtomicIntegralBasicTest::TestIsLockFree() -{ - { - const AtomicType atomic{ 5 }; - - VERIFY(atomic.is_lock_free() == true); - - VERIFY(AtomicType::is_always_lock_free == true); - } -} - -template -void AtomicIntegralBasicTest::TestStore() -{ - { - AtomicType atomic{ 0 }; - - atomic.store(0, eastl::memory_order_relaxed); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); - } - - { - AtomicType atomic{ 0 }; - - atomic.store(1, eastl::memory_order_relaxed); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } -} - -template -void AtomicIntegralBasicTest::TestLoad() -{ - { - AtomicType atomic{ 0 }; - - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); - - bool ret = atomic == 0; - VERIFY(ret == true); - - VERIFY(atomic == 0); - } - - { - AtomicType atomic{ 5 }; - - VERIFY(atomic.load(eastl::memory_order_relaxed) == 5); - - bool ret = atomic == 5; - VERIFY(ret == true); - - VERIFY(atomic == 5); - } -} - -template -void AtomicIntegralBasicTest::TestExchange() -{ - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic.exchange(0, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic{ 0 }; - - IntegralType ret = atomic.exchange(1, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - - ret = atomic.load(eastl::memory_order_relaxed); - - VERIFY(ret == 1); - } -} - -template -void AtomicIntegralBasicTest::TestCompareExchangeWeak() -{ - { - AtomicType atomic{ 0 }; - - IntegralType observed = 0; - bool ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_relaxed); - - if (ret == true) - { - VERIFY(ret == true); - VERIFY(observed == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - } - - { - AtomicType atomic{ 0 }; - - IntegralType observed = 1; - bool ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_relaxed); - - VERIFY(ret == false); - VERIFY(observed == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); - } -} - -template -void AtomicIntegralBasicTest::TestCompareExchangeStrong() -{ - { - AtomicType atomic{ 0 }; - - IntegralType observed = 0; - bool ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_relaxed); - - VERIFY(ret == true); - VERIFY(observed == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - - { - AtomicType atomic{ 0 }; - - IntegralType observed = 1; - bool ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_relaxed); - - VERIFY(ret == false); - VERIFY(observed == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); - } -} - -template -void AtomicIntegralBasicTest::TestAllMemoryOrders() -{ - { - AtomicType atomic{}; - - atomic.store(1); - - atomic.store(1, eastl::memory_order_relaxed); - - atomic.store(1, eastl::memory_order_release); - - atomic.store(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.load(); - - ret = atomic.load(eastl::memory_order_relaxed); - - ret = atomic.load(eastl::memory_order_acquire); - - ret = atomic.load(eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.exchange(1); - - ret = atomic.exchange(1, eastl::memory_order_relaxed); - - ret = atomic.exchange(1, eastl::memory_order_acquire); - - ret = atomic.exchange(1, eastl::memory_order_release); - - ret = atomic.exchange(1, eastl::memory_order_acq_rel); - - ret = atomic.exchange(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.fetch_add(1); - - ret = atomic.fetch_add(1, eastl::memory_order_relaxed); - - ret = atomic.fetch_add(1, eastl::memory_order_acquire); - - ret = atomic.fetch_add(1, eastl::memory_order_release); - - ret = atomic.fetch_add(1, eastl::memory_order_acq_rel); - - ret = atomic.fetch_add(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.add_fetch(1); - - ret = atomic.add_fetch(1, eastl::memory_order_relaxed); - - ret = atomic.add_fetch(1, eastl::memory_order_acquire); - - ret = atomic.add_fetch(1, eastl::memory_order_release); - - ret = atomic.add_fetch(1, eastl::memory_order_acq_rel); - - ret = atomic.add_fetch(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.fetch_sub(1); - - ret = atomic.fetch_sub(1, eastl::memory_order_relaxed); - - ret = atomic.fetch_sub(1, eastl::memory_order_acquire); - - ret = atomic.fetch_sub(1, eastl::memory_order_release); - - ret = atomic.fetch_sub(1, eastl::memory_order_acq_rel); - - ret = atomic.fetch_sub(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.sub_fetch(1); - - ret = atomic.sub_fetch(1, eastl::memory_order_relaxed); - - ret = atomic.sub_fetch(1, eastl::memory_order_acquire); - - ret = atomic.sub_fetch(1, eastl::memory_order_release); - - ret = atomic.sub_fetch(1, eastl::memory_order_acq_rel); - - ret = atomic.sub_fetch(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.fetch_and(1); - - ret = atomic.fetch_and(1, eastl::memory_order_relaxed); - - ret = atomic.fetch_and(1, eastl::memory_order_acquire); - - ret = atomic.fetch_and(1, eastl::memory_order_release); - - ret = atomic.fetch_and(1, eastl::memory_order_acq_rel); - - ret = atomic.fetch_and(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.and_fetch(1); - - ret = atomic.and_fetch(1, eastl::memory_order_relaxed); - - ret = atomic.and_fetch(1, eastl::memory_order_acquire); - - ret = atomic.and_fetch(1, eastl::memory_order_release); - - ret = atomic.and_fetch(1, eastl::memory_order_acq_rel); - - ret = atomic.and_fetch(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.fetch_or(1); - - ret = atomic.fetch_or(1, eastl::memory_order_relaxed); - - ret = atomic.fetch_or(1, eastl::memory_order_acquire); - - ret = atomic.fetch_or(1, eastl::memory_order_release); - - ret = atomic.fetch_or(1, eastl::memory_order_acq_rel); - - ret = atomic.fetch_or(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.or_fetch(1); - - ret = atomic.or_fetch(1, eastl::memory_order_relaxed); - - ret = atomic.or_fetch(1, eastl::memory_order_acquire); - - ret = atomic.or_fetch(1, eastl::memory_order_release); - - ret = atomic.or_fetch(1, eastl::memory_order_acq_rel); - - ret = atomic.or_fetch(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.fetch_xor(1); - - ret = atomic.fetch_xor(1, eastl::memory_order_relaxed); - - ret = atomic.fetch_xor(1, eastl::memory_order_acquire); - - ret = atomic.fetch_xor(1, eastl::memory_order_release); - - ret = atomic.fetch_xor(1, eastl::memory_order_acq_rel); - - ret = atomic.fetch_xor(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType ret = atomic.xor_fetch(1); - - ret = atomic.xor_fetch(1, eastl::memory_order_relaxed); - - ret = atomic.xor_fetch(1, eastl::memory_order_acquire); - - ret = atomic.xor_fetch(1, eastl::memory_order_release); - - ret = atomic.xor_fetch(1, eastl::memory_order_acq_rel); - - ret = atomic.xor_fetch(1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType observed = 0; - bool ret; - - ret = atomic.compare_exchange_weak(observed, 1); - - ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_release); - - ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_acq_rel); - - ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType observed = 0; - bool ret; - - ret = atomic.compare_exchange_strong(observed, 1); - - ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_release); - - ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_acq_rel); - - ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType observed = 0; - bool ret; - - ret = atomic.compare_exchange_weak(observed, 1, - eastl::memory_order_relaxed, - eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, 1, - eastl::memory_order_acquire, - eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, 1, - eastl::memory_order_acquire, - eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, 1, - eastl::memory_order_release, - eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, 1, - eastl::memory_order_acq_rel, - eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, 1, - eastl::memory_order_acq_rel, - eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, 1, - eastl::memory_order_seq_cst, - eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_weak(observed, 1, - eastl::memory_order_seq_cst, - eastl::memory_order_acquire); - - ret = atomic.compare_exchange_weak(observed, 1, - eastl::memory_order_seq_cst, - eastl::memory_order_seq_cst); - } - - { - AtomicType atomic{}; - - IntegralType observed = 0; - bool ret; - - ret = atomic.compare_exchange_strong(observed, 1, - eastl::memory_order_relaxed, - eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, 1, - eastl::memory_order_acquire, - eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, 1, - eastl::memory_order_acquire, - eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, 1, - eastl::memory_order_release, - eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, 1, - eastl::memory_order_acq_rel, - eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, 1, - eastl::memory_order_acq_rel, - eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, 1, - eastl::memory_order_seq_cst, - eastl::memory_order_relaxed); - - ret = atomic.compare_exchange_strong(observed, 1, - eastl::memory_order_seq_cst, - eastl::memory_order_acquire); - - ret = atomic.compare_exchange_strong(observed, 1, - eastl::memory_order_seq_cst, - eastl::memory_order_seq_cst); - } - -} - -template -void AtomicIntegralBasicTest::TestAtomicStandalone() -{ - { - AtomicType atomic; - - IntegralType expected = 0; - bool ret = atomic_compare_exchange_weak(&atomic, &expected, 1); - - if (ret) - { - VERIFY(ret == true); - - VERIFY(expected == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - } - - { - AtomicType atomic; - - IntegralType expected = 0; - bool ret = atomic_compare_exchange_weak_explicit(&atomic, &expected, 1, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - if (ret) - { - VERIFY(ret == true); - - VERIFY(expected == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - } - - { - AtomicType atomic; - - IntegralType expected = 0; - bool ret = atomic_compare_exchange_strong(&atomic, &expected, 1); - - VERIFY(ret == true); - - VERIFY(expected == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - - { - AtomicType atomic; - - IntegralType expected = 0; - bool ret = atomic_compare_exchange_strong_explicit(&atomic, &expected, 1, eastl::memory_order_relaxed, eastl::memory_order_relaxed); - - VERIFY(ret == true); - - VERIFY(expected == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_fetch_xor(&atomic, 0x1); - - VERIFY(ret == 0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_fetch_xor_explicit(&atomic, 0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_xor_fetch(&atomic, 0x1); - - VERIFY(ret == 0x1); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_xor_fetch_explicit(&atomic, 0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_fetch_or(&atomic, 0x1); - - VERIFY(ret == 0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_fetch_or_explicit(&atomic, 0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_or_fetch(&atomic, 0x1); - - VERIFY(ret == 0x1); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_or_fetch_explicit(&atomic, 0x1, eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic_fetch_and(&atomic, 0x0); - - VERIFY(ret == 0x1); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x0); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic_fetch_and_explicit(&atomic, 0x0, eastl::memory_order_relaxed); - - VERIFY(ret == 0x1); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x0); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic_and_fetch(&atomic, 0x0); - - VERIFY(ret == 0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x0); - } - - { - AtomicType atomic{ 0x1 }; - - IntegralType ret = atomic_and_fetch_explicit(&atomic, 0x0, eastl::memory_order_relaxed); - - VERIFY(ret == 0x0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x0); - } - - { - AtomicType atomic{ 1 }; - - IntegralType ret = atomic_fetch_sub(&atomic, 1); - - VERIFY(ret == 1); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); - } - - { - AtomicType atomic{ 1 }; - - IntegralType ret = atomic_fetch_sub_explicit(&atomic, 1, eastl::memory_order_relaxed); - - VERIFY(ret == 1); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); - } - - { - AtomicType atomic{ 1 }; - - IntegralType ret = atomic_sub_fetch(&atomic, 1); - - VERIFY(ret == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); - } - - { - AtomicType atomic{ 1 }; - - IntegralType ret = atomic_sub_fetch_explicit(&atomic, 1, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_fetch_add(&atomic, 1); - - VERIFY(ret == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_fetch_add_explicit(&atomic, 1, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_add_fetch(&atomic, 1); - - VERIFY(ret == 1); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_add_fetch_explicit(&atomic, 1, eastl::memory_order_relaxed); - - VERIFY(ret == 1); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_exchange(&atomic, 1); - - VERIFY(ret == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_exchange_explicit(&atomic, 1, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_load(&atomic); - - VERIFY(ret == 0); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_load_explicit(&atomic, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_load_cond(&atomic, [](IntegralType val) { return true; }); - - VERIFY(ret == 0); - } - - { - AtomicType atomic; - - IntegralType ret = atomic_load_cond_explicit(&atomic, [](IntegralType val) { return true; }, eastl::memory_order_relaxed); - - VERIFY(ret == 0); - } - - { - AtomicType atomic; - - atomic_store(&atomic, 1); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - - { - AtomicType atomic; - - atomic_store_explicit(&atomic, 1, eastl::memory_order_relaxed); - - VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); - } - - { - AtomicType atomic; - - VERIFY(atomic_is_lock_free(&atomic) == true); - } -} - -struct AtomicNonDefaultConstructible -{ - AtomicNonDefaultConstructible(uint8_t a) - : a(a) - { - } - - friend bool operator==(const AtomicNonDefaultConstructible& a, const AtomicNonDefaultConstructible& b) - { - return a.a == b.a; - } - - uint8_t a; -}; - -#if defined(EASTL_ATOMIC_HAS_8BIT) - -int TestAtomicNonDefaultConstructible() -{ - int nErrorCount = 0; - - { - eastl::atomic atomic{AtomicNonDefaultConstructible{(uint8_t)3}}; - - VERIFY(atomic.load() == AtomicNonDefaultConstructible{(uint8_t)3}); - } - - { - eastl::atomic atomic{AtomicNonDefaultConstructible{(uint8_t)3}}; - - atomic.store(AtomicNonDefaultConstructible{(uint8_t)4}); - - VERIFY(atomic.load() == AtomicNonDefaultConstructible{(uint8_t)4}); - } - - return nErrorCount; -} - -#endif - -struct Atomic128LoadType -{ - friend bool operator==(const Atomic128LoadType& a, const Atomic128LoadType& b) - { - return a.a == b.a && a.b == b.b && a.c == b.c && a.d == b.d; - } - - uint32_t a, b, c, d; -}; - -#if defined(EASTL_ATOMIC_HAS_128BIT) - -int TestAtomic128Loads() -{ - int nErrorCount = 0; - - { - eastl::atomic atomic{Atomic128LoadType{1, 1, 0, 0}}; - - VERIFY((atomic.load() == Atomic128LoadType{1, 1, 0, 0})); - } - - { - eastl::atomic atomic{Atomic128LoadType{0, 0, 1, 1}}; - - VERIFY((atomic.load() == Atomic128LoadType{0, 0, 1, 1})); - } - - { - eastl::atomic atomic{Atomic128LoadType{0, 1, 0, 1}}; - - VERIFY((atomic.load() == Atomic128LoadType{0, 1, 0, 1})); - } - - { - eastl::atomic atomic{Atomic128LoadType{1, 0, 1, 0}}; - - VERIFY((atomic.load() == Atomic128LoadType{1, 0, 1, 0})); - } - - return nErrorCount; -} - -#endif - -int TestAtomicBasic() -{ - int nErrorCount = 0; - - #if defined(EASTL_ATOMIC_HAS_8BIT) - { - AtomicIntegralBasicTest u8AtomicTest; - - nErrorCount += u8AtomicTest.RunTest(); - } - #endif - - #if defined(EASTL_ATOMIC_HAS_16BIT) - { - AtomicIntegralBasicTest u16AtomicTest; - - nErrorCount += u16AtomicTest.RunTest(); - } - #endif - - #if defined(EASTL_ATOMIC_HAS_32BIT) - { - AtomicIntegralBasicTest u32AtomicTest; - - nErrorCount += u32AtomicTest.RunTest(); - } - #endif - - #if defined(EASTL_ATOMIC_HAS_64BIT) - { - AtomicIntegralBasicTest u64AtomicTest; - - nErrorCount += u64AtomicTest.RunTest(); - } - #endif - - #if defined(EASTL_ATOMIC_HAS_128BIT) && (defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) - { - AtomicIntegralBasicTest<__uint128_t> u128AtomicTest; - - nErrorCount += u128AtomicTest.RunTest(); - } - - { - AtomicIntegralBasicTest u128AtomicTest; - - nErrorCount += u128AtomicTest.RunTest(); - } - #endif - - { - AtomicBoolBasicTest boolAtomicTest; - - nErrorCount += boolAtomicTest.RunTest(); - } - - #if defined(EASTL_ATOMIC_HAS_16BIT) - { - AtomicUserTypeBasicTest userTypeAtomicTest; - - nErrorCount += userTypeAtomicTest.RunTest(); - } - #endif - - #if defined(EASTL_ATOMIC_HAS_32BIT) - { - AtomicUserTypeBasicTest userTypeAtomicTest; - - nErrorCount += userTypeAtomicTest.RunTest(); - } - - { - AtomicUserTypeBasicTest userTypeAtomicTest; - - nErrorCount += userTypeAtomicTest.RunTest(); - } - #endif - - #if defined(EASTL_ATOMIC_HAS_128BIT) - { - AtomicUserTypeBasicTest userTypeAtomicTest; - - nErrorCount += userTypeAtomicTest.RunTest(); - } - #endif - - { - AtomicPointerBasicTest ptrAtomicTest; - - nErrorCount += ptrAtomicTest.RunTest(); - } - - { - AtomicVoidPointerBasicTest voidPtrAtomicTest; - - nErrorCount += voidPtrAtomicTest.RunTest(); - } - - { - AtomicFlagBasicTest atomicFlagBasicTest; - - nErrorCount += atomicFlagBasicTest.RunTest(); - } - - { - AtomicStandaloneBasicTest atomicStandaloneBasicTest; - - nErrorCount += atomicStandaloneBasicTest.RunTest(); - } - -#if defined(EASTL_ATOMIC_HAS_128BIT) - - nErrorCount += TestAtomic128Loads(); - -#endif - -#if defined(EASTL_ATOMIC_HAS_8BIT) - - nErrorCount += TestAtomicNonDefaultConstructible(); - -#endif - - return nErrorCount; -} +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#include "EASTLTest.h" + +#include + + +/** + * This is a basic test suite that tests all functionality is implemented + * and that all operations do as expected. + * I.E. fetch_add returns the previous value and add_fetch returns the current value + */ + +static eastl::atomic sAtomicInt{ 4 }; +static eastl::atomic sAtomicPtr{ nullptr }; + +static int TestAtomicConstantInitialization() +{ + int nErrorCount; + + EATEST_VERIFY(sAtomicInt.load() == 4); + EATEST_VERIFY(sAtomicPtr == nullptr); + + return 0; +} + +class AtomicStandaloneBasicTest +{ +public: + + int RunTest() + { + AtomicSignalFence(); + + AtomicThreadFence(); + + AtomicCpuPause(); + + AtomicCompilerBarrier(); + + return nErrorCount; + } + +private: + + void AtomicSignalFence(); + + void AtomicThreadFence(); + + void AtomicCpuPause(); + + void AtomicCompilerBarrier(); + +private: + + int nErrorCount = 0; +}; + +void AtomicStandaloneBasicTest::AtomicSignalFence() +{ + eastl::atomic_signal_fence(eastl::memory_order_relaxed); + + eastl::atomic_signal_fence(eastl::memory_order_acquire); + + eastl::atomic_signal_fence(eastl::memory_order_release); + + eastl::atomic_signal_fence(eastl::memory_order_acq_rel); + + eastl::atomic_signal_fence(eastl::memory_order_seq_cst); +} + +void AtomicStandaloneBasicTest::AtomicThreadFence() +{ + eastl::atomic_thread_fence(eastl::memory_order_relaxed); + + eastl::atomic_thread_fence(eastl::memory_order_acquire); + + eastl::atomic_thread_fence(eastl::memory_order_release); + + eastl::atomic_thread_fence(eastl::memory_order_acq_rel); + + eastl::atomic_thread_fence(eastl::memory_order_seq_cst); +} + +void AtomicStandaloneBasicTest::AtomicCpuPause() +{ + eastl::cpu_pause(); +} + +void AtomicStandaloneBasicTest::AtomicCompilerBarrier() +{ + eastl::compiler_barrier(); + + { + bool ret = false; + eastl::compiler_barrier_data_dependency(ret); + } +} + +class AtomicFlagBasicTest +{ +public: + + using AtomicType = eastl::atomic_flag; + using BoolType = bool; + + int RunTest() + { + TestAtomicFlagCtor(); + + TestAtomicFlagClear(); + + TestAtomicFlagTestAndSet(); + + TestAtomicFlagTest(); + + TestAllMemoryOrders(); + + TestAtomicFlagStandalone(); + + return nErrorCount; + } + +private: + + void TestAtomicFlagCtor(); + + void TestAtomicFlagClear(); + + void TestAtomicFlagTestAndSet(); + + void TestAtomicFlagTest(); + + void TestAllMemoryOrders(); + + void TestAtomicFlagStandalone(); + +private: + + int nErrorCount = 0; +}; + +void AtomicFlagBasicTest::TestAtomicFlagCtor() +{ + { + AtomicType atomic; + + VERIFY(atomic.test(eastl::memory_order_relaxed) == false); + } + + { + AtomicType atomic{ false }; + + VERIFY(atomic.test(eastl::memory_order_relaxed) == false); + } + + { + AtomicType atomic{ true }; + + VERIFY(atomic.test(eastl::memory_order_relaxed) == true); + } +} + +void AtomicFlagBasicTest::TestAtomicFlagClear() +{ + { + AtomicType atomic; + + atomic.clear(eastl::memory_order_relaxed); + + VERIFY(atomic.test(eastl::memory_order_relaxed) == false); + } + + { + AtomicType atomic{ true }; + + atomic.clear(eastl::memory_order_relaxed); + + VERIFY(atomic.test(eastl::memory_order_relaxed) == false); + } +} + +void AtomicFlagBasicTest::TestAtomicFlagTestAndSet() +{ + { + AtomicType atomic; + + BoolType ret = atomic.test_and_set(eastl::memory_order_relaxed); + + VERIFY(ret == false); + + VERIFY(atomic.test(eastl::memory_order_relaxed) == true); + } + + { + AtomicType atomic{ true }; + + BoolType ret = atomic.test_and_set(eastl::memory_order_relaxed); + + VERIFY(ret == true); + + VERIFY(atomic.test(eastl::memory_order_relaxed) == true); + } +} + +void AtomicFlagBasicTest::TestAtomicFlagTest() +{ + { + AtomicType atomic; + + VERIFY(atomic.test(eastl::memory_order_relaxed) == false); + } + + { + AtomicType atomic{ true }; + + VERIFY(atomic.test(eastl::memory_order_relaxed) == true); + } +} + +void AtomicFlagBasicTest::TestAllMemoryOrders() +{ + { + AtomicType atomic; + + atomic.clear(); + + atomic.clear(eastl::memory_order_relaxed); + + atomic.clear(eastl::memory_order_release); + + atomic.clear(eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + atomic.test_and_set(); + + atomic.test_and_set(eastl::memory_order_relaxed); + + atomic.test_and_set(eastl::memory_order_acquire); + + atomic.test_and_set(eastl::memory_order_release); + + atomic.test_and_set(eastl::memory_order_acq_rel); + + atomic.test_and_set(eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + BoolType ret = atomic.test(); + + ret = atomic.test(eastl::memory_order_relaxed); + + ret = atomic.test(eastl::memory_order_acquire); + + ret = atomic.test(eastl::memory_order_seq_cst); + } +} + +void AtomicFlagBasicTest::TestAtomicFlagStandalone() +{ + { + AtomicType atomic; + + BoolType ret = atomic_flag_test_and_set(&atomic); + + ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_relaxed); + + ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_acquire); + + ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_release); + + ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_acq_rel); + + ret = atomic_flag_test_and_set_explicit(&atomic, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + atomic_flag_clear(&atomic); + + atomic_flag_clear_explicit(&atomic, eastl::memory_order_relaxed); + + atomic_flag_clear_explicit(&atomic, eastl::memory_order_release); + + atomic_flag_clear_explicit(&atomic, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + BoolType ret = atomic_flag_test(&atomic); + + ret = atomic_flag_test_explicit(&atomic, eastl::memory_order_relaxed); + + ret = atomic_flag_test_explicit(&atomic, eastl::memory_order_acquire); + + ret = atomic_flag_test_explicit(&atomic, eastl::memory_order_seq_cst); + } +} + +class AtomicVoidPointerBasicTest +{ +public: + + using AtomicType = eastl::atomic; + using PtrType = void*; + + int RunTest() + { + TestAtomicCtor(); + + TestAssignmentOperators(); + + TestIsLockFree(); + + TestStore(); + + TestLoad(); + + TestExchange(); + + TestCompareExchangeWeak(); + + TestCompareExchangeStrong(); + + TestAllMemoryOrders(); + + return nErrorCount; + } + +private: + + void TestAtomicCtor(); + + void TestAssignmentOperators(); + + void TestIsLockFree(); + + void TestStore(); + + void TestLoad(); + + void TestExchange(); + + void TestCompareExchangeWeak(); + + void TestCompareExchangeStrong(); + + void TestAllMemoryOrders(); + +private: + + int nErrorCount = 0; +}; + +void AtomicVoidPointerBasicTest::TestAtomicCtor() +{ + { + AtomicType atomic; + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } + + { + AtomicType atomic{ (PtrType)0x04 }; + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x04); + } +} + +void AtomicVoidPointerBasicTest::TestAssignmentOperators() +{ + { + AtomicType atomic; + + PtrType ret = atomic = (PtrType)0x04; + + VERIFY(ret == (PtrType)0x04); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x04); + } + + { + AtomicType atomic; + + PtrType ret = atomic = (PtrType)0x0; + + VERIFY(ret == (PtrType)0x0); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } +} + +void AtomicVoidPointerBasicTest::TestIsLockFree() +{ + { + AtomicType atomic; + + VERIFY(atomic.is_lock_free() == true); + + VERIFY(atomic.is_always_lock_free == true); + } +} + +void AtomicVoidPointerBasicTest::TestStore() +{ + { + PtrType val = (PtrType)0x0; + AtomicType atomic; + + atomic.store(val, eastl::memory_order_relaxed); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == val); + } + + { + PtrType val = (PtrType)0x4; + AtomicType atomic; + + atomic.store(val, eastl::memory_order_relaxed); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == val); + } +} + +void AtomicVoidPointerBasicTest::TestLoad() +{ + { + AtomicType atomic{ (PtrType)0x4 }; + + PtrType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic == (PtrType)0x4); + } +} + +void AtomicVoidPointerBasicTest::TestExchange() +{ + { + AtomicType atomic; + + PtrType ret = atomic.exchange((PtrType)0x4, eastl::memory_order_release); + + VERIFY(ret == (PtrType)0x0); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } +} + +void AtomicVoidPointerBasicTest::TestCompareExchangeWeak() +{ + { + AtomicType atomic; + + PtrType observed = (PtrType)0x0; + bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + if (ret) + { + VERIFY(ret == true); + VERIFY(observed == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + } + + { + AtomicType atomic; + + PtrType observed = (PtrType)0x4; + bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + VERIFY(ret == false); + VERIFY(observed == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } +} + +void AtomicVoidPointerBasicTest::TestCompareExchangeStrong() +{ + { + AtomicType atomic; + + PtrType observed = (PtrType)0x0; + bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + VERIFY(ret == true); + VERIFY(observed == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + + { + AtomicType atomic; + + PtrType observed = (PtrType)0x4; + bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + VERIFY(ret == false); + VERIFY(observed == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } +} + +void AtomicVoidPointerBasicTest::TestAllMemoryOrders() +{ + { + AtomicType atomic; + PtrType val = (PtrType)0x4; + + atomic.store(val); + + atomic.store(val, eastl::memory_order_relaxed); + + atomic.store(val, eastl::memory_order_release); + + atomic.store(val, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + PtrType ret = atomic.load(); + + ret = atomic.load(eastl::memory_order_relaxed); + + ret = atomic.load(eastl::memory_order_acquire); + + ret = atomic.load(eastl::memory_order_seq_cst); + + ret = atomic.load(eastl::memory_order_read_depends); + } + + { + AtomicType atomic; + + PtrType ret = atomic.exchange((PtrType)0x4); + + ret = atomic.exchange((PtrType)0x4, eastl::memory_order_relaxed); + + ret = atomic.exchange((PtrType)0x4, eastl::memory_order_acquire); + + ret = atomic.exchange((PtrType)0x4, eastl::memory_order_release); + + ret = atomic.exchange((PtrType)0x4, eastl::memory_order_acq_rel); + + ret = atomic.exchange((PtrType)0x4, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + PtrType observed = (PtrType)0x0; + + bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_release); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + PtrType observed = (PtrType)0x0; + + bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_release); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + PtrType observed = (PtrType)0x0; + bool ret; + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_release, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + PtrType observed = (PtrType)0x0; + bool ret; + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_release, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); + } +} + +class AtomicPointerBasicTest +{ +public: + + using AtomicType = eastl::atomic; + using PtrType = uint32_t*; + + int RunTest() + { + TestAtomicCtor(); + + TestAssignmentOperators(); + + TestIsLockFree(); + + TestStore(); + + TestLoad(); + + TestExchange(); + + TestCompareExchangeWeak(); + + TestCompareExchangeStrong(); + + TestAllMemoryOrders(); + + TestFetchAdd(); + TestAddFetch(); + + TestFetchSub(); + TestSubFetch(); + + TestAtomicPointerStandalone(); + + return nErrorCount; + } + +private: + + void TestAtomicCtor(); + + void TestAssignmentOperators(); + + void TestIsLockFree(); + + void TestStore(); + + void TestLoad(); + + void TestExchange(); + + void TestCompareExchangeWeak(); + + void TestCompareExchangeStrong(); + + void TestAllMemoryOrders(); + + void TestFetchAdd(); + void TestAddFetch(); + + void TestFetchSub(); + void TestSubFetch(); + + void TestAtomicPointerStandalone(); + +private: + + int nErrorCount = 0; +}; + +void AtomicPointerBasicTest::TestAtomicCtor() +{ + { + AtomicType atomic{}; + + PtrType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == nullptr); + } + + { + AtomicType atomic{ (PtrType)0x4 }; + + PtrType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x4); + } +} + +void AtomicPointerBasicTest::TestAssignmentOperators() +{ + { + PtrType val = (PtrType)0x4; + AtomicType atomic{val}; + + PtrType expected = (PtrType)0x8; + + PtrType ret = atomic = expected; + + VERIFY(ret == expected); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } + + { + PtrType val = (PtrType)0x0; + AtomicType atomic{val}; + + PtrType ret = atomic = val; + + VERIFY(ret == val); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == val); + } + + { + PtrType val = (PtrType)0x4; + AtomicType atomic{val}; + + PtrType expected = (PtrType)0x8; + PtrType ret = ++atomic; + + VERIFY(ret == expected); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } + + { + PtrType val = (PtrType)0x4; + + AtomicType atomic{val}; + + PtrType expected = (PtrType)0x8; + PtrType ret = atomic++; + + VERIFY(ret == val); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } + + { + PtrType val = (PtrType)0x4; + AtomicType atomic{val}; + + PtrType expected = (PtrType)0x10; + PtrType ret = atomic += 3; + + VERIFY(ret == expected); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } + + { + PtrType val = (PtrType)0x4; + AtomicType atomic{val}; + + PtrType expected = (PtrType)0x4; + PtrType ret = atomic += 0; + + VERIFY(ret == expected); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } + + { + PtrType val = (PtrType)0x4; + AtomicType atomic{val}; + + PtrType expected = (PtrType)0x0; + PtrType ret = atomic -= 1; + + VERIFY(ret == expected); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } + + { + PtrType val = (PtrType)0x4; + AtomicType atomic{val}; + + PtrType expected = (PtrType)0x4; + PtrType ret = atomic -= 0; + + VERIFY(ret == expected); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } +} + +void AtomicPointerBasicTest::TestIsLockFree() +{ + { + AtomicType atomic; + + VERIFY(atomic.is_lock_free() == true); + + VERIFY(atomic.is_always_lock_free == true); + } +} + +void AtomicPointerBasicTest::TestStore() +{ + { + PtrType val = (PtrType)0x0; + AtomicType atomic; + + atomic.store(val, eastl::memory_order_relaxed); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == val); + } + + { + PtrType val = (PtrType)0x4; + AtomicType atomic; + + atomic.store(val, eastl::memory_order_relaxed); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == val); + } +} + +void AtomicPointerBasicTest::TestLoad() +{ + { + AtomicType atomic{ (PtrType)0x4 }; + + PtrType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic == (PtrType)0x4); + } +} + +void AtomicPointerBasicTest::TestCompareExchangeWeak() +{ + { + AtomicType atomic; + + PtrType observed = (PtrType)0x0; + bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + if (ret) + { + VERIFY(ret == true); + VERIFY(observed == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + } + + { + AtomicType atomic; + + PtrType observed = (PtrType)0x4; + bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + VERIFY(ret == false); + VERIFY(observed == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } +} + +void AtomicPointerBasicTest::TestCompareExchangeStrong() +{ + { + AtomicType atomic; + + PtrType observed = (PtrType)0x0; + bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + VERIFY(ret == true); + VERIFY(observed == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + + { + AtomicType atomic; + + PtrType observed = (PtrType)0x4; + bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + VERIFY(ret == false); + VERIFY(observed == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } +} + +void AtomicPointerBasicTest::TestExchange() +{ + { + AtomicType atomic; + + PtrType ret = atomic.exchange((PtrType)0x4, eastl::memory_order_release); + + VERIFY(ret == (PtrType)0x0); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } +} + +void AtomicPointerBasicTest::TestAllMemoryOrders() +{ + { + AtomicType atomic; + PtrType val = (PtrType)0x4; + + atomic.store(val); + + atomic.store(val, eastl::memory_order_relaxed); + + atomic.store(val, eastl::memory_order_release); + + atomic.store(val, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + PtrType ret = atomic.load(); + + ret = atomic.load(eastl::memory_order_relaxed); + + ret = atomic.load(eastl::memory_order_acquire); + + ret = atomic.load(eastl::memory_order_seq_cst); + + ret = atomic.load(eastl::memory_order_read_depends); + } + + { + AtomicType atomic; + + PtrType ret = atomic.fetch_add(0); + + ret = atomic.fetch_add(0, eastl::memory_order_relaxed); + + ret = atomic.fetch_add(0, eastl::memory_order_acquire); + + ret = atomic.fetch_add(0, eastl::memory_order_release); + + ret = atomic.fetch_add(0, eastl::memory_order_acq_rel); + + ret = atomic.fetch_add(0, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + PtrType ret = atomic.fetch_sub(0); + + ret = atomic.fetch_sub(0, eastl::memory_order_relaxed); + + ret = atomic.fetch_sub(0, eastl::memory_order_acquire); + + ret = atomic.fetch_sub(0, eastl::memory_order_release); + + ret = atomic.fetch_sub(0, eastl::memory_order_acq_rel); + + ret = atomic.fetch_sub(0, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + PtrType ret = atomic.add_fetch(0); + + ret = atomic.add_fetch(0, eastl::memory_order_relaxed); + + ret = atomic.add_fetch(0, eastl::memory_order_acquire); + + ret = atomic.add_fetch(0, eastl::memory_order_release); + + ret = atomic.add_fetch(0, eastl::memory_order_acq_rel); + + ret = atomic.add_fetch(0, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + PtrType ret = atomic.sub_fetch(0); + + ret = atomic.sub_fetch(0, eastl::memory_order_relaxed); + + ret = atomic.sub_fetch(0, eastl::memory_order_acquire); + + ret = atomic.sub_fetch(0, eastl::memory_order_release); + + ret = atomic.sub_fetch(0, eastl::memory_order_acq_rel); + + ret = atomic.sub_fetch(0, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + PtrType ret = atomic.exchange((PtrType)0x4); + + ret = atomic.exchange((PtrType)0x4, eastl::memory_order_relaxed); + + ret = atomic.exchange((PtrType)0x4, eastl::memory_order_acquire); + + ret = atomic.exchange((PtrType)0x4, eastl::memory_order_release); + + ret = atomic.exchange((PtrType)0x4, eastl::memory_order_acq_rel); + + ret = atomic.exchange((PtrType)0x4, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + PtrType observed = (PtrType)0x0; + + bool ret = atomic.compare_exchange_weak(observed, (PtrType)0x4); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_release); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + PtrType observed = (PtrType)0x0; + + bool ret = atomic.compare_exchange_strong(observed, (PtrType)0x4); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_release); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + PtrType observed = (PtrType)0x0; + bool ret; + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_release, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + PtrType observed = (PtrType)0x0; + bool ret; + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acquire, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_release, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_acq_rel, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, (PtrType)0x4, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); + } +} + +void AtomicPointerBasicTest::TestFetchAdd() +{ + { + PtrType val = (PtrType)0x4; + AtomicType atomic{ val }; + + PtrType ret = atomic.fetch_add(1, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x8); + } + + { + PtrType val = (PtrType)0x4; + AtomicType atomic{ val }; + + PtrType ret = atomic.fetch_add(0, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } +} + +void AtomicPointerBasicTest::TestAddFetch() +{ + { + PtrType val = (PtrType)0x4; + AtomicType atomic{ val }; + + PtrType ret = atomic.add_fetch(1, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x8); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x8); + } + + { + PtrType val = (PtrType)0x4; + AtomicType atomic{ val }; + + PtrType ret = atomic.add_fetch(0, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } +} + +void AtomicPointerBasicTest::TestFetchSub() +{ + { + PtrType val = (PtrType)0x4; + AtomicType atomic{ val }; + + PtrType ret = atomic.fetch_sub(1, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } + + { + PtrType val = (PtrType)0x4; + AtomicType atomic{ val }; + + PtrType ret = atomic.fetch_sub(0, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } +} + +void AtomicPointerBasicTest::TestSubFetch() +{ + { + PtrType val = (PtrType)0x4; + AtomicType atomic{ val }; + + PtrType ret = atomic.sub_fetch(1, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x0); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } + + { + PtrType val = (PtrType)0x4; + AtomicType atomic{ val }; + + PtrType ret = atomic.sub_fetch(0, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } +} + +void AtomicPointerBasicTest::TestAtomicPointerStandalone() +{ + { + AtomicType atomic; + + VERIFY(atomic_is_lock_free(&atomic) == true); + } + + { + AtomicType atomic; + PtrType val = (PtrType)0x4; + + atomic_store(&atomic, val); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == val); + } + + { + AtomicType atomic; + PtrType val = (PtrType)0x4; + + atomic_store_explicit(&atomic, val, eastl::memory_order_relaxed); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == val); + } + + { + AtomicType atomic; + + PtrType ret = atomic_load(&atomic); + + VERIFY(ret == (PtrType)0x0); + } + + { + AtomicType atomic; + + PtrType ret = atomic_load_explicit(&atomic, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x0); + } + + { + AtomicType atomic; + + PtrType ret = atomic_load_cond(&atomic, [](PtrType val) { return true; }); + + VERIFY(ret == (PtrType)0x0); + } + + { + AtomicType atomic; + + PtrType ret = atomic_load_cond_explicit(&atomic, [](PtrType val) { return true; }, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x0); + } + + { + AtomicType atomic; + + PtrType ret = atomic_exchange(&atomic, (PtrType)0x4); + + VERIFY(ret == (PtrType)0x0); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + + { + AtomicType atomic; + + PtrType ret = atomic_exchange_explicit(&atomic, (PtrType)0x4, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x0); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + + { + AtomicType atomic; + + PtrType ret = atomic_add_fetch(&atomic, 1); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + + { + AtomicType atomic; + + PtrType ret = atomic_add_fetch_explicit(&atomic, 1, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + + { + AtomicType atomic; + + PtrType ret = atomic_fetch_add(&atomic, 1); + + VERIFY(ret == (PtrType)0x0); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + + { + AtomicType atomic; + + PtrType ret = atomic_fetch_add_explicit(&atomic, 1, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x0); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + + { + AtomicType atomic{ (PtrType)0x4 }; + + PtrType ret = atomic_fetch_sub(&atomic, 1); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } + + { + AtomicType atomic{ (PtrType)0x4 }; + + PtrType ret = atomic_fetch_sub_explicit(&atomic, 1, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x4); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } + + { + AtomicType atomic{ (PtrType)0x4 }; + + PtrType ret = atomic_sub_fetch(&atomic, 1); + + VERIFY(ret == (PtrType)0x0); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } + + { + AtomicType atomic{ (PtrType)0x4 }; + + PtrType ret = atomic_sub_fetch_explicit(&atomic, 1, eastl::memory_order_relaxed); + + VERIFY(ret == (PtrType)0x0); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x0); + } + + { + AtomicType atomic; + + PtrType expected = (PtrType)0x0; + bool ret = atomic_compare_exchange_strong(&atomic, &expected, (PtrType)0x4); + + VERIFY(ret == true); + + VERIFY(expected == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + + { + AtomicType atomic; + + PtrType expected = (PtrType)0x0; + bool ret = atomic_compare_exchange_strong_explicit(&atomic, &expected, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + VERIFY(ret == true); + + VERIFY(expected == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + + { + AtomicType atomic; + + PtrType expected = (PtrType)0x0; + bool ret = atomic_compare_exchange_weak(&atomic, &expected, (PtrType)0x4); + + if (ret) + { + VERIFY(ret == true); + + VERIFY(expected == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + } + + { + AtomicType atomic; + + PtrType expected = (PtrType)0x0; + bool ret = atomic_compare_exchange_weak_explicit(&atomic, &expected, (PtrType)0x4, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + if (ret) + { + VERIFY(ret == true); + + VERIFY(expected == (PtrType)0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == (PtrType)0x4); + } + } +} + +struct AtomicNonTriviallyConstructible +{ + AtomicNonTriviallyConstructible() + : a(0) + , b(0) + { + } + + AtomicNonTriviallyConstructible(uint16_t a, uint16_t b) + : a(a) + , b(b) + { + } + + friend bool operator==(const AtomicNonTriviallyConstructible& a, const AtomicNonTriviallyConstructible& b) + { + return a.a == b.a && a.b == b.b; + } + + uint16_t a; + uint16_t b; +}; + +struct AtomicNonTriviallyConstructibleNoExcept +{ + AtomicNonTriviallyConstructibleNoExcept() noexcept + : a(0) + , b(0) + { + } + + AtomicNonTriviallyConstructibleNoExcept(uint16_t a, uint16_t b) noexcept + : a(a) + , b(b) + { + } + + friend bool operator==(const AtomicNonTriviallyConstructibleNoExcept& a, const AtomicNonTriviallyConstructibleNoExcept& b) + { + return a.a == b.a && a.b == b.b; + } + + uint16_t a; + uint16_t b; +}; + +struct AtomicUserType16 +{ + uint8_t a; + uint8_t b; + + friend bool operator==(const AtomicUserType16& a, const AtomicUserType16& b) + { + return (a.a == b.a) && (a.b == b.b); + } +}; + +struct AtomicUserType128 +{ + uint32_t a; + uint32_t b; + uint32_t c; + uint32_t d; + + AtomicUserType128() = default; + + AtomicUserType128(const AtomicUserType128&) = default; + + AtomicUserType128(uint32_t a, uint32_t b) + : a(a) + , b(b) + , c(0) + , d(0) + { + } + + AtomicUserType128& operator=(const AtomicUserType128&) = default; + + friend bool operator==(const AtomicUserType128& a, const AtomicUserType128& b) + { + return (a.a == b.a) && (a.b == b.b) && (a.c == b.c) && (a.d == b.d); + } +}; + +template +class AtomicUserTypeBasicTest +{ +public: + + using AtomicType = eastl::atomic; + using UserType = T; + + int RunTest() + { + TestAtomicCtor(); + + TestAssignmentOperators(); + + TestIsLockFree(); + + TestStore(); + + TestLoad(); + + TestExchange(); + + TestCompareExchangeWeak(); + + TestCompareExchangeStrong(); + + TestAllMemoryOrders(); + + return nErrorCount; + } + +private: + + void TestAtomicCtor(); + + void TestAssignmentOperators(); + + void TestIsLockFree(); + + void TestStore(); + + void TestLoad(); + + void TestExchange(); + + void TestCompareExchangeWeak(); + + void TestCompareExchangeStrong(); + + void TestAllMemoryOrders(); + +private: + + int nErrorCount = 0; +}; + +template +void AtomicUserTypeBasicTest::TestAtomicCtor() +{ + { + AtomicType atomic; + UserType expected{0, 0}; + + UserType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == expected); + } + + { + AtomicType atomic{ {5, 8} }; + UserType expected{5, 8}; + + UserType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == expected); + } +} + +template +void AtomicUserTypeBasicTest::TestAssignmentOperators() +{ + { + AtomicType atomic; + UserType expected{5, 6}; + + atomic = {5, 6}; + + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } + + { + AtomicType atomic; + UserType expected{0, 0}; + + atomic = {0, 0}; + + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } +} + +template +void AtomicUserTypeBasicTest::TestIsLockFree() +{ + { + AtomicType atomic; + + VERIFY(atomic.is_lock_free() == true); + + VERIFY(AtomicType::is_always_lock_free == true); + } +} + +template +void AtomicUserTypeBasicTest::TestStore() +{ + { + AtomicType atomic; + UserType expected{5, 6}; + + atomic.store(expected, eastl::memory_order_relaxed); + + UserType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == expected); + } + + { + AtomicType atomic; + UserType expected{5, 6}; + + atomic.store({5, 6}, eastl::memory_order_relaxed); + + UserType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == expected); + } +} + +template +void AtomicUserTypeBasicTest::TestLoad() +{ + { + AtomicType atomic; + UserType expected{0, 0}; + + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + + VERIFY(atomic == expected); + } + + { + AtomicType atomic{ {5, 6} }; + UserType expected{5, 6}; + + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + + VERIFY(atomic == expected); + } +} + +template +void AtomicUserTypeBasicTest::TestExchange() +{ + { + AtomicType atomic; + UserType expected{0, 0}; + + UserType ret = atomic.exchange({0, 0}, eastl::memory_order_relaxed); + + VERIFY(ret == expected); + } + + { + AtomicType atomic; + UserType expected{0, 0}; + UserType expected2{0, 1}; + + UserType ret = atomic.exchange({0, 1}, eastl::memory_order_relaxed); + + VERIFY(ret == expected); + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected2); + } +} + +template +void AtomicUserTypeBasicTest::TestCompareExchangeWeak() +{ + { + AtomicType atomic; + + UserType observed{0, 0}; + bool ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_relaxed); + + UserType expected{0, 0}; + if (ret) + { + VERIFY(ret == true); + VERIFY(observed == expected); + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } + } + + { + AtomicType atomic; + + UserType observed{0, 0}; + bool ret = atomic.compare_exchange_weak(observed, {0, 1}, eastl::memory_order_relaxed); + + UserType expected{0, 1}; + UserType expected2{0, 0}; + if (ret) + { + VERIFY(ret == true); + VERIFY(observed == expected2); + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } + } + + { + AtomicType atomic; + + UserType observed{0, 1}; + bool ret = atomic.compare_exchange_weak(observed, {0, 1}, eastl::memory_order_relaxed); + + UserType expected{0, 0}; + + VERIFY(ret == false); + VERIFY(observed == expected); + } +} + +template +void AtomicUserTypeBasicTest::TestCompareExchangeStrong() +{ + { + AtomicType atomic; + + UserType observed{0, 0}; + bool ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_relaxed); + + UserType expected{0, 0}; + + VERIFY(ret == true); + VERIFY(observed == expected); + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } + + { + AtomicType atomic; + + UserType observed{0, 0}; + bool ret = atomic.compare_exchange_strong(observed, {0, 1}, eastl::memory_order_relaxed); + + UserType expected{0, 1}; + UserType expected2{0, 0}; + + VERIFY(ret == true); + VERIFY(observed == expected2); + VERIFY(atomic.load(eastl::memory_order_relaxed) == expected); + } + + { + AtomicType atomic; + + UserType observed{0, 1}; + bool ret = atomic.compare_exchange_strong(observed, {0, 1}, eastl::memory_order_relaxed); + + UserType expected{0, 0}; + + VERIFY(ret == false); + VERIFY(observed == expected); + } +} + +template +void AtomicUserTypeBasicTest::TestAllMemoryOrders() +{ + { + AtomicType atomic; + UserType val{0, 1}; + + atomic.store(val); + + atomic.store(val, eastl::memory_order_relaxed); + + atomic.store(val, eastl::memory_order_release); + + atomic.store(val, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + UserType ret = atomic.load(); + + ret = atomic.load(eastl::memory_order_relaxed); + + ret = atomic.load(eastl::memory_order_acquire); + + ret = atomic.load(eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + UserType ret = atomic.exchange({0, 1}); + + ret = atomic.exchange({0, 0}, eastl::memory_order_relaxed); + + ret = atomic.exchange({0, 0}, eastl::memory_order_acquire); + + ret = atomic.exchange({0, 0}, eastl::memory_order_release); + + ret = atomic.exchange({0, 0}, eastl::memory_order_acq_rel); + + ret = atomic.exchange({0, 0}, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + UserType observed{0, 0}; + + bool ret = atomic.compare_exchange_weak(observed, {0, 0}); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_release); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acq_rel); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + UserType observed{0, 0}; + + bool ret = atomic.compare_exchange_strong(observed, {0, 0}); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_release); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acq_rel); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + UserType observed{0, 0}; + bool ret; + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acquire, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acquire, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_release, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_acq_rel, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + UserType observed{0, 0}; + bool ret; + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acquire, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acquire, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_release, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_acq_rel, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, {0, 0}, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); + } +} + + +class AtomicBoolBasicTest +{ +public: + + using AtomicType = eastl::atomic; + using BoolType = bool; + + int RunTest() + { + TestAtomicCtor(); + + TestAssignmentOperators(); + + TestIsLockFree(); + + TestStore(); + + TestLoad(); + + TestExchange(); + + TestCompareExchangeWeak(); + + TestCompareExchangeStrong(); + + TestAllMemoryOrders(); + + return nErrorCount; + } + +private: + + void TestAtomicCtor(); + + void TestAssignmentOperators(); + + void TestIsLockFree(); + + void TestStore(); + + void TestLoad(); + + void TestExchange(); + + void TestCompareExchangeWeak(); + + void TestCompareExchangeStrong(); + + void TestAllMemoryOrders(); + +private: + + int nErrorCount = 0; +}; + +void AtomicBoolBasicTest::TestAtomicCtor() +{ + { + AtomicType atomic{ false }; + + BoolType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == false); + } + + { + AtomicType atomic{ true }; + + BoolType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == true); + } + + { + AtomicType atomic; + + BoolType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == false); + } + + { + AtomicType atomic{}; + + BoolType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == false); + } +} + +void AtomicBoolBasicTest::TestAssignmentOperators() +{ + { + AtomicType atomic; + + BoolType ret = atomic = true; + + VERIFY(ret == true); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == true); + } +} + +void AtomicBoolBasicTest::TestIsLockFree() +{ + { + AtomicType atomic; + + bool ret = atomic.is_lock_free(); + + VERIFY(ret == true); + + VERIFY(AtomicType::is_always_lock_free == true); + } +} + +void AtomicBoolBasicTest::TestStore() +{ + { + AtomicType atomic; + + atomic.store(true, eastl::memory_order_relaxed); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == true); + } +} + +void AtomicBoolBasicTest::TestLoad() +{ + { + AtomicType atomic; + + VERIFY(atomic.load(eastl::memory_order_relaxed) == false); + + VERIFY(atomic == false); + } + + { + AtomicType atomic{ true }; + + VERIFY(atomic.load(eastl::memory_order_relaxed) == true); + + VERIFY(atomic == true); + } +} + +void AtomicBoolBasicTest::TestExchange() +{ + { + AtomicType atomic; + + BoolType ret = atomic.exchange(false, eastl::memory_order_relaxed); + + VERIFY(ret == false); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == false); + } + + { + AtomicType atomic; + + BoolType ret = atomic.exchange(true, eastl::memory_order_relaxed); + + VERIFY(ret == false); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == true); + } +} + +void AtomicBoolBasicTest::TestCompareExchangeWeak() +{ + { + AtomicType atomic{ false }; + + BoolType observed = false; + bool ret = atomic.compare_exchange_weak(observed, false, eastl::memory_order_relaxed); + + if (ret) + { + VERIFY(ret == true); + VERIFY(observed == false); + VERIFY(atomic.load(eastl::memory_order_relaxed) == false); + } + } + + { + AtomicType atomic{ false }; + + BoolType observed = false; + bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); + + if (ret) + { + VERIFY(ret == true); + VERIFY(observed == false); + VERIFY(atomic.load(eastl::memory_order_relaxed) == true); + } + } + + { + AtomicType atomic{ false }; + + BoolType observed = true; + bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); + + VERIFY(ret == false); + VERIFY(observed == false); + } +} + +void AtomicBoolBasicTest::TestCompareExchangeStrong() +{ + { + AtomicType atomic{ false }; + + BoolType observed = false; + bool ret = atomic.compare_exchange_weak(observed, false, eastl::memory_order_relaxed); + + VERIFY(ret == true); + VERIFY(observed == false); + VERIFY(atomic.load(eastl::memory_order_relaxed) == false); + } + + { + AtomicType atomic{ false }; + + BoolType observed = false; + bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); + + VERIFY(ret == true); + VERIFY(observed == false); + VERIFY(atomic.load(eastl::memory_order_relaxed) == true); + } + + { + AtomicType atomic{ false }; + + BoolType observed = true; + bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); + + VERIFY(ret == false); + VERIFY(observed == false); + } +} + +void AtomicBoolBasicTest::TestAllMemoryOrders() +{ + { + AtomicType atomic; + + atomic.store(true); + + atomic.store(true, eastl::memory_order_relaxed); + + atomic.store(true, eastl::memory_order_release); + + atomic.store(true, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + BoolType ret = atomic.load(); + + ret = atomic.load(eastl::memory_order_relaxed); + + ret = atomic.load(eastl::memory_order_acquire); + + ret = atomic.load(eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + BoolType ret = atomic.exchange(true); + + ret = atomic.exchange(true, eastl::memory_order_relaxed); + + ret = atomic.exchange(true, eastl::memory_order_acquire); + + ret = atomic.exchange(true, eastl::memory_order_release); + + ret = atomic.exchange(true, eastl::memory_order_acq_rel); + + ret = atomic.exchange(true, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + BoolType observed = false; + bool ret = atomic.compare_exchange_weak(observed, true); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_release); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acq_rel); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + BoolType observed = false; + bool ret = atomic.compare_exchange_strong(observed, true); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_release); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acq_rel); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + BoolType observed = false; + bool ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acquire, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acquire, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_release, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_acq_rel, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic; + + BoolType observed = false; + bool ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acquire, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acquire, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_release, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acq_rel, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_acq_rel, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, true, eastl::memory_order_seq_cst, eastl::memory_order_seq_cst); + } +} + + +template +class AtomicIntegralBasicTest +{ +public: + + using AtomicType = eastl::atomic; + using IntegralType = T; + + int RunTest() + { + TestAtomicCtor(); + + TestAtomicFetchAdd(); + TestAtomicAddFetch(); + + TestAtomicFetchSub(); + TestAtomicSubFetch(); + + TestAtomicFetchAnd(); + TestAtomicAndFetch(); + + TestAtomicFetchOr(); + TestAtomicOrFetch(); + + TestAtomicFetchXor(); + TestAtomicXorFetch(); + + TestAssignmentOperators(); + + TestIsLockFree(); + + TestStore(); + + TestLoad(); + + TestExchange(); + + TestCompareExchangeWeak(); + + TestCompareExchangeStrong(); + + TestAllMemoryOrders(); + + TestAtomicStandalone(); + + return nErrorCount; + } + +private: + + void TestAtomicCtor(); + + void TestAtomicFetchAdd(); + void TestAtomicAddFetch(); + + void TestAtomicFetchSub(); + void TestAtomicSubFetch(); + + void TestAtomicFetchAnd(); + void TestAtomicAndFetch(); + + void TestAtomicFetchOr(); + void TestAtomicOrFetch(); + + void TestAtomicFetchXor(); + void TestAtomicXorFetch(); + + void TestAssignmentOperators(); + + void TestIsLockFree(); + + void TestStore(); + + void TestLoad(); + + void TestExchange(); + + void TestCompareExchangeWeak(); + + void TestCompareExchangeStrong(); + + void TestAllMemoryOrders(); + + void TestAtomicStandalone(); + +private: + + int nErrorCount = 0; +}; + +template +void AtomicIntegralBasicTest::TestAtomicCtor() +{ + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 1 }; + + IntegralType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 1); + } + + { + AtomicType atomic{ 20 }; + + IntegralType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 20); + } + + { + AtomicType atomic; + + IntegralType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } +} + +template +void AtomicIntegralBasicTest::TestAtomicFetchAdd() +{ + { + AtomicType atomic; + + IntegralType ret = atomic.fetch_add(1, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic.fetch_add(0, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 5 }; + + IntegralType ret = atomic.fetch_add(0, eastl::memory_order_relaxed); + + VERIFY(ret == 5); + + ret = atomic.fetch_add(4, eastl::memory_order_relaxed); + + VERIFY(ret == 5); + + ret = atomic.fetch_add(1, eastl::memory_order_relaxed); + + VERIFY(ret == 9); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 10); + } +} + +template +void AtomicIntegralBasicTest::TestAtomicAddFetch() +{ + { + AtomicType atomic; + + IntegralType ret = atomic.add_fetch(1, eastl::memory_order_relaxed); + + VERIFY(ret == 1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic.add_fetch(0, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 5 }; + + IntegralType ret = atomic.add_fetch(0, eastl::memory_order_relaxed); + + VERIFY(ret == 5); + + ret = atomic.add_fetch(4, eastl::memory_order_relaxed); + + VERIFY(ret == 9); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 9); + } +} + +template +void AtomicIntegralBasicTest::TestAtomicFetchSub() +{ + { + AtomicType atomic{ 1 }; + + IntegralType ret = atomic.fetch_sub(1, eastl::memory_order_relaxed); + + VERIFY(ret == 1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 1 }; + + IntegralType ret = atomic.fetch_sub(0, eastl::memory_order_relaxed); + + VERIFY(ret == 1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 1); + } + + { + AtomicType atomic{ 5 }; + + IntegralType ret = atomic.fetch_sub(2, eastl::memory_order_relaxed); + + VERIFY(ret == 5); + + ret = atomic.fetch_sub(1, eastl::memory_order_relaxed); + + VERIFY(ret == 3); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 2); + } +} + +template +void AtomicIntegralBasicTest::TestAtomicSubFetch() +{ + { + AtomicType atomic{ 1 }; + + IntegralType ret = atomic.sub_fetch(1, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 1 }; + + IntegralType ret = atomic.sub_fetch(0, eastl::memory_order_relaxed); + + VERIFY(ret == 1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 1); + } + + { + AtomicType atomic{ 5 }; + + IntegralType ret = atomic.sub_fetch(2, eastl::memory_order_relaxed); + + VERIFY(ret == 3); + + ret = atomic.sub_fetch(1, eastl::memory_order_relaxed); + + VERIFY(ret == 2); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 2); + } +} + +template +void AtomicIntegralBasicTest::TestAtomicFetchAnd() +{ + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic.fetch_and(0x0, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic.fetch_and(0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 0xF }; + + IntegralType ret = atomic.fetch_and(0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0xF); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0X1); + } + + { + AtomicType atomic{ 0xF }; + + IntegralType ret = atomic.fetch_and(0xF0, eastl::memory_order_relaxed); + + VERIFY(ret == 0xF); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + } +} + +template +void AtomicIntegralBasicTest::TestAtomicAndFetch() +{ + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic.and_fetch(0x0, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic.and_fetch(0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 0xF }; + + IntegralType ret = atomic.and_fetch(0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + } + + { + AtomicType atomic{ 0xF }; + + IntegralType ret = atomic.and_fetch(0xF0, eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + } +} + +template +void AtomicIntegralBasicTest::TestAtomicFetchOr() +{ + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic.fetch_or(0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic.fetch_or(0x0, eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic.fetch_or(0x2, eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x3); + } +} + +template +void AtomicIntegralBasicTest::TestAtomicOrFetch() +{ + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic.or_fetch(0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic.or_fetch(0x0, eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic.or_fetch(0x2, eastl::memory_order_relaxed); + + VERIFY(ret == 0x3); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x3); + } +} + +template +void AtomicIntegralBasicTest::TestAtomicFetchXor() +{ + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic.fetch_xor(0x0, eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic.fetch_xor(0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + } + + { + AtomicType atomic{ 0x0 }; + + IntegralType ret = atomic.fetch_xor(0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + } +} + +template +void AtomicIntegralBasicTest::TestAtomicXorFetch() +{ + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic.xor_fetch(0x0, eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic.xor_fetch(0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + } + + { + AtomicType atomic{ 0x0 }; + + IntegralType ret = atomic.xor_fetch(0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + } +} + +template +void AtomicIntegralBasicTest::TestAssignmentOperators() +{ + { + AtomicType atomic{ 0 }; + + IntegralType ret = (atomic = 5); + + VERIFY(ret == 5); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 5); + } + + { + AtomicType atomic{ 0 }; + + IntegralType ret = ++atomic; + + VERIFY(ret == 1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 1); + } + + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic++; + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 1); + } + + { + AtomicType atomic{ 1 }; + + IntegralType ret = --atomic; + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 1 }; + + IntegralType ret = atomic--; + + VERIFY(ret == 1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic += 5; + + VERIFY(ret == 5); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 5); + } + + { + AtomicType atomic{ 5 }; + + IntegralType ret = atomic -= 3; + + VERIFY(ret == 2); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 2); + } + + { + AtomicType atomic{ 0x0 }; + + IntegralType ret = atomic |= 0x1; + + VERIFY(ret == 0x1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic &= 0x1; + + VERIFY(ret == 0x1); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic ^= 0x1; + + VERIFY(ret == 0x0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + } +} + +template +void AtomicIntegralBasicTest::TestIsLockFree() +{ + { + const AtomicType atomic{ 5 }; + + VERIFY(atomic.is_lock_free() == true); + + VERIFY(AtomicType::is_always_lock_free == true); + } +} + +template +void AtomicIntegralBasicTest::TestStore() +{ + { + AtomicType atomic{ 0 }; + + atomic.store(0, eastl::memory_order_relaxed); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); + } + + { + AtomicType atomic{ 0 }; + + atomic.store(1, eastl::memory_order_relaxed); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } +} + +template +void AtomicIntegralBasicTest::TestLoad() +{ + { + AtomicType atomic{ 0 }; + + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); + + bool ret = atomic == 0; + VERIFY(ret == true); + + VERIFY(atomic == 0); + } + + { + AtomicType atomic{ 5 }; + + VERIFY(atomic.load(eastl::memory_order_relaxed) == 5); + + bool ret = atomic == 5; + VERIFY(ret == true); + + VERIFY(atomic == 5); + } +} + +template +void AtomicIntegralBasicTest::TestExchange() +{ + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic.exchange(0, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic{ 0 }; + + IntegralType ret = atomic.exchange(1, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + + ret = atomic.load(eastl::memory_order_relaxed); + + VERIFY(ret == 1); + } +} + +template +void AtomicIntegralBasicTest::TestCompareExchangeWeak() +{ + { + AtomicType atomic{ 0 }; + + IntegralType observed = 0; + bool ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_relaxed); + + if (ret == true) + { + VERIFY(ret == true); + VERIFY(observed == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + } + + { + AtomicType atomic{ 0 }; + + IntegralType observed = 1; + bool ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_relaxed); + + VERIFY(ret == false); + VERIFY(observed == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); + } +} + +template +void AtomicIntegralBasicTest::TestCompareExchangeStrong() +{ + { + AtomicType atomic{ 0 }; + + IntegralType observed = 0; + bool ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_relaxed); + + VERIFY(ret == true); + VERIFY(observed == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + + { + AtomicType atomic{ 0 }; + + IntegralType observed = 1; + bool ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_relaxed); + + VERIFY(ret == false); + VERIFY(observed == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); + } +} + +template +void AtomicIntegralBasicTest::TestAllMemoryOrders() +{ + { + AtomicType atomic{}; + + atomic.store(1); + + atomic.store(1, eastl::memory_order_relaxed); + + atomic.store(1, eastl::memory_order_release); + + atomic.store(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.load(); + + ret = atomic.load(eastl::memory_order_relaxed); + + ret = atomic.load(eastl::memory_order_acquire); + + ret = atomic.load(eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.exchange(1); + + ret = atomic.exchange(1, eastl::memory_order_relaxed); + + ret = atomic.exchange(1, eastl::memory_order_acquire); + + ret = atomic.exchange(1, eastl::memory_order_release); + + ret = atomic.exchange(1, eastl::memory_order_acq_rel); + + ret = atomic.exchange(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.fetch_add(1); + + ret = atomic.fetch_add(1, eastl::memory_order_relaxed); + + ret = atomic.fetch_add(1, eastl::memory_order_acquire); + + ret = atomic.fetch_add(1, eastl::memory_order_release); + + ret = atomic.fetch_add(1, eastl::memory_order_acq_rel); + + ret = atomic.fetch_add(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.add_fetch(1); + + ret = atomic.add_fetch(1, eastl::memory_order_relaxed); + + ret = atomic.add_fetch(1, eastl::memory_order_acquire); + + ret = atomic.add_fetch(1, eastl::memory_order_release); + + ret = atomic.add_fetch(1, eastl::memory_order_acq_rel); + + ret = atomic.add_fetch(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.fetch_sub(1); + + ret = atomic.fetch_sub(1, eastl::memory_order_relaxed); + + ret = atomic.fetch_sub(1, eastl::memory_order_acquire); + + ret = atomic.fetch_sub(1, eastl::memory_order_release); + + ret = atomic.fetch_sub(1, eastl::memory_order_acq_rel); + + ret = atomic.fetch_sub(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.sub_fetch(1); + + ret = atomic.sub_fetch(1, eastl::memory_order_relaxed); + + ret = atomic.sub_fetch(1, eastl::memory_order_acquire); + + ret = atomic.sub_fetch(1, eastl::memory_order_release); + + ret = atomic.sub_fetch(1, eastl::memory_order_acq_rel); + + ret = atomic.sub_fetch(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.fetch_and(1); + + ret = atomic.fetch_and(1, eastl::memory_order_relaxed); + + ret = atomic.fetch_and(1, eastl::memory_order_acquire); + + ret = atomic.fetch_and(1, eastl::memory_order_release); + + ret = atomic.fetch_and(1, eastl::memory_order_acq_rel); + + ret = atomic.fetch_and(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.and_fetch(1); + + ret = atomic.and_fetch(1, eastl::memory_order_relaxed); + + ret = atomic.and_fetch(1, eastl::memory_order_acquire); + + ret = atomic.and_fetch(1, eastl::memory_order_release); + + ret = atomic.and_fetch(1, eastl::memory_order_acq_rel); + + ret = atomic.and_fetch(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.fetch_or(1); + + ret = atomic.fetch_or(1, eastl::memory_order_relaxed); + + ret = atomic.fetch_or(1, eastl::memory_order_acquire); + + ret = atomic.fetch_or(1, eastl::memory_order_release); + + ret = atomic.fetch_or(1, eastl::memory_order_acq_rel); + + ret = atomic.fetch_or(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.or_fetch(1); + + ret = atomic.or_fetch(1, eastl::memory_order_relaxed); + + ret = atomic.or_fetch(1, eastl::memory_order_acquire); + + ret = atomic.or_fetch(1, eastl::memory_order_release); + + ret = atomic.or_fetch(1, eastl::memory_order_acq_rel); + + ret = atomic.or_fetch(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.fetch_xor(1); + + ret = atomic.fetch_xor(1, eastl::memory_order_relaxed); + + ret = atomic.fetch_xor(1, eastl::memory_order_acquire); + + ret = atomic.fetch_xor(1, eastl::memory_order_release); + + ret = atomic.fetch_xor(1, eastl::memory_order_acq_rel); + + ret = atomic.fetch_xor(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType ret = atomic.xor_fetch(1); + + ret = atomic.xor_fetch(1, eastl::memory_order_relaxed); + + ret = atomic.xor_fetch(1, eastl::memory_order_acquire); + + ret = atomic.xor_fetch(1, eastl::memory_order_release); + + ret = atomic.xor_fetch(1, eastl::memory_order_acq_rel); + + ret = atomic.xor_fetch(1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType observed = 0; + bool ret; + + ret = atomic.compare_exchange_weak(observed, 1); + + ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_release); + + ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_acq_rel); + + ret = atomic.compare_exchange_weak(observed, 1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType observed = 0; + bool ret; + + ret = atomic.compare_exchange_strong(observed, 1); + + ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_release); + + ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_acq_rel); + + ret = atomic.compare_exchange_strong(observed, 1, eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType observed = 0; + bool ret; + + ret = atomic.compare_exchange_weak(observed, 1, + eastl::memory_order_relaxed, + eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, 1, + eastl::memory_order_acquire, + eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, 1, + eastl::memory_order_acquire, + eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, 1, + eastl::memory_order_release, + eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, 1, + eastl::memory_order_acq_rel, + eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, 1, + eastl::memory_order_acq_rel, + eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, 1, + eastl::memory_order_seq_cst, + eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_weak(observed, 1, + eastl::memory_order_seq_cst, + eastl::memory_order_acquire); + + ret = atomic.compare_exchange_weak(observed, 1, + eastl::memory_order_seq_cst, + eastl::memory_order_seq_cst); + } + + { + AtomicType atomic{}; + + IntegralType observed = 0; + bool ret; + + ret = atomic.compare_exchange_strong(observed, 1, + eastl::memory_order_relaxed, + eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, 1, + eastl::memory_order_acquire, + eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, 1, + eastl::memory_order_acquire, + eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, 1, + eastl::memory_order_release, + eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, 1, + eastl::memory_order_acq_rel, + eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, 1, + eastl::memory_order_acq_rel, + eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, 1, + eastl::memory_order_seq_cst, + eastl::memory_order_relaxed); + + ret = atomic.compare_exchange_strong(observed, 1, + eastl::memory_order_seq_cst, + eastl::memory_order_acquire); + + ret = atomic.compare_exchange_strong(observed, 1, + eastl::memory_order_seq_cst, + eastl::memory_order_seq_cst); + } + +} + +template +void AtomicIntegralBasicTest::TestAtomicStandalone() +{ + { + AtomicType atomic; + + IntegralType expected = 0; + bool ret = atomic_compare_exchange_weak(&atomic, &expected, 1); + + if (ret) + { + VERIFY(ret == true); + + VERIFY(expected == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + } + + { + AtomicType atomic; + + IntegralType expected = 0; + bool ret = atomic_compare_exchange_weak_explicit(&atomic, &expected, 1, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + if (ret) + { + VERIFY(ret == true); + + VERIFY(expected == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + } + + { + AtomicType atomic; + + IntegralType expected = 0; + bool ret = atomic_compare_exchange_strong(&atomic, &expected, 1); + + VERIFY(ret == true); + + VERIFY(expected == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + + { + AtomicType atomic; + + IntegralType expected = 0; + bool ret = atomic_compare_exchange_strong_explicit(&atomic, &expected, 1, eastl::memory_order_relaxed, eastl::memory_order_relaxed); + + VERIFY(ret == true); + + VERIFY(expected == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_fetch_xor(&atomic, 0x1); + + VERIFY(ret == 0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_fetch_xor_explicit(&atomic, 0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_xor_fetch(&atomic, 0x1); + + VERIFY(ret == 0x1); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_xor_fetch_explicit(&atomic, 0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_fetch_or(&atomic, 0x1); + + VERIFY(ret == 0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_fetch_or_explicit(&atomic, 0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_or_fetch(&atomic, 0x1); + + VERIFY(ret == 0x1); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_or_fetch_explicit(&atomic, 0x1, eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x1); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic_fetch_and(&atomic, 0x0); + + VERIFY(ret == 0x1); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x0); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic_fetch_and_explicit(&atomic, 0x0, eastl::memory_order_relaxed); + + VERIFY(ret == 0x1); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x0); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic_and_fetch(&atomic, 0x0); + + VERIFY(ret == 0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x0); + } + + { + AtomicType atomic{ 0x1 }; + + IntegralType ret = atomic_and_fetch_explicit(&atomic, 0x0, eastl::memory_order_relaxed); + + VERIFY(ret == 0x0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0x0); + } + + { + AtomicType atomic{ 1 }; + + IntegralType ret = atomic_fetch_sub(&atomic, 1); + + VERIFY(ret == 1); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); + } + + { + AtomicType atomic{ 1 }; + + IntegralType ret = atomic_fetch_sub_explicit(&atomic, 1, eastl::memory_order_relaxed); + + VERIFY(ret == 1); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); + } + + { + AtomicType atomic{ 1 }; + + IntegralType ret = atomic_sub_fetch(&atomic, 1); + + VERIFY(ret == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); + } + + { + AtomicType atomic{ 1 }; + + IntegralType ret = atomic_sub_fetch_explicit(&atomic, 1, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 0); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_fetch_add(&atomic, 1); + + VERIFY(ret == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_fetch_add_explicit(&atomic, 1, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_add_fetch(&atomic, 1); + + VERIFY(ret == 1); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_add_fetch_explicit(&atomic, 1, eastl::memory_order_relaxed); + + VERIFY(ret == 1); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_exchange(&atomic, 1); + + VERIFY(ret == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_exchange_explicit(&atomic, 1, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_load(&atomic); + + VERIFY(ret == 0); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_load_explicit(&atomic, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_load_cond(&atomic, [](IntegralType val) { return true; }); + + VERIFY(ret == 0); + } + + { + AtomicType atomic; + + IntegralType ret = atomic_load_cond_explicit(&atomic, [](IntegralType val) { return true; }, eastl::memory_order_relaxed); + + VERIFY(ret == 0); + } + + { + AtomicType atomic; + + atomic_store(&atomic, 1); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + + { + AtomicType atomic; + + atomic_store_explicit(&atomic, 1, eastl::memory_order_relaxed); + + VERIFY(atomic.load(eastl::memory_order_relaxed) == 1); + } + + { + AtomicType atomic; + + VERIFY(atomic_is_lock_free(&atomic) == true); + } +} + +struct AtomicNonDefaultConstructible +{ + AtomicNonDefaultConstructible(uint8_t a) + : a(a) + { + } + + friend bool operator==(const AtomicNonDefaultConstructible& a, const AtomicNonDefaultConstructible& b) + { + return a.a == b.a; + } + + uint8_t a; +}; + +#if defined(EASTL_ATOMIC_HAS_8BIT) + +int TestAtomicNonDefaultConstructible() +{ + int nErrorCount = 0; + + { + eastl::atomic atomic{AtomicNonDefaultConstructible{(uint8_t)3}}; + + VERIFY(atomic.load() == AtomicNonDefaultConstructible{(uint8_t)3}); + } + + { + eastl::atomic atomic{AtomicNonDefaultConstructible{(uint8_t)3}}; + + atomic.store(AtomicNonDefaultConstructible{(uint8_t)4}); + + VERIFY(atomic.load() == AtomicNonDefaultConstructible{(uint8_t)4}); + } + + { + eastl::atomic atomic{AtomicNonDefaultConstructible{(uint8_t)3}}; + + VERIFY(atomic_load_cond(&atomic, [] (AtomicNonDefaultConstructible) { return true; }) == AtomicNonDefaultConstructible{(uint8_t)3}); + } + + { + eastl::atomic atomic{AtomicNonDefaultConstructible{(uint8_t)3}}; + + VERIFY(atomic_load_cond_explicit(&atomic, [] (AtomicNonDefaultConstructible) { return true; }, eastl::memory_order_seq_cst) == AtomicNonDefaultConstructible{(uint8_t)3}); + } + + return nErrorCount; +} + +#endif + +struct Atomic128LoadType +{ + friend bool operator==(const Atomic128LoadType& a, const Atomic128LoadType& b) + { + return a.a == b.a && a.b == b.b && a.c == b.c && a.d == b.d; + } + + uint32_t a, b, c, d; +}; + +#if defined(EASTL_ATOMIC_HAS_128BIT) + +int TestAtomic128Loads() +{ + int nErrorCount = 0; + + { + eastl::atomic atomic{Atomic128LoadType{1, 1, 0, 0}}; + + VERIFY((atomic.load() == Atomic128LoadType{1, 1, 0, 0})); + } + + { + eastl::atomic atomic{Atomic128LoadType{0, 0, 1, 1}}; + + VERIFY((atomic.load() == Atomic128LoadType{0, 0, 1, 1})); + } + + { + eastl::atomic atomic{Atomic128LoadType{0, 1, 0, 1}}; + + VERIFY((atomic.load() == Atomic128LoadType{0, 1, 0, 1})); + } + + { + eastl::atomic atomic{Atomic128LoadType{1, 0, 1, 0}}; + + VERIFY((atomic.load() == Atomic128LoadType{1, 0, 1, 0})); + } + + { + eastl::atomic atomic{Atomic128LoadType{1, 1, 0, 0}}; + + Atomic128LoadType expected{0, 0, 0, 0}; + atomic.compare_exchange_strong(expected, Atomic128LoadType{1, 1, 0, 0}); + + VERIFY((expected == Atomic128LoadType{1, 1, 0, 0})); + } + + { + eastl::atomic atomic{Atomic128LoadType{0, 0, 1, 1}}; + + Atomic128LoadType expected{0, 0, 0, 0}; + atomic.compare_exchange_strong(expected, Atomic128LoadType{0, 0, 1, 1}); + + VERIFY((expected == Atomic128LoadType{0, 0, 1, 1})); + } + + { + eastl::atomic atomic{Atomic128LoadType{0, 1, 0, 1}}; + + Atomic128LoadType expected{0, 0, 0, 0}; + atomic.compare_exchange_strong(expected, Atomic128LoadType{0, 1, 0, 1}); + + VERIFY((expected == Atomic128LoadType{0, 1, 0, 1})); + } + + { + eastl::atomic atomic{Atomic128LoadType{1, 0, 1, 0}}; + + Atomic128LoadType expected{0, 0, 0, 0}; + atomic.compare_exchange_strong(expected, Atomic128LoadType{1, 0, 1, 0}); + + VERIFY((expected == Atomic128LoadType{1, 0, 1, 0})); + } + + { + eastl::atomic atomic{Atomic128LoadType{0, 0, 0, 0}}; + + Atomic128LoadType expected{0, 0, 0, 0}; + atomic.compare_exchange_strong(expected, Atomic128LoadType{1, 1, 0, 0}); + + VERIFY((atomic.load() == Atomic128LoadType{1, 1, 0, 0})); + } + + { + eastl::atomic atomic{Atomic128LoadType{0, 0, 0, 0}}; + + Atomic128LoadType expected{0, 0, 0, 0}; + atomic.compare_exchange_strong(expected, Atomic128LoadType{0, 0, 1, 1}); + + VERIFY((atomic.load() == Atomic128LoadType{0, 0, 1, 1})); + } + + { + eastl::atomic atomic{Atomic128LoadType{0, 0, 0, 0}}; + + Atomic128LoadType expected{0, 0, 0, 0}; + atomic.compare_exchange_strong(expected, Atomic128LoadType{0, 1, 0, 1}); + + VERIFY((atomic.load() == Atomic128LoadType{0, 1, 0, 1})); + } + + { + eastl::atomic atomic{Atomic128LoadType{0, 0, 0, 0}}; + + Atomic128LoadType expected{0, 0, 0, 0}; + atomic.compare_exchange_strong(expected, Atomic128LoadType{1, 0, 1, 0}); + + VERIFY((atomic.load() == Atomic128LoadType{1, 0, 1, 0})); + } + + return nErrorCount; +} + +#endif + +int TestAtomicBasic() +{ + int nErrorCount = 0; + + #if defined(EASTL_ATOMIC_HAS_8BIT) + { + AtomicIntegralBasicTest u8AtomicTest; + + nErrorCount += u8AtomicTest.RunTest(); + } + #endif + + #if defined(EASTL_ATOMIC_HAS_16BIT) + { + AtomicIntegralBasicTest u16AtomicTest; + + nErrorCount += u16AtomicTest.RunTest(); + } + #endif + + #if defined(EASTL_ATOMIC_HAS_32BIT) + { + AtomicIntegralBasicTest u32AtomicTest; + + nErrorCount += u32AtomicTest.RunTest(); + } + #endif + + #if defined(EASTL_ATOMIC_HAS_64BIT) + { + AtomicIntegralBasicTest u64AtomicTest; + + nErrorCount += u64AtomicTest.RunTest(); + } + #endif + + #if defined(EASTL_ATOMIC_HAS_128BIT) && (defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)) + { + AtomicIntegralBasicTest<__uint128_t> u128AtomicTest; + + nErrorCount += u128AtomicTest.RunTest(); + } + + { + AtomicIntegralBasicTest u128AtomicTest; + + nErrorCount += u128AtomicTest.RunTest(); + } + #endif + + { + AtomicBoolBasicTest boolAtomicTest; + + nErrorCount += boolAtomicTest.RunTest(); + } + + #if defined(EASTL_ATOMIC_HAS_16BIT) + { + AtomicUserTypeBasicTest userTypeAtomicTest; + + nErrorCount += userTypeAtomicTest.RunTest(); + } + #endif + + #if defined(EASTL_ATOMIC_HAS_32BIT) + { + AtomicUserTypeBasicTest userTypeAtomicTest; + + nErrorCount += userTypeAtomicTest.RunTest(); + } + + { + AtomicUserTypeBasicTest userTypeAtomicTest; + + nErrorCount += userTypeAtomicTest.RunTest(); + } + #endif + + #if defined(EASTL_ATOMIC_HAS_128BIT) + { + AtomicUserTypeBasicTest userTypeAtomicTest; + + nErrorCount += userTypeAtomicTest.RunTest(); + } + #endif + + { + AtomicPointerBasicTest ptrAtomicTest; + + nErrorCount += ptrAtomicTest.RunTest(); + } + + { + AtomicVoidPointerBasicTest voidPtrAtomicTest; + + nErrorCount += voidPtrAtomicTest.RunTest(); + } + + { + AtomicFlagBasicTest atomicFlagBasicTest; + + nErrorCount += atomicFlagBasicTest.RunTest(); + } + + { + AtomicStandaloneBasicTest atomicStandaloneBasicTest; + + nErrorCount += atomicStandaloneBasicTest.RunTest(); + } + +#if defined(EASTL_ATOMIC_HAS_128BIT) + + nErrorCount += TestAtomic128Loads(); + +#endif + +#if defined(EASTL_ATOMIC_HAS_8BIT) + + nErrorCount += TestAtomicNonDefaultConstructible(); + +#endif + + nErrorCount += TestAtomicConstantInitialization(); + + return nErrorCount; +} diff --git a/test/source/TestIterator.cpp b/test/source/TestIterator.cpp index 6a7ea95b..e1681182 100644 --- a/test/source/TestIterator.cpp +++ b/test/source/TestIterator.cpp @@ -42,15 +42,15 @@ int TestIterator_advance() for(i = 0; i < num_elements; i++) { EATEST_VERIFY(*it == v[i]); - eastl::advance(it, 1); + eastl::advance(it, 1); } // test backwards advancement eastl::vector::iterator it2 = v.end(); i = num_elements - 1; do - { - eastl::advance(it2, -1); + { + eastl::advance(it2, -1); EATEST_VERIFY(*it2 == v[i]); } while(i-- != 0); @@ -114,7 +114,7 @@ int TestIterator_advance() eastl::vector::iterator it = v.end(); EATEST_VERIFY(*eastl::prev(it, 2) == 42); - EATEST_VERIFY(*eastl::prev(it /*testing the iterator distance default value*/) == 2); + EATEST_VERIFY(*eastl::prev(it /*testing the iterator distance default value*/) == 2); } return nErrorCount; @@ -130,12 +130,12 @@ int TestIterator_moveIterator() // operator++(int) auto moveIter = constBeginMoveIter; - moveIter++; // the result of the expression is the incremented value, we need this test to read the existing state of the iterator. + moveIter++; // the result of the expression is the incremented value, we need this test to read the existing state of the iterator. EATEST_VERIFY(*moveIter != *constBeginMoveIter); // operator--(int) moveIter = constBeginMoveIter + 2; // points to '42' - moveIter--; // the result of the expression is the incremented value, we need this test to read the existing state of the iterator. + moveIter--; // the result of the expression is the incremented value, we need this test to read the existing state of the iterator. EATEST_VERIFY(*moveIter != *(constBeginMoveIter + 2)); } @@ -152,7 +152,7 @@ int TestIterator() int nErrorCount = 0; nErrorCount += TestIterator_advance(); nErrorCount += TestIterator_moveIterator(); - + { // reverse_iterator // reverse_iterator make_reverse_iterator(Iterator mi) @@ -227,8 +227,9 @@ int TestIterator() { // difference_type distance(InputIterator first, InputIterator last) - // To do. - } + eastl::vector intVector = {0, 1, 2, 3, 4, 5, 6, 7}; + EATEST_VERIFY(eastl::distance(intVector.begin(), intVector.end()) == 8); + } { @@ -260,7 +261,7 @@ int TestIterator() eastl::string8 str8; eastl::string8::iterator string8Iterator = eastl::begin(str8); EATEST_VERIFY(string8Iterator == eastl::end(str8)); - #endif + #endif } // eastl::data @@ -292,6 +293,7 @@ int TestIterator() int intCArray[34]; EATEST_VERIFY(eastl::size(intCArray) == 34); + static_assert(eastl::size(intCArray) == 34, "eastl::size failure"); } // eastl::ssize @@ -304,6 +306,7 @@ int TestIterator() int intCArray[34]; EATEST_VERIFY(eastl::ssize(intCArray) == (signed)34); + static_assert(eastl::ssize(intCArray) == 34, "eastl::ssize failure"); } // eastl::empty @@ -311,25 +314,22 @@ int TestIterator() eastl::vector intVector; EATEST_VERIFY(eastl::empty(intVector)); intVector.push_back(); - EATEST_VERIFY(!eastl::empty(intVector)); + EATEST_VERIFY(!eastl::empty(intVector)); std::initializer_list intInitListEmpty; EATEST_VERIFY(eastl::empty(intInitListEmpty)); - - #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) - EATEST_VERIFY(!eastl::empty({1, 2, 3, 4, 5, 6})); - #endif + EATEST_VERIFY(!eastl::empty({1, 2, 3, 4, 5, 6})); } // Range-based for loops - #if !defined(EA_COMPILER_NO_RANGE_BASED_FOR_LOOP) + { { eastl::vector v; int I = 0; v.push_back(0); v.push_back(1); - + for(int i : v) EATEST_VERIFY(i == I++); } @@ -340,11 +340,11 @@ int TestIterator() s8.push_back('a'); s8.push_back('b'); - + for(char c : s8) EATEST_VERIFY(c == C++); } - #endif + } { diff --git a/test/source/TestSort.cpp b/test/source/TestSort.cpp index fffa3b0a..2d0116f1 100644 --- a/test/source/TestSort.cpp +++ b/test/source/TestSort.cpp @@ -305,6 +305,23 @@ int TestSort() } } + // Test tim sort with a specific array size and seed that caused a crash + { + vector intArray; + int i = 1000000; + { + EASTLTest_Rand testRng(232526); + + for (int n = 0; n < i; n++) + { + intArray.push_back(testRng.Rand()); + } + vector buffer(intArray.size() / 2); + tim_sort_buffer(intArray.begin(), intArray.end(), buffer.data()); + EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end())); + } + } + // Test insertion_sort() does not invalidate a BidirectionalIterator by doing --BidirectionalIterator.begin() { // Test Passes if the Test doesn't crash