about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--absl/base/casts.h51
-rw-r--r--absl/meta/type_traits.h2
2 files changed, 52 insertions, 1 deletions
diff --git a/absl/base/casts.h b/absl/base/casts.h
index 8bd5264d9780..20fd34da7010 100644
--- a/absl/base/casts.h
+++ b/absl/base/casts.h
@@ -25,12 +25,36 @@
 #define ABSL_BASE_CASTS_H_
 
 #include <cstring>
+#include <memory>
 #include <type_traits>
 
 #include "absl/base/internal/identity.h"
+#include "absl/base/macros.h"
 
 namespace absl {
 
+namespace internal_casts {
+
+// NOTE: Not a fully compliant implementation of `std::is_trivially_copyable`.
+// TODO(calabrese) Branch on implementations that directly provide
+// `std::is_trivially_copyable`, create a more rigorous workaround, and publicly
+// expose in meta/type_traits.
+template <class T>
+struct is_trivially_copyable
+    : std::integral_constant<
+          bool, std::is_destructible<T>::value&& __has_trivial_destructor(T) &&
+                    __has_trivial_copy(T) && __has_trivial_assign(T)> {};
+
+template <class Dest, class Source>
+struct is_bitcastable
+    : std::integral_constant<bool,
+                             sizeof(Dest) == sizeof(Source) &&
+                                 is_trivially_copyable<Source>::value &&
+                                 is_trivially_copyable<Dest>::value &&
+                                 std::is_default_constructible<Dest>::value> {};
+
+}  // namespace internal_casts
+
 // implicit_cast()
 //
 // Performs an implicit conversion between types following the language
@@ -125,7 +149,32 @@ inline To implicit_cast(typename absl::internal::identity_t<To> to) {
 // and reading its bits back using a different type. A `bit_cast()` avoids this
 // issue by implementing its casts using `memcpy()`, which avoids introducing
 // this undefined behavior.
-template <typename Dest, typename Source>
+//
+// NOTE: The requirements here are more strict than the bit_cast of standard
+// proposal p0476 due to the need for workarounds and lack of intrinsics.
+// Specifically, this implementation also requires `Dest` to be
+// default-constructible.
+template <
+    typename Dest, typename Source,
+    typename std::enable_if<internal_casts::is_bitcastable<Dest, Source>::value,
+                            int>::type = 0>
+inline Dest bit_cast(const Source& source) {
+  Dest dest;
+  memcpy(static_cast<void*>(std::addressof(dest)),
+         static_cast<const void*>(std::addressof(source)), sizeof(dest));
+  return dest;
+}
+
+// NOTE: This overload is only picked if the requirements of bit_cast are not
+// met. It is therefore UB, but is provided temporarily as previous versions of
+// this function template were unchecked. Do not use this in new code.
+template <
+    typename Dest, typename Source,
+    typename std::enable_if<
+        !internal_casts::is_bitcastable<Dest, Source>::value, int>::type = 0>
+ABSL_DEPRECATED(
+    "absl::bit_cast type requirements were violated. Update the types being "
+    "used such that they are the same size and are both TriviallyCopyable.")
 inline Dest bit_cast(const Source& source) {
   static_assert(sizeof(Dest) == sizeof(Source),
                 "Source and destination types should have equal sizes.");
diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h
index 88af17c395df..c3e01fe2990c 100644
--- a/absl/meta/type_traits.h
+++ b/absl/meta/type_traits.h
@@ -369,4 +369,6 @@ struct IsHashEnabled
 }  // namespace type_traits_internal
 
 }  // namespace absl
+
+
 #endif  // ABSL_META_TYPE_TRAITS_H_