Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef BASE_TEMPLATE_UTIL_H_
      6 #define BASE_TEMPLATE_UTIL_H_
      7 
      8 #include <stddef.h>
      9 #include <iosfwd>
     10 #include <type_traits>
     11 #include <utility>
     12 
     13 #include "build/build_config.h"
     14 
     15 // This hacks around libstdc++ 4.6 missing stuff in type_traits, while we need
     16 // to support it.
     17 #define CR_GLIBCXX_4_7_0 20120322
     18 #define CR_GLIBCXX_4_5_4 20120702
     19 #define CR_GLIBCXX_4_6_4 20121127
     20 #if defined(__GLIBCXX__) &&                                               \
     21     (__GLIBCXX__ < CR_GLIBCXX_4_7_0 || __GLIBCXX__ == CR_GLIBCXX_4_5_4 || \
     22      __GLIBCXX__ == CR_GLIBCXX_4_6_4)
     23 #define CR_USE_FALLBACKS_FOR_OLD_GLIBCXX
     24 #endif
     25 
     26 namespace base {
     27 
     28 template <class T> struct is_non_const_reference : std::false_type {};
     29 template <class T> struct is_non_const_reference<T&> : std::true_type {};
     30 template <class T> struct is_non_const_reference<const T&> : std::false_type {};
     31 
     32 // is_assignable
     33 
     34 namespace internal {
     35 
     36 template <typename First, typename Second>
     37 struct SelectSecond {
     38   using type = Second;
     39 };
     40 
     41 struct Any {
     42   Any(...);
     43 };
     44 
     45 // True case: If |Lvalue| can be assigned to from |Rvalue|, then the return
     46 // value is a true_type.
     47 template <class Lvalue, class Rvalue>
     48 typename internal::SelectSecond<
     49     decltype((std::declval<Lvalue>() = std::declval<Rvalue>())),
     50     std::true_type>::type
     51 IsAssignableTest(Lvalue&&, Rvalue&&);
     52 
     53 // False case: Otherwise the return value is a false_type.
     54 template <class Rvalue>
     55 std::false_type IsAssignableTest(internal::Any, Rvalue&&);
     56 
     57 // Default case: Neither Lvalue nor Rvalue is void. Uses IsAssignableTest to
     58 // determine the type of IsAssignableImpl.
     59 template <class Lvalue,
     60           class Rvalue,
     61           bool = std::is_void<Lvalue>::value || std::is_void<Rvalue>::value>
     62 struct IsAssignableImpl
     63     : public std::common_type<decltype(
     64           internal::IsAssignableTest(std::declval<Lvalue>(),
     65                                      std::declval<Rvalue>()))>::type {};
     66 
     67 // Void case: Either Lvalue or Rvalue is void. Then the type of IsAssignableTest
     68 // is false_type.
     69 template <class Lvalue, class Rvalue>
     70 struct IsAssignableImpl<Lvalue, Rvalue, true> : public std::false_type {};
     71 
     72 // Uses expression SFINAE to detect whether using operator<< would work.
     73 template <typename T, typename = void>
     74 struct SupportsOstreamOperator : std::false_type {};
     75 template <typename T>
     76 struct SupportsOstreamOperator<T,
     77                                decltype(void(std::declval<std::ostream&>()
     78                                              << std::declval<T>()))>
     79     : std::true_type {};
     80 
     81 }  // namespace internal
     82 
     83 // TODO(crbug.com/554293): Remove this when all platforms have this in the std
     84 // namespace.
     85 template <class Lvalue, class Rvalue>
     86 struct is_assignable : public internal::IsAssignableImpl<Lvalue, Rvalue> {};
     87 
     88 // is_copy_assignable is true if a T const& is assignable to a T&.
     89 // TODO(crbug.com/554293): Remove this when all platforms have this in the std
     90 // namespace.
     91 template <class T>
     92 struct is_copy_assignable
     93     : public is_assignable<typename std::add_lvalue_reference<T>::type,
     94                            typename std::add_lvalue_reference<
     95                                typename std::add_const<T>::type>::type> {};
     96 
     97 // is_move_assignable is true if a T&& is assignable to a T&.
     98 // TODO(crbug.com/554293): Remove this when all platforms have this in the std
     99 // namespace.
    100 template <class T>
    101 struct is_move_assignable
    102     : public is_assignable<typename std::add_lvalue_reference<T>::type,
    103                            const typename std::add_rvalue_reference<T>::type> {
    104 };
    105 
    106 // underlying_type produces the integer type backing an enum type.
    107 // TODO(crbug.com/554293): Remove this when all platforms have this in the std
    108 // namespace.
    109 #if defined(CR_USE_FALLBACKS_FOR_OLD_GLIBCXX)
    110 template <typename T>
    111 struct underlying_type {
    112   using type = __underlying_type(T);
    113 };
    114 #else
    115 template <typename T>
    116 using underlying_type = std::underlying_type<T>;
    117 #endif
    118 
    119 // TODO(crbug.com/554293): Remove this when all platforms have this in the std
    120 // namespace.
    121 #if defined(CR_USE_FALLBACKS_FOR_OLD_GLIBCXX)
    122 template <class T>
    123 using is_trivially_destructible = std::has_trivial_destructor<T>;
    124 #else
    125 template <class T>
    126 using is_trivially_destructible = std::is_trivially_destructible<T>;
    127 #endif
    128 
    129 }  // namespace base
    130 
    131 #undef CR_USE_FALLBACKS_FOR_OLD_GLIBCXX
    132 
    133 #endif  // BASE_TEMPLATE_UTIL_H_
    134