diff --git a/java/jni/YGJNIVanilla.cpp b/java/jni/YGJNIVanilla.cpp index 46d2248a..6a1406c1 100644 --- a/java/jni/YGJNIVanilla.cpp +++ b/java/jni/YGJNIVanilla.cpp @@ -16,6 +16,7 @@ #include "YogaJniException.h" #include +#include // TODO: Reconcile missing layoutContext functionality from callbacks in the C // API and use that @@ -677,11 +678,10 @@ static YGSize YGJNIMeasureFunc( uint32_t wBits = 0xFFFFFFFF & (measureResult >> 32); uint32_t hBits = 0xFFFFFFFF & measureResult; - // TODO: this is unsafe under strict aliasing and should use bit_cast - const float* measuredWidth = reinterpret_cast(&wBits); - const float* measuredHeight = reinterpret_cast(&hBits); + const float measuredWidth = yoga::bit_cast(wBits); + const float measuredHeight = yoga::bit_cast(hBits); - return YGSize{*measuredWidth, *measuredHeight}; + return YGSize{measuredWidth, measuredHeight}; } else { return YGSize{ widthMode == YGMeasureModeUndefined ? 0 : width, diff --git a/yoga/bits/BitCast.h b/yoga/bits/BitCast.h new file mode 100644 index 00000000..eaca348c --- /dev/null +++ b/yoga/bits/BitCast.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +namespace facebook::yoga { + +// Polyfill for std::bit_cast() from C++20, to allow safe type punning +// https://en.cppreference.com/w/cpp/numeric/bit_cast +template +std::enable_if_t< + sizeof(To) == sizeof(From) && std::is_trivially_copyable_v && + std::is_trivially_copyable_v && + std::is_trivially_constructible_v, + To> +bit_cast(const From& src) noexcept { + To dst; + std::memcpy(&dst, &src, sizeof(To)); + return dst; +} + +} // namespace facebook::yoga diff --git a/yoga/style/CompactValue.h b/yoga/style/CompactValue.h index 498b984a..282a518f 100644 --- a/yoga/style/CompactValue.h +++ b/yoga/style/CompactValue.h @@ -14,19 +14,7 @@ #include #include -#if defined(__has_include) && __has_include() -// needed to be able to evaluate defined(__cpp_lib_bit_cast) -#include -#else -// needed to be able to evaluate defined(__cpp_lib_bit_cast) -#include -#endif - -#ifdef __cpp_lib_bit_cast -#include -#else -#include -#endif +#include static_assert( std::numeric_limits::is_iec559, @@ -76,7 +64,7 @@ public: } uint32_t unitBit = Unit == YGUnitPercent ? PERCENT_BIT : 0; - auto data = asU32(value); + auto data = yoga::bit_cast(value); data -= BIAS; data |= unitBit; return {data}; @@ -129,7 +117,7 @@ public: return YGValue{0.0f, YGUnitPercent}; } - if (std::isnan(asFloat(repr_))) { + if (std::isnan(yoga::bit_cast(repr_))) { return YGValueUndefined; } @@ -138,13 +126,14 @@ public: data += BIAS; return YGValue{ - asFloat(data), repr_ & 0x40000000 ? YGUnitPercent : YGUnitPoint}; + yoga::bit_cast(data), + repr_ & 0x40000000 ? YGUnitPercent : YGUnitPoint}; } bool isUndefined() const noexcept { return ( repr_ != AUTO_BITS && repr_ != ZERO_BITS_POINT && - repr_ != ZERO_BITS_PERCENT && std::isnan(asFloat(repr_))); + repr_ != ZERO_BITS_PERCENT && std::isnan(yoga::bit_cast(repr_))); } bool isAuto() const noexcept { return repr_ == AUTO_BITS; } @@ -164,30 +153,6 @@ private: constexpr CompactValue(uint32_t data) noexcept : repr_(data) {} VISIBLE_FOR_TESTING uint32_t repr() { return repr_; } - - static uint32_t asU32(float f) { -#ifdef __cpp_lib_bit_cast - return std::bit_cast(f); -#else - uint32_t u; - static_assert( - sizeof(u) == sizeof(f), "uint32_t and float must have the same size"); - std::memcpy(&u, &f, sizeof(f)); - return u; -#endif - } - - static float asFloat(uint32_t u) { -#ifdef __cpp_lib_bit_cast - return std::bit_cast(u); -#else - float f; - static_assert( - sizeof(f) == sizeof(u), "uint32_t and float must have the same size"); - std::memcpy(&f, &u, sizeof(u)); - return f; -#endif - } }; template <>