/* * 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 #include #include namespace UnitTest { class ConceptsTestFixture : public LeakDetectionFixture {}; TEST_F(ConceptsTestFixture, GeneralConcepts) { // concept same_as static_assert(AZStd::same_as); static_assert(!AZStd::same_as); // concept derived_from static_assert(AZStd::derived_from); static_assert(!AZStd::derived_from); // concept convertible_to static_assert(AZStd::convertible_to); static_assert(!AZStd::convertible_to); // Test structs to validate common_reference_with and common_with concepts struct Base {}; struct TestBase : Base {}; struct TestDerived : TestBase {}; struct TestDerived2 : TestBase {}; struct NoMove { NoMove(NoMove&&) = delete; NoMove& operator=(NoMove&&) = delete; }; struct NoDestructible { ~NoDestructible() = delete; }; struct NoDefaultInitializable { NoDefaultInitializable(bool); }; struct CopyOnly { CopyOnly(const CopyOnly&) = default; }; struct MoveOnly { MoveOnly(MoveOnly&&) = default; }; struct MoveableButNotCopyable { MoveableButNotCopyable(MoveableButNotCopyable&&) = default; MoveableButNotCopyable& operator=(MoveableButNotCopyable&&) = default; }; // concept common_reference_with static_assert(AZStd::common_reference_with); static_assert(AZStd::same_as, const Base&>); static_assert(!AZStd::common_reference_with); // concept common_with static_assert(AZStd::common_with); static_assert(!AZStd::common_with); // arithmetic concepts // concept integral static_assert(AZStd::integral); static_assert(!AZStd::integral); // concept signed_integral static_assert(AZStd::signed_integral); static_assert(!AZStd::signed_integral); static_assert(!AZStd::signed_integral); // concept signed_integral static_assert(AZStd::unsigned_integral); static_assert(!AZStd::unsigned_integral); static_assert(!AZStd::unsigned_integral); // concept floating_point static_assert(AZStd::floating_point); static_assert(!AZStd::floating_point); // concept assignable_from static_assert(AZStd::assignable_from); static_assert(!AZStd::assignable_from); // concept swappable static_assert(AZStd::swappable); static_assert(!AZStd::swappable); static_assert(AZStd::swappable_with); static_assert(!AZStd::swappable_with); // concept destructible static_assert(AZStd::destructible); static_assert(!AZStd::destructible); // concept constructible_from static_assert(AZStd::constructible_from); static_assert(!AZStd::constructible_from); // concept default_initializable static_assert(AZStd::default_initializable); static_assert(!AZStd::default_initializable); // concept move_constructible static_assert(AZStd::move_constructible); static_assert(!AZStd::move_constructible); // concept copy_constructible static_assert(AZStd::copy_constructible); static_assert(!AZStd::copy_constructible); // concept equality_comparable static_assert(AZStd::equality_comparable); static_assert(!AZStd::equality_comparable); static_assert(AZStd::equality_comparable_with); static_assert(!AZStd::equality_comparable_with); static_assert(!AZStd::equality_comparable_with); // concept totally_ordered static_assert(AZStd::totally_ordered); static_assert(!AZStd::totally_ordered); static_assert(AZStd::totally_ordered_with); static_assert(!AZStd::totally_ordered_with); static_assert(!AZStd::totally_ordered_with); // concept movable static_assert(AZStd::movable); static_assert(!AZStd::movable); // concept copyable static_assert(AZStd::copyable); static_assert(!AZStd::copyable); // concept semiregular static_assert(AZStd::semiregular); static_assert(!AZStd::semiregular); // concept regular static_assert(AZStd::regular); static_assert(!AZStd::regular); // concept invocable static_assert(AZStd::invocable); static_assert(!AZStd::invocable); // concept predicate auto BooleanPredicate = [](double) -> int { return 0; }; auto BasePredicate = [](int) -> Base { return Base{}; }; static_assert(AZStd::predicate); static_assert(!AZStd::predicate); static_assert(!AZStd::predicate); // concept relation struct RelationPredicate { bool operator()(AZStd::string_view, Base) const; bool operator()(Base, AZStd::string_view) const; bool operator()(AZStd::string_view, AZStd::string_view) const; bool operator()(Base, Base) const; // non-complete relation bool operator()(Base, int) const; bool operator()(int, Base) const; }; static_assert(AZStd::relation); static_assert(AZStd::relation); static_assert(!AZStd::relation); static_assert(!AZStd::relation); //concept equivalence_relation static_assert(AZStd::equivalence_relation); static_assert(AZStd::equivalence_relation); static_assert(!AZStd::equivalence_relation); static_assert(!AZStd::equivalence_relation); //concept strict_weak_order static_assert(AZStd::strict_weak_order); static_assert(AZStd::strict_weak_order); static_assert(!AZStd::strict_weak_order); static_assert(!AZStd::strict_weak_order); } 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); static_assert(AZStd::indirectly_unary_invocable); static_assert(!AZStd::indirectly_unary_invocable); // 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); static_assert(AZStd::indirectly_regular_unary_invocable); static_assert(!AZStd::indirectly_regular_unary_invocable); // 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); static_assert(AZStd::indirect_unary_predicate); static_assert(!AZStd::indirect_unary_predicate); static_assert(!AZStd::indirect_unary_predicate); // 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); static_assert(AZStd::indirect_binary_predicate); // string_view iterator value type(char) cannot bind to int& static_assert(!AZStd::indirect_binary_predicate); // string_view is not convertible to bool static_assert(!AZStd::indirect_binary_predicate); // Ok - iter_reference_t = uint32_t& static_assert(AZStd::indirect_binary_predicate); // 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); static_assert(AZStd::indirect_equivalence_relation); static_assert(!AZStd::indirect_equivalence_relation); static_assert(!AZStd::indirect_equivalence_relation); // The "relation" concept requires that both both arguments can be bind to // either of the two binary parameters static_assert(!AZStd::indirect_equivalence_relation); // 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); static_assert(AZStd::indirect_strict_weak_order); static_assert(!AZStd::indirect_strict_weak_order); static_assert(!AZStd::indirect_strict_weak_order); // 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); // indirect_result_t type alias static_assert(AZStd::same_as, uint32_t>); // projected operator* returns indirect result of the projection function static_assert(AZStd::same_as>, int&>); } TEST_F(ConceptsTestFixture, IteratorAlgorithmConcepts) { static_assert(AZStd::indirectly_swappable); static_assert(!AZStd::indirectly_swappable); auto CharIntIndirectlyComparable = [](const char lhs, int rhs) -> bool { return lhs == rhs; }; static_assert(AZStd::indirectly_comparable); static_assert(!AZStd::indirectly_comparable); static_assert(AZStd::permutable::iterator>); // const iterator isn't indirectlly swappable or indirectly movable static_assert(!AZStd::permutable::const_iterator>); static_assert(AZStd::mergeable::iterator, AZStd::string_view::iterator, AZStd::vector::iterator>); static_assert(!AZStd::mergeable::iterator, AZStd::string_view::iterator, AZStd::string_view::iterator>); static_assert(AZStd::sortable); // Not sortable becaue the iter_reference_t = const int& which isn't swappable static_assert(!AZStd::sortable); } }