1697 lines
60 KiB
C++
1697 lines
60 KiB
C++
|
// 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 <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);
|
||
|
|
||
|
EXPECT_TRUE(static_cast<bool>(fun));
|
||
|
EXPECT_EQ(38, TypeParam::ToThisParam(fun)(10, 11, 12).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);
|
||
|
|
||
|
EXPECT_TRUE(static_cast<bool>(fun));
|
||
|
EXPECT_EQ(38, TypeParam::ToThisParam(fun)(10, 11, 12).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);
|
||
|
|
||
|
EXPECT_TRUE(static_cast<bool>(fun));
|
||
|
EXPECT_EQ(38, TypeParam::ToThisParam(fun)(10, 11, 12).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;
|
||
|
|
||
|
// TODO(b/217761454): Fix this and re-enable for MSVC.
|
||
|
#ifndef _MSC_VER
|
||
|
EXPECT_FALSE((std::is_constructible<
|
||
|
AnyInvType,
|
||
|
typename TypeParam::AnyInvocableFunTypeNotNoexcept*>::value));
|
||
|
#endif
|
||
|
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;
|
||
|
|
||
|
// TODO(b/217761454): Fix this and re-enable for MSVC.
|
||
|
#ifndef _MSC_VER
|
||
|
EXPECT_FALSE((std::is_assignable<
|
||
|
AnyInvType&,
|
||
|
typename TypeParam::AnyInvocableFunTypeNotNoexcept*>::value));
|
||
|
#endif
|
||
|
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));
|
||
|
}
|
||
|
|
||
|
// 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);
|
||
|
|
||
|
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
|