Merge branch 'development' into math_string_converters

This commit is contained in:
puvvadar
2022-02-14 10:42:48 -08:00
committed by GitHub
373 changed files with 15071 additions and 5781 deletions
@@ -8,6 +8,7 @@
#include <AzCore/UnitTest/TestTypes.h>
#include <AzCore/std/concepts/concepts.h>
#include <AzCore/std/ranges/ranges_functional.h>
namespace UnitTest
{
@@ -199,4 +200,122 @@ namespace UnitTest
static_assert(!AZStd::strict_weak_order<RelationPredicate, int, Base>);
static_assert(!AZStd::strict_weak_order<RelationPredicate, Base, int>);
}
TEST_F(ConceptsTestFixture, IteratorInvocableConcepts)
{
// concept indirectly unary invocable
// i.e Is deferencing an iterator like type and invoking
// a unary callable a well formed expression
auto CharUnaryCallable = [](const char) -> int { return {}; };
auto IntUnaryCallable = [](int) -> int { return {}; };
auto IntRefUnaryCallable = [](int&) -> int { return {}; };
static_assert(AZStd::indirectly_unary_invocable<decltype(CharUnaryCallable), AZStd::string_view::iterator>);
static_assert(AZStd::indirectly_unary_invocable<decltype(IntUnaryCallable), AZStd::string_view::iterator>);
static_assert(!AZStd::indirectly_unary_invocable<decltype(IntRefUnaryCallable), AZStd::string_view::iterator>);
// concept indirectly regular unary invocable
// i.e Is deferencing an iterator like type and invoking with a unary callable
// which will not modify the input arguments(hence the term "regular") a well formed expression
static_assert(AZStd::indirectly_regular_unary_invocable<decltype(CharUnaryCallable), AZStd::string_view::iterator>);
static_assert(AZStd::indirectly_regular_unary_invocable<decltype(IntUnaryCallable), AZStd::string_view::iterator>);
static_assert(!AZStd::indirectly_regular_unary_invocable<decltype(IntRefUnaryCallable), AZStd::string_view::iterator>);
// concept indirect unary predicate
// i.e Is deferencing an iterator like type and invoking with a unary predicate
// i.e which is a callable that accepts one argument and returns value testable in a boolean context
auto CharUnaryPredicate = [](const char) -> bool { return {}; };
auto IntUnaryPredicate = [](int) -> int { return {}; };// Return value is an int which is convertible to bool
auto IntRefUnaryPredicate = [](int&) -> int { return {}; }; // string_view iterator value type(char) can't bind to an int&
auto CharUnaryNonPredicate = [](const char) -> AZStd::string_view { return {}; }; // string_view is not convertible to bool
static_assert(AZStd::indirect_unary_predicate<decltype(CharUnaryPredicate), AZStd::string_view::iterator>);
static_assert(AZStd::indirect_unary_predicate<decltype(IntUnaryPredicate), AZStd::string_view::iterator>);
static_assert(!AZStd::indirect_unary_predicate<decltype(IntRefUnaryPredicate), AZStd::string_view::iterator>);
static_assert(!AZStd::indirect_unary_predicate<decltype(CharUnaryNonPredicate), AZStd::string_view::iterator>);
// concept indirect binary predicate
// i.e Is deferencing two iterator like types and invoking a binary predicate with those values
// well formed and returns value testable in a boolean context.
auto CharIntBinaryPredicate = [](const char, int) -> bool { return{}; };
auto CharCharRefBinaryPredicate = [](const char, const char&) -> uint32_t { return{}; };
auto UIntRefCharBinaryPredicate = [](uint32_t&, char) -> bool { return{}; };
auto CharCharBinaryNonPredicate = [](const char, const char) -> AZStd::string_view { return {}; };
static_assert(AZStd::indirect_binary_predicate<decltype(CharIntBinaryPredicate),
AZStd::string_view::iterator, AZStd::string_view::iterator>);
static_assert(AZStd::indirect_binary_predicate<decltype(CharCharRefBinaryPredicate),
AZStd::string_view::iterator, AZStd::string_view::iterator>);
// string_view iterator value type(char) cannot bind to int&
static_assert(!AZStd::indirect_binary_predicate<decltype(UIntRefCharBinaryPredicate),
AZStd::string_view::iterator, AZStd::string_view::iterator>);
// string_view is not convertible to bool
static_assert(!AZStd::indirect_binary_predicate<decltype(CharCharBinaryNonPredicate),
AZStd::string_view::iterator, AZStd::string_view::iterator>);
// Ok - iter_reference_t<uint32_t*> = uint32_t&
static_assert(AZStd::indirect_binary_predicate<decltype(UIntRefCharBinaryPredicate),
uint32_t*, AZStd::string_view::iterator>);
// concept indirect equivalence relation
// i.e Is deferencing two iterator like types and invoking a binary predicate with those values
// well formed and returns value testable in a boolean context.
// The dereferenced iterator types should be model an equivalence relationship
// (a == b) && (b == c) == (a ==c)
static_assert(AZStd::indirect_equivalence_relation<decltype(CharIntBinaryPredicate),
AZStd::string_view::iterator, AZStd::string_view::iterator>);
static_assert(AZStd::indirect_equivalence_relation<decltype(CharCharRefBinaryPredicate),
AZStd::string_view::iterator, AZStd::string_view::iterator>);
static_assert(!AZStd::indirect_equivalence_relation<decltype(UIntRefCharBinaryPredicate),
AZStd::string_view::iterator, AZStd::string_view::iterator>);
static_assert(!AZStd::indirect_equivalence_relation<decltype(CharCharBinaryNonPredicate),
AZStd::string_view::iterator, AZStd::string_view::iterator>);
// The "relation" concept requires that both both arguments can be bind to
// either of the two binary parameters
static_assert(!AZStd::indirect_equivalence_relation<decltype(UIntRefCharBinaryPredicate),
uint32_t*, AZStd::string_view::iterator>);
// concept indirect strict weak order
// i.e Is deferencing two iterator like types and invoking a binary predicate with those values
// well formed and returns value testable in a boolean context.
// The dereferenced iterator types should be model a strict weak order relation
// (a < b) && (b < c) == (a < c)
static_assert(AZStd::indirect_strict_weak_order<decltype(CharIntBinaryPredicate),
AZStd::string_view::iterator, AZStd::string_view::iterator>);
static_assert(AZStd::indirect_strict_weak_order<decltype(CharCharRefBinaryPredicate),
AZStd::string_view::iterator, AZStd::string_view::iterator>);
static_assert(!AZStd::indirect_strict_weak_order<decltype(UIntRefCharBinaryPredicate),
AZStd::string_view::iterator, AZStd::string_view::iterator>);
static_assert(!AZStd::indirect_strict_weak_order<decltype(CharCharBinaryNonPredicate),
AZStd::string_view::iterator, AZStd::string_view::iterator>);
// The "relation" concept requires that both both arguments can be bind to
// either of the two binary parameters
static_assert(!AZStd::indirect_strict_weak_order<decltype(UIntRefCharBinaryPredicate),
uint32_t*, AZStd::string_view::iterator>);
// indirect_result_t type alias
static_assert(AZStd::same_as<AZStd::indirect_result_t<decltype(CharCharRefBinaryPredicate),
AZStd::string_view::iterator, const char*>, uint32_t>);
// projected operator* returns indirect result of the projection function
static_assert(AZStd::same_as<AZStd::iter_reference_t<AZStd::projected<int*, AZStd::identity>>, int&>);
}
TEST_F(ConceptsTestFixture, IteratorAlgorithmConcepts)
{
static_assert(AZStd::indirectly_swappable<int*, int*>);
static_assert(!AZStd::indirectly_swappable<int*, const int*>);
auto CharIntIndirectlyComparable = [](const char lhs, int rhs) -> bool { return lhs == rhs; };
static_assert(AZStd::indirectly_comparable<const char*, int*, decltype(CharIntIndirectlyComparable)>);
static_assert(!AZStd::indirectly_comparable<AZStd::string_view, int*, decltype(CharIntIndirectlyComparable)>);
static_assert(AZStd::permutable<typename AZStd::vector<int>::iterator>);
// const iterator isn't indirectlly swappable or indirectly movable
static_assert(!AZStd::permutable<typename AZStd::vector<int>::const_iterator>);
static_assert(AZStd::mergeable<AZStd::vector<int>::iterator, AZStd::string_view::iterator, AZStd::vector<int>::iterator>);
static_assert(!AZStd::mergeable<AZStd::vector<int>::iterator, AZStd::string_view::iterator, AZStd::string_view::iterator>);
static_assert(AZStd::sortable<int*>);
// Not sortable becaue the iter_reference_t<const int*> = const int& which isn't swappable
static_assert(!AZStd::sortable<const int*>);
}
}
@@ -0,0 +1,250 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/UnitTest/TestTypes.h>
#include <AzCore/std/string/string_view.h>
#include <AzCore/std/ranges/ranges_algorithm.h>
namespace UnitTest
{
class RangesAlgorithmTestFixture
: public ScopedAllocatorSetupFixture
{};
// range algorithm min and max
TEST_F(RangesAlgorithmTestFixture, RangesMin_ReturnsSmallestElement)
{
// Simple Elements
EXPECT_EQ(-1, AZStd::ranges::min(5, -1));
EXPECT_EQ(78235, AZStd::ranges::min(78235, 124785));
EXPECT_EQ(7, AZStd::ranges::min(7, 7));
// Initializer list
AZStd::initializer_list<int> testIList{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, 1000, 45 };
EXPECT_EQ(-8, AZStd::ranges::min(testIList));
// Range
AZStd::vector testVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, 1000, 45 };
EXPECT_EQ(-8, AZStd::ranges::min(testVector));
}
TEST_F(RangesAlgorithmTestFixture, RangesMax_ReturnsLargestElement)
{
// Simple Elements
EXPECT_EQ(5, AZStd::ranges::max(5, -1));
EXPECT_EQ(124785, AZStd::ranges::max(78235, 124785));
EXPECT_EQ(7, AZStd::ranges::max(7, 7));
// Initializer list
AZStd::initializer_list<int> testIList{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, 1000, 45 };
EXPECT_EQ(1000, AZStd::ranges::max(testIList));
// Range
AZStd::vector testVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, 1000, 45 };
EXPECT_EQ(1000, AZStd::ranges::max(testVector));
}
TEST_F(RangesAlgorithmTestFixture, RangesMinMax_ReturnsSmallestAndLargestValue)
{
// Simple Elements
AZStd::ranges::minmax_result<int> expectedMinMax{ -1, 5 };
AZStd::ranges::minmax_result<int> testMinMax = AZStd::ranges::minmax(5, -1);
EXPECT_EQ(expectedMinMax.min, testMinMax.min);
EXPECT_EQ(expectedMinMax.max, testMinMax.max);
expectedMinMax = { 78235, 124785 };
testMinMax = AZStd::ranges::minmax(78235, 124785);
EXPECT_EQ(expectedMinMax.min, testMinMax.min);
EXPECT_EQ(expectedMinMax.max, testMinMax.max);
expectedMinMax = { 7, 7 };
testMinMax = AZStd::ranges::minmax(7, 7);
EXPECT_EQ(expectedMinMax.min, testMinMax.min);
EXPECT_EQ(expectedMinMax.max, testMinMax.max);
// Initializer list
AZStd::initializer_list<int> testIList{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, 1000, 45 };
expectedMinMax = { -8, 1000 };
testMinMax = AZStd::ranges::minmax(testIList);
EXPECT_EQ(expectedMinMax.min, testMinMax.min);
EXPECT_EQ(expectedMinMax.max, testMinMax.max);
// Range
AZStd::vector testVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, 1000, 45 };
expectedMinMax = { -8, 1000 };
testMinMax = AZStd::ranges::minmax(testVector);
EXPECT_EQ(expectedMinMax.min, testMinMax.min);
EXPECT_EQ(expectedMinMax.max, testMinMax.max);
}
TEST_F(RangesAlgorithmTestFixture, RangesMinElement_ReturnsIteratorToLeftmostSmallestElement)
{
AZStd::vector testVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, 1000, 45 };
// iterator
auto leftmostSmallestIt = AZStd::ranges::min_element(testVector.begin(), testVector.end());
ASSERT_EQ(testVector.begin() + 4, leftmostSmallestIt);
EXPECT_EQ(-8, *leftmostSmallestIt);
// Range
leftmostSmallestIt = AZStd::ranges::min_element(testVector);
ASSERT_EQ(testVector.begin() + 4, leftmostSmallestIt);
EXPECT_EQ(-8, *leftmostSmallestIt);
}
TEST_F(RangesAlgorithmTestFixture, RangesMaxElement_ReturnsIteratorToLeftmostLargestElement)
{
AZStd::vector testVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, 1000, 45 };
// iterator
auto leftmostLargestIt = AZStd::ranges::max_element(testVector.begin(), testVector.end());
ASSERT_EQ(testVector.begin() + 6, leftmostLargestIt);
EXPECT_EQ(1000, *leftmostLargestIt);
// Range
leftmostLargestIt = AZStd::ranges::max_element(testVector);
ASSERT_EQ(testVector.begin() + 6, leftmostLargestIt);
EXPECT_EQ(1000, *leftmostLargestIt);
}
TEST_F(RangesAlgorithmTestFixture, RangesMinMaxElement_ReturnsIteratorToLeftmostSmallestElement_IteratorToRightmostLargestElement)
{
// The behavior of minmax_element is explicitly different from max_element
// as it relates to the max element being returned
// mixmax_element returns the rightmost largest element(assuming comparison function object is ranges::less)
// https://eel.is/c++draft/algorithms#footnoteref-225
AZStd::vector testVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, 1000, 45 };
// iterator
{
auto [leftmostSmallestIt, rightmostLargestIt] = AZStd::ranges::minmax_element(testVector.begin(), testVector.end());
ASSERT_EQ(testVector.begin() + 4, leftmostSmallestIt);
ASSERT_EQ(testVector.begin() + 10, rightmostLargestIt);
EXPECT_EQ(-8, *leftmostSmallestIt);
EXPECT_EQ(1000, *rightmostLargestIt);
}
// Range
auto [leftmostSmallestIt, rightmostLargestIt] = AZStd::ranges::minmax_element(testVector);
ASSERT_EQ(testVector.begin() + 4, leftmostSmallestIt);
ASSERT_EQ(testVector.begin() + 10, rightmostLargestIt);
EXPECT_EQ(-8, *leftmostSmallestIt);
EXPECT_EQ(1000, *rightmostLargestIt);
}
TEST_F(RangesAlgorithmTestFixture, RangesFind_LocatesElementInContainer_Succeeds)
{
AZStd::vector testVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, 1000, 45 };
auto foundIt = AZStd::ranges::find(testVector, 22);
ASSERT_NE(testVector.end(), foundIt);
EXPECT_EQ(22, *foundIt);
foundIt = AZStd::ranges::find_if(testVector, [](int value) { return value < 0; });
ASSERT_NE(testVector.end(), foundIt);
EXPECT_EQ(-8, *foundIt);
foundIt = AZStd::ranges::find_if_not(testVector, [](int value) { return value < 1000; });
ASSERT_NE(testVector.end(), foundIt);
EXPECT_EQ(1000, *foundIt);
}
TEST_F(RangesAlgorithmTestFixture, RangesFindFirstOf_LocatesElementInContainer_Succeeds)
{
AZStd::vector testVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, 1000, 45 };
AZStd::array testArray{ -8, 47 };
auto foundIt = AZStd::ranges::find_first_of(testVector, testArray);
ASSERT_NE(testVector.end(), foundIt);
EXPECT_EQ(47, *foundIt);
AZStd::array<int, 0> emptyArray{};
foundIt = AZStd::ranges::find_first_of(testVector, emptyArray);
EXPECT_EQ(testVector.end(), foundIt);
}
TEST_F(RangesAlgorithmTestFixture, RangesSearch_LocatesElementInContainer_Succeeds)
{
AZStd::vector testVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, -8, 1000, 45 };
AZStd::array testArray{ 1000 };
auto testSubrange = AZStd::ranges::search(testVector, testArray);
ASSERT_FALSE(testSubrange.empty());
EXPECT_EQ(1000, testSubrange.front());
AZStd::array testArray2{ 1000, 45 };
testSubrange = AZStd::ranges::search(testVector, testArray2);
ASSERT_EQ(2, testSubrange.size());
EXPECT_EQ(1000, testSubrange[0]);
EXPECT_EQ(45, testSubrange[1]);
testSubrange = AZStd::ranges::search_n(testVector, 1, 22);
ASSERT_FALSE(testSubrange.empty());
EXPECT_EQ(22, testSubrange.front());
// 2 Consecutive values of 22 does not exist in vector
testSubrange = AZStd::ranges::search_n(testVector, 2, 22);
EXPECT_TRUE(testSubrange.empty());
// 2 Consecutive values of -8 does exist in vector
testSubrange = AZStd::ranges::search_n(testVector, 2,- 8);
ASSERT_EQ(2, testSubrange.size());
EXPECT_EQ(-8, testSubrange[0]);
EXPECT_EQ(-8, testSubrange[1]);
}
TEST_F(RangesAlgorithmTestFixture, RangesFindEnd_LocatesElementLastElement_Succeeds)
{
AZStd::vector testVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, -8, 1000, 45 };
AZStd::array testArray{ -8 };
auto testSubrange = AZStd::ranges::find_end(testVector, testArray);
ASSERT_FALSE(testSubrange.empty());
EXPECT_EQ(-8, testSubrange.front());
EXPECT_EQ(testVector.end() - 3, testSubrange.begin());
}
TEST_F(RangesAlgorithmTestFixture, RangesEqual_IsAbleToCompareTwoRanges_Succeeds)
{
AZStd::vector testVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, -8, 1000, 45 };
AZStd::vector longerVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, -8, 1000, 45, 929 };
AZStd::vector shorterVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, -8, 1000 };
AZStd::vector unequalVector{ 5, 1, 22, 47, -8, -5, 1000, 14, 22, -8, -8, 1000, 25 };
EXPECT_TRUE(AZStd::ranges::equal(testVector, testVector));
EXPECT_FALSE(AZStd::ranges::equal(testVector, longerVector));
EXPECT_FALSE(AZStd::ranges::equal(longerVector, testVector));
EXPECT_FALSE(AZStd::ranges::equal(testVector, shorterVector));
EXPECT_FALSE(AZStd::ranges::equal(shorterVector, testVector));
EXPECT_FALSE(AZStd::ranges::equal(testVector, unequalVector));
}
TEST_F(RangesAlgorithmTestFixture, RangesMismatch_Returns_IteratorsToMismatchElements)
{
AZStd::vector testVector{ 1, 2, 3, 4, 5 ,6 };
AZStd::vector secondVector{ 1, 2, 3, 14, 5, 6 };
AZStd::vector<int> emptyVector;
AZStd::vector<int> longerVector{ 1, 2, 3, 4, 5, 6, 7 };
{
auto [mismatchIt1, mismatchIt2] = AZStd::ranges::mismatch(testVector, secondVector);
ASSERT_NE(testVector.end(), mismatchIt1);
EXPECT_EQ(4, *mismatchIt1);
ASSERT_NE(secondVector.end(), mismatchIt2);
EXPECT_EQ(14, *mismatchIt2);
}
{
auto [mismatchIt1, mismatchIt2] = AZStd::ranges::mismatch(testVector, emptyVector);
ASSERT_NE(testVector.end(), mismatchIt1);
EXPECT_EQ(1, *mismatchIt1);
EXPECT_EQ(emptyVector.end(), mismatchIt2);
}
{
auto [mismatchIt1, mismatchIt2] = AZStd::ranges::mismatch(testVector, longerVector);
EXPECT_EQ(testVector.end(), mismatchIt1);
ASSERT_NE(longerVector.end(), mismatchIt2);
EXPECT_EQ(7, *mismatchIt2);
}
}
}
@@ -0,0 +1,483 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/UnitTest/TestTypes.h>
#include <AzCore/std/containers/list.h>
#include <AzCore/std/containers/map.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/ranges/all_view.h>
#include <AzCore/std/ranges/elements_view.h>
#include <AzCore/std/ranges/empty_view.h>
#include <AzCore/std/ranges/join_view.h>
#include <AzCore/std/ranges/ranges_adaptor.h>
#include <AzCore/std/ranges/single_view.h>
#include <AzCore/std/ranges/split_view.h>
#include <AzCore/std/ranges/subrange.h>
#include <AzCore/std/ranges/zip_view.h>
#include <AzCore/std/string/string_view.h>
namespace UnitTest
{
class RangesViewTestFixture
: public ScopedAllocatorSetupFixture
{};
TEST_F(RangesViewTestFixture, AllRangeAdaptor_Succeeds)
{
AZStd::string_view testString{ "Hello World" };
auto testAllView = AZStd::ranges::views::all(testString);
EXPECT_EQ(testString.size(), testAllView.size());
EXPECT_EQ(testString.data(), testAllView.data());
EXPECT_EQ(testString.begin(), testAllView.begin());
EXPECT_EQ(testString.end(), testAllView.end());
EXPECT_EQ(testString.empty(), testAllView.empty());
EXPECT_EQ(testString.front(), testAllView.front());
EXPECT_EQ(testString.back(), testAllView.back());
EXPECT_EQ(testString[5], testAllView[5]);
auto testAllViewChain = testString | AZStd::ranges::views::all;
EXPECT_EQ(testString.size(), testAllViewChain.size());
EXPECT_EQ(testString.data(), testAllViewChain.data());
EXPECT_EQ(testString.begin(), testAllViewChain.begin());
EXPECT_EQ(testString.end(), testAllViewChain.end());
EXPECT_EQ(testString.empty(), testAllViewChain.empty());
EXPECT_EQ(testString.front(), testAllViewChain.front());
EXPECT_EQ(testString.back(), testAllViewChain.back());
EXPECT_EQ(testString[5], testAllViewChain[5]);
}
TEST_F(RangesViewTestFixture, Subrange_DeductionGuides_Compile)
{
AZStd::string_view testString{ "Hello World" };
AZStd::ranges::subrange rangeDeduction(testString);
AZStd::ranges::subrange rangeDeductionWithSize(testString, testString.size());
AZStd::ranges::subrange iteratorDeduction(testString.begin(), testString.end());
AZStd::ranges::subrange iteratorDeductionWithSize(testString.begin(), testString.end(),
testString.size());
EXPECT_TRUE(rangeDeduction);
EXPECT_TRUE(rangeDeductionWithSize);
EXPECT_TRUE(iteratorDeduction);
EXPECT_TRUE(iteratorDeductionWithSize);
}
TEST_F(RangesViewTestFixture, Subrange_CanTakeSubsetOfContainer_Succeeds)
{
AZStd::vector<int> testVector{ 1, 3, 5, 6, 7, 6, 89, -178 };
AZStd::ranges::subrange subVector(testVector);
EXPECT_TRUE(subVector);
ASSERT_FALSE(subVector.empty());
EXPECT_EQ(testVector.data(), subVector.data());
EXPECT_EQ(testVector.begin(), subVector.begin());
EXPECT_EQ(testVector.end(), subVector.end());
EXPECT_EQ(testVector.size(), subVector.size());
EXPECT_EQ(testVector[0], subVector[0]);
EXPECT_EQ(testVector.front(), subVector.front());
EXPECT_EQ(testVector.back(), subVector.back());
// Now validate the iterator operations
subVector.advance(2);
subVector = subVector.prev();
subVector.advance(2);
subVector = subVector.next();
subVector.advance(-4);
EXPECT_EQ(testVector.begin(), subVector.begin());
// Obtain a copy of the subrange with the first and last elements removed
AZStd::ranges::subrange subVectorSplice(subVector.begin() + 1, subVector.end() - 1);
EXPECT_TRUE(subVectorSplice);
ASSERT_FALSE(subVector.empty());
EXPECT_LT(testVector.data(), subVectorSplice.data());
EXPECT_EQ(testVector.begin() + 1, subVectorSplice.begin());
EXPECT_EQ(testVector.end() - 1, subVectorSplice.end());
ASSERT_EQ(testVector.size() - 2, subVectorSplice.size());
EXPECT_EQ(testVector[1], subVectorSplice.front());
EXPECT_EQ(testVector[testVector.size() - 2], subVectorSplice.back());
EXPECT_NE(testVector.front(), subVectorSplice.front());
EXPECT_NE(testVector.back(), subVectorSplice.back());
}
TEST_F(RangesViewTestFixture, EmptyView_ReturnsEmptyViewRange_Succeeds)
{
AZStd::ranges::empty_view<int> emptyView;
EXPECT_EQ(nullptr, emptyView.data());
EXPECT_EQ(0, emptyView.size());
EXPECT_TRUE(emptyView.empty());
EXPECT_EQ(emptyView.end(), emptyView.begin());
EXPECT_EQ(nullptr, AZStd::ranges::views::empty<AZStd::string_view>.data());
EXPECT_EQ(0, AZStd::ranges::views::empty<AZStd::string_view>.size());
EXPECT_TRUE(AZStd::ranges::views::empty<AZStd::string_view>.empty());
EXPECT_EQ(AZStd::ranges::views::empty<AZStd::string_view>.end(), AZStd::ranges::views::empty<AZStd::string_view>.begin());
}
TEST_F(RangesViewTestFixture, SingleView_ReturnsViewOverSingleElement_Succeeds)
{
AZStd::string_view testString{ "Hello World" };
AZStd::ranges::single_view singleView{ AZStd::move(testString) };
EXPECT_NE(nullptr, singleView.data());
EXPECT_EQ(1, singleView.size());
EXPECT_FALSE(singleView.empty());
ASSERT_NE(singleView.end(), singleView.begin());
auto singleViewStringIt = singleView.begin();
EXPECT_EQ("Hello World", *singleViewStringIt);
}
TEST_F(RangesViewTestFixture, RefView_CanWrapStringView_Succeeds)
{
AZStd::string_view testString{ "Hello World" };
AZStd::ranges::ref_view refView(testString);
EXPECT_EQ(testString.size(), refView.size());
EXPECT_EQ(testString.data(), refView.data());
EXPECT_EQ(testString.begin(), refView.begin());
EXPECT_EQ(testString.end(), refView.end());
EXPECT_EQ(testString.empty(), refView.empty());
EXPECT_EQ(testString.front(), refView.front());
EXPECT_EQ(testString.back(), refView.back());
EXPECT_EQ(testString[5], refView[5]);
}
TEST_F(RangesViewTestFixture, OwningView_CanWrapStringView_Succeeds)
{
AZStd::string_view sourceView{ "Hello World" };
AZStd::string_view testString{ sourceView };
AZStd::ranges::owning_view owningView(AZStd::move(testString));
EXPECT_TRUE(testString.empty());
EXPECT_FALSE(owningView.empty());
EXPECT_EQ(sourceView.size(), owningView.size());
EXPECT_EQ(sourceView.data(), owningView.data());
EXPECT_EQ(sourceView.begin(), owningView.begin());
EXPECT_EQ(sourceView.end(), owningView.end());
EXPECT_EQ(sourceView.empty(), owningView.empty());
EXPECT_EQ(sourceView.front(), owningView.front());
EXPECT_EQ(sourceView.back(), owningView.back());
EXPECT_EQ(sourceView[5], owningView[5]);
}
MATCHER_P(ZipViewAtSentinel, sentinel, "") {
*result_listener << "zip view has iterated to sentinel";
return !(arg == sentinel);
}
TEST_F(RangesViewTestFixture, ZipView_CompilesWithRange_Succeeds)
{
AZStd::string_view sourceView{ "Hello World" };
AZStd::ranges::zip_view zipView(AZStd::move(sourceView));
auto zipItTuple = zipView.begin();
auto zipSentinelTuple = zipView.end();
ASSERT_THAT(zipItTuple, ZipViewAtSentinel(zipSentinelTuple));
EXPECT_EQ('H', AZStd::get<0>(*zipItTuple));
ptrdiff_t zipDistance = zipSentinelTuple - zipItTuple;
EXPECT_EQ(11, zipDistance);
AZStd::list<int> sourceList{ 1, 2, 3, 4, 5 };
AZStd::ranges::zip_view zipView2(AZStd::move(sourceList));
auto zipListTupleIt = zipView2.begin();
auto zipListTupleEnd = zipView2.end();
ASSERT_THAT(zipListTupleIt, ZipViewAtSentinel(zipListTupleEnd));
}
TEST_F(RangesViewTestFixture, ZipView_CanIteratOverMultipleContainers_Succeeds)
{
AZStd::string_view sourceView{ "abcdef" };
AZStd::vector intVector{ 1, 2, 3, 4, 5 };
AZStd::list<uint32_t> uintList{ 2, 4, 6, 8, 10 };
constexpr int expectedIterations = 5;
int iterationCount{};
for (auto [charX, intY, uintZ] : (AZStd::ranges::views::zip(sourceView, AZStd::move(intVector), AZStd::move(uintList))))
{
++iterationCount;
switch (charX)
{
case 'a':
EXPECT_EQ(1, intY);
EXPECT_EQ(2, uintZ);
break;
case 'b':
EXPECT_EQ(2, intY);
EXPECT_EQ(4, uintZ);
break;
case 'c':
EXPECT_EQ(3, intY);
EXPECT_EQ(6, uintZ);
break;
case 'd':
EXPECT_EQ(4, intY);
EXPECT_EQ(8, uintZ);
break;
case 'e':
EXPECT_EQ(5, intY);
EXPECT_EQ(10, uintZ);
break;
default:
ADD_FAILURE() << "Unexpected character value " << charX << " found when iterating zip view";
}
}
EXPECT_EQ(expectedIterations, iterationCount);
}
TEST_F(RangesViewTestFixture, SplitView_CanSplitPatterns_Succeeds)
{
AZStd::string_view emptyView{ "" };
auto splitView = AZStd::ranges::views::split(emptyView, " ");
auto splitIt = splitView.begin();
EXPECT_EQ(splitView.end(), splitIt);
AZStd::string_view testView1{ "Hello" };
auto splitViewCharPattern = AZStd::ranges::views::split(testView1, ' ');
auto splitCharIt = splitViewCharPattern.begin();
ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
EXPECT_EQ("Hello", AZStd::string_view(*splitCharIt));
++splitCharIt;
EXPECT_EQ(splitViewCharPattern.end(), splitCharIt);
AZStd::string_view testView2{ "Hello World" };
splitViewCharPattern = AZStd::ranges::views::split(testView2, ' ');
splitCharIt = splitViewCharPattern.begin();
ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
EXPECT_EQ("Hello", AZStd::string_view(*splitCharIt));
++splitCharIt;
ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
EXPECT_EQ("World", AZStd::string_view(*splitCharIt));
++splitCharIt;
EXPECT_EQ(splitViewCharPattern.end(), splitCharIt);
AZStd::string_view testView3{ "Hello World Moon" };
splitViewCharPattern = AZStd::ranges::views::split(testView3, ' ');
splitCharIt = splitViewCharPattern.begin();
ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
EXPECT_EQ("Hello", AZStd::string_view(*splitCharIt));
++splitCharIt;
ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
EXPECT_EQ("World", AZStd::string_view(*splitCharIt));
++splitCharIt;
ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
EXPECT_EQ("Moon", AZStd::string_view(*splitCharIt));
++splitCharIt;
EXPECT_EQ(splitViewCharPattern.end(), splitCharIt);
AZStd::string_view testView4{ "Hello World Moon " };
splitViewCharPattern = AZStd::ranges::views::split(testView4, ' ');
splitCharIt = splitViewCharPattern.begin();
ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
EXPECT_EQ("Hello", AZStd::string_view(*splitCharIt));
++splitCharIt;
ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
EXPECT_EQ("World", AZStd::string_view(*splitCharIt));
++splitCharIt;
ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
EXPECT_EQ("Moon", AZStd::string_view(*splitCharIt));
++splitCharIt;
ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
EXPECT_EQ("", AZStd::string_view(*splitCharIt));
++splitCharIt;
EXPECT_EQ(splitViewCharPattern.end(), splitCharIt);
AZStd::string_view testView5{ "Hello World Moon " };
splitViewCharPattern = AZStd::ranges::views::split(testView5, ' ');
splitCharIt = splitViewCharPattern.begin();
ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
EXPECT_EQ("Hello", AZStd::string_view(*splitCharIt));
++splitCharIt;
ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
EXPECT_EQ("World", AZStd::string_view(*splitCharIt));
++splitCharIt;
ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
EXPECT_EQ("Moon", AZStd::string_view(*splitCharIt));
++splitCharIt;
ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
EXPECT_EQ("", AZStd::string_view(*splitCharIt));
++splitCharIt;
ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
EXPECT_EQ("", AZStd::string_view(*splitCharIt));
++splitCharIt;
EXPECT_EQ(splitViewCharPattern.end(), splitCharIt);
AZStd::string_view testView6{ "Hello World Moon" };
splitViewCharPattern = AZStd::ranges::views::split(testView6, ' ');
splitCharIt = splitViewCharPattern.begin();
ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
EXPECT_EQ("Hello", AZStd::string_view(*splitCharIt));
++splitCharIt;
ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
EXPECT_EQ("", AZStd::string_view(*splitCharIt));
++splitCharIt;
ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
EXPECT_EQ("World", AZStd::string_view(*splitCharIt));
++splitCharIt;
ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
EXPECT_EQ("Moon", AZStd::string_view(*splitCharIt));
++splitCharIt;
EXPECT_EQ(splitViewCharPattern.end(), splitCharIt);
}
TEST_F(RangesViewTestFixture, SplitView_SplitsFromNonString_Succeeds)
{
const AZStd::vector<int> testVector{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// Split the vector on 3
auto splitView = AZStd::ranges::views::split(testVector, 3);
auto splitIt = splitView.begin();
ASSERT_NE(splitView.end(), splitIt);
auto splitSubrange = *splitIt;
{
AZStd::array expectedValue{ 1, 2 };
EXPECT_TRUE(AZStd::ranges::equal(expectedValue, splitSubrange));
}
++splitIt;
ASSERT_NE(splitView.end(), splitIt);
splitSubrange = *splitIt;
{
AZStd::array expectedValue{ 4, 5, 6, 7, 8, 9, 10 };
EXPECT_TRUE(AZStd::ranges::equal(expectedValue, splitSubrange));
}
}
TEST_F(RangesViewTestFixture, JoinView_IteratesOverInnerViews_Succeeds)
{
constexpr AZStd::string_view expectedString = "HelloWorldMoonSun";
using Rope = AZStd::fixed_vector<AZStd::string_view, 32>;
Rope rope{ "Hello", "World", "Moon", "Sun" };
AZStd::fixed_string<128> accumString;
for (auto&& charElement : AZStd::ranges::join_view(rope))
{
accumString.push_back(charElement);
}
EXPECT_EQ(expectedString, accumString);
}
TEST_F(RangesViewTestFixture, JoinView_IteratesCanIterateOverSplitView_Succeeds)
{
constexpr AZStd::string_view expectedString = "HelloWorldMoonSun";
constexpr AZStd::string_view splitExpression = "Hello,World,Moon,Sun";
AZStd::fixed_string<128> accumString;
for (auto&& charElement : AZStd::ranges::views::join(AZStd::ranges::views::split(splitExpression, ',')))
{
accumString.push_back(charElement);
}
EXPECT_EQ(expectedString, accumString);
}
TEST_F(RangesViewTestFixture, JoinView_IterSwapCustomization_Succeeds)
{
AZStd::fixed_vector<AZStd::string, 8> testVector1{ "World", "Hello" };
AZStd::fixed_vector<AZStd::string, 8> testVector2{ "Value", "First" };
auto joinView1 = AZStd::ranges::views::join(testVector1);
auto joinView2 = AZStd::ranges::views::join(testVector2);
auto joinViewIter1 = joinView1.begin();
auto joinViewIter2 = joinView2.begin();
// swaps the 'W' and 'V'
AZStd::ranges::iter_swap(joinViewIter1, joinViewIter2);
AZStd::ranges::advance(joinViewIter1, 5, joinView1.end());
AZStd::ranges::advance(joinViewIter2, 5, joinView2.end());
// swaps the 'H' and 'F' of the second string of each vector
AZStd::ranges::iter_swap(joinViewIter1, joinViewIter2);
EXPECT_EQ("Vorld", testVector1[0]);
EXPECT_EQ("Fello", testVector1[1]);
EXPECT_EQ("Walue", testVector2[0]);
EXPECT_EQ("Hirst", testVector2[1]);
}
TEST_F(RangesViewTestFixture, JoinView_IterMoveCustomization_Succeeds)
{
using StringWrapper = AZStd::ranges::single_view<AZStd::string>;
AZStd::fixed_vector<StringWrapper, 8> testVector1{ StringWrapper{"5"}, StringWrapper{"10"} };
AZStd::fixed_vector<StringWrapper, 8> testVector2{ StringWrapper{"15"}, StringWrapper{"20"} };
auto joinView1 = AZStd::ranges::views::join(testVector1);
auto joinView2 = AZStd::ranges::views::join(testVector2);
auto joinViewIter1 = joinView1.begin();
auto joinViewIter2 = joinView2.begin();
AZStd::string value = AZStd::ranges::iter_move(joinViewIter1);
EXPECT_EQ("5", value);
EXPECT_TRUE((*joinViewIter1).empty());
++joinViewIter2;
value = AZStd::ranges::iter_move(joinViewIter2);
EXPECT_EQ("20", value);
EXPECT_TRUE((*joinViewIter2).empty());
}
TEST_F(RangesViewTestFixture, ElementsView_CanIterateVectorOfTuple_Succeeds)
{
using TestTuple = AZStd::tuple<int, AZStd::string, bool>;
AZStd::vector testVector{ TestTuple{1, "hello", false}, TestTuple{2, "world", true},
TestTuple{3, "Moon", false} };
auto firstElementView = AZStd::ranges::views::elements<0>(testVector);
auto firstElementBegin = AZStd::ranges::begin(firstElementView);
auto firstElementEnd = AZStd::ranges::end(firstElementView);
EXPECT_NE(firstElementEnd, firstElementBegin);
ASSERT_EQ(3, firstElementView.size());
EXPECT_EQ(1, firstElementView[0]);
EXPECT_EQ(2, firstElementView[1]);
EXPECT_EQ(3, firstElementView[2]);
auto secondElementView = AZStd::ranges::views::elements<1>(testVector);
ASSERT_EQ(3, secondElementView.size());
EXPECT_EQ("hello", secondElementView[0]);
EXPECT_EQ("world", secondElementView[1]);
EXPECT_EQ("Moon", secondElementView[2]);
auto thirdElementView = AZStd::ranges::views::elements<2>(testVector);
ASSERT_EQ(3, thirdElementView.size());
EXPECT_FALSE(thirdElementView[0]);
EXPECT_TRUE(thirdElementView[1]);
EXPECT_FALSE(thirdElementView[2]);
using TestPair = AZStd::pair<AZStd::string, int>;
AZStd::vector testPairVector{ TestPair{"hello", 5}, TestPair{"world", 10}, TestPair{"Sun", 15} };
using ElementsViewBase = AZStd::ranges::views::all_t<decltype((testPairVector))>;
using ElementsViewType = AZStd::ranges::elements_view<ElementsViewBase, 0>;
constexpr AZStd::string_view expectedString = "helloworldSun";
AZStd::string accumString;
for (auto&& stringValue : ElementsViewType(testPairVector))
{
accumString += stringValue;
}
EXPECT_EQ(expectedString, accumString);
}
TEST_F(RangesViewTestFixture, ElementsView_KeysAlias_CanIterateAssociativeContainerKeyType)
{
using PairType = AZStd::pair<int, const char*>;
AZStd::map testMap{ PairType{1, "Hello"}, PairType{2, "World"}, PairType{3, "Sun"}, PairType{45, "RandomText"} };
int accumResult{};
for (int key : AZStd::ranges::views::keys(testMap))
{
accumResult += key;
}
EXPECT_EQ(51, accumResult);
}
TEST_F(RangesViewTestFixture, ElementsView_ValuesAlias_CanIterateAssociativeContainerMappedType)
{
using PairType = AZStd::pair<int, const char*>;
AZStd::map testMap{ PairType{1, "Hello"}, PairType{2, "World"}, PairType{3, "Sun"}, PairType{45, "RandomText"} };
AZStd::string accumResult{};
for (const char* value : AZStd::ranges::views::values(testMap))
{
accumResult += value;
}
EXPECT_EQ("HelloWorldSunRandomText", accumResult);
}
}
+2 -17
View File
@@ -7,28 +7,13 @@
*/
#include <AzCore/UnitTest/UnitTest.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzTest/AzTest.h>
#if defined(HAVE_BENCHMARK)
namespace AzCore
{
class AzCoreBenchmarkEnvironment
: public AZ::Test::BenchmarkEnvironmentBase
{
void SetUpBenchmark() override
{
AZ::AllocatorInstance<AZ::SystemAllocator>::Create();
}
void TearDownBenchmark() override
{
AZ::AllocatorInstance<AZ::SystemAllocator>::Destroy();
}
};
}
AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV, AzCore::AzCoreBenchmarkEnvironment)
AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV, UnitTest::ScopedAllocatorBenchmarkEnvironment)
#else
@@ -291,7 +291,7 @@ namespace Benchmark
for (auto _ : state)
{
state.PauseTiming();
AZStd::vector<void*>& perThreadAllocations = base::GetPerThreadAllocations(state.thread_index);
const size_t numberOfAllocations = perThreadAllocations.size();
size_t totalAllocationSize = 0;
@@ -300,7 +300,7 @@ namespace Benchmark
const AllocationSizeArray& allocationArray = s_allocationSizes[TAllocationSize];
const size_t allocationSize = allocationArray[allocationIndex % allocationArray.size()];
totalAllocationSize += allocationSize;
state.ResumeTiming();
perThreadAllocations[allocationIndex] = TestAllocatorType::Allocate(allocationSize, 0);
state.PauseTiming();
@@ -319,6 +319,8 @@ namespace Benchmark
TestAllocatorType::GarbageCollect();
state.SetItemsProcessed(numberOfAllocations);
state.ResumeTiming();
}
}
};
@@ -364,6 +366,8 @@ namespace Benchmark
state.SetItemsProcessed(numberOfAllocations);
TestAllocatorType::GarbageCollect();
state.ResumeTiming();
}
}
};
@@ -519,6 +523,8 @@ namespace Benchmark
state.SetItemsProcessed(itemsProcessed);
TestAllocatorType::GarbageCollect();
state.ResumeTiming();
}
}
};
@@ -207,7 +207,9 @@ set(FILES
AZStd/Optional.cpp
AZStd/Pair.cpp
AZStd/Parallel.cpp
AZStd/RangesAlgorithmTests.cpp
AZStd/RangesTests.cpp
AZStd/RangesViewTests.cpp
AZStd/ScopedLockTests.cpp
AZStd/SetsIntrusive.cpp
AZStd/SmartPtr.cpp