summaryrefslogtreecommitdiff
path: root/absl/base/casts.h
diff options
context:
space:
mode:
Diffstat (limited to 'absl/base/casts.h')
-rw-r--r--absl/base/casts.h51
1 files changed, 50 insertions, 1 deletions
diff --git a/absl/base/casts.h b/absl/base/casts.h
index 8bd5264d..20fd34da 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.");