blob: b2463225f8ed63663c4041101299549db1e5748e [file] [log] [blame]
Chris Palmer79e548e2017-03-16 11:39:48 -07001// 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 "third_party/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// Some versions of libstdc++ have partial support for type_traits, but misses
27// a smaller subset while removing some of the older non-standard stuff. Assume
28// that all versions below 5.0 fall in this category, along with one 5.0
29// experimental release. Test for this by consulting compiler major version,
30// the only reliable option available, so theoretically this could fail should
31// you attempt to mix an earlier version of libstdc++ with >= GCC5. But
32// that's unlikely to work out, especially as GCC5 changed ABI.
33#define CR_GLIBCXX_5_0_0 20150123
34#if (defined(__GNUC__) && __GNUC__ < 5) || \
35 (defined(__GLIBCXX__) && __GLIBCXX__ == CR_GLIBCXX_5_0_0)
36#define CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX
37#endif
38
39// This hacks around using gcc with libc++ which has some incompatibilies.
40// - is_trivially_* doesn't work: https://llvm.org/bugs/show_bug.cgi?id=27538
41// TODO(danakj): Remove this when android builders are all using a newer version
42// of gcc, or the android ndk is updated to a newer libc++ that works with older
43// gcc versions.
44#if !defined(__clang__) && defined(_LIBCPP_VERSION)
45#define CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX
46#endif
47
48namespace base {
49
50template <class T>
51struct is_non_const_reference : std::false_type {};
52template <class T>
53struct is_non_const_reference<T&> : std::true_type {};
54template <class T>
55struct is_non_const_reference<const T&> : std::false_type {};
56
57// is_assignable
58
59namespace internal {
60
61template <typename First, typename Second>
62struct SelectSecond {
63 using type = Second;
64};
65
66struct Any {
67 Any(...);
68};
69
70// True case: If |Lvalue| can be assigned to from |Rvalue|, then the return
71// value is a true_type.
72template <class Lvalue, class Rvalue>
73typename internal::SelectSecond<
74 decltype((std::declval<Lvalue>() = std::declval<Rvalue>())),
75 std::true_type>::type
76IsAssignableTest(Lvalue&&, Rvalue&&);
77
78// False case: Otherwise the return value is a false_type.
79template <class Rvalue>
80std::false_type IsAssignableTest(internal::Any, Rvalue&&);
81
82// Default case: Neither Lvalue nor Rvalue is void. Uses IsAssignableTest to
83// determine the type of IsAssignableImpl.
84template <class Lvalue,
85 class Rvalue,
86 bool = std::is_void<Lvalue>::value || std::is_void<Rvalue>::value>
87struct IsAssignableImpl
88 : public std::common_type<decltype(
89 internal::IsAssignableTest(std::declval<Lvalue>(),
90 std::declval<Rvalue>()))>::type {};
91
92// Void case: Either Lvalue or Rvalue is void. Then the type of IsAssignableTest
93// is false_type.
94template <class Lvalue, class Rvalue>
95struct IsAssignableImpl<Lvalue, Rvalue, true> : public std::false_type {};
96
97// Uses expression SFINAE to detect whether using operator<< would work.
98template <typename T, typename = void>
99struct SupportsOstreamOperator : std::false_type {};
100template <typename T>
101struct SupportsOstreamOperator<T,
102 decltype(void(std::declval<std::ostream&>()
103 << std::declval<T>()))>
104 : std::true_type {};
105
106} // namespace internal
107
108// TODO(crbug.com/554293): Remove this when all platforms have this in the std
109// namespace.
110template <class Lvalue, class Rvalue>
111struct is_assignable : public internal::IsAssignableImpl<Lvalue, Rvalue> {};
112
113// is_copy_assignable is true if a T const& is assignable to a T&.
114// TODO(crbug.com/554293): Remove this when all platforms have this in the std
115// namespace.
116template <class T>
117struct is_copy_assignable
118 : public is_assignable<typename std::add_lvalue_reference<T>::type,
119 typename std::add_lvalue_reference<
120 typename std::add_const<T>::type>::type> {};
121
122// is_move_assignable is true if a T&& is assignable to a T&.
123// TODO(crbug.com/554293): Remove this when all platforms have this in the std
124// namespace.
125template <class T>
126struct is_move_assignable
127 : public is_assignable<typename std::add_lvalue_reference<T>::type,
128 const typename std::add_rvalue_reference<T>::type> {
129};
130
131// underlying_type produces the integer type backing an enum type.
132// TODO(crbug.com/554293): Remove this when all platforms have this in the std
133// namespace.
134#if defined(CR_USE_FALLBACKS_FOR_OLD_GLIBCXX)
135template <typename T>
136struct underlying_type {
137 using type = __underlying_type(T);
138};
139#else
140template <typename T>
141using underlying_type = std::underlying_type<T>;
142#endif
143
144// TODO(crbug.com/554293): Remove this when all platforms have this in the std
145// namespace.
146#if defined(CR_USE_FALLBACKS_FOR_OLD_GLIBCXX)
147template <class T>
148using is_trivially_destructible = std::has_trivial_destructor<T>;
149#else
150template <class T>
151using is_trivially_destructible = std::is_trivially_destructible<T>;
152#endif
153
154// is_trivially_copyable is especially hard to get right.
155// - Older versions of libstdc++ will fail to have it like they do for other
156// type traits. In this case we should provide it based on compiler
157// intrinsics. This is covered by the CR_USE_FALLBACKS_FOR_OLD_GLIBCXX define.
158// - An experimental release of gcc includes most of type_traits but misses
159// is_trivially_copyable, so we still have to avoid using libstdc++ in this
160// case, which is covered by CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX.
161// - When compiling libc++ from before r239653, with a gcc compiler, the
162// std::is_trivially_copyable can fail. So we need to work around that by not
163// using the one in libc++ in this case. This is covered by the
164// CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX define, and is discussed in
165// https://llvm.org/bugs/show_bug.cgi?id=27538#c1 where they point out that
166// in libc++'s commit r239653 this is fixed by libc++ checking for gcc 5.1.
167// - In both of the above cases we are using the gcc compiler. When defining
168// this ourselves on compiler intrinsics, the __is_trivially_copyable()
169// intrinsic is not available on gcc before version 5.1 (see the discussion in
170// https://llvm.org/bugs/show_bug.cgi?id=27538#c1 again), so we must check for
171// that version.
172// - When __is_trivially_copyable() is not available because we are on gcc older
173// than 5.1, we need to fall back to something, so we use __has_trivial_copy()
174// instead based on what was done one-off in bit_cast() previously.
175
176// TODO(crbug.com/554293): Remove this when all platforms have this in the std
177// namespace and it works with gcc as needed.
178#if defined(CR_USE_FALLBACKS_FOR_OLD_GLIBCXX) || \
179 defined(CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX) || \
180 defined(CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX)
181template <typename T>
182struct is_trivially_copyable {
183// TODO(danakj): Remove this when android builders are all using a newer version
184// of gcc, or the android ndk is updated to a newer libc++ that does this for
185// us.
186#if _GNUC_VER >= 501
187 static constexpr bool value = __is_trivially_copyable(T);
188#else
189 static constexpr bool value = __has_trivial_copy(T);
190#endif
191};
192#else
193template <class T>
194using is_trivially_copyable = std::is_trivially_copyable<T>;
195#endif
196
197} // namespace base
198
199#undef CR_USE_FALLBACKS_FOR_OLD_GLIBCXX
200#undef CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX
201#undef CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX
202
203#endif // BASE_TEMPLATE_UTIL_H_