diff options
-rw-r--r-- | absl/base/casts.h | 51 | ||||
-rw-r--r-- | absl/meta/type_traits.h | 2 |
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_ |