about summary refs log tree commit diff
path: root/absl/meta/type_traits.h
diff options
context:
space:
mode:
Diffstat (limited to 'absl/meta/type_traits.h')
-rw-r--r--absl/meta/type_traits.h109
1 files changed, 106 insertions, 3 deletions
diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h
index a8068e315ed3..c08e3754689b 100644
--- a/absl/meta/type_traits.h
+++ b/absl/meta/type_traits.h
@@ -43,8 +43,39 @@
 
 namespace absl {
 
+// Defined and documented later on in this file.
+template <typename T>
+struct is_trivially_move_assignable;
+
 namespace type_traits_internal {
 
+// Silence MSVC warnings about the destructor being defined as deleted.
+#if defined(_MSC_VER) && !defined(__GNUC__)
+#pragma warning(push)
+#pragma warning(disable : 4624)
+#endif  // defined(_MSC_VER) && !defined(__GNUC__)
+
+template <class T>
+union SingleMemberUnion {
+  T t;
+};
+
+// Restore the state of the destructor warning that was silenced above.
+#if defined(_MSC_VER) && !defined(__GNUC__)
+#pragma warning(pop)
+#endif  // defined(_MSC_VER) && !defined(__GNUC__)
+
+template <class T>
+struct IsTriviallyMoveAssignableReference : std::false_type {};
+
+template <class T>
+struct IsTriviallyMoveAssignableReference<T&>
+    : absl::is_trivially_move_assignable<T>::type {};
+
+template <class T>
+struct IsTriviallyMoveAssignableReference<T&&>
+    : absl::is_trivially_move_assignable<T>::type {};
+
 template <typename... Ts>
 struct VoidTImpl {
   using type = void;
@@ -275,6 +306,40 @@ struct is_trivially_default_constructible
 #endif  // ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
 };
 
+// is_trivially_move_constructible()
+//
+// Determines whether the passed type `T` is trivially move constructible.
+//
+// This metafunction is designed to be a drop-in replacement for the C++11
+// `std::is_trivially_move_constructible()` metafunction for platforms that have
+// incomplete C++11 support (such as libstdc++ 4.x). On any platforms that do
+// fully support C++11, we check whether this yields the same result as the std
+// implementation.
+//
+// NOTE: `T obj(declval<T>());` needs to be well-formed and not call any
+// nontrivial operation.  Nontrivially destructible types will cause the
+// expression to be nontrivial.
+template <typename T>
+struct is_trivially_move_constructible
+    : std::conditional<
+          std::is_object<T>::value && !std::is_array<T>::value,
+          std::is_move_constructible<
+              type_traits_internal::SingleMemberUnion<T>>,
+          std::is_reference<T>>::type::type {
+#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+ private:
+  static constexpr bool compliant =
+      std::is_trivially_move_constructible<T>::value ==
+      is_trivially_move_constructible::value;
+  static_assert(compliant || std::is_trivially_move_constructible<T>::value,
+                "Not compliant with std::is_trivially_move_constructible; "
+                "Standard: false, Implementation: true");
+  static_assert(compliant || !std::is_trivially_move_constructible<T>::value,
+                "Not compliant with std::is_trivially_move_constructible; "
+                "Standard: true, Implementation: false");
+#endif  // ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+};
+
 // is_trivially_copy_constructible()
 //
 // Determines whether the passed type `T` is trivially copy constructible.
@@ -290,9 +355,11 @@ struct is_trivially_default_constructible
 // expression to be nontrivial.
 template <typename T>
 struct is_trivially_copy_constructible
-    : std::integral_constant<bool, __has_trivial_copy(T) &&
-                                   std::is_copy_constructible<T>::value &&
-                                   is_trivially_destructible<T>::value> {
+    : std::conditional<
+          std::is_object<T>::value && !std::is_array<T>::value,
+          std::is_copy_constructible<
+              type_traits_internal::SingleMemberUnion<T>>,
+          std::is_lvalue_reference<T>>::type::type {
 #ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
  private:
   static constexpr bool compliant =
@@ -307,6 +374,42 @@ struct is_trivially_copy_constructible
 #endif  // ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
 };
 
+// is_trivially_move_assignable()
+//
+// Determines whether the passed type `T` is trivially move assignable.
+//
+// This metafunction is designed to be a drop-in replacement for the C++11
+// `std::is_trivially_move_assignable()` metafunction for platforms that have
+// incomplete C++11 support (such as libstdc++ 4.x). On any platforms that do
+// fully support C++11, we check whether this yields the same result as the std
+// implementation.
+//
+// NOTE: `is_assignable<T, U>::value` is `true` if the expression
+// `declval<T>() = declval<U>()` is well-formed when treated as an unevaluated
+// operand. `is_trivially_assignable<T, U>` requires the assignment to call no
+// operation that is not trivial. `is_trivially_copy_assignable<T>` is simply
+// `is_trivially_assignable<T&, T>`.
+template <typename T>
+struct is_trivially_move_assignable
+    : std::conditional<
+          std::is_object<T>::value && !std::is_array<T>::value,
+          std::is_move_assignable<type_traits_internal::SingleMemberUnion<T>>,
+          type_traits_internal::IsTriviallyMoveAssignableReference<T>>::type::
+          type {
+#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
+ private:
+  static constexpr bool compliant =
+      std::is_trivially_move_assignable<T>::value ==
+      is_trivially_move_assignable::value;
+  static_assert(compliant || std::is_trivially_move_assignable<T>::value,
+                "Not compliant with std::is_trivially_move_assignable; "
+                "Standard: false, Implementation: true");
+  static_assert(compliant || !std::is_trivially_move_assignable<T>::value,
+                "Not compliant with std::is_trivially_move_assignable; "
+                "Standard: true, Implementation: false");
+#endif  // ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
+};
+
 // is_trivially_copy_assignable()
 //
 // Determines whether the passed type `T` is trivially copy assignable.