blob: 1e056bb285c36fe160cc7b6ee15acebb95b46e28 [file] [log] [blame]
// Copyright 2017 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/meta/type_traits.h"
#include <cstdint>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include "gtest/gtest.h"
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#ifdef ABSL_HAVE_STD_STRING_VIEW
#include <string_view>
#endif
namespace {
using ::testing::StaticAssertTypeEq;
template <typename T>
using IsOwnerAndNotView =
absl::conjunction<absl::type_traits_internal::IsOwner<T>,
absl::negation<absl::type_traits_internal::IsView<T>>>;
static_assert(IsOwnerAndNotView<std::vector<int>>::value,
"vector is an owner, not a view");
static_assert(IsOwnerAndNotView<std::string>::value,
"string is an owner, not a view");
static_assert(IsOwnerAndNotView<std::wstring>::value,
"wstring is an owner, not a view");
#ifdef ABSL_HAVE_STD_STRING_VIEW
static_assert(!IsOwnerAndNotView<std::string_view>::value,
"string_view is a view, not an owner");
static_assert(!IsOwnerAndNotView<std::wstring_view>::value,
"wstring_view is a view, not an owner");
#endif
template <class T, class U>
struct simple_pair {
T first;
U second;
};
struct Dummy {};
struct ReturnType {};
struct ConvertibleToReturnType {
operator ReturnType() const; // NOLINT
};
// Unique types used as parameter types for testing the detection idiom.
struct StructA {};
struct StructB {};
struct StructC {};
struct TypeWithBarFunction {
template <class T,
absl::enable_if_t<std::is_same<T&&, StructA&>::value, int> = 0>
ReturnType bar(T&&, const StructB&, StructC&&) &&; // NOLINT
};
struct TypeWithBarFunctionAndConvertibleReturnType {
template <class T,
absl::enable_if_t<std::is_same<T&&, StructA&>::value, int> = 0>
ConvertibleToReturnType bar(T&&, const StructB&, StructC&&) &&; // NOLINT
};
template <class Class, class... Ts>
using BarIsCallableImpl =
decltype(std::declval<Class>().bar(std::declval<Ts>()...));
template <class Class, class... T>
using BarIsCallable =
absl::type_traits_internal::is_detected<BarIsCallableImpl, Class, T...>;
template <class Class, class... T>
using BarIsCallableConv = absl::type_traits_internal::is_detected_convertible<
ReturnType, BarIsCallableImpl, Class, T...>;
// NOTE: Test of detail type_traits_internal::is_detected.
TEST(IsDetectedTest, BasicUsage) {
EXPECT_TRUE((BarIsCallable<TypeWithBarFunction, StructA&, const StructB&,
StructC>::value));
EXPECT_TRUE(
(BarIsCallable<TypeWithBarFunction, StructA&, StructB&, StructC>::value));
EXPECT_TRUE(
(BarIsCallable<TypeWithBarFunction, StructA&, StructB, StructC>::value));
EXPECT_FALSE((BarIsCallable<int, StructA&, const StructB&, StructC>::value));
EXPECT_FALSE((BarIsCallable<TypeWithBarFunction&, StructA&, const StructB&,
StructC>::value));
EXPECT_FALSE((BarIsCallable<TypeWithBarFunction, StructA, const StructB&,
StructC>::value));
}
// NOTE: Test of detail type_traits_internal::is_detected_convertible.
TEST(IsDetectedConvertibleTest, BasicUsage) {
EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunction, StructA&, const StructB&,
StructC>::value));
EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunction, StructA&, StructB&,
StructC>::value));
EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunction, StructA&, StructB,
StructC>::value));
EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunctionAndConvertibleReturnType,
StructA&, const StructB&, StructC>::value));
EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunctionAndConvertibleReturnType,
StructA&, StructB&, StructC>::value));
EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunctionAndConvertibleReturnType,
StructA&, StructB, StructC>::value));
EXPECT_FALSE(
(BarIsCallableConv<int, StructA&, const StructB&, StructC>::value));
EXPECT_FALSE((BarIsCallableConv<TypeWithBarFunction&, StructA&,
const StructB&, StructC>::value));
EXPECT_FALSE((BarIsCallableConv<TypeWithBarFunction, StructA, const StructB&,
StructC>::value));
EXPECT_FALSE((BarIsCallableConv<TypeWithBarFunctionAndConvertibleReturnType&,
StructA&, const StructB&, StructC>::value));
EXPECT_FALSE((BarIsCallableConv<TypeWithBarFunctionAndConvertibleReturnType,
StructA, const StructB&, StructC>::value));
}
TEST(VoidTTest, BasicUsage) {
StaticAssertTypeEq<void, absl::void_t<Dummy>>();
StaticAssertTypeEq<void, absl::void_t<Dummy, Dummy, Dummy>>();
}
TEST(ConjunctionTest, BasicBooleanLogic) {
EXPECT_TRUE(absl::conjunction<>::value);
EXPECT_TRUE(absl::conjunction<std::true_type>::value);
EXPECT_TRUE((absl::conjunction<std::true_type, std::true_type>::value));
EXPECT_FALSE((absl::conjunction<std::true_type, std::false_type>::value));
EXPECT_FALSE((absl::conjunction<std::false_type, std::true_type>::value));
EXPECT_FALSE((absl::conjunction<std::false_type, std::false_type>::value));
}
struct MyTrueType {
static constexpr bool value = true;
};
struct MyFalseType {
static constexpr bool value = false;
};
TEST(ConjunctionTest, ShortCircuiting) {
EXPECT_FALSE(
(absl::conjunction<std::true_type, std::false_type, Dummy>::value));
EXPECT_TRUE((std::is_base_of<MyFalseType,
absl::conjunction<std::true_type, MyFalseType,
std::false_type>>::value));
EXPECT_TRUE(
(std::is_base_of<MyTrueType,
absl::conjunction<std::true_type, MyTrueType>>::value));
}
TEST(DisjunctionTest, BasicBooleanLogic) {
EXPECT_FALSE(absl::disjunction<>::value);
EXPECT_FALSE(absl::disjunction<std::false_type>::value);
EXPECT_TRUE((absl::disjunction<std::true_type, std::true_type>::value));
EXPECT_TRUE((absl::disjunction<std::true_type, std::false_type>::value));
EXPECT_TRUE((absl::disjunction<std::false_type, std::true_type>::value));
EXPECT_FALSE((absl::disjunction<std::false_type, std::false_type>::value));
}
TEST(DisjunctionTest, ShortCircuiting) {
EXPECT_TRUE(
(absl::disjunction<std::false_type, std::true_type, Dummy>::value));
EXPECT_TRUE((
std::is_base_of<MyTrueType, absl::disjunction<std::false_type, MyTrueType,
std::true_type>>::value));
EXPECT_TRUE((
std::is_base_of<MyFalseType,
absl::disjunction<std::false_type, MyFalseType>>::value));
}
TEST(NegationTest, BasicBooleanLogic) {
EXPECT_FALSE(absl::negation<std::true_type>::value);
EXPECT_FALSE(absl::negation<MyTrueType>::value);
EXPECT_TRUE(absl::negation<std::false_type>::value);
EXPECT_TRUE(absl::negation<MyFalseType>::value);
}
// all member functions are trivial
class Trivial {
int n_;
};
struct TrivialDestructor {
~TrivialDestructor() = default;
};
struct NontrivialDestructor {
~NontrivialDestructor() {}
};
struct DeletedDestructor {
~DeletedDestructor() = delete;
};
class TrivialDefaultCtor {
public:
TrivialDefaultCtor() = default;
explicit TrivialDefaultCtor(int n) : n_(n) {}
private:
int n_;
};
class NontrivialDefaultCtor {
public:
NontrivialDefaultCtor() : n_(1) {}
private:
int n_;
};
class DeletedDefaultCtor {
public:
DeletedDefaultCtor() = delete;
explicit DeletedDefaultCtor(int n) : n_(n) {}
private:
int n_;
};
class TrivialMoveCtor {
public:
explicit TrivialMoveCtor(int n) : n_(n) {}
TrivialMoveCtor(TrivialMoveCtor&&) = default;
TrivialMoveCtor& operator=(const TrivialMoveCtor& t) {
n_ = t.n_;
return *this;
}
private:
int n_;
};
class NontrivialMoveCtor {
public:
explicit NontrivialMoveCtor(int n) : n_(n) {}
NontrivialMoveCtor(NontrivialMoveCtor&& t) noexcept : n_(t.n_) {}
NontrivialMoveCtor& operator=(const NontrivialMoveCtor&) = default;
private:
int n_;
};
class TrivialCopyCtor {
public:
explicit TrivialCopyCtor(int n) : n_(n) {}
TrivialCopyCtor(const TrivialCopyCtor&) = default;
TrivialCopyCtor& operator=(const TrivialCopyCtor& t) {
n_ = t.n_;
return *this;
}
private:
int n_;
};
class NontrivialCopyCtor {
public:
explicit NontrivialCopyCtor(int n) : n_(n) {}
NontrivialCopyCtor(const NontrivialCopyCtor& t) : n_(t.n_) {}
NontrivialCopyCtor& operator=(const NontrivialCopyCtor&) = default;
private:
int n_;
};
class DeletedCopyCtor {
public:
explicit DeletedCopyCtor(int n) : n_(n) {}
DeletedCopyCtor(const DeletedCopyCtor&) = delete;
DeletedCopyCtor& operator=(const DeletedCopyCtor&) = default;
private:
int n_;
};
class TrivialMoveAssign {
public:
explicit TrivialMoveAssign(int n) : n_(n) {}
TrivialMoveAssign(const TrivialMoveAssign& t) : n_(t.n_) {}
TrivialMoveAssign& operator=(TrivialMoveAssign&&) = default;
~TrivialMoveAssign() {} // can have nontrivial destructor
private:
int n_;
};
class NontrivialMoveAssign {
public:
explicit NontrivialMoveAssign(int n) : n_(n) {}
NontrivialMoveAssign(const NontrivialMoveAssign&) = default;
NontrivialMoveAssign& operator=(NontrivialMoveAssign&& t) noexcept {
n_ = t.n_;
return *this;
}
private:
int n_;
};
class TrivialCopyAssign {
public:
explicit TrivialCopyAssign(int n) : n_(n) {}
TrivialCopyAssign(const TrivialCopyAssign& t) : n_(t.n_) {}
TrivialCopyAssign& operator=(const TrivialCopyAssign& t) = default;
~TrivialCopyAssign() {} // can have nontrivial destructor
private:
int n_;
};
class NontrivialCopyAssign {
public:
explicit NontrivialCopyAssign(int n) : n_(n) {}
NontrivialCopyAssign(const NontrivialCopyAssign&) = default;
NontrivialCopyAssign& operator=(const NontrivialCopyAssign& t) {
n_ = t.n_;
return *this;
}
private:
int n_;
};
class DeletedCopyAssign {
public:
explicit DeletedCopyAssign(int n) : n_(n) {}
DeletedCopyAssign(const DeletedCopyAssign&) = default;
DeletedCopyAssign& operator=(const DeletedCopyAssign&) = delete;
private:
int n_;
};
struct MovableNonCopyable {
MovableNonCopyable() = default;
MovableNonCopyable(const MovableNonCopyable&) = delete;
MovableNonCopyable(MovableNonCopyable&&) = default;
MovableNonCopyable& operator=(const MovableNonCopyable&) = delete;
MovableNonCopyable& operator=(MovableNonCopyable&&) = default;
};
struct NonCopyableOrMovable {
NonCopyableOrMovable() = default;
virtual ~NonCopyableOrMovable() = default;
NonCopyableOrMovable(const NonCopyableOrMovable&) = delete;
NonCopyableOrMovable(NonCopyableOrMovable&&) = delete;
NonCopyableOrMovable& operator=(const NonCopyableOrMovable&) = delete;
NonCopyableOrMovable& operator=(NonCopyableOrMovable&&) = delete;
};
class Base {
public:
virtual ~Base() {}
};
TEST(TypeTraitsTest, TestIsFunction) {
struct Callable {
void operator()() {}
};
EXPECT_TRUE(absl::is_function<void()>::value);
EXPECT_TRUE(absl::is_function<void()&>::value);
EXPECT_TRUE(absl::is_function<void() const>::value);
EXPECT_TRUE(absl::is_function<void() noexcept>::value);
EXPECT_TRUE(absl::is_function<void(...) noexcept>::value);
EXPECT_FALSE(absl::is_function<void (*)()>::value);
EXPECT_FALSE(absl::is_function<void (&)()>::value);
EXPECT_FALSE(absl::is_function<int>::value);
EXPECT_FALSE(absl::is_function<Callable>::value);
}
TEST(TypeTraitsTest, TestRemoveCVRef) {
EXPECT_TRUE(
(std::is_same<typename absl::remove_cvref<int>::type, int>::value));
EXPECT_TRUE(
(std::is_same<typename absl::remove_cvref<int&>::type, int>::value));
EXPECT_TRUE(
(std::is_same<typename absl::remove_cvref<int&&>::type, int>::value));
EXPECT_TRUE((
std::is_same<typename absl::remove_cvref<const int&>::type, int>::value));
EXPECT_TRUE(
(std::is_same<typename absl::remove_cvref<int*>::type, int*>::value));
// Does not remove const in this case.
EXPECT_TRUE((std::is_same<typename absl::remove_cvref<const int*>::type,
const int*>::value));
EXPECT_TRUE(
(std::is_same<typename absl::remove_cvref<int[2]>::type, int[2]>::value));
EXPECT_TRUE((std::is_same<typename absl::remove_cvref<int(&)[2]>::type,
int[2]>::value));
EXPECT_TRUE((std::is_same<typename absl::remove_cvref<int(&&)[2]>::type,
int[2]>::value));
EXPECT_TRUE((std::is_same<typename absl::remove_cvref<const int[2]>::type,
int[2]>::value));
EXPECT_TRUE((std::is_same<typename absl::remove_cvref<const int(&)[2]>::type,
int[2]>::value));
EXPECT_TRUE((std::is_same<typename absl::remove_cvref<const int(&&)[2]>::type,
int[2]>::value));
}
#define ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(trait_name, ...) \
EXPECT_TRUE((std::is_same<typename std::trait_name<__VA_ARGS__>::type, \
absl::trait_name##_t<__VA_ARGS__>>::value))
TEST(TypeTraitsTest, TestRemoveCVAliases) {
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_cv, int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_cv, const int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_cv, volatile int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_cv, const volatile int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_const, int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_const, const int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_const, volatile int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_const, const volatile int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_volatile, int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_volatile, const int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_volatile, volatile int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_volatile, const volatile int);
}
TEST(TypeTraitsTest, TestAddCVAliases) {
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_cv, int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_cv, const int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_cv, volatile int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_cv, const volatile int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_const, int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_const, const int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_const, volatile int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_const, const volatile int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_volatile, int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_volatile, const int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_volatile, volatile int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_volatile, const volatile int);
}
TEST(TypeTraitsTest, TestReferenceAliases) {
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, volatile int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, int&);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, volatile int&);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, int&&);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, volatile int&&);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, volatile int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, int&);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, volatile int&);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, int&&);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, volatile int&&);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, volatile int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, int&);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, volatile int&);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, int&&);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, volatile int&&);
}
TEST(TypeTraitsTest, TestPointerAliases) {
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_pointer, int*);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_pointer, volatile int*);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_pointer, int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_pointer, volatile int);
}
TEST(TypeTraitsTest, TestSignednessAliases) {
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_signed, int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_signed, volatile int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_signed, unsigned);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_signed, volatile unsigned);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_unsigned, int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_unsigned, volatile int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_unsigned, unsigned);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_unsigned, volatile unsigned);
}
TEST(TypeTraitsTest, TestExtentAliases) {
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_extent, int[]);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_extent, int[1]);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_extent, int[1][1]);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_extent, int[][1]);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_all_extents, int[]);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_all_extents, int[1]);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_all_extents, int[1][1]);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_all_extents, int[][1]);
}
TEST(TypeTraitsTest, TestDecay) {
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, volatile int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const volatile int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int&);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const int&);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, volatile int&);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const volatile int&);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int&);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const int&);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, volatile int&);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const volatile int&);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int[1]);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int[1][1]);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int[][1]);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int());
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int(float)); // NOLINT
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int(char, ...)); // NOLINT
}
struct TypeA {};
struct TypeB {};
struct TypeC {};
struct TypeD {};
template <typename T>
struct Wrap {};
enum class TypeEnum { A, B, C, D };
struct GetTypeT {
template <typename T,
absl::enable_if_t<std::is_same<T, TypeA>::value, int> = 0>
TypeEnum operator()(Wrap<T>) const {
return TypeEnum::A;
}
template <typename T,
absl::enable_if_t<std::is_same<T, TypeB>::value, int> = 0>
TypeEnum operator()(Wrap<T>) const {
return TypeEnum::B;
}
template <typename T,
absl::enable_if_t<std::is_same<T, TypeC>::value, int> = 0>
TypeEnum operator()(Wrap<T>) const {
return TypeEnum::C;
}
// NOTE: TypeD is intentionally not handled
} constexpr GetType = {};
TEST(TypeTraitsTest, TestEnableIf) {
EXPECT_EQ(TypeEnum::A, GetType(Wrap<TypeA>()));
EXPECT_EQ(TypeEnum::B, GetType(Wrap<TypeB>()));
EXPECT_EQ(TypeEnum::C, GetType(Wrap<TypeC>()));
}
TEST(TypeTraitsTest, TestConditional) {
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(conditional, true, int, char);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(conditional, false, int, char);
}
// TODO(calabrese) Check with specialized std::common_type
TEST(TypeTraitsTest, TestCommonType) {
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int, char);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int, char, int);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int&);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int, char&);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int, char, int&);
}
TEST(TypeTraitsTest, TestUnderlyingType) {
enum class enum_char : char {};
enum class enum_long_long : long long {}; // NOLINT(runtime/int)
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(underlying_type, enum_char);
ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(underlying_type, enum_long_long);
}
struct GetTypeExtT {
template <typename T>
absl::result_of_t<const GetTypeT&(T)> operator()(T&& arg) const {
return GetType(std::forward<T>(arg));
}
TypeEnum operator()(Wrap<TypeD>) const { return TypeEnum::D; }
} constexpr GetTypeExt = {};
TEST(TypeTraitsTest, TestResultOf) {
EXPECT_EQ(TypeEnum::A, GetTypeExt(Wrap<TypeA>()));
EXPECT_EQ(TypeEnum::B, GetTypeExt(Wrap<TypeB>()));
EXPECT_EQ(TypeEnum::C, GetTypeExt(Wrap<TypeC>()));
EXPECT_EQ(TypeEnum::D, GetTypeExt(Wrap<TypeD>()));
}
namespace adl_namespace {
struct DeletedSwap {};
void swap(DeletedSwap&, DeletedSwap&) = delete;
struct SpecialNoexceptSwap {
SpecialNoexceptSwap(SpecialNoexceptSwap&&) {}
SpecialNoexceptSwap& operator=(SpecialNoexceptSwap&&) { return *this; }
~SpecialNoexceptSwap() = default;
};
void swap(SpecialNoexceptSwap&, SpecialNoexceptSwap&) noexcept {}
} // namespace adl_namespace
TEST(TypeTraitsTest, IsSwappable) {
using absl::type_traits_internal::IsSwappable;
using absl::type_traits_internal::StdSwapIsUnconstrained;
EXPECT_TRUE(IsSwappable<int>::value);
struct S {};
EXPECT_TRUE(IsSwappable<S>::value);
struct NoConstruct {
NoConstruct(NoConstruct&&) = delete;
NoConstruct& operator=(NoConstruct&&) { return *this; }
~NoConstruct() = default;
};
EXPECT_EQ(IsSwappable<NoConstruct>::value, StdSwapIsUnconstrained::value);
struct NoAssign {
NoAssign(NoAssign&&) {}
NoAssign& operator=(NoAssign&&) = delete;
~NoAssign() = default;
};
EXPECT_EQ(IsSwappable<NoAssign>::value, StdSwapIsUnconstrained::value);
EXPECT_FALSE(IsSwappable<adl_namespace::DeletedSwap>::value);
EXPECT_TRUE(IsSwappable<adl_namespace::SpecialNoexceptSwap>::value);
}
TEST(TypeTraitsTest, IsNothrowSwappable) {
using absl::type_traits_internal::IsNothrowSwappable;
using absl::type_traits_internal::StdSwapIsUnconstrained;
EXPECT_TRUE(IsNothrowSwappable<int>::value);
struct NonNoexceptMoves {
NonNoexceptMoves(NonNoexceptMoves&&) {}
NonNoexceptMoves& operator=(NonNoexceptMoves&&) { return *this; }
~NonNoexceptMoves() = default;
};
EXPECT_FALSE(IsNothrowSwappable<NonNoexceptMoves>::value);
struct NoConstruct {
NoConstruct(NoConstruct&&) = delete;
NoConstruct& operator=(NoConstruct&&) { return *this; }
~NoConstruct() = default;
};
EXPECT_FALSE(IsNothrowSwappable<NoConstruct>::value);
struct NoAssign {
NoAssign(NoAssign&&) {}
NoAssign& operator=(NoAssign&&) = delete;
~NoAssign() = default;
};
EXPECT_FALSE(IsNothrowSwappable<NoAssign>::value);
EXPECT_FALSE(IsNothrowSwappable<adl_namespace::DeletedSwap>::value);
EXPECT_TRUE(IsNothrowSwappable<adl_namespace::SpecialNoexceptSwap>::value);
}
TEST(TriviallyRelocatable, PrimitiveTypes) {
static_assert(absl::is_trivially_relocatable<int>::value, "");
static_assert(absl::is_trivially_relocatable<char>::value, "");
static_assert(absl::is_trivially_relocatable<void*>::value, "");
}
// User-defined types can be trivially relocatable as long as they don't have a
// user-provided move constructor or destructor.
TEST(TriviallyRelocatable, UserDefinedTriviallyRelocatable) {
struct S {
int x;
int y;
};
static_assert(absl::is_trivially_relocatable<S>::value, "");
}
// A user-provided move constructor disqualifies a type from being trivially
// relocatable.
TEST(TriviallyRelocatable, UserProvidedMoveConstructor) {
struct S {
S(S&&) {} // NOLINT(modernize-use-equals-default)
};
static_assert(!absl::is_trivially_relocatable<S>::value, "");
}
// A user-provided copy constructor disqualifies a type from being trivially
// relocatable.
TEST(TriviallyRelocatable, UserProvidedCopyConstructor) {
struct S {
S(const S&) {} // NOLINT(modernize-use-equals-default)
};
static_assert(!absl::is_trivially_relocatable<S>::value, "");
}
// A user-provided copy assignment operator disqualifies a type from
// being trivially relocatable.
TEST(TriviallyRelocatable, UserProvidedCopyAssignment) {
struct S {
S(const S&) = default;
S& operator=(const S&) { // NOLINT(modernize-use-equals-default)
return *this;
}
};
static_assert(!absl::is_trivially_relocatable<S>::value, "");
}
// A user-provided move assignment operator disqualifies a type from
// being trivially relocatable.
TEST(TriviallyRelocatable, UserProvidedMoveAssignment) {
struct S {
S(S&&) = default;
S& operator=(S&&) { return *this; } // NOLINT(modernize-use-equals-default)
};
static_assert(!absl::is_trivially_relocatable<S>::value, "");
}
// A user-provided destructor disqualifies a type from being trivially
// relocatable.
TEST(TriviallyRelocatable, UserProvidedDestructor) {
struct S {
~S() {} // NOLINT(modernize-use-equals-default)
};
static_assert(!absl::is_trivially_relocatable<S>::value, "");
}
// TODO(b/275003464): remove the opt-out for Clang on Windows once
// __is_trivially_relocatable is used there again.
// TODO(b/324278148): remove the opt-out for Apple once
// __is_trivially_relocatable is fixed there.
#if defined(ABSL_HAVE_ATTRIBUTE_TRIVIAL_ABI) && \
ABSL_HAVE_BUILTIN(__is_trivially_relocatable) && \
(defined(__cpp_impl_trivially_relocatable) || \
(!defined(__clang__) && !defined(__APPLE__) && !defined(__NVCC__)))
// A type marked with the "trivial ABI" attribute is trivially relocatable even
// if it has user-provided special members.
TEST(TriviallyRelocatable, TrivialAbi) {
struct ABSL_ATTRIBUTE_TRIVIAL_ABI S {
S(S&&) {} // NOLINT(modernize-use-equals-default)
S(const S&) {} // NOLINT(modernize-use-equals-default)
void operator=(S&&) {}
void operator=(const S&) {}
~S() {} // NOLINT(modernize-use-equals-default)
};
static_assert(absl::is_trivially_relocatable<S>::value, "");
}
#endif
#ifdef ABSL_HAVE_CONSTANT_EVALUATED
constexpr int64_t NegateIfConstantEvaluated(int64_t i) {
if (absl::is_constant_evaluated()) {
return -i;
} else {
return i;
}
}
#endif // ABSL_HAVE_CONSTANT_EVALUATED
TEST(IsConstantEvaluated, is_constant_evaluated) {
#ifdef ABSL_HAVE_CONSTANT_EVALUATED
constexpr int64_t constant = NegateIfConstantEvaluated(42);
EXPECT_EQ(constant, -42);
int64_t now = absl::ToUnixSeconds(absl::Now());
int64_t not_constant = NegateIfConstantEvaluated(now);
EXPECT_EQ(not_constant, now);
static int64_t const_init = NegateIfConstantEvaluated(42);
EXPECT_EQ(const_init, -42);
#else
GTEST_SKIP() << "absl::is_constant_evaluated is not defined";
#endif // ABSL_HAVE_CONSTANT_EVALUATED
}
} // namespace