Repo created
This commit is contained in:
parent
81b91f4139
commit
f8c34fa5ee
22732 changed files with 4815320 additions and 2 deletions
670
TMessagesProj/jni/voip/webrtc/absl/meta/type_traits.h
Normal file
670
TMessagesProj/jni/voip/webrtc/absl/meta/type_traits.h
Normal file
|
|
@ -0,0 +1,670 @@
|
|||
//
|
||||
// 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.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// type_traits.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This file contains C++11-compatible versions of standard <type_traits> API
|
||||
// functions for determining the characteristics of types. Such traits can
|
||||
// support type inference, classification, and transformation, as well as
|
||||
// make it easier to write templates based on generic type behavior.
|
||||
//
|
||||
// See https://en.cppreference.com/w/cpp/header/type_traits
|
||||
//
|
||||
// WARNING: use of many of the constructs in this header will count as "complex
|
||||
// template metaprogramming", so before proceeding, please carefully consider
|
||||
// https://google.github.io/styleguide/cppguide.html#Template_metaprogramming
|
||||
//
|
||||
// WARNING: using template metaprogramming to detect or depend on API
|
||||
// features is brittle and not guaranteed. Neither the standard library nor
|
||||
// Abseil provides any guarantee that APIs are stable in the face of template
|
||||
// metaprogramming. Use with caution.
|
||||
#ifndef ABSL_META_TYPE_TRAITS_H_
|
||||
#define ABSL_META_TYPE_TRAITS_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
|
||||
#ifdef __cpp_lib_span
|
||||
#include <span> // NOLINT(build/c++20)
|
||||
#endif
|
||||
|
||||
#ifdef ABSL_HAVE_STD_STRING_VIEW
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
// Defines the default alignment. `__STDCPP_DEFAULT_NEW_ALIGNMENT__` is a C++17
|
||||
// feature.
|
||||
#if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__)
|
||||
#define ABSL_INTERNAL_DEFAULT_NEW_ALIGNMENT __STDCPP_DEFAULT_NEW_ALIGNMENT__
|
||||
#else // defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__)
|
||||
#define ABSL_INTERNAL_DEFAULT_NEW_ALIGNMENT alignof(std::max_align_t)
|
||||
#endif // defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__)
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
namespace type_traits_internal {
|
||||
|
||||
template <typename... Ts>
|
||||
struct VoidTImpl {
|
||||
using type = void;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
// Library Fundamentals V2 TS //
|
||||
////////////////////////////////
|
||||
|
||||
// NOTE: The `is_detected` family of templates here differ from the library
|
||||
// fundamentals specification in that for library fundamentals, `Op<Args...>` is
|
||||
// evaluated as soon as the type `is_detected<Op, Args...>` undergoes
|
||||
// substitution, regardless of whether or not the `::value` is accessed. That
|
||||
// is inconsistent with all other standard traits and prevents lazy evaluation
|
||||
// in larger contexts (such as if the `is_detected` check is a trailing argument
|
||||
// of a `conjunction`. This implementation opts to instead be lazy in the same
|
||||
// way that the standard traits are (this "defect" of the detection idiom
|
||||
// specifications has been reported).
|
||||
|
||||
template <class Enabler, template <class...> class Op, class... Args>
|
||||
struct is_detected_impl {
|
||||
using type = std::false_type;
|
||||
};
|
||||
|
||||
template <template <class...> class Op, class... Args>
|
||||
struct is_detected_impl<typename VoidTImpl<Op<Args...>>::type, Op, Args...> {
|
||||
using type = std::true_type;
|
||||
};
|
||||
|
||||
template <template <class...> class Op, class... Args>
|
||||
struct is_detected : is_detected_impl<void, Op, Args...>::type {};
|
||||
|
||||
template <class Enabler, class To, template <class...> class Op, class... Args>
|
||||
struct is_detected_convertible_impl {
|
||||
using type = std::false_type;
|
||||
};
|
||||
|
||||
template <class To, template <class...> class Op, class... Args>
|
||||
struct is_detected_convertible_impl<
|
||||
typename std::enable_if<std::is_convertible<Op<Args...>, To>::value>::type,
|
||||
To, Op, Args...> {
|
||||
using type = std::true_type;
|
||||
};
|
||||
|
||||
template <class To, template <class...> class Op, class... Args>
|
||||
struct is_detected_convertible
|
||||
: is_detected_convertible_impl<void, To, Op, Args...>::type {};
|
||||
|
||||
} // namespace type_traits_internal
|
||||
|
||||
// void_t()
|
||||
//
|
||||
// Ignores the type of any its arguments and returns `void`. In general, this
|
||||
// metafunction allows you to create a general case that maps to `void` while
|
||||
// allowing specializations that map to specific types.
|
||||
//
|
||||
// This metafunction is designed to be a drop-in replacement for the C++17
|
||||
// `std::void_t` metafunction.
|
||||
//
|
||||
// NOTE: `absl::void_t` does not use the standard-specified implementation so
|
||||
// that it can remain compatible with gcc < 5.1. This can introduce slightly
|
||||
// different behavior, such as when ordering partial specializations.
|
||||
template <typename... Ts>
|
||||
using void_t = typename type_traits_internal::VoidTImpl<Ts...>::type;
|
||||
|
||||
// conjunction
|
||||
//
|
||||
// Performs a compile-time logical AND operation on the passed types (which
|
||||
// must have `::value` members convertible to `bool`. Short-circuits if it
|
||||
// encounters any `false` members (and does not compare the `::value` members
|
||||
// of any remaining arguments).
|
||||
//
|
||||
// This metafunction is designed to be a drop-in replacement for the C++17
|
||||
// `std::conjunction` metafunction.
|
||||
template <typename... Ts>
|
||||
struct conjunction : std::true_type {};
|
||||
|
||||
template <typename T, typename... Ts>
|
||||
struct conjunction<T, Ts...>
|
||||
: std::conditional<T::value, conjunction<Ts...>, T>::type {};
|
||||
|
||||
template <typename T>
|
||||
struct conjunction<T> : T {};
|
||||
|
||||
// disjunction
|
||||
//
|
||||
// Performs a compile-time logical OR operation on the passed types (which
|
||||
// must have `::value` members convertible to `bool`. Short-circuits if it
|
||||
// encounters any `true` members (and does not compare the `::value` members
|
||||
// of any remaining arguments).
|
||||
//
|
||||
// This metafunction is designed to be a drop-in replacement for the C++17
|
||||
// `std::disjunction` metafunction.
|
||||
template <typename... Ts>
|
||||
struct disjunction : std::false_type {};
|
||||
|
||||
template <typename T, typename... Ts>
|
||||
struct disjunction<T, Ts...>
|
||||
: std::conditional<T::value, T, disjunction<Ts...>>::type {};
|
||||
|
||||
template <typename T>
|
||||
struct disjunction<T> : T {};
|
||||
|
||||
// negation
|
||||
//
|
||||
// Performs a compile-time logical NOT operation on the passed type (which
|
||||
// must have `::value` members convertible to `bool`.
|
||||
//
|
||||
// This metafunction is designed to be a drop-in replacement for the C++17
|
||||
// `std::negation` metafunction.
|
||||
template <typename T>
|
||||
struct negation : std::integral_constant<bool, !T::value> {};
|
||||
|
||||
// is_function()
|
||||
//
|
||||
// Determines whether the passed type `T` is a function type.
|
||||
//
|
||||
// This metafunction is designed to be a drop-in replacement for the C++11
|
||||
// `std::is_function()` metafunction for platforms that have incomplete C++11
|
||||
// support (such as libstdc++ 4.x).
|
||||
//
|
||||
// This metafunction works because appending `const` to a type does nothing to
|
||||
// function types and reference types (and forms a const-qualified type
|
||||
// otherwise).
|
||||
template <typename T>
|
||||
struct is_function
|
||||
: std::integral_constant<
|
||||
bool, !(std::is_reference<T>::value ||
|
||||
std::is_const<typename std::add_const<T>::type>::value)> {};
|
||||
|
||||
// is_copy_assignable()
|
||||
// is_move_assignable()
|
||||
// is_trivially_destructible()
|
||||
// is_trivially_default_constructible()
|
||||
// is_trivially_move_constructible()
|
||||
// is_trivially_copy_constructible()
|
||||
// is_trivially_move_assignable()
|
||||
// is_trivially_copy_assignable()
|
||||
//
|
||||
// Historical note: Abseil once provided implementations of these type traits
|
||||
// for platforms that lacked full support. New code should prefer to use the
|
||||
// std variants.
|
||||
//
|
||||
// See the documentation for the STL <type_traits> header for more information:
|
||||
// https://en.cppreference.com/w/cpp/header/type_traits
|
||||
using std::is_copy_assignable;
|
||||
using std::is_move_assignable;
|
||||
using std::is_trivially_copy_assignable;
|
||||
using std::is_trivially_copy_constructible;
|
||||
using std::is_trivially_default_constructible;
|
||||
using std::is_trivially_destructible;
|
||||
using std::is_trivially_move_assignable;
|
||||
using std::is_trivially_move_constructible;
|
||||
|
||||
#if defined(__cpp_lib_remove_cvref) && __cpp_lib_remove_cvref >= 201711L
|
||||
template <typename T>
|
||||
using remove_cvref = std::remove_cvref<T>;
|
||||
|
||||
template <typename T>
|
||||
using remove_cvref_t = typename std::remove_cvref<T>::type;
|
||||
#else
|
||||
// remove_cvref()
|
||||
//
|
||||
// C++11 compatible implementation of std::remove_cvref which was added in
|
||||
// C++20.
|
||||
template <typename T>
|
||||
struct remove_cvref {
|
||||
using type =
|
||||
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using remove_cvref_t = typename remove_cvref<T>::type;
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// C++14 "_t" trait aliases
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
template <typename T>
|
||||
using remove_cv_t = typename std::remove_cv<T>::type;
|
||||
|
||||
template <typename T>
|
||||
using remove_const_t = typename std::remove_const<T>::type;
|
||||
|
||||
template <typename T>
|
||||
using remove_volatile_t = typename std::remove_volatile<T>::type;
|
||||
|
||||
template <typename T>
|
||||
using add_cv_t = typename std::add_cv<T>::type;
|
||||
|
||||
template <typename T>
|
||||
using add_const_t = typename std::add_const<T>::type;
|
||||
|
||||
template <typename T>
|
||||
using add_volatile_t = typename std::add_volatile<T>::type;
|
||||
|
||||
template <typename T>
|
||||
using remove_reference_t = typename std::remove_reference<T>::type;
|
||||
|
||||
template <typename T>
|
||||
using add_lvalue_reference_t = typename std::add_lvalue_reference<T>::type;
|
||||
|
||||
template <typename T>
|
||||
using add_rvalue_reference_t = typename std::add_rvalue_reference<T>::type;
|
||||
|
||||
template <typename T>
|
||||
using remove_pointer_t = typename std::remove_pointer<T>::type;
|
||||
|
||||
template <typename T>
|
||||
using add_pointer_t = typename std::add_pointer<T>::type;
|
||||
|
||||
template <typename T>
|
||||
using make_signed_t = typename std::make_signed<T>::type;
|
||||
|
||||
template <typename T>
|
||||
using make_unsigned_t = typename std::make_unsigned<T>::type;
|
||||
|
||||
template <typename T>
|
||||
using remove_extent_t = typename std::remove_extent<T>::type;
|
||||
|
||||
template <typename T>
|
||||
using remove_all_extents_t = typename std::remove_all_extents<T>::type;
|
||||
|
||||
template <typename T>
|
||||
using decay_t = typename std::decay<T>::type;
|
||||
|
||||
template <bool B, typename T = void>
|
||||
using enable_if_t = typename std::enable_if<B, T>::type;
|
||||
|
||||
template <bool B, typename T, typename F>
|
||||
using conditional_t = typename std::conditional<B, T, F>::type;
|
||||
|
||||
template <typename... T>
|
||||
using common_type_t = typename std::common_type<T...>::type;
|
||||
|
||||
template <typename T>
|
||||
using underlying_type_t = typename std::underlying_type<T>::type;
|
||||
|
||||
namespace type_traits_internal {
|
||||
|
||||
#if (defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703L) || \
|
||||
(defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
|
||||
// std::result_of is deprecated (C++17) or removed (C++20)
|
||||
template <typename>
|
||||
struct result_of;
|
||||
template <typename F, typename... Args>
|
||||
struct result_of<F(Args...)> : std::invoke_result<F, Args...> {};
|
||||
#else
|
||||
template <typename F>
|
||||
using result_of = std::result_of<F>;
|
||||
#endif
|
||||
|
||||
} // namespace type_traits_internal
|
||||
|
||||
template <typename F>
|
||||
using result_of_t = typename type_traits_internal::result_of<F>::type;
|
||||
|
||||
namespace type_traits_internal {
|
||||
// In MSVC we can't probe std::hash or stdext::hash because it triggers a
|
||||
// static_assert instead of failing substitution. Libc++ prior to 4.0
|
||||
// also used a static_assert.
|
||||
//
|
||||
#if defined(_MSC_VER) || (defined(_LIBCPP_VERSION) && \
|
||||
_LIBCPP_VERSION < 4000 && _LIBCPP_STD_VER > 11)
|
||||
#define ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 0
|
||||
#else
|
||||
#define ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 1
|
||||
#endif
|
||||
|
||||
#if !ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
|
||||
template <typename Key, typename = size_t>
|
||||
struct IsHashable : std::true_type {};
|
||||
#else // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
|
||||
template <typename Key, typename = void>
|
||||
struct IsHashable : std::false_type {};
|
||||
|
||||
template <typename Key>
|
||||
struct IsHashable<
|
||||
Key,
|
||||
absl::enable_if_t<std::is_convertible<
|
||||
decltype(std::declval<std::hash<Key>&>()(std::declval<Key const&>())),
|
||||
std::size_t>::value>> : std::true_type {};
|
||||
#endif // !ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
|
||||
|
||||
struct AssertHashEnabledHelper {
|
||||
private:
|
||||
static void Sink(...) {}
|
||||
struct NAT {};
|
||||
|
||||
template <class Key>
|
||||
static auto GetReturnType(int)
|
||||
-> decltype(std::declval<std::hash<Key>>()(std::declval<Key const&>()));
|
||||
template <class Key>
|
||||
static NAT GetReturnType(...);
|
||||
|
||||
template <class Key>
|
||||
static std::nullptr_t DoIt() {
|
||||
static_assert(IsHashable<Key>::value,
|
||||
"std::hash<Key> does not provide a call operator");
|
||||
static_assert(
|
||||
std::is_default_constructible<std::hash<Key>>::value,
|
||||
"std::hash<Key> must be default constructible when it is enabled");
|
||||
static_assert(
|
||||
std::is_copy_constructible<std::hash<Key>>::value,
|
||||
"std::hash<Key> must be copy constructible when it is enabled");
|
||||
static_assert(absl::is_copy_assignable<std::hash<Key>>::value,
|
||||
"std::hash<Key> must be copy assignable when it is enabled");
|
||||
// is_destructible is unchecked as it's implied by each of the
|
||||
// is_constructible checks.
|
||||
using ReturnType = decltype(GetReturnType<Key>(0));
|
||||
static_assert(std::is_same<ReturnType, NAT>::value ||
|
||||
std::is_same<ReturnType, size_t>::value,
|
||||
"std::hash<Key> must return size_t");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class... Ts>
|
||||
friend void AssertHashEnabled();
|
||||
};
|
||||
|
||||
template <class... Ts>
|
||||
inline void AssertHashEnabled() {
|
||||
using Helper = AssertHashEnabledHelper;
|
||||
Helper::Sink(Helper::DoIt<Ts>()...);
|
||||
}
|
||||
|
||||
} // namespace type_traits_internal
|
||||
|
||||
// An internal namespace that is required to implement the C++17 swap traits.
|
||||
// It is not further nested in type_traits_internal to avoid long symbol names.
|
||||
namespace swap_internal {
|
||||
|
||||
// Necessary for the traits.
|
||||
using std::swap;
|
||||
|
||||
// This declaration prevents global `swap` and `absl::swap` overloads from being
|
||||
// considered unless ADL picks them up.
|
||||
void swap();
|
||||
|
||||
template <class T>
|
||||
using IsSwappableImpl = decltype(swap(std::declval<T&>(), std::declval<T&>()));
|
||||
|
||||
// NOTE: This dance with the default template parameter is for MSVC.
|
||||
template <class T,
|
||||
class IsNoexcept = std::integral_constant<
|
||||
bool, noexcept(swap(std::declval<T&>(), std::declval<T&>()))>>
|
||||
using IsNothrowSwappableImpl = typename std::enable_if<IsNoexcept::value>::type;
|
||||
|
||||
// IsSwappable
|
||||
//
|
||||
// Determines whether the standard swap idiom is a valid expression for
|
||||
// arguments of type `T`.
|
||||
template <class T>
|
||||
struct IsSwappable
|
||||
: absl::type_traits_internal::is_detected<IsSwappableImpl, T> {};
|
||||
|
||||
// IsNothrowSwappable
|
||||
//
|
||||
// Determines whether the standard swap idiom is a valid expression for
|
||||
// arguments of type `T` and is noexcept.
|
||||
template <class T>
|
||||
struct IsNothrowSwappable
|
||||
: absl::type_traits_internal::is_detected<IsNothrowSwappableImpl, T> {};
|
||||
|
||||
// Swap()
|
||||
//
|
||||
// Performs the swap idiom from a namespace where valid candidates may only be
|
||||
// found in `std` or via ADL.
|
||||
template <class T, absl::enable_if_t<IsSwappable<T>::value, int> = 0>
|
||||
void Swap(T& lhs, T& rhs) noexcept(IsNothrowSwappable<T>::value) {
|
||||
swap(lhs, rhs);
|
||||
}
|
||||
|
||||
// StdSwapIsUnconstrained
|
||||
//
|
||||
// Some standard library implementations are broken in that they do not
|
||||
// constrain `std::swap`. This will effectively tell us if we are dealing with
|
||||
// one of those implementations.
|
||||
using StdSwapIsUnconstrained = IsSwappable<void()>;
|
||||
|
||||
} // namespace swap_internal
|
||||
|
||||
namespace type_traits_internal {
|
||||
|
||||
// Make the swap-related traits/function accessible from this namespace.
|
||||
using swap_internal::IsNothrowSwappable;
|
||||
using swap_internal::IsSwappable;
|
||||
using swap_internal::StdSwapIsUnconstrained;
|
||||
using swap_internal::Swap;
|
||||
|
||||
} // namespace type_traits_internal
|
||||
|
||||
// absl::is_trivially_relocatable<T>
|
||||
//
|
||||
// Detects whether a type is known to be "trivially relocatable" -- meaning it
|
||||
// can be relocated from one place to another as if by memcpy/memmove.
|
||||
// This implies that its object representation doesn't depend on its address,
|
||||
// and also none of its special member functions do anything strange.
|
||||
//
|
||||
// This trait is conservative. If it's true then the type is definitely
|
||||
// trivially relocatable, but if it's false then the type may or may not be. For
|
||||
// example, std::vector<int> is trivially relocatable on every known STL
|
||||
// implementation, but absl::is_trivially_relocatable<std::vector<int>> remains
|
||||
// false.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// if constexpr (absl::is_trivially_relocatable<T>::value) {
|
||||
// memcpy(new_location, old_location, sizeof(T));
|
||||
// } else {
|
||||
// new(new_location) T(std::move(*old_location));
|
||||
// old_location->~T();
|
||||
// }
|
||||
//
|
||||
// Upstream documentation:
|
||||
//
|
||||
// https://clang.llvm.org/docs/LanguageExtensions.html#:~:text=__is_trivially_relocatable
|
||||
|
||||
// If the compiler offers a builtin that tells us the answer, we can use that.
|
||||
// This covers all of the cases in the fallback below, plus types that opt in
|
||||
// using e.g. [[clang::trivial_abi]].
|
||||
//
|
||||
// Clang on Windows has the builtin, but it falsely claims types with a
|
||||
// user-provided destructor are trivial (http://b/275003464). So we opt out
|
||||
// there.
|
||||
//
|
||||
// TODO(b/275003464): remove the opt-out once the bug is fixed.
|
||||
//
|
||||
// Starting with Xcode 15, the Apple compiler will falsely say a type
|
||||
// with a user-provided move constructor is trivially relocatable
|
||||
// (b/324278148). We will opt out without a version check, due to
|
||||
// the fluidity of Apple versions.
|
||||
//
|
||||
// TODO(b/324278148): If all versions we use have the bug fixed, then
|
||||
// remove the condition.
|
||||
//
|
||||
// Clang on all platforms fails to detect that a type with a user-provided
|
||||
// move-assignment operator is not trivially relocatable so we also check for
|
||||
// is_trivially_move_assignable for Clang.
|
||||
//
|
||||
// TODO(b/325479096): Remove the Clang is_trivially_move_assignable version once
|
||||
// Clang's behavior is fixed.
|
||||
//
|
||||
// According to https://github.com/abseil/abseil-cpp/issues/1479, this does not
|
||||
// work with NVCC either.
|
||||
#if ABSL_HAVE_BUILTIN(__is_trivially_relocatable) && \
|
||||
(defined(__cpp_impl_trivially_relocatable) || \
|
||||
(!defined(__clang__) && !defined(__APPLE__) && !defined(__NVCC__)))
|
||||
template <class T>
|
||||
struct is_trivially_relocatable
|
||||
: std::integral_constant<bool, __is_trivially_relocatable(T)> {};
|
||||
#elif ABSL_HAVE_BUILTIN(__is_trivially_relocatable) && defined(__clang__) && \
|
||||
!(defined(_WIN32) || defined(_WIN64)) && !defined(__APPLE__) && \
|
||||
!defined(__NVCC__)
|
||||
template <class T>
|
||||
struct is_trivially_relocatable
|
||||
: std::integral_constant<
|
||||
bool, std::is_trivially_copyable<T>::value ||
|
||||
(__is_trivially_relocatable(T) &&
|
||||
std::is_trivially_move_assignable<T>::value)> {};
|
||||
#else
|
||||
// Otherwise we use a fallback that detects only those types we can feasibly
|
||||
// detect. Any type that is trivially copyable is by definition trivially
|
||||
// relocatable.
|
||||
template <class T>
|
||||
struct is_trivially_relocatable : std::is_trivially_copyable<T> {};
|
||||
#endif
|
||||
|
||||
// absl::is_constant_evaluated()
|
||||
//
|
||||
// Detects whether the function call occurs within a constant-evaluated context.
|
||||
// Returns true if the evaluation of the call occurs within the evaluation of an
|
||||
// expression or conversion that is manifestly constant-evaluated; otherwise
|
||||
// returns false.
|
||||
//
|
||||
// This function is implemented in terms of `std::is_constant_evaluated` for
|
||||
// c++20 and up. For older c++ versions, the function is implemented in terms
|
||||
// of `__builtin_is_constant_evaluated` if available, otherwise the function
|
||||
// will fail to compile.
|
||||
//
|
||||
// Applications can inspect `ABSL_HAVE_CONSTANT_EVALUATED` at compile time
|
||||
// to check if this function is supported.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// constexpr MyClass::MyClass(int param) {
|
||||
// #ifdef ABSL_HAVE_CONSTANT_EVALUATED
|
||||
// if (!absl::is_constant_evaluated()) {
|
||||
// ABSL_LOG(INFO) << "MyClass(" << param << ")";
|
||||
// }
|
||||
// #endif // ABSL_HAVE_CONSTANT_EVALUATED
|
||||
// }
|
||||
//
|
||||
// Upstream documentation:
|
||||
//
|
||||
// http://en.cppreference.com/w/cpp/types/is_constant_evaluated
|
||||
// http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#:~:text=__builtin_is_constant_evaluated
|
||||
//
|
||||
#if defined(ABSL_HAVE_CONSTANT_EVALUATED)
|
||||
constexpr bool is_constant_evaluated() noexcept {
|
||||
#ifdef __cpp_lib_is_constant_evaluated
|
||||
return std::is_constant_evaluated();
|
||||
#elif ABSL_HAVE_BUILTIN(__builtin_is_constant_evaluated)
|
||||
return __builtin_is_constant_evaluated();
|
||||
#endif
|
||||
}
|
||||
#endif // ABSL_HAVE_CONSTANT_EVALUATED
|
||||
|
||||
namespace type_traits_internal {
|
||||
|
||||
// Detects if a class's definition has declared itself to be an owner by
|
||||
// declaring
|
||||
// using absl_internal_is_view = std::true_type;
|
||||
// as a member.
|
||||
// Types that don't want either must either omit this declaration entirely, or
|
||||
// (if e.g. inheriting from a base class) define the member to something that
|
||||
// isn't a Boolean trait class, such as `void`.
|
||||
// Do not specialize or use this directly. It's an implementation detail.
|
||||
template <typename T, typename = void>
|
||||
struct IsOwnerImpl : std::false_type {
|
||||
static_assert(std::is_same<T, absl::remove_cvref_t<T>>::value,
|
||||
"type must lack qualifiers");
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct IsOwnerImpl<
|
||||
T,
|
||||
std::enable_if_t<std::is_class<typename T::absl_internal_is_view>::value>>
|
||||
: absl::negation<typename T::absl_internal_is_view> {};
|
||||
|
||||
// A trait to determine whether a type is an owner.
|
||||
// Do *not* depend on the correctness of this trait for correct code behavior.
|
||||
// It is only a safety feature and its value may change in the future.
|
||||
// Do not specialize this; instead, define the member trait inside your type so
|
||||
// that it can be auto-detected, and to prevent ODR violations.
|
||||
// If it ever becomes possible to detect [[gsl::Owner]], we should leverage it:
|
||||
// https://wg21.link/p1179
|
||||
template <typename T>
|
||||
struct IsOwner : IsOwnerImpl<T> {};
|
||||
|
||||
template <typename T, typename Traits, typename Alloc>
|
||||
struct IsOwner<std::basic_string<T, Traits, Alloc>> : std::true_type {};
|
||||
|
||||
template <typename T, typename Alloc>
|
||||
struct IsOwner<std::vector<T, Alloc>> : std::true_type {};
|
||||
|
||||
// Detects if a class's definition has declared itself to be a view by declaring
|
||||
// using absl_internal_is_view = std::true_type;
|
||||
// as a member.
|
||||
// Do not specialize or use this directly.
|
||||
template <typename T, typename = void>
|
||||
struct IsViewImpl : std::false_type {
|
||||
static_assert(std::is_same<T, absl::remove_cvref_t<T>>::value,
|
||||
"type must lack qualifiers");
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct IsViewImpl<
|
||||
T,
|
||||
std::enable_if_t<std::is_class<typename T::absl_internal_is_view>::value>>
|
||||
: T::absl_internal_is_view {};
|
||||
|
||||
// A trait to determine whether a type is a view.
|
||||
// Do *not* depend on the correctness of this trait for correct code behavior.
|
||||
// It is only a safety feature, and its value may change in the future.
|
||||
// Do not specialize this trait. Instead, define the member
|
||||
// using absl_internal_is_view = std::true_type;
|
||||
// in your class to allow its detection while preventing ODR violations.
|
||||
// If it ever becomes possible to detect [[gsl::Pointer]], we should leverage
|
||||
// it: https://wg21.link/p1179
|
||||
template <typename T>
|
||||
struct IsView : std::integral_constant<bool, std::is_pointer<T>::value ||
|
||||
IsViewImpl<T>::value> {};
|
||||
|
||||
#ifdef ABSL_HAVE_STD_STRING_VIEW
|
||||
template <typename Char, typename Traits>
|
||||
struct IsView<std::basic_string_view<Char, Traits>> : std::true_type {};
|
||||
#endif
|
||||
|
||||
#ifdef __cpp_lib_span
|
||||
template <typename T>
|
||||
struct IsView<std::span<T>> : std::true_type {};
|
||||
#endif
|
||||
|
||||
// Determines whether the assignment of the given types is lifetime-bound.
|
||||
// Do *not* depend on the correctness of this trait for correct code behavior.
|
||||
// It is only a safety feature and its value may change in the future.
|
||||
// If it ever becomes possible to detect [[clang::lifetimebound]] directly,
|
||||
// we should change the implementation to leverage that.
|
||||
// Until then, we consider an assignment from an "owner" (such as std::string)
|
||||
// to a "view" (such as std::string_view) to be a lifetime-bound assignment.
|
||||
template <typename T, typename U>
|
||||
using IsLifetimeBoundAssignment = absl::conjunction<
|
||||
std::integral_constant<bool, !std::is_lvalue_reference<U>::value>,
|
||||
IsOwner<absl::remove_cvref_t<U>>, IsView<absl::remove_cvref_t<T>>>;
|
||||
|
||||
} // namespace type_traits_internal
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_META_TYPE_TRAITS_H_
|
||||
841
TMessagesProj/jni/voip/webrtc/absl/meta/type_traits_test.cc
Normal file
841
TMessagesProj/jni/voip/webrtc/absl/meta/type_traits_test.cc
Normal file
|
|
@ -0,0 +1,841 @@
|
|||
// 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.
|
||||
// TODO(b/325479096): remove the opt-out for Clang 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)
|
||||
S& operator=(S&&) { return *this; }
|
||||
S& operator=(const S&) { return *this; }
|
||||
~S() {} // NOLINT(modernize-use-equals-default)
|
||||
};
|
||||
|
||||
static_assert(absl::is_trivially_relocatable<S>::value, "");
|
||||
}
|
||||
#endif
|
||||
|
||||
// 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(__clang__) && \
|
||||
!(defined(_WIN32) || defined(_WIN64)) && !defined(__APPLE__) && \
|
||||
!defined(__NVCC__)
|
||||
// A type marked with the "trivial ABI" attribute is trivially relocatable even
|
||||
// if it has a user-provided copy constructor and a user-provided destructor.
|
||||
TEST(TriviallyRelocatable, TrivialAbi_NoUserProvidedMove) {
|
||||
struct ABSL_ATTRIBUTE_TRIVIAL_ABI S {
|
||||
S(const S&) {} // NOLINT(modernize-use-equals-default)
|
||||
~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
|
||||
Loading…
Add table
Add a link
Reference in a new issue