| // Copyright 2022 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "absl/functional/any_invocable.h" |
| |
| #include <cstddef> |
| #include <initializer_list> |
| #include <memory> |
| #include <numeric> |
| #include <type_traits> |
| |
| #include "gtest/gtest.h" |
| #include "absl/base/config.h" |
| #include "absl/meta/type_traits.h" |
| #include "absl/utility/utility.h" |
| |
| static_assert(absl::internal_any_invocable::kStorageSize >= sizeof(void*), |
| "These tests assume that the small object storage is at least " |
| "the size of a pointer."); |
| |
| namespace { |
| |
| // Helper macro used to avoid spelling `noexcept` in language versions older |
| // than C++17, where it is not part of the type system, in order to avoid |
| // compilation failures and internal compiler errors. |
| #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L |
| #define ABSL_INTERNAL_NOEXCEPT_SPEC(noex) noexcept(noex) |
| #else |
| #define ABSL_INTERNAL_NOEXCEPT_SPEC(noex) |
| #endif |
| |
| // A dummy type we use when passing qualifiers to metafunctions |
| struct _ {}; |
| |
| template <class T> |
| struct Wrapper { |
| template <class U, |
| class = absl::enable_if_t<std::is_convertible<U, T>::value>> |
| Wrapper(U&&); // NOLINT |
| }; |
| |
| // This will cause a recursive trait instantiation if the SFINAE checks are |
| // not ordered correctly for constructibility. |
| static_assert(std::is_constructible<Wrapper<absl::AnyInvocable<void()>>, |
| Wrapper<absl::AnyInvocable<void()>>>::value, |
| ""); |
| |
| // A metafunction that takes the cv and l-value reference qualifiers that were |
| // associated with a function type (here passed via qualifiers of an object |
| // type), and . |
| template <class Qualifiers, class This> |
| struct QualifiersForThisImpl { |
| static_assert(std::is_object<This>::value, ""); |
| using type = |
| absl::conditional_t<std::is_const<Qualifiers>::value, const This, This>&; |
| }; |
| |
| template <class Qualifiers, class This> |
| struct QualifiersForThisImpl<Qualifiers&, This> |
| : QualifiersForThisImpl<Qualifiers, This> {}; |
| |
| template <class Qualifiers, class This> |
| struct QualifiersForThisImpl<Qualifiers&&, This> { |
| static_assert(std::is_object<This>::value, ""); |
| using type = |
| absl::conditional_t<std::is_const<Qualifiers>::value, const This, This>&&; |
| }; |
| |
| template <class Qualifiers, class This> |
| using QualifiersForThis = |
| typename QualifiersForThisImpl<Qualifiers, This>::type; |
| |
| // A metafunction that takes the cv and l-value reference qualifier of T and |
| // applies them to U's function type qualifiers. |
| template <class T, class Fun> |
| struct GiveQualifiersToFunImpl; |
| |
| template <class T, class R, class... P> |
| struct GiveQualifiersToFunImpl<T, R(P...)> { |
| using type = |
| absl::conditional_t<std::is_const<T>::value, R(P...) const, R(P...)>; |
| }; |
| |
| template <class T, class R, class... P> |
| struct GiveQualifiersToFunImpl<T&, R(P...)> { |
| using type = |
| absl::conditional_t<std::is_const<T>::value, R(P...) const&, R(P...)&>; |
| }; |
| |
| template <class T, class R, class... P> |
| struct GiveQualifiersToFunImpl<T&&, R(P...)> { |
| using type = |
| absl::conditional_t<std::is_const<T>::value, R(P...) const&&, R(P...) &&>; |
| }; |
| |
| // If noexcept is a part of the type system, then provide the noexcept forms. |
| #if defined(__cpp_noexcept_function_type) |
| |
| template <class T, class R, class... P> |
| struct GiveQualifiersToFunImpl<T, R(P...) noexcept> { |
| using type = absl::conditional_t<std::is_const<T>::value, |
| R(P...) const noexcept, R(P...) noexcept>; |
| }; |
| |
| template <class T, class R, class... P> |
| struct GiveQualifiersToFunImpl<T&, R(P...) noexcept> { |
| using type = |
| absl::conditional_t<std::is_const<T>::value, R(P...) const & noexcept, |
| R(P...) & noexcept>; |
| }; |
| |
| template <class T, class R, class... P> |
| struct GiveQualifiersToFunImpl<T&&, R(P...) noexcept> { |
| using type = |
| absl::conditional_t<std::is_const<T>::value, R(P...) const && noexcept, |
| R(P...) && noexcept>; |
| }; |
| |
| #endif // defined(__cpp_noexcept_function_type) |
| |
| template <class T, class Fun> |
| using GiveQualifiersToFun = typename GiveQualifiersToFunImpl<T, Fun>::type; |
| |
| // This is used in template parameters to decide whether or not to use a type |
| // that fits in the small object optimization storage. |
| enum class ObjSize { small, large }; |
| |
| // A base type that is used with classes as a means to insert an |
| // appropriately-sized dummy datamember when Size is ObjSize::large so that the |
| // user's class type is guaranteed to not fit in small object storage. |
| template <ObjSize Size> |
| struct TypeErasedPadding; |
| |
| template <> |
| struct TypeErasedPadding<ObjSize::small> {}; |
| |
| template <> |
| struct TypeErasedPadding<ObjSize::large> { |
| char dummy_data[absl::internal_any_invocable::kStorageSize + 1] = {}; |
| }; |
| |
| struct Int { |
| Int(int v) noexcept : value(v) {} // NOLINT |
| #ifndef _MSC_VER |
| Int(Int&&) noexcept { |
| // NOTE: Prior to C++17, this not being called requires optimizations to |
| // take place when performing the top-level invocation. In practice, |
| // most supported compilers perform this optimization prior to C++17. |
| std::abort(); |
| } |
| #else |
| Int(Int&& v) noexcept = default; |
| #endif |
| operator int() && noexcept { return value; } // NOLINT |
| |
| int MemberFunctionAdd(int const& b, int c) noexcept { // NOLINT |
| return value + b + c; |
| } |
| |
| int value; |
| }; |
| |
| enum class Movable { no, yes, nothrow, trivial }; |
| |
| enum class NothrowCall { no, yes }; |
| |
| enum class Destructible { nothrow, trivial }; |
| |
| enum class ObjAlign : std::size_t { |
| normal = absl::internal_any_invocable::kAlignment, |
| large = absl::internal_any_invocable::kAlignment * 2, |
| }; |
| |
| // A function-object template that has knobs for each property that can affect |
| // how the object is stored in AnyInvocable. |
| template <Movable Movability, Destructible Destructibility, class Qual, |
| NothrowCall CallExceptionSpec, ObjSize Size, ObjAlign Alignment> |
| struct add; |
| |
| #define ABSL_INTERNALS_ADD(qual) \ |
| template <NothrowCall CallExceptionSpec, ObjSize Size, ObjAlign Alignment> \ |
| struct alignas(static_cast<std::size_t>(Alignment)) \ |
| add<Movable::trivial, Destructible::trivial, _ qual, CallExceptionSpec, \ |
| Size, Alignment> : TypeErasedPadding<Size> { \ |
| explicit add(int state_init) : state(state_init) {} \ |
| explicit add(std::initializer_list<int> state_init, int tail) \ |
| : state(std::accumulate(std::begin(state_init), std::end(state_init), \ |
| 0) + \ |
| tail) {} \ |
| add(add&& other) = default; /*NOLINT*/ \ |
| Int operator()(int a, int b, int c) qual \ |
| ABSL_INTERNAL_NOEXCEPT_SPEC(CallExceptionSpec == NothrowCall::yes) { \ |
| return state + a + b + c; \ |
| } \ |
| int state; \ |
| }; \ |
| \ |
| template <NothrowCall CallExceptionSpec, ObjSize Size, ObjAlign Alignment> \ |
| struct alignas(static_cast<std::size_t>(Alignment)) \ |
| add<Movable::trivial, Destructible::nothrow, _ qual, CallExceptionSpec, \ |
| Size, Alignment> : TypeErasedPadding<Size> { \ |
| explicit add(int state_init) : state(state_init) {} \ |
| explicit add(std::initializer_list<int> state_init, int tail) \ |
| : state(std::accumulate(std::begin(state_init), std::end(state_init), \ |
| 0) + \ |
| tail) {} \ |
| ~add() noexcept {} \ |
| add(add&& other) = default; /*NOLINT*/ \ |
| Int operator()(int a, int b, int c) qual \ |
| ABSL_INTERNAL_NOEXCEPT_SPEC(CallExceptionSpec == NothrowCall::yes) { \ |
| return state + a + b + c; \ |
| } \ |
| int state; \ |
| } |
| |
| // Explicitly specify an empty argument. |
| // MSVC (at least up to _MSC_VER 1931, if not beyond) warns that |
| // ABSL_INTERNALS_ADD() is an undefined zero-arg overload. |
| #define ABSL_INTERNALS_NOARG |
| ABSL_INTERNALS_ADD(ABSL_INTERNALS_NOARG); |
| #undef ABSL_INTERNALS_NOARG |
| |
| ABSL_INTERNALS_ADD(const); |
| ABSL_INTERNALS_ADD(&); |
| ABSL_INTERNALS_ADD(const&); |
| ABSL_INTERNALS_ADD(&&); // NOLINT |
| ABSL_INTERNALS_ADD(const&&); // NOLINT |
| |
| #undef ABSL_INTERNALS_ADD |
| |
| template <Destructible Destructibility, class Qual, |
| NothrowCall CallExceptionSpec, ObjSize Size, ObjAlign Alignment> |
| struct add<Movable::no, Destructibility, Qual, CallExceptionSpec, Size, |
| Alignment> : private add<Movable::trivial, Destructibility, Qual, |
| CallExceptionSpec, Size, Alignment> { |
| using Base = add<Movable::trivial, Destructibility, Qual, CallExceptionSpec, |
| Size, Alignment>; |
| |
| explicit add(int state_init) : Base(state_init) {} |
| |
| explicit add(std::initializer_list<int> state_init, int tail) |
| : Base(state_init, tail) {} |
| |
| add(add&&) = delete; |
| |
| using Base::operator(); |
| using Base::state; |
| }; |
| |
| template <Destructible Destructibility, class Qual, |
| NothrowCall CallExceptionSpec, ObjSize Size, ObjAlign Alignment> |
| struct add<Movable::yes, Destructibility, Qual, CallExceptionSpec, Size, |
| Alignment> : private add<Movable::trivial, Destructibility, Qual, |
| CallExceptionSpec, Size, Alignment> { |
| using Base = add<Movable::trivial, Destructibility, Qual, CallExceptionSpec, |
| Size, Alignment>; |
| |
| explicit add(int state_init) : Base(state_init) {} |
| |
| explicit add(std::initializer_list<int> state_init, int tail) |
| : Base(state_init, tail) {} |
| |
| add(add&& other) noexcept(false) : Base(other.state) {} // NOLINT |
| |
| using Base::operator(); |
| using Base::state; |
| }; |
| |
| template <Destructible Destructibility, class Qual, |
| NothrowCall CallExceptionSpec, ObjSize Size, ObjAlign Alignment> |
| struct add<Movable::nothrow, Destructibility, Qual, CallExceptionSpec, Size, |
| Alignment> : private add<Movable::trivial, Destructibility, Qual, |
| CallExceptionSpec, Size, Alignment> { |
| using Base = add<Movable::trivial, Destructibility, Qual, CallExceptionSpec, |
| Size, Alignment>; |
| |
| explicit add(int state_init) : Base(state_init) {} |
| |
| explicit add(std::initializer_list<int> state_init, int tail) |
| : Base(state_init, tail) {} |
| |
| add(add&& other) noexcept : Base(other.state) {} |
| |
| using Base::operator(); |
| using Base::state; |
| }; |
| |
| // Actual non-member functions rather than function objects |
| Int add_function(Int&& a, int b, int c) noexcept { return a.value + b + c; } |
| |
| Int mult_function(Int&& a, int b, int c) noexcept { return a.value * b * c; } |
| |
| Int square_function(Int const&& a) noexcept { return a.value * a.value; } |
| |
| template <class Sig> |
| using AnyInvocable = absl::AnyInvocable<Sig>; |
| |
| // Instantiations of this template contains all of the compile-time parameters |
| // for a given instantiation of the AnyInvocable test suite. |
| template <Movable Movability, Destructible Destructibility, class Qual, |
| NothrowCall CallExceptionSpec, ObjSize Size, ObjAlign Alignment> |
| struct TestParams { |
| static constexpr Movable kMovability = Movability; |
| static constexpr Destructible kDestructibility = Destructibility; |
| using Qualifiers = Qual; |
| static constexpr NothrowCall kCallExceptionSpec = CallExceptionSpec; |
| static constexpr bool kIsNoexcept = kCallExceptionSpec == NothrowCall::yes; |
| static constexpr bool kIsRvalueQualified = |
| std::is_rvalue_reference<Qual>::value; |
| static constexpr ObjSize kSize = Size; |
| static constexpr ObjAlign kAlignment = Alignment; |
| |
| // These types are used when testing with member object pointer Invocables |
| using UnqualifiedUnaryFunType = int(Int const&&) |
| ABSL_INTERNAL_NOEXCEPT_SPEC(CallExceptionSpec == NothrowCall::yes); |
| using UnaryFunType = GiveQualifiersToFun<Qualifiers, UnqualifiedUnaryFunType>; |
| using MemObjPtrType = int(Int::*); |
| using UnaryAnyInvType = AnyInvocable<UnaryFunType>; |
| using UnaryThisParamType = QualifiersForThis<Qualifiers, UnaryAnyInvType>; |
| |
| template <class T> |
| static UnaryThisParamType ToUnaryThisParam(T&& fun) { |
| return static_cast<UnaryThisParamType>(fun); |
| } |
| |
| // This function type intentionally uses 3 "kinds" of parameter types. |
| // - A user-defined type |
| // - A reference type |
| // - A scalar type |
| // |
| // These were chosen because internal forwarding takes place on parameters |
| // differently depending based on type properties (scalars are forwarded by |
| // value). |
| using ResultType = Int; |
| using AnyInvocableFunTypeNotNoexcept = Int(Int, const int&, int); |
| using UnqualifiedFunType = |
| typename std::conditional<kIsNoexcept, Int(Int, const int&, int) noexcept, |
| Int(Int, const int&, int)>::type; |
| using FunType = GiveQualifiersToFun<Qualifiers, UnqualifiedFunType>; |
| using MemFunPtrType = |
| typename std::conditional<kIsNoexcept, |
| Int (Int::*)(const int&, int) noexcept, |
| Int (Int::*)(const int&, int)>::type; |
| using AnyInvType = AnyInvocable<FunType>; |
| using AddType = add<kMovability, kDestructibility, Qualifiers, |
| kCallExceptionSpec, kSize, kAlignment>; |
| using ThisParamType = QualifiersForThis<Qualifiers, AnyInvType>; |
| |
| template <class T> |
| static ThisParamType ToThisParam(T&& fun) { |
| return static_cast<ThisParamType>(fun); |
| } |
| |
| // These typedefs are used when testing void return type covariance. |
| using UnqualifiedVoidFunType = |
| typename std::conditional<kIsNoexcept, |
| void(Int, const int&, int) noexcept, |
| void(Int, const int&, int)>::type; |
| using VoidFunType = GiveQualifiersToFun<Qualifiers, UnqualifiedVoidFunType>; |
| using VoidAnyInvType = AnyInvocable<VoidFunType>; |
| using VoidThisParamType = QualifiersForThis<Qualifiers, VoidAnyInvType>; |
| |
| template <class T> |
| static VoidThisParamType ToVoidThisParam(T&& fun) { |
| return static_cast<VoidThisParamType>(fun); |
| } |
| |
| using CompatibleAnyInvocableFunType = |
| absl::conditional_t<std::is_rvalue_reference<Qual>::value, |
| GiveQualifiersToFun<const _&&, UnqualifiedFunType>, |
| GiveQualifiersToFun<const _&, UnqualifiedFunType>>; |
| |
| using CompatibleAnyInvType = AnyInvocable<CompatibleAnyInvocableFunType>; |
| |
| using IncompatibleInvocable = |
| absl::conditional_t<std::is_rvalue_reference<Qual>::value, |
| GiveQualifiersToFun<_&, UnqualifiedFunType>(_::*), |
| GiveQualifiersToFun<_&&, UnqualifiedFunType>(_::*)>; |
| }; |
| |
| // Given a member-pointer type, this metafunction yields the target type of the |
| // pointer, not including the class-type. It is used to verify that the function |
| // call operator of AnyInvocable has the proper signature, corresponding to the |
| // function type that the user provided. |
| template <class MemberPtrType> |
| struct MemberTypeOfImpl; |
| |
| template <class Class, class T> |
| struct MemberTypeOfImpl<T(Class::*)> { |
| using type = T; |
| }; |
| |
| template <class MemberPtrType> |
| using MemberTypeOf = typename MemberTypeOfImpl<MemberPtrType>::type; |
| |
| template <class T, class = void> |
| struct IsMemberSwappableImpl : std::false_type { |
| static constexpr bool kIsNothrow = false; |
| }; |
| |
| template <class T> |
| struct IsMemberSwappableImpl< |
| T, absl::void_t<decltype(std::declval<T&>().swap(std::declval<T&>()))>> |
| : std::true_type { |
| static constexpr bool kIsNothrow = |
| noexcept(std::declval<T&>().swap(std::declval<T&>())); |
| }; |
| |
| template <class T> |
| using IsMemberSwappable = IsMemberSwappableImpl<T>; |
| |
| template <class T> |
| using IsNothrowMemberSwappable = |
| std::integral_constant<bool, IsMemberSwappableImpl<T>::kIsNothrow>; |
| |
| template <class T> |
| class AnyInvTestBasic : public ::testing::Test {}; |
| |
| TYPED_TEST_SUITE_P(AnyInvTestBasic); |
| |
| TYPED_TEST_P(AnyInvTestBasic, DefaultConstruction) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| |
| AnyInvType fun; |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| |
| EXPECT_TRUE(std::is_nothrow_default_constructible<AnyInvType>::value); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, ConstructionNullptr) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| |
| AnyInvType fun = nullptr; |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| |
| EXPECT_TRUE( |
| (std::is_nothrow_constructible<AnyInvType, std::nullptr_t>::value)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, ConstructionNullFunctionPtr) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using UnqualifiedFunType = typename TypeParam::UnqualifiedFunType; |
| |
| UnqualifiedFunType* const null_fun_ptr = nullptr; |
| AnyInvType fun = null_fun_ptr; |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, ConstructionNullMemberFunctionPtr) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using MemFunPtrType = typename TypeParam::MemFunPtrType; |
| |
| const MemFunPtrType null_mem_fun_ptr = nullptr; |
| AnyInvType fun = null_mem_fun_ptr; |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, ConstructionNullMemberObjectPtr) { |
| using UnaryAnyInvType = typename TypeParam::UnaryAnyInvType; |
| using MemObjPtrType = typename TypeParam::MemObjPtrType; |
| |
| const MemObjPtrType null_mem_obj_ptr = nullptr; |
| UnaryAnyInvType fun = null_mem_obj_ptr; |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, ConstructionMemberFunctionPtr) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| |
| AnyInvType fun = &Int::MemberFunctionAdd; |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(24, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, ConstructionMemberObjectPtr) { |
| using UnaryAnyInvType = typename TypeParam::UnaryAnyInvType; |
| |
| UnaryAnyInvType fun = &Int::value; |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(13, TypeParam::ToUnaryThisParam(fun)(13)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, ConstructionFunctionReferenceDecay) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| |
| AnyInvType fun = add_function; |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(24, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, ConstructionCompatibleAnyInvocableEmpty) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using CompatibleAnyInvType = typename TypeParam::CompatibleAnyInvType; |
| |
| CompatibleAnyInvType other; |
| AnyInvType fun = std::move(other); |
| |
| EXPECT_FALSE(static_cast<bool>(other)); // NOLINT |
| EXPECT_EQ(other, nullptr); // NOLINT |
| EXPECT_EQ(nullptr, other); // NOLINT |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, ConstructionCompatibleAnyInvocableNonempty) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using CompatibleAnyInvType = typename TypeParam::CompatibleAnyInvType; |
| |
| CompatibleAnyInvType other = &add_function; |
| AnyInvType fun = std::move(other); |
| |
| EXPECT_FALSE(static_cast<bool>(other)); // NOLINT |
| EXPECT_EQ(other, nullptr); // NOLINT |
| EXPECT_EQ(nullptr, other); // NOLINT |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(24, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, ConversionToBool) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| |
| { |
| AnyInvType fun; |
| |
| // This tests contextually-convertible-to-bool. |
| EXPECT_FALSE(fun ? true : false); // NOLINT |
| |
| // Make sure that the conversion is not implicit. |
| EXPECT_TRUE( |
| (std::is_nothrow_constructible<bool, const AnyInvType&>::value)); |
| EXPECT_FALSE((std::is_convertible<const AnyInvType&, bool>::value)); |
| } |
| |
| { |
| AnyInvType fun = &add_function; |
| |
| // This tests contextually-convertible-to-bool. |
| EXPECT_TRUE(fun ? true : false); // NOLINT |
| } |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, Invocation) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| |
| using FunType = typename TypeParam::FunType; |
| using AnyInvCallType = MemberTypeOf<decltype(&AnyInvType::operator())>; |
| |
| // Make sure the function call operator of AnyInvocable always has the |
| // type that was specified via the template argument. |
| EXPECT_TRUE((std::is_same<AnyInvCallType, FunType>::value)); |
| |
| AnyInvType fun = &add_function; |
| |
| EXPECT_EQ(24, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, InPlaceConstruction) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| AnyInvType fun(absl::in_place_type<AddType>, 5); |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, InPlaceConstructionInitializerList) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| AnyInvType fun(absl::in_place_type<AddType>, {1, 2, 3, 4}, 5); |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(39, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, InPlaceNullFunPtrConstruction) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using UnqualifiedFunType = typename TypeParam::UnqualifiedFunType; |
| |
| AnyInvType fun(absl::in_place_type<UnqualifiedFunType*>, nullptr); |
| |
| // In-place construction does not lead to empty. |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, InPlaceNullFunPtrConstructionValueInit) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using UnqualifiedFunType = typename TypeParam::UnqualifiedFunType; |
| |
| AnyInvType fun(absl::in_place_type<UnqualifiedFunType*>); |
| |
| // In-place construction does not lead to empty. |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, InPlaceNullMemFunPtrConstruction) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using MemFunPtrType = typename TypeParam::MemFunPtrType; |
| |
| AnyInvType fun(absl::in_place_type<MemFunPtrType>, nullptr); |
| |
| // In-place construction does not lead to empty. |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, InPlaceNullMemFunPtrConstructionValueInit) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using MemFunPtrType = typename TypeParam::MemFunPtrType; |
| |
| AnyInvType fun(absl::in_place_type<MemFunPtrType>); |
| |
| // In-place construction does not lead to empty. |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, InPlaceNullMemObjPtrConstruction) { |
| using UnaryAnyInvType = typename TypeParam::UnaryAnyInvType; |
| using MemObjPtrType = typename TypeParam::MemObjPtrType; |
| |
| UnaryAnyInvType fun(absl::in_place_type<MemObjPtrType>, nullptr); |
| |
| // In-place construction does not lead to empty. |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, InPlaceNullMemObjPtrConstructionValueInit) { |
| using UnaryAnyInvType = typename TypeParam::UnaryAnyInvType; |
| using MemObjPtrType = typename TypeParam::MemObjPtrType; |
| |
| UnaryAnyInvType fun(absl::in_place_type<MemObjPtrType>); |
| |
| // In-place construction does not lead to empty. |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, InPlaceVoidCovarianceConstruction) { |
| using VoidAnyInvType = typename TypeParam::VoidAnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| VoidAnyInvType fun(absl::in_place_type<AddType>, 5); |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, MoveConstructionFromEmpty) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| |
| AnyInvType source_fun; |
| AnyInvType fun(std::move(source_fun)); |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| |
| EXPECT_TRUE(std::is_nothrow_move_constructible<AnyInvType>::value); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, MoveConstructionFromNonEmpty) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| AnyInvType source_fun(absl::in_place_type<AddType>, 5); |
| AnyInvType fun(std::move(source_fun)); |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| |
| EXPECT_TRUE(std::is_nothrow_move_constructible<AnyInvType>::value); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, ComparisonWithNullptrEmpty) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| |
| AnyInvType fun; |
| |
| EXPECT_TRUE(fun == nullptr); |
| EXPECT_TRUE(nullptr == fun); |
| |
| EXPECT_FALSE(fun != nullptr); |
| EXPECT_FALSE(nullptr != fun); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, ComparisonWithNullptrNonempty) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| AnyInvType fun(absl::in_place_type<AddType>, 5); |
| |
| EXPECT_FALSE(fun == nullptr); |
| EXPECT_FALSE(nullptr == fun); |
| |
| EXPECT_TRUE(fun != nullptr); |
| EXPECT_TRUE(nullptr != fun); |
| } |
| |
| TYPED_TEST_P(AnyInvTestBasic, ResultType) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using ExpectedResultType = typename TypeParam::ResultType; |
| |
| EXPECT_TRUE((std::is_same<typename AnyInvType::result_type, |
| ExpectedResultType>::value)); |
| } |
| |
| template <class T> |
| class AnyInvTestCombinatoric : public ::testing::Test {}; |
| |
| TYPED_TEST_SUITE_P(AnyInvTestCombinatoric); |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, MoveAssignEmptyEmptyLhsRhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| |
| AnyInvType source_fun; |
| AnyInvType fun; |
| |
| fun = std::move(source_fun); |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, MoveAssignEmptyLhsNonemptyRhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| AnyInvType source_fun(absl::in_place_type<AddType>, 5); |
| AnyInvType fun; |
| |
| fun = std::move(source_fun); |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, MoveAssignNonemptyEmptyLhsRhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| AnyInvType source_fun; |
| AnyInvType fun(absl::in_place_type<AddType>, 5); |
| |
| fun = std::move(source_fun); |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, MoveAssignNonemptyLhsNonemptyRhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| AnyInvType source_fun(absl::in_place_type<AddType>, 5); |
| AnyInvType fun(absl::in_place_type<AddType>, 20); |
| |
| fun = std::move(source_fun); |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, SelfMoveAssignEmpty) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| |
| AnyInvType source_fun; |
| source_fun = std::move(source_fun); |
| |
| // This space intentionally left blank. |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, SelfMoveAssignNonempty) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| AnyInvType source_fun(absl::in_place_type<AddType>, 5); |
| source_fun = std::move(source_fun); |
| |
| // This space intentionally left blank. |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, AssignNullptrEmptyLhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| |
| AnyInvType fun; |
| fun = nullptr; |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, AssignNullFunctionPtrEmptyLhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using UnqualifiedFunType = typename TypeParam::UnqualifiedFunType; |
| |
| UnqualifiedFunType* const null_fun_ptr = nullptr; |
| AnyInvType fun; |
| fun = null_fun_ptr; |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, AssignNullMemberFunctionPtrEmptyLhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using MemFunPtrType = typename TypeParam::MemFunPtrType; |
| |
| const MemFunPtrType null_mem_fun_ptr = nullptr; |
| AnyInvType fun; |
| fun = null_mem_fun_ptr; |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, AssignNullMemberObjectPtrEmptyLhs) { |
| using UnaryAnyInvType = typename TypeParam::UnaryAnyInvType; |
| using MemObjPtrType = typename TypeParam::MemObjPtrType; |
| |
| const MemObjPtrType null_mem_obj_ptr = nullptr; |
| UnaryAnyInvType fun; |
| fun = null_mem_obj_ptr; |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, AssignMemberFunctionPtrEmptyLhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| |
| AnyInvType fun; |
| fun = &Int::MemberFunctionAdd; |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(24, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, AssignMemberObjectPtrEmptyLhs) { |
| using UnaryAnyInvType = typename TypeParam::UnaryAnyInvType; |
| |
| UnaryAnyInvType fun; |
| fun = &Int::value; |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(13, TypeParam::ToUnaryThisParam(fun)(13)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, AssignFunctionReferenceDecayEmptyLhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| |
| AnyInvType fun; |
| fun = add_function; |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(24, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, |
| AssignCompatibleAnyInvocableEmptyLhsEmptyRhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using CompatibleAnyInvType = typename TypeParam::CompatibleAnyInvType; |
| |
| CompatibleAnyInvType other; |
| AnyInvType fun; |
| fun = std::move(other); |
| |
| EXPECT_FALSE(static_cast<bool>(other)); // NOLINT |
| EXPECT_EQ(other, nullptr); // NOLINT |
| EXPECT_EQ(nullptr, other); // NOLINT |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, |
| AssignCompatibleAnyInvocableEmptyLhsNonemptyRhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using CompatibleAnyInvType = typename TypeParam::CompatibleAnyInvType; |
| |
| CompatibleAnyInvType other = &add_function; |
| AnyInvType fun; |
| fun = std::move(other); |
| |
| EXPECT_FALSE(static_cast<bool>(other)); // NOLINT |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(24, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, AssignNullptrNonemptyLhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| |
| AnyInvType fun = &mult_function; |
| fun = nullptr; |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, AssignNullFunctionPtrNonemptyLhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using UnqualifiedFunType = typename TypeParam::UnqualifiedFunType; |
| |
| UnqualifiedFunType* const null_fun_ptr = nullptr; |
| AnyInvType fun = &mult_function; |
| fun = null_fun_ptr; |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, AssignNullMemberFunctionPtrNonemptyLhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using MemFunPtrType = typename TypeParam::MemFunPtrType; |
| |
| const MemFunPtrType null_mem_fun_ptr = nullptr; |
| AnyInvType fun = &mult_function; |
| fun = null_mem_fun_ptr; |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, AssignNullMemberObjectPtrNonemptyLhs) { |
| using UnaryAnyInvType = typename TypeParam::UnaryAnyInvType; |
| using MemObjPtrType = typename TypeParam::MemObjPtrType; |
| |
| const MemObjPtrType null_mem_obj_ptr = nullptr; |
| UnaryAnyInvType fun = &square_function; |
| fun = null_mem_obj_ptr; |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, AssignMemberFunctionPtrNonemptyLhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| |
| AnyInvType fun = &mult_function; |
| fun = &Int::MemberFunctionAdd; |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(24, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, AssignMemberObjectPtrNonemptyLhs) { |
| using UnaryAnyInvType = typename TypeParam::UnaryAnyInvType; |
| |
| UnaryAnyInvType fun = &square_function; |
| fun = &Int::value; |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(13, TypeParam::ToUnaryThisParam(fun)(13)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, AssignFunctionReferenceDecayNonemptyLhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| |
| AnyInvType fun = &mult_function; |
| fun = add_function; |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(24, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, |
| AssignCompatibleAnyInvocableNonemptyLhsEmptyRhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using CompatibleAnyInvType = typename TypeParam::CompatibleAnyInvType; |
| |
| CompatibleAnyInvType other; |
| AnyInvType fun = &mult_function; |
| fun = std::move(other); |
| |
| EXPECT_FALSE(static_cast<bool>(other)); // NOLINT |
| EXPECT_EQ(other, nullptr); // NOLINT |
| EXPECT_EQ(nullptr, other); // NOLINT |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, |
| AssignCompatibleAnyInvocableNonemptyLhsNonemptyRhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using CompatibleAnyInvType = typename TypeParam::CompatibleAnyInvType; |
| |
| CompatibleAnyInvType other = &add_function; |
| AnyInvType fun = &mult_function; |
| fun = std::move(other); |
| |
| EXPECT_FALSE(static_cast<bool>(other)); // NOLINT |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(24, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, SwapEmptyLhsEmptyRhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| |
| // Swap idiom |
| { |
| AnyInvType fun; |
| AnyInvType other; |
| |
| using std::swap; |
| swap(fun, other); |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| EXPECT_FALSE(static_cast<bool>(other)); |
| |
| EXPECT_TRUE( |
| absl::type_traits_internal::IsNothrowSwappable<AnyInvType>::value); |
| } |
| |
| // Member swap |
| { |
| AnyInvType fun; |
| AnyInvType other; |
| |
| fun.swap(other); |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| EXPECT_FALSE(static_cast<bool>(other)); |
| |
| EXPECT_TRUE(IsNothrowMemberSwappable<AnyInvType>::value); |
| } |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, SwapEmptyLhsNonemptyRhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| // Swap idiom |
| { |
| AnyInvType fun; |
| AnyInvType other(absl::in_place_type<AddType>, 5); |
| |
| using std::swap; |
| swap(fun, other); |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_FALSE(static_cast<bool>(other)); |
| |
| EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| |
| EXPECT_TRUE( |
| absl::type_traits_internal::IsNothrowSwappable<AnyInvType>::value); |
| } |
| |
| // Member swap |
| { |
| AnyInvType fun; |
| AnyInvType other(absl::in_place_type<AddType>, 5); |
| |
| fun.swap(other); |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_FALSE(static_cast<bool>(other)); |
| |
| EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| |
| EXPECT_TRUE(IsNothrowMemberSwappable<AnyInvType>::value); |
| } |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, SwapNonemptyLhsEmptyRhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| // Swap idiom |
| { |
| AnyInvType fun(absl::in_place_type<AddType>, 5); |
| AnyInvType other; |
| |
| using std::swap; |
| swap(fun, other); |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| EXPECT_TRUE(static_cast<bool>(other)); |
| |
| EXPECT_EQ(29, TypeParam::ToThisParam(other)(7, 8, 9).value); |
| |
| EXPECT_TRUE( |
| absl::type_traits_internal::IsNothrowSwappable<AnyInvType>::value); |
| } |
| |
| // Member swap |
| { |
| AnyInvType fun(absl::in_place_type<AddType>, 5); |
| AnyInvType other; |
| |
| fun.swap(other); |
| |
| EXPECT_FALSE(static_cast<bool>(fun)); |
| EXPECT_TRUE(static_cast<bool>(other)); |
| |
| EXPECT_EQ(29, TypeParam::ToThisParam(other)(7, 8, 9).value); |
| |
| EXPECT_TRUE(IsNothrowMemberSwappable<AnyInvType>::value); |
| } |
| } |
| |
| TYPED_TEST_P(AnyInvTestCombinatoric, SwapNonemptyLhsNonemptyRhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| // Swap idiom |
| { |
| AnyInvType fun(absl::in_place_type<AddType>, 5); |
| AnyInvType other(absl::in_place_type<AddType>, 6); |
| |
| using std::swap; |
| swap(fun, other); |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_TRUE(static_cast<bool>(other)); |
| |
| EXPECT_EQ(30, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| EXPECT_EQ(29, TypeParam::ToThisParam(other)(7, 8, 9).value); |
| |
| EXPECT_TRUE( |
| absl::type_traits_internal::IsNothrowSwappable<AnyInvType>::value); |
| } |
| |
| // Member swap |
| { |
| AnyInvType fun(absl::in_place_type<AddType>, 5); |
| AnyInvType other(absl::in_place_type<AddType>, 6); |
| |
| fun.swap(other); |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_TRUE(static_cast<bool>(other)); |
| |
| EXPECT_EQ(30, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| EXPECT_EQ(29, TypeParam::ToThisParam(other)(7, 8, 9).value); |
| |
| EXPECT_TRUE(IsNothrowMemberSwappable<AnyInvType>::value); |
| } |
| } |
| |
| template <class T> |
| class AnyInvTestMovable : public ::testing::Test {}; |
| |
| TYPED_TEST_SUITE_P(AnyInvTestMovable); |
| |
| TYPED_TEST_P(AnyInvTestMovable, ConversionConstructionUserDefinedType) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| AnyInvType fun(AddType(5)); |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| } |
| |
| TYPED_TEST_P(AnyInvTestMovable, ConversionConstructionVoidCovariance) { |
| using VoidAnyInvType = typename TypeParam::VoidAnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| VoidAnyInvType fun(AddType(5)); |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestMovable, ConversionAssignUserDefinedTypeEmptyLhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| AnyInvType fun; |
| fun = AddType(5); |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| } |
| |
| TYPED_TEST_P(AnyInvTestMovable, ConversionAssignUserDefinedTypeNonemptyLhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| AnyInvType fun = &add_function; |
| fun = AddType(5); |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| } |
| |
| TYPED_TEST_P(AnyInvTestMovable, ConversionAssignVoidCovariance) { |
| using VoidAnyInvType = typename TypeParam::VoidAnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| VoidAnyInvType fun; |
| fun = AddType(5); |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| } |
| |
| template <class T> |
| class AnyInvTestNoexceptFalse : public ::testing::Test {}; |
| |
| TYPED_TEST_SUITE_P(AnyInvTestNoexceptFalse); |
| |
| TYPED_TEST_P(AnyInvTestNoexceptFalse, ConversionConstructionConstraints) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| |
| EXPECT_TRUE((std::is_constructible< |
| AnyInvType, |
| typename TypeParam::AnyInvocableFunTypeNotNoexcept*>::value)); |
| EXPECT_FALSE(( |
| std::is_constructible<AnyInvType, |
| typename TypeParam::IncompatibleInvocable>::value)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestNoexceptFalse, ConversionAssignConstraints) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| |
| EXPECT_TRUE((std::is_assignable< |
| AnyInvType&, |
| typename TypeParam::AnyInvocableFunTypeNotNoexcept*>::value)); |
| EXPECT_FALSE( |
| (std::is_assignable<AnyInvType&, |
| typename TypeParam::IncompatibleInvocable>::value)); |
| } |
| |
| template <class T> |
| class AnyInvTestNoexceptTrue : public ::testing::Test {}; |
| |
| TYPED_TEST_SUITE_P(AnyInvTestNoexceptTrue); |
| |
| TYPED_TEST_P(AnyInvTestNoexceptTrue, ConversionConstructionConstraints) { |
| #if ABSL_INTERNAL_CPLUSPLUS_LANG < 201703L |
| GTEST_SKIP() << "Noexcept was not part of the type system before C++17."; |
| #else |
| using AnyInvType = typename TypeParam::AnyInvType; |
| |
| EXPECT_FALSE((std::is_constructible< |
| AnyInvType, |
| typename TypeParam::AnyInvocableFunTypeNotNoexcept*>::value)); |
| EXPECT_FALSE(( |
| std::is_constructible<AnyInvType, |
| typename TypeParam::IncompatibleInvocable>::value)); |
| #endif |
| } |
| |
| TYPED_TEST_P(AnyInvTestNoexceptTrue, ConversionAssignConstraints) { |
| #if ABSL_INTERNAL_CPLUSPLUS_LANG < 201703L |
| GTEST_SKIP() << "Noexcept was not part of the type system before C++17."; |
| #else |
| using AnyInvType = typename TypeParam::AnyInvType; |
| |
| EXPECT_FALSE((std::is_assignable< |
| AnyInvType&, |
| typename TypeParam::AnyInvocableFunTypeNotNoexcept*>::value)); |
| EXPECT_FALSE( |
| (std::is_assignable<AnyInvType&, |
| typename TypeParam::IncompatibleInvocable>::value)); |
| #endif |
| } |
| |
| template <class T> |
| class AnyInvTestNonRvalue : public ::testing::Test {}; |
| |
| TYPED_TEST_SUITE_P(AnyInvTestNonRvalue); |
| |
| TYPED_TEST_P(AnyInvTestNonRvalue, ConversionConstructionReferenceWrapper) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| AddType add(4); |
| AnyInvType fun = std::ref(add); |
| add.state = 5; |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(38, TypeParam::ToThisParam(fun)(10, 11, 12).value); |
| } |
| |
| TYPED_TEST_P(AnyInvTestNonRvalue, NonMoveableResultType) { |
| #if ABSL_INTERNAL_CPLUSPLUS_LANG < 201703L |
| GTEST_SKIP() << "Copy/move elision was not standard before C++17"; |
| #else |
| // Define a result type that cannot be copy- or move-constructed. |
| struct Result { |
| int x; |
| |
| explicit Result(const int x_in) : x(x_in) {} |
| Result(Result&&) = delete; |
| }; |
| |
| static_assert(!std::is_move_constructible<Result>::value, ""); |
| static_assert(!std::is_copy_constructible<Result>::value, ""); |
| |
| // Assumption check: it should nevertheless be possible to use functors that |
| // return a Result struct according to the language rules. |
| const auto return_17 = []() noexcept { return Result(17); }; |
| EXPECT_EQ(17, return_17().x); |
| |
| // Just like plain functors, it should work fine to use an AnyInvocable that |
| // returns the non-moveable type. |
| using UnqualifiedFun = |
| absl::conditional_t<TypeParam::kIsNoexcept, Result() noexcept, Result()>; |
| |
| using Fun = |
| GiveQualifiersToFun<typename TypeParam::Qualifiers, UnqualifiedFun>; |
| |
| AnyInvocable<Fun> any_inv(return_17); |
| EXPECT_EQ(17, any_inv().x); |
| #endif |
| } |
| |
| TYPED_TEST_P(AnyInvTestNonRvalue, ConversionAssignReferenceWrapperEmptyLhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| AddType add(4); |
| AnyInvType fun; |
| fun = std::ref(add); |
| add.state = 5; |
| EXPECT_TRUE( |
| (std::is_nothrow_assignable<AnyInvType&, |
| std::reference_wrapper<AddType>>::value)); |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(38, TypeParam::ToThisParam(fun)(10, 11, 12).value); |
| } |
| |
| TYPED_TEST_P(AnyInvTestNonRvalue, ConversionAssignReferenceWrapperNonemptyLhs) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| AddType add(4); |
| AnyInvType fun = &mult_function; |
| fun = std::ref(add); |
| add.state = 5; |
| EXPECT_TRUE( |
| (std::is_nothrow_assignable<AnyInvType&, |
| std::reference_wrapper<AddType>>::value)); |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| EXPECT_EQ(38, TypeParam::ToThisParam(fun)(10, 11, 12).value); |
| } |
| |
| template <class T> |
| class AnyInvTestRvalue : public ::testing::Test {}; |
| |
| TYPED_TEST_SUITE_P(AnyInvTestRvalue); |
| |
| TYPED_TEST_P(AnyInvTestRvalue, ConversionConstructionReferenceWrapper) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| EXPECT_FALSE(( |
| std::is_convertible<std::reference_wrapper<AddType>, AnyInvType>::value)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestRvalue, NonMoveableResultType) { |
| #if ABSL_INTERNAL_CPLUSPLUS_LANG < 201703L |
| GTEST_SKIP() << "Copy/move elision was not standard before C++17"; |
| #else |
| // Define a result type that cannot be copy- or move-constructed. |
| struct Result { |
| int x; |
| |
| explicit Result(const int x_in) : x(x_in) {} |
| Result(Result&&) = delete; |
| }; |
| |
| static_assert(!std::is_move_constructible<Result>::value, ""); |
| static_assert(!std::is_copy_constructible<Result>::value, ""); |
| |
| // Assumption check: it should nevertheless be possible to use functors that |
| // return a Result struct according to the language rules. |
| const auto return_17 = []() noexcept { return Result(17); }; |
| EXPECT_EQ(17, return_17().x); |
| |
| // Just like plain functors, it should work fine to use an AnyInvocable that |
| // returns the non-moveable type. |
| using UnqualifiedFun = |
| absl::conditional_t<TypeParam::kIsNoexcept, Result() noexcept, Result()>; |
| |
| using Fun = |
| GiveQualifiersToFun<typename TypeParam::Qualifiers, UnqualifiedFun>; |
| |
| EXPECT_EQ(17, AnyInvocable<Fun>(return_17)().x); |
| #endif |
| } |
| |
| TYPED_TEST_P(AnyInvTestRvalue, ConversionAssignReferenceWrapper) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| EXPECT_FALSE(( |
| std::is_assignable<AnyInvType&, std::reference_wrapper<AddType>>::value)); |
| } |
| |
| TYPED_TEST_P(AnyInvTestRvalue, NonConstCrashesOnSecondCall) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| using AddType = typename TypeParam::AddType; |
| |
| AnyInvType fun(absl::in_place_type<AddType>, 5); |
| |
| EXPECT_TRUE(static_cast<bool>(fun)); |
| std::move(fun)(7, 8, 9); |
| |
| // Ensure we're still valid |
| EXPECT_TRUE(static_cast<bool>(fun)); // NOLINT(bugprone-use-after-move) |
| |
| #if !defined(NDEBUG) || ABSL_OPTION_HARDENED == 1 |
| EXPECT_DEATH_IF_SUPPORTED(std::move(fun)(7, 8, 9), ""); |
| #endif |
| } |
| |
| // Ensure that any qualifiers (in particular &&-qualifiers) do not affect |
| // when the destructor is actually run. |
| TYPED_TEST_P(AnyInvTestRvalue, QualifierIndependentObjectLifetime) { |
| using AnyInvType = typename TypeParam::AnyInvType; |
| |
| auto refs = std::make_shared<std::nullptr_t>(); |
| { |
| AnyInvType fun([refs](auto&&...) noexcept { return 0; }); |
| EXPECT_GT(refs.use_count(), 1); |
| |
| std::move(fun)(7, 8, 9); |
| |
| // Ensure destructor hasn't run even if rref-qualified |
| EXPECT_GT(refs.use_count(), 1); |
| } |
| EXPECT_EQ(refs.use_count(), 1); |
| } |
| |
| // NOTE: This test suite originally attempted to enumerate all possible |
| // combinations of type properties but the build-time started getting too large. |
| // Instead, it is now assumed that certain parameters are orthogonal and so |
| // some combinations are elided. |
| |
| // A metafunction to form a TypeList of all cv and non-rvalue ref combinations, |
| // coupled with all of the other explicitly specified parameters. |
| template <Movable Mov, Destructible Dest, NothrowCall CallExceptionSpec, |
| ObjSize Size, ObjAlign Align> |
| using NonRvalueQualifiedTestParams = ::testing::Types< // |
| TestParams<Mov, Dest, _, CallExceptionSpec, Size, Align>, // |
| TestParams<Mov, Dest, const _, CallExceptionSpec, Size, Align>, // |
| TestParams<Mov, Dest, _&, CallExceptionSpec, Size, Align>, // |
| TestParams<Mov, Dest, const _&, CallExceptionSpec, Size, Align>>; |
| |
| // A metafunction to form a TypeList of const and non-const rvalue ref |
| // qualifiers, coupled with all of the other explicitly specified parameters. |
| template <Movable Mov, Destructible Dest, NothrowCall CallExceptionSpec, |
| ObjSize Size, ObjAlign Align> |
| using RvalueQualifiedTestParams = ::testing::Types< |
| TestParams<Mov, Dest, _&&, CallExceptionSpec, Size, Align>, // |
| TestParams<Mov, Dest, const _&&, CallExceptionSpec, Size, Align> // |
| >; |
| |
| // All qualifier combinations and a noexcept function type |
| using TestParameterListNonRvalueQualifiersNothrowCall = |
| NonRvalueQualifiedTestParams<Movable::trivial, Destructible::trivial, |
| NothrowCall::yes, ObjSize::small, |
| ObjAlign::normal>; |
| using TestParameterListRvalueQualifiersNothrowCall = |
| RvalueQualifiedTestParams<Movable::trivial, Destructible::trivial, |
| NothrowCall::yes, ObjSize::small, |
| ObjAlign::normal>; |
| |
| // All qualifier combinations and a non-noexcept function type |
| using TestParameterListNonRvalueQualifiersCallMayThrow = |
| NonRvalueQualifiedTestParams<Movable::trivial, Destructible::trivial, |
| NothrowCall::no, ObjSize::small, |
| ObjAlign::normal>; |
| using TestParameterListRvalueQualifiersCallMayThrow = |
| RvalueQualifiedTestParams<Movable::trivial, Destructible::trivial, |
| NothrowCall::no, ObjSize::small, |
| ObjAlign::normal>; |
| |
| // Lists of various cases that should lead to remote storage |
| using TestParameterListRemoteMovable = ::testing::Types< |
| // "Normal" aligned types that are large and have trivial destructors |
| TestParams<Movable::trivial, Destructible::trivial, _, NothrowCall::no, |
| ObjSize::large, ObjAlign::normal>, // |
| TestParams<Movable::nothrow, Destructible::trivial, _, NothrowCall::no, |
| ObjSize::large, ObjAlign::normal>, // |
| TestParams<Movable::yes, Destructible::trivial, _, NothrowCall::no, |
| ObjSize::small, ObjAlign::normal>, // |
| TestParams<Movable::yes, Destructible::trivial, _, NothrowCall::no, |
| ObjSize::large, ObjAlign::normal>, // |
| |
| // Same as above but with non-trivial destructors |
| TestParams<Movable::trivial, Destructible::nothrow, _, NothrowCall::no, |
| ObjSize::large, ObjAlign::normal>, // |
| TestParams<Movable::nothrow, Destructible::nothrow, _, NothrowCall::no, |
| ObjSize::large, ObjAlign::normal>, // |
| TestParams<Movable::yes, Destructible::nothrow, _, NothrowCall::no, |
| ObjSize::small, ObjAlign::normal>, // |
| TestParams<Movable::yes, Destructible::nothrow, _, NothrowCall::no, |
| ObjSize::large, ObjAlign::normal> // |
| |
| // Dynamic memory allocation for over-aligned data was introduced in C++17. |
| // See https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0035r4.html |
| #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L |
| // Types that must use remote storage because of a large alignment. |
| , |
| TestParams<Movable::trivial, Destructible::trivial, _, NothrowCall::no, |
| ObjSize::small, ObjAlign::large>, // |
| TestParams<Movable::nothrow, Destructible::trivial, _, NothrowCall::no, |
| ObjSize::small, ObjAlign::large>, // |
| TestParams<Movable::trivial, Destructible::nothrow, _, NothrowCall::no, |
| ObjSize::small, ObjAlign::large>, // |
| TestParams<Movable::nothrow, Destructible::nothrow, _, NothrowCall::no, |
| ObjSize::small, ObjAlign::large> // |
| #endif |
| >; |
| using TestParameterListRemoteNonMovable = ::testing::Types< |
| // "Normal" aligned types that are large and have trivial destructors |
| TestParams<Movable::no, Destructible::trivial, _, NothrowCall::no, |
| ObjSize::small, ObjAlign::normal>, // |
| TestParams<Movable::no, Destructible::trivial, _, NothrowCall::no, |
| ObjSize::large, ObjAlign::normal>, // |
| // Same as above but with non-trivial destructors |
| TestParams<Movable::no, Destructible::nothrow, _, NothrowCall::no, |
| ObjSize::small, ObjAlign::normal>, // |
| TestParams<Movable::no, Destructible::nothrow, _, NothrowCall::no, |
| ObjSize::large, ObjAlign::normal> // |
| >; |
| |
| // Parameters that lead to local storage |
| using TestParameterListLocal = ::testing::Types< |
| // Types that meet the requirements and have trivial destructors |
| TestParams<Movable::trivial, Destructible::trivial, _, NothrowCall::no, |
| ObjSize::small, ObjAlign::normal>, // |
| TestParams<Movable::nothrow, Destructible::trivial, _, NothrowCall::no, |
| ObjSize::small, ObjAlign::normal>, // |
| |
| // Same as above but with non-trivial destructors |
| TestParams<Movable::trivial, Destructible::trivial, _, NothrowCall::no, |
| ObjSize::small, ObjAlign::normal>, // |
| TestParams<Movable::nothrow, Destructible::trivial, _, NothrowCall::no, |
| ObjSize::small, ObjAlign::normal> // |
| >; |
| |
| // All of the tests that are run for every possible combination of types. |
| REGISTER_TYPED_TEST_SUITE_P( |
| AnyInvTestBasic, DefaultConstruction, ConstructionNullptr, |
| ConstructionNullFunctionPtr, ConstructionNullMemberFunctionPtr, |
| ConstructionNullMemberObjectPtr, ConstructionMemberFunctionPtr, |
| ConstructionMemberObjectPtr, ConstructionFunctionReferenceDecay, |
| ConstructionCompatibleAnyInvocableEmpty, |
| ConstructionCompatibleAnyInvocableNonempty, InPlaceConstruction, |
| ConversionToBool, Invocation, InPlaceConstructionInitializerList, |
| InPlaceNullFunPtrConstruction, InPlaceNullFunPtrConstructionValueInit, |
| InPlaceNullMemFunPtrConstruction, InPlaceNullMemFunPtrConstructionValueInit, |
| InPlaceNullMemObjPtrConstruction, InPlaceNullMemObjPtrConstructionValueInit, |
| InPlaceVoidCovarianceConstruction, MoveConstructionFromEmpty, |
| MoveConstructionFromNonEmpty, ComparisonWithNullptrEmpty, |
| ComparisonWithNullptrNonempty, ResultType); |
| |
| INSTANTIATE_TYPED_TEST_SUITE_P( |
| NonRvalueCallMayThrow, AnyInvTestBasic, |
| TestParameterListNonRvalueQualifiersCallMayThrow); |
| INSTANTIATE_TYPED_TEST_SUITE_P(RvalueCallMayThrow, AnyInvTestBasic, |
| TestParameterListRvalueQualifiersCallMayThrow); |
| |
| INSTANTIATE_TYPED_TEST_SUITE_P(RemoteMovable, AnyInvTestBasic, |
| TestParameterListRemoteMovable); |
| INSTANTIATE_TYPED_TEST_SUITE_P(RemoteNonMovable, AnyInvTestBasic, |
| TestParameterListRemoteNonMovable); |
| |
| INSTANTIATE_TYPED_TEST_SUITE_P(Local, AnyInvTestBasic, TestParameterListLocal); |
| |
| INSTANTIATE_TYPED_TEST_SUITE_P(NonRvalueCallNothrow, AnyInvTestBasic, |
| TestParameterListNonRvalueQualifiersNothrowCall); |
| INSTANTIATE_TYPED_TEST_SUITE_P(CallNothrowRvalue, AnyInvTestBasic, |
| TestParameterListRvalueQualifiersNothrowCall); |
| |
| // Tests for functions that take two operands. |
| REGISTER_TYPED_TEST_SUITE_P( |
| AnyInvTestCombinatoric, MoveAssignEmptyEmptyLhsRhs, |
| MoveAssignEmptyLhsNonemptyRhs, MoveAssignNonemptyEmptyLhsRhs, |
| MoveAssignNonemptyLhsNonemptyRhs, SelfMoveAssignEmpty, |
| SelfMoveAssignNonempty, AssignNullptrEmptyLhs, |
| AssignNullFunctionPtrEmptyLhs, AssignNullMemberFunctionPtrEmptyLhs, |
| AssignNullMemberObjectPtrEmptyLhs, AssignMemberFunctionPtrEmptyLhs, |
| AssignMemberObjectPtrEmptyLhs, AssignFunctionReferenceDecayEmptyLhs, |
| AssignCompatibleAnyInvocableEmptyLhsEmptyRhs, |
| AssignCompatibleAnyInvocableEmptyLhsNonemptyRhs, AssignNullptrNonemptyLhs, |
| AssignNullFunctionPtrNonemptyLhs, AssignNullMemberFunctionPtrNonemptyLhs, |
| AssignNullMemberObjectPtrNonemptyLhs, AssignMemberFunctionPtrNonemptyLhs, |
| AssignMemberObjectPtrNonemptyLhs, AssignFunctionReferenceDecayNonemptyLhs, |
| AssignCompatibleAnyInvocableNonemptyLhsEmptyRhs, |
| AssignCompatibleAnyInvocableNonemptyLhsNonemptyRhs, SwapEmptyLhsEmptyRhs, |
| SwapEmptyLhsNonemptyRhs, SwapNonemptyLhsEmptyRhs, |
| SwapNonemptyLhsNonemptyRhs); |
| |
| INSTANTIATE_TYPED_TEST_SUITE_P( |
| NonRvalueCallMayThrow, AnyInvTestCombinatoric, |
| TestParameterListNonRvalueQualifiersCallMayThrow); |
| INSTANTIATE_TYPED_TEST_SUITE_P(RvalueCallMayThrow, AnyInvTestCombinatoric, |
| TestParameterListRvalueQualifiersCallMayThrow); |
| |
| INSTANTIATE_TYPED_TEST_SUITE_P(RemoteMovable, AnyInvTestCombinatoric, |
| TestParameterListRemoteMovable); |
| INSTANTIATE_TYPED_TEST_SUITE_P(RemoteNonMovable, AnyInvTestCombinatoric, |
| TestParameterListRemoteNonMovable); |
| |
| INSTANTIATE_TYPED_TEST_SUITE_P(Local, AnyInvTestCombinatoric, |
| TestParameterListLocal); |
| |
| INSTANTIATE_TYPED_TEST_SUITE_P(NonRvalueCallNothrow, AnyInvTestCombinatoric, |
| TestParameterListNonRvalueQualifiersNothrowCall); |
| INSTANTIATE_TYPED_TEST_SUITE_P(RvalueCallNothrow, AnyInvTestCombinatoric, |
| TestParameterListRvalueQualifiersNothrowCall); |
| |
| REGISTER_TYPED_TEST_SUITE_P(AnyInvTestMovable, |
| ConversionConstructionUserDefinedType, |
| ConversionConstructionVoidCovariance, |
| ConversionAssignUserDefinedTypeEmptyLhs, |
| ConversionAssignUserDefinedTypeNonemptyLhs, |
| ConversionAssignVoidCovariance); |
| |
| INSTANTIATE_TYPED_TEST_SUITE_P( |
| NonRvalueCallMayThrow, AnyInvTestMovable, |
| TestParameterListNonRvalueQualifiersCallMayThrow); |
| INSTANTIATE_TYPED_TEST_SUITE_P(RvalueCallMayThrow, AnyInvTestMovable, |
| TestParameterListRvalueQualifiersCallMayThrow); |
| |
| INSTANTIATE_TYPED_TEST_SUITE_P(RemoteMovable, AnyInvTestMovable, |
| TestParameterListRemoteMovable); |
| |
| INSTANTIATE_TYPED_TEST_SUITE_P(Local, AnyInvTestMovable, |
| TestParameterListLocal); |
| |
| INSTANTIATE_TYPED_TEST_SUITE_P(NonRvalueCallNothrow, AnyInvTestMovable, |
| TestParameterListNonRvalueQualifiersNothrowCall); |
| INSTANTIATE_TYPED_TEST_SUITE_P(RvalueCallNothrow, AnyInvTestMovable, |
| TestParameterListRvalueQualifiersNothrowCall); |
| |
| REGISTER_TYPED_TEST_SUITE_P(AnyInvTestNoexceptFalse, |
| ConversionConstructionConstraints, |
| ConversionAssignConstraints); |
| |
| INSTANTIATE_TYPED_TEST_SUITE_P( |
| NonRvalueCallMayThrow, AnyInvTestNoexceptFalse, |
| TestParameterListNonRvalueQualifiersCallMayThrow); |
| INSTANTIATE_TYPED_TEST_SUITE_P(RvalueCallMayThrow, AnyInvTestNoexceptFalse, |
| TestParameterListRvalueQualifiersCallMayThrow); |
| |
| INSTANTIATE_TYPED_TEST_SUITE_P(RemoteMovable, AnyInvTestNoexceptFalse, |
| TestParameterListRemoteMovable); |
| INSTANTIATE_TYPED_TEST_SUITE_P(RemoteNonMovable, AnyInvTestNoexceptFalse, |
| TestParameterListRemoteNonMovable); |
| |
| INSTANTIATE_TYPED_TEST_SUITE_P(Local, AnyInvTestNoexceptFalse, |
| TestParameterListLocal); |
| |
| REGISTER_TYPED_TEST_SUITE_P(AnyInvTestNoexceptTrue, |
| ConversionConstructionConstraints, |
| ConversionAssignConstraints); |
| |
| INSTANTIATE_TYPED_TEST_SUITE_P(NonRvalueCallNothrow, AnyInvTestNoexceptTrue, |
| TestParameterListNonRvalueQualifiersNothrowCall); |
| INSTANTIATE_TYPED_TEST_SUITE_P(RvalueCallNothrow, AnyInvTestNoexceptTrue, |
| TestParameterListRvalueQualifiersNothrowCall); |
| |
| REGISTER_TYPED_TEST_SUITE_P(AnyInvTestNonRvalue, |
| ConversionConstructionReferenceWrapper, |
| NonMoveableResultType, |
| ConversionAssignReferenceWrapperEmptyLhs, |
| ConversionAssignReferenceWrapperNonemptyLhs); |
| |
| INSTANTIATE_TYPED_TEST_SUITE_P( |
| NonRvalueCallMayThrow, AnyInvTestNonRvalue, |
| TestParameterListNonRvalueQualifiersCallMayThrow); |
| |
| INSTANTIATE_TYPED_TEST_SUITE_P(RemoteMovable, AnyInvTestNonRvalue, |
| TestParameterListRemoteMovable); |
| INSTANTIATE_TYPED_TEST_SUITE_P(RemoteNonMovable, AnyInvTestNonRvalue, |
| TestParameterListRemoteNonMovable); |
| |
| INSTANTIATE_TYPED_TEST_SUITE_P(Local, AnyInvTestNonRvalue, |
| TestParameterListLocal); |
| |
| INSTANTIATE_TYPED_TEST_SUITE_P(NonRvalueCallNothrow, AnyInvTestNonRvalue, |
| TestParameterListNonRvalueQualifiersNothrowCall); |
| |
| REGISTER_TYPED_TEST_SUITE_P(AnyInvTestRvalue, |
| ConversionConstructionReferenceWrapper, |
| NonMoveableResultType, |
| ConversionAssignReferenceWrapper, |
| NonConstCrashesOnSecondCall, |
| QualifierIndependentObjectLifetime); |
| |
| INSTANTIATE_TYPED_TEST_SUITE_P(RvalueCallMayThrow, AnyInvTestRvalue, |
| TestParameterListRvalueQualifiersCallMayThrow); |
| |
| INSTANTIATE_TYPED_TEST_SUITE_P(CallNothrowRvalue, AnyInvTestRvalue, |
| TestParameterListRvalueQualifiersNothrowCall); |
| |
| // Minimal SFINAE testing for platforms where we can't run the tests, but we can |
| // build binaries for. |
| static_assert( |
| std::is_convertible<void (*)(), absl::AnyInvocable<void() &&>>::value, ""); |
| static_assert(!std::is_convertible<void*, absl::AnyInvocable<void() &&>>::value, |
| ""); |
| |
| #undef ABSL_INTERNAL_NOEXCEPT_SPEC |
| |
| } // namespace |