1//
2// Copyright 2017 The Abseil Authors.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// https://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16// -----------------------------------------------------------------------------
17// type_traits.h
18// -----------------------------------------------------------------------------
19//
20// This file contains C++11-compatible versions of standard <type_traits> API
21// functions for determining the characteristics of types. Such traits can
22// support type inference, classification, and transformation, as well as
23// make it easier to write templates based on generic type behavior.
24//
25// See https://en.cppreference.com/w/cpp/header/type_traits
26//
27// WARNING: use of many of the constructs in this header will count as "complex
28// template metaprogramming", so before proceeding, please carefully consider
29// https://google.github.io/styleguide/cppguide.html#Template_metaprogramming
30//
31// WARNING: using template metaprogramming to detect or depend on API
32// features is brittle and not guaranteed. Neither the standard library nor
33// Abseil provides any guarantee that APIs are stable in the face of template
34// metaprogramming. Use with caution.
35#ifndef ABSL_META_TYPE_TRAITS_H_
36#define ABSL_META_TYPE_TRAITS_H_
37
38#include <cstddef>
39#include <functional>
40#include <type_traits>
41
42#include "absl/base/attributes.h"
43#include "absl/base/config.h"
44
45// Defines the default alignment. `__STDCPP_DEFAULT_NEW_ALIGNMENT__` is a C++17
46// feature.
47#if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__)
48#define ABSL_INTERNAL_DEFAULT_NEW_ALIGNMENT __STDCPP_DEFAULT_NEW_ALIGNMENT__
49#else // defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__)
50#define ABSL_INTERNAL_DEFAULT_NEW_ALIGNMENT alignof(std::max_align_t)
51#endif // defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__)
52
53namespace absl {
54ABSL_NAMESPACE_BEGIN
55
56namespace type_traits_internal {
57
58template <typename... Ts>
59struct VoidTImpl {
60 using type = void;
61};
62
63////////////////////////////////
64// Library Fundamentals V2 TS //
65////////////////////////////////
66
67// NOTE: The `is_detected` family of templates here differ from the library
68// fundamentals specification in that for library fundamentals, `Op<Args...>` is
69// evaluated as soon as the type `is_detected<Op, Args...>` undergoes
70// substitution, regardless of whether or not the `::value` is accessed. That
71// is inconsistent with all other standard traits and prevents lazy evaluation
72// in larger contexts (such as if the `is_detected` check is a trailing argument
73// of a `conjunction`. This implementation opts to instead be lazy in the same
74// way that the standard traits are (this "defect" of the detection idiom
75// specifications has been reported).
76
77template <class Enabler, template <class...> class Op, class... Args>
78struct is_detected_impl {
79 using type = std::false_type;
80};
81
82template <template <class...> class Op, class... Args>
83struct is_detected_impl<typename VoidTImpl<Op<Args...>>::type, Op, Args...> {
84 using type = std::true_type;
85};
86
87template <template <class...> class Op, class... Args>
88struct is_detected : is_detected_impl<void, Op, Args...>::type {};
89
90template <class Enabler, class To, template <class...> class Op, class... Args>
91struct is_detected_convertible_impl {
92 using type = std::false_type;
93};
94
95template <class To, template <class...> class Op, class... Args>
96struct is_detected_convertible_impl<
97 typename std::enable_if<std::is_convertible<Op<Args...>, To>::value>::type,
98 To, Op, Args...> {
99 using type = std::true_type;
100};
101
102template <class To, template <class...> class Op, class... Args>
103struct is_detected_convertible
104 : is_detected_convertible_impl<void, To, Op, Args...>::type {};
105
106} // namespace type_traits_internal
107
108// void_t()
109//
110// Ignores the type of any its arguments and returns `void`. In general, this
111// metafunction allows you to create a general case that maps to `void` while
112// allowing specializations that map to specific types.
113//
114// This metafunction is designed to be a drop-in replacement for the C++17
115// `std::void_t` metafunction.
116//
117// NOTE: `absl::void_t` does not use the standard-specified implementation so
118// that it can remain compatible with gcc < 5.1. This can introduce slightly
119// different behavior, such as when ordering partial specializations.
120template <typename... Ts>
121using void_t = typename type_traits_internal::VoidTImpl<Ts...>::type;
122
123// conjunction
124//
125// Performs a compile-time logical AND operation on the passed types (which
126// must have `::value` members convertible to `bool`. Short-circuits if it
127// encounters any `false` members (and does not compare the `::value` members
128// of any remaining arguments).
129//
130// This metafunction is designed to be a drop-in replacement for the C++17
131// `std::conjunction` metafunction.
132template <typename... Ts>
133struct conjunction : std::true_type {};
134
135template <typename T, typename... Ts>
136struct conjunction<T, Ts...>
137 : std::conditional<T::value, conjunction<Ts...>, T>::type {};
138
139template <typename T>
140struct conjunction<T> : T {};
141
142// disjunction
143//
144// Performs a compile-time logical OR operation on the passed types (which
145// must have `::value` members convertible to `bool`. Short-circuits if it
146// encounters any `true` members (and does not compare the `::value` members
147// of any remaining arguments).
148//
149// This metafunction is designed to be a drop-in replacement for the C++17
150// `std::disjunction` metafunction.
151template <typename... Ts>
152struct disjunction : std::false_type {};
153
154template <typename T, typename... Ts>
155struct disjunction<T, Ts...> :
156 std::conditional<T::value, T, disjunction<Ts...>>::type {};
157
158template <typename T>
159struct disjunction<T> : T {};
160
161// negation
162//
163// Performs a compile-time logical NOT operation on the passed type (which
164// must have `::value` members convertible to `bool`.
165//
166// This metafunction is designed to be a drop-in replacement for the C++17
167// `std::negation` metafunction.
168template <typename T>
169struct negation : std::integral_constant<bool, !T::value> {};
170
171// is_function()
172//
173// Determines whether the passed type `T` is a function type.
174//
175// This metafunction is designed to be a drop-in replacement for the C++11
176// `std::is_function()` metafunction for platforms that have incomplete C++11
177// support (such as libstdc++ 4.x).
178//
179// This metafunction works because appending `const` to a type does nothing to
180// function types and reference types (and forms a const-qualified type
181// otherwise).
182template <typename T>
183struct is_function
184 : std::integral_constant<
185 bool, !(std::is_reference<T>::value ||
186 std::is_const<typename std::add_const<T>::type>::value)> {};
187
188// is_copy_assignable()
189// is_move_assignable()
190// is_trivially_destructible()
191// is_trivially_default_constructible()
192// is_trivially_move_constructible()
193// is_trivially_copy_constructible()
194// is_trivially_move_assignable()
195// is_trivially_copy_assignable()
196//
197// Historical note: Abseil once provided implementations of these type traits
198// for platforms that lacked full support. New code should prefer to use the
199// std variants.
200//
201// See the documentation for the STL <type_traits> header for more information:
202// https://en.cppreference.com/w/cpp/header/type_traits
203using std::is_copy_assignable;
204using std::is_move_assignable;
205using std::is_trivially_copy_assignable;
206using std::is_trivially_copy_constructible;
207using std::is_trivially_default_constructible;
208using std::is_trivially_destructible;
209using std::is_trivially_move_assignable;
210using std::is_trivially_move_constructible;
211
212#if defined(__cpp_lib_remove_cvref) && __cpp_lib_remove_cvref >= 201711L
213template <typename T>
214using remove_cvref = std::remove_cvref<T>;
215
216template <typename T>
217using remove_cvref_t = typename std::remove_cvref<T>::type;
218#else
219// remove_cvref()
220//
221// C++11 compatible implementation of std::remove_cvref which was added in
222// C++20.
223template <typename T>
224struct remove_cvref {
225 using type =
226 typename std::remove_cv<typename std::remove_reference<T>::type>::type;
227};
228
229template <typename T>
230using remove_cvref_t = typename remove_cvref<T>::type;
231#endif
232
233// -----------------------------------------------------------------------------
234// C++14 "_t" trait aliases
235// -----------------------------------------------------------------------------
236
237template <typename T>
238using remove_cv_t = typename std::remove_cv<T>::type;
239
240template <typename T>
241using remove_const_t = typename std::remove_const<T>::type;
242
243template <typename T>
244using remove_volatile_t = typename std::remove_volatile<T>::type;
245
246template <typename T>
247using add_cv_t = typename std::add_cv<T>::type;
248
249template <typename T>
250using add_const_t = typename std::add_const<T>::type;
251
252template <typename T>
253using add_volatile_t = typename std::add_volatile<T>::type;
254
255template <typename T>
256using remove_reference_t = typename std::remove_reference<T>::type;
257
258template <typename T>
259using add_lvalue_reference_t = typename std::add_lvalue_reference<T>::type;
260
261template <typename T>
262using add_rvalue_reference_t = typename std::add_rvalue_reference<T>::type;
263
264template <typename T>
265using remove_pointer_t = typename std::remove_pointer<T>::type;
266
267template <typename T>
268using add_pointer_t = typename std::add_pointer<T>::type;
269
270template <typename T>
271using make_signed_t = typename std::make_signed<T>::type;
272
273template <typename T>
274using make_unsigned_t = typename std::make_unsigned<T>::type;
275
276template <typename T>
277using remove_extent_t = typename std::remove_extent<T>::type;
278
279template <typename T>
280using remove_all_extents_t = typename std::remove_all_extents<T>::type;
281
282ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
283namespace type_traits_internal {
284// This trick to retrieve a default alignment is necessary for our
285// implementation of aligned_storage_t to be consistent with any
286// implementation of std::aligned_storage.
287template <size_t Len, typename T = std::aligned_storage<Len>>
288struct default_alignment_of_aligned_storage;
289
290template <size_t Len, size_t Align>
291struct default_alignment_of_aligned_storage<
292 Len, std::aligned_storage<Len, Align>> {
293 static constexpr size_t value = Align;
294};
295} // namespace type_traits_internal
296
297// TODO(b/260219225): std::aligned_storage(_t) is deprecated in C++23.
298template <size_t Len, size_t Align = type_traits_internal::
299 default_alignment_of_aligned_storage<Len>::value>
300using aligned_storage_t = typename std::aligned_storage<Len, Align>::type;
301ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
302
303template <typename T>
304using decay_t = typename std::decay<T>::type;
305
306template <bool B, typename T = void>
307using enable_if_t = typename std::enable_if<B, T>::type;
308
309template <bool B, typename T, typename F>
310using conditional_t = typename std::conditional<B, T, F>::type;
311
312template <typename... T>
313using common_type_t = typename std::common_type<T...>::type;
314
315template <typename T>
316using underlying_type_t = typename std::underlying_type<T>::type;
317
318
319namespace type_traits_internal {
320
321#if (defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703L) || \
322 (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
323// std::result_of is deprecated (C++17) or removed (C++20)
324template<typename> struct result_of;
325template<typename F, typename... Args>
326struct result_of<F(Args...)> : std::invoke_result<F, Args...> {};
327#else
328template<typename F> using result_of = std::result_of<F>;
329#endif
330
331} // namespace type_traits_internal
332
333template<typename F>
334using result_of_t = typename type_traits_internal::result_of<F>::type;
335
336namespace type_traits_internal {
337// In MSVC we can't probe std::hash or stdext::hash because it triggers a
338// static_assert instead of failing substitution. Libc++ prior to 4.0
339// also used a static_assert.
340//
341#if defined(_MSC_VER) || (defined(_LIBCPP_VERSION) && \
342 _LIBCPP_VERSION < 4000 && _LIBCPP_STD_VER > 11)
343#define ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 0
344#else
345#define ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 1
346#endif
347
348#if !ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
349template <typename Key, typename = size_t>
350struct IsHashable : std::true_type {};
351#else // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
352template <typename Key, typename = void>
353struct IsHashable : std::false_type {};
354
355template <typename Key>
356struct IsHashable<
357 Key,
358 absl::enable_if_t<std::is_convertible<
359 decltype(std::declval<std::hash<Key>&>()(std::declval<Key const&>())),
360 std::size_t>::value>> : std::true_type {};
361#endif // !ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
362
363struct AssertHashEnabledHelper {
364 private:
365 static void Sink(...) {}
366 struct NAT {};
367
368 template <class Key>
369 static auto GetReturnType(int)
370 -> decltype(std::declval<std::hash<Key>>()(std::declval<Key const&>()));
371 template <class Key>
372 static NAT GetReturnType(...);
373
374 template <class Key>
375 static std::nullptr_t DoIt() {
376 static_assert(IsHashable<Key>::value,
377 "std::hash<Key> does not provide a call operator");
378 static_assert(
379 std::is_default_constructible<std::hash<Key>>::value,
380 "std::hash<Key> must be default constructible when it is enabled");
381 static_assert(
382 std::is_copy_constructible<std::hash<Key>>::value,
383 "std::hash<Key> must be copy constructible when it is enabled");
384 static_assert(absl::is_copy_assignable<std::hash<Key>>::value,
385 "std::hash<Key> must be copy assignable when it is enabled");
386 // is_destructible is unchecked as it's implied by each of the
387 // is_constructible checks.
388 using ReturnType = decltype(GetReturnType<Key>(0));
389 static_assert(std::is_same<ReturnType, NAT>::value ||
390 std::is_same<ReturnType, size_t>::value,
391 "std::hash<Key> must return size_t");
392 return nullptr;
393 }
394
395 template <class... Ts>
396 friend void AssertHashEnabled();
397};
398
399template <class... Ts>
400inline void AssertHashEnabled() {
401 using Helper = AssertHashEnabledHelper;
402 Helper::Sink(Helper::DoIt<Ts>()...);
403}
404
405} // namespace type_traits_internal
406
407// An internal namespace that is required to implement the C++17 swap traits.
408// It is not further nested in type_traits_internal to avoid long symbol names.
409namespace swap_internal {
410
411// Necessary for the traits.
412using std::swap;
413
414// This declaration prevents global `swap` and `absl::swap` overloads from being
415// considered unless ADL picks them up.
416void swap();
417
418template <class T>
419using IsSwappableImpl = decltype(swap(std::declval<T&>(), std::declval<T&>()));
420
421// NOTE: This dance with the default template parameter is for MSVC.
422template <class T,
423 class IsNoexcept = std::integral_constant<
424 bool, noexcept(swap(std::declval<T&>(), std::declval<T&>()))>>
425using IsNothrowSwappableImpl = typename std::enable_if<IsNoexcept::value>::type;
426
427// IsSwappable
428//
429// Determines whether the standard swap idiom is a valid expression for
430// arguments of type `T`.
431template <class T>
432struct IsSwappable
433 : absl::type_traits_internal::is_detected<IsSwappableImpl, T> {};
434
435// IsNothrowSwappable
436//
437// Determines whether the standard swap idiom is a valid expression for
438// arguments of type `T` and is noexcept.
439template <class T>
440struct IsNothrowSwappable
441 : absl::type_traits_internal::is_detected<IsNothrowSwappableImpl, T> {};
442
443// Swap()
444//
445// Performs the swap idiom from a namespace where valid candidates may only be
446// found in `std` or via ADL.
447template <class T, absl::enable_if_t<IsSwappable<T>::value, int> = 0>
448void Swap(T& lhs, T& rhs) noexcept(IsNothrowSwappable<T>::value) {
449 swap(lhs, rhs);
450}
451
452// StdSwapIsUnconstrained
453//
454// Some standard library implementations are broken in that they do not
455// constrain `std::swap`. This will effectively tell us if we are dealing with
456// one of those implementations.
457using StdSwapIsUnconstrained = IsSwappable<void()>;
458
459} // namespace swap_internal
460
461namespace type_traits_internal {
462
463// Make the swap-related traits/function accessible from this namespace.
464using swap_internal::IsNothrowSwappable;
465using swap_internal::IsSwappable;
466using swap_internal::Swap;
467using swap_internal::StdSwapIsUnconstrained;
468
469} // namespace type_traits_internal
470
471// absl::is_trivially_relocatable<T>
472//
473// Detects whether a type is known to be "trivially relocatable" -- meaning it
474// can be relocated without invoking the constructor/destructor, using a form of
475// move elision.
476//
477// This trait is conservative, for backwards compatibility. If it's true then
478// the type is definitely trivially relocatable, but if it's false then the type
479// may or may not be.
480//
481// Example:
482//
483// if constexpr (absl::is_trivially_relocatable<T>::value) {
484// memcpy(new_location, old_location, sizeof(T));
485// } else {
486// new(new_location) T(std::move(*old_location));
487// old_location->~T();
488// }
489//
490// Upstream documentation:
491//
492// https://clang.llvm.org/docs/LanguageExtensions.html#:~:text=__is_trivially_relocatable
493
494// If the compiler offers a builtin that tells us the answer, we can use that.
495// This covers all of the cases in the fallback below, plus types that opt in
496// using e.g. [[clang::trivial_abi]].
497//
498// Clang on Windows has the builtin, but it falsely claims types with a
499// user-provided destructor are trivial (http://b/275003464). So we opt out
500// there.
501//
502// TODO(b/275003464): remove the opt-out once the bug is fixed.
503//
504// According to https://github.com/abseil/abseil-cpp/issues/1479, this does not
505// work with NVCC either.
506#if ABSL_HAVE_BUILTIN(__is_trivially_relocatable) && \
507 !(defined(__clang__) && (defined(_WIN32) || defined(_WIN64))) && \
508 !defined(__NVCC__)
509template <class T>
510struct is_trivially_relocatable
511 : std::integral_constant<bool, __is_trivially_relocatable(T)> {};
512#else
513// Otherwise we use a fallback that detects only those types we can feasibly
514// detect. Any time that has trivial move-construction and destruction
515// operations is by definition trivially relocatable.
516template <class T>
517struct is_trivially_relocatable
518 : absl::conjunction<absl::is_trivially_move_constructible<T>,
519 absl::is_trivially_destructible<T>> {};
520#endif
521
522// absl::is_constant_evaluated()
523//
524// Detects whether the function call occurs within a constant-evaluated context.
525// Returns true if the evaluation of the call occurs within the evaluation of an
526// expression or conversion that is manifestly constant-evaluated; otherwise
527// returns false.
528//
529// This function is implemented in terms of `std::is_constant_evaluated` for
530// c++20 and up. For older c++ versions, the function is implemented in terms
531// of `__builtin_is_constant_evaluated` if available, otherwise the function
532// will fail to compile.
533//
534// Applications can inspect `ABSL_HAVE_CONSTANT_EVALUATED` at compile time
535// to check if this function is supported.
536//
537// Example:
538//
539// constexpr MyClass::MyClass(int param) {
540// #ifdef ABSL_HAVE_CONSTANT_EVALUATED
541// if (!absl::is_constant_evaluated()) {
542// ABSL_LOG(INFO) << "MyClass(" << param << ")";
543// }
544// #endif // ABSL_HAVE_CONSTANT_EVALUATED
545// }
546//
547// Upstream documentation:
548//
549// http://en.cppreference.com/w/cpp/types/is_constant_evaluated
550// http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#:~:text=__builtin_is_constant_evaluated
551//
552#if defined(ABSL_HAVE_CONSTANT_EVALUATED)
553constexpr bool is_constant_evaluated() noexcept {
554#ifdef __cpp_lib_is_constant_evaluated
555 return std::is_constant_evaluated();
556#elif ABSL_HAVE_BUILTIN(__builtin_is_constant_evaluated)
557 return __builtin_is_constant_evaluated();
558#endif
559}
560#endif // ABSL_HAVE_CONSTANT_EVALUATED
561ABSL_NAMESPACE_END
562} // namespace absl
563
564#endif // ABSL_META_TYPE_TRAITS_H_
565