Home | History | Annotate | Line # | Download | only in Support
      1 //===- llvm/Support/type_traits.h - Simplfied type traits -------*- C++ -*-===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 // This file provides useful additions to the standard type_traits library.
     10 //
     11 //===----------------------------------------------------------------------===//
     12 
     13 #ifndef LLVM_SUPPORT_TYPE_TRAITS_H
     14 #define LLVM_SUPPORT_TYPE_TRAITS_H
     15 
     16 #include "llvm/Support/Compiler.h"
     17 #include <type_traits>
     18 #include <utility>
     19 
     20 namespace llvm {
     21 
     22 
     23 /// Metafunction that determines whether the given type is either an
     24 /// integral type or an enumeration type, including enum classes.
     25 ///
     26 /// Note that this accepts potentially more integral types than is_integral
     27 /// because it is based on being implicitly convertible to an integral type.
     28 /// Also note that enum classes aren't implicitly convertible to integral types,
     29 /// the value may therefore need to be explicitly converted before being used.
     30 template <typename T> class is_integral_or_enum {
     31   using UnderlyingT = std::remove_reference_t<T>;
     32 
     33 public:
     34   static const bool value =
     35       !std::is_class<UnderlyingT>::value && // Filter conversion operators.
     36       !std::is_pointer<UnderlyingT>::value &&
     37       !std::is_floating_point<UnderlyingT>::value &&
     38       (std::is_enum<UnderlyingT>::value ||
     39        std::is_convertible<UnderlyingT, unsigned long long>::value);
     40 };
     41 
     42 /// If T is a pointer, just return it. If it is not, return T&.
     43 template<typename T, typename Enable = void>
     44 struct add_lvalue_reference_if_not_pointer { using type = T &; };
     45 
     46 template <typename T>
     47 struct add_lvalue_reference_if_not_pointer<
     48     T, std::enable_if_t<std::is_pointer<T>::value>> {
     49   using type = T;
     50 };
     51 
     52 /// If T is a pointer to X, return a pointer to const X. If it is not,
     53 /// return const T.
     54 template<typename T, typename Enable = void>
     55 struct add_const_past_pointer { using type = const T; };
     56 
     57 template <typename T>
     58 struct add_const_past_pointer<T, std::enable_if_t<std::is_pointer<T>::value>> {
     59   using type = const std::remove_pointer_t<T> *;
     60 };
     61 
     62 template <typename T, typename Enable = void>
     63 struct const_pointer_or_const_ref {
     64   using type = const T &;
     65 };
     66 template <typename T>
     67 struct const_pointer_or_const_ref<T,
     68                                   std::enable_if_t<std::is_pointer<T>::value>> {
     69   using type = typename add_const_past_pointer<T>::type;
     70 };
     71 
     72 namespace detail {
     73 /// Internal utility to detect trivial copy construction.
     74 template<typename T> union copy_construction_triviality_helper {
     75     T t;
     76     copy_construction_triviality_helper() = default;
     77     copy_construction_triviality_helper(const copy_construction_triviality_helper&) = default;
     78     ~copy_construction_triviality_helper() = default;
     79 };
     80 /// Internal utility to detect trivial move construction.
     81 template<typename T> union move_construction_triviality_helper {
     82     T t;
     83     move_construction_triviality_helper() = default;
     84     move_construction_triviality_helper(move_construction_triviality_helper&&) = default;
     85     ~move_construction_triviality_helper() = default;
     86 };
     87 
     88 template<class T>
     89 union trivial_helper {
     90     T t;
     91 };
     92 
     93 } // end namespace detail
     94 
     95 /// An implementation of `std::is_trivially_copy_constructible` since we have
     96 /// users with STLs that don't yet include it.
     97 template <typename T>
     98 struct is_trivially_copy_constructible
     99     : std::is_copy_constructible<
    100           ::llvm::detail::copy_construction_triviality_helper<T>> {};
    101 template <typename T>
    102 struct is_trivially_copy_constructible<T &> : std::true_type {};
    103 template <typename T>
    104 struct is_trivially_copy_constructible<T &&> : std::false_type {};
    105 
    106 /// An implementation of `std::is_trivially_move_constructible` since we have
    107 /// users with STLs that don't yet include it.
    108 template <typename T>
    109 struct is_trivially_move_constructible
    110     : std::is_move_constructible<
    111           ::llvm::detail::move_construction_triviality_helper<T>> {};
    112 template <typename T>
    113 struct is_trivially_move_constructible<T &> : std::true_type {};
    114 template <typename T>
    115 struct is_trivially_move_constructible<T &&> : std::true_type {};
    116 
    117 
    118 template <typename T>
    119 struct is_copy_assignable {
    120   template<class F>
    121     static auto get(F*) -> decltype(std::declval<F &>() = std::declval<const F &>(), std::true_type{});
    122     static std::false_type get(...);
    123     static constexpr bool value = decltype(get((T*)nullptr))::value;
    124 };
    125 
    126 template <typename T>
    127 struct is_move_assignable {
    128   template<class F>
    129     static auto get(F*) -> decltype(std::declval<F &>() = std::declval<F &&>(), std::true_type{});
    130     static std::false_type get(...);
    131     static constexpr bool value = decltype(get((T*)nullptr))::value;
    132 };
    133 
    134 
    135 // An implementation of `std::is_trivially_copyable` since STL version
    136 // is not equally supported by all compilers, especially GCC 4.9.
    137 // Uniform implementation of this trait is important for ABI compatibility
    138 // as it has an impact on SmallVector's ABI (among others).
    139 template <typename T>
    140 class is_trivially_copyable {
    141 
    142   // copy constructors
    143   static constexpr bool has_trivial_copy_constructor =
    144       std::is_copy_constructible<detail::trivial_helper<T>>::value;
    145   static constexpr bool has_deleted_copy_constructor =
    146       !std::is_copy_constructible<T>::value;
    147 
    148   // move constructors
    149   static constexpr bool has_trivial_move_constructor =
    150       std::is_move_constructible<detail::trivial_helper<T>>::value;
    151   static constexpr bool has_deleted_move_constructor =
    152       !std::is_move_constructible<T>::value;
    153 
    154   // copy assign
    155   static constexpr bool has_trivial_copy_assign =
    156       is_copy_assignable<detail::trivial_helper<T>>::value;
    157   static constexpr bool has_deleted_copy_assign =
    158       !is_copy_assignable<T>::value;
    159 
    160   // move assign
    161   static constexpr bool has_trivial_move_assign =
    162       is_move_assignable<detail::trivial_helper<T>>::value;
    163   static constexpr bool has_deleted_move_assign =
    164       !is_move_assignable<T>::value;
    165 
    166   // destructor
    167   static constexpr bool has_trivial_destructor =
    168       std::is_destructible<detail::trivial_helper<T>>::value;
    169 
    170   public:
    171 
    172   static constexpr bool value =
    173       has_trivial_destructor &&
    174       (has_deleted_move_assign || has_trivial_move_assign) &&
    175       (has_deleted_move_constructor || has_trivial_move_constructor) &&
    176       (has_deleted_copy_assign || has_trivial_copy_assign) &&
    177       (has_deleted_copy_constructor || has_trivial_copy_constructor);
    178 
    179 #ifdef HAVE_STD_IS_TRIVIALLY_COPYABLE
    180   static_assert(value == std::is_trivially_copyable<T>::value,
    181                 "inconsistent behavior between llvm:: and std:: implementation of is_trivially_copyable");
    182 #endif
    183 };
    184 template <typename T>
    185 class is_trivially_copyable<T*> : public std::true_type {
    186 };
    187 
    188 
    189 } // end namespace llvm
    190 
    191 #endif // LLVM_SUPPORT_TYPE_TRAITS_H
    192