From 699d063d88c16fa2f3e4d142ff12bd03bd7089ea Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Wed, 6 Dec 2023 20:16:00 -0800 Subject: [PATCH] and (#1497) Summary: The lowest common denominator build encountered for Yoga internally has been Clang 12 + MSVC 2017 stdlib. This has allowed Yoga to use C++ 20 language features, but not library features. React Native for mobile has not been bound to this restriction. Builds using that toolchain are being updated to latest MSVC 2019 stdlib (which has good C++ 20 library support), along with Clang 17 (or maybe a stop at 15) pending projects using `-fcoroutines-ts` being migrated to C++ 20. This tests out some C++ 20 standard library usages against the current Clang 12 + MSVC 2019 stdlib toolchain that didn't work before, and adds a couple concepts for better constraints/compiler error messages if misused. Yoga OSS CI tests as far back as Clang/libc++ 14 along with a similar era GCC/libstdc++ as part of tests against Ubuntu 22.04 LTS stock toolchain. Once this internal toolchain is updated, that will be the least common denominator (compared to mobile builds or any internal builds). Changelog: [Internal] Differential Revision: D51604487 --- .github/actions/setup-apple/action.yml | 4 ++++ .github/workflows/validate-apple.yml | 7 ++++-- enums.py | 5 ----- yoga/bits/BitCast.h | 30 -------------------------- yoga/enums/Align.h | 5 ----- yoga/enums/Dimension.h | 5 ----- yoga/enums/Direction.h | 5 ----- yoga/enums/Display.h | 5 ----- yoga/enums/Edge.h | 5 ----- yoga/enums/ExperimentalFeature.h | 5 ----- yoga/enums/FlexDirection.h | 5 ----- yoga/enums/Gutter.h | 5 ----- yoga/enums/Justify.h | 5 ----- yoga/enums/LogLevel.h | 5 ----- yoga/enums/MeasureMode.h | 5 ----- yoga/enums/NodeType.h | 5 ----- yoga/enums/Overflow.h | 5 ----- yoga/enums/PositionType.h | 5 ----- yoga/enums/Unit.h | 5 ----- yoga/enums/Wrap.h | 5 ----- yoga/enums/YogaEnums.h | 27 +++++++++++++++++++---- yoga/numeric/Comparison.h | 13 +++++++---- yoga/style/CompactValue.h | 10 ++++----- 23 files changed, 46 insertions(+), 130 deletions(-) delete mode 100644 yoga/bits/BitCast.h diff --git a/.github/actions/setup-apple/action.yml b/.github/actions/setup-apple/action.yml index 6ef41f5806..4087ecbb74 100644 --- a/.github/actions/setup-apple/action.yml +++ b/.github/actions/setup-apple/action.yml @@ -7,3 +7,7 @@ runs: - name: Install Cocoapods shell: bash run: sudo gem install cocoapods + + - uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: 14.3.1 diff --git a/.github/workflows/validate-apple.yml b/.github/workflows/validate-apple.yml index 598ca2e830..3097cfe23d 100644 --- a/.github/workflows/validate-apple.yml +++ b/.github/workflows/validate-apple.yml @@ -11,7 +11,7 @@ on: jobs: lint-pods: name: Build [CocoaPods] - runs-on: macos-latest + runs-on: macos-13 steps: - uses: actions/checkout@v3 @@ -24,11 +24,14 @@ jobs: test: name: Build [SwiftPM] - runs-on: macos-latest + runs-on: macos-13 steps: - uses: actions/checkout@v3 + - name: Setup + uses: ./.github/actions/setup-apple + - name: Build Debug run: swift build -c debug diff --git a/enums.py b/enums.py index c7c3b29b0e..58b2f500fc 100755 --- a/enums.py +++ b/enums.py @@ -175,11 +175,6 @@ def to_hyphenated_lower(symbol): f.write(f" return {len(values)};\n") f.write("} \n\n") - f.write("template <>\n") - f.write(f"constexpr inline int32_t bitCount<{name}>() {{\n") - f.write(f" return {math.ceil(math.log(len(values), 2))};\n") - f.write("} \n\n") - f.write(f"constexpr inline {name} scopedEnum(YG{name} unscoped) {{\n") f.write(f" return static_cast<{name}>(unscoped);\n") f.write("}\n\n") diff --git a/yoga/bits/BitCast.h b/yoga/bits/BitCast.h deleted file mode 100644 index 13fb0e41f2..0000000000 --- a/yoga/bits/BitCast.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 -// TODO: Remove when we upgrade to NDK 26+ -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/enums/Align.h b/yoga/enums/Align.h index 67777fc31b..9a881b0fc1 100644 --- a/yoga/enums/Align.h +++ b/yoga/enums/Align.h @@ -32,11 +32,6 @@ constexpr inline int32_t ordinalCount() { return 9; } -template <> -constexpr inline int32_t bitCount() { - return 4; -} - constexpr inline Align scopedEnum(YGAlign unscoped) { return static_cast(unscoped); } diff --git a/yoga/enums/Dimension.h b/yoga/enums/Dimension.h index 2274a980a5..3ca2eace7a 100644 --- a/yoga/enums/Dimension.h +++ b/yoga/enums/Dimension.h @@ -25,11 +25,6 @@ constexpr inline int32_t ordinalCount() { return 2; } -template <> -constexpr inline int32_t bitCount() { - return 1; -} - constexpr inline Dimension scopedEnum(YGDimension unscoped) { return static_cast(unscoped); } diff --git a/yoga/enums/Direction.h b/yoga/enums/Direction.h index 1b5e19c93c..23b3bdfae9 100644 --- a/yoga/enums/Direction.h +++ b/yoga/enums/Direction.h @@ -26,11 +26,6 @@ constexpr inline int32_t ordinalCount() { return 3; } -template <> -constexpr inline int32_t bitCount() { - return 2; -} - constexpr inline Direction scopedEnum(YGDirection unscoped) { return static_cast(unscoped); } diff --git a/yoga/enums/Display.h b/yoga/enums/Display.h index c1d8c7a82e..c6559760af 100644 --- a/yoga/enums/Display.h +++ b/yoga/enums/Display.h @@ -25,11 +25,6 @@ constexpr inline int32_t ordinalCount() { return 2; } -template <> -constexpr inline int32_t bitCount() { - return 1; -} - constexpr inline Display scopedEnum(YGDisplay unscoped) { return static_cast(unscoped); } diff --git a/yoga/enums/Edge.h b/yoga/enums/Edge.h index d6d2b0ee66..0e72cc4258 100644 --- a/yoga/enums/Edge.h +++ b/yoga/enums/Edge.h @@ -32,11 +32,6 @@ constexpr inline int32_t ordinalCount() { return 9; } -template <> -constexpr inline int32_t bitCount() { - return 4; -} - constexpr inline Edge scopedEnum(YGEdge unscoped) { return static_cast(unscoped); } diff --git a/yoga/enums/ExperimentalFeature.h b/yoga/enums/ExperimentalFeature.h index 6ed358155b..447352240a 100644 --- a/yoga/enums/ExperimentalFeature.h +++ b/yoga/enums/ExperimentalFeature.h @@ -25,11 +25,6 @@ constexpr inline int32_t ordinalCount() { return 2; } -template <> -constexpr inline int32_t bitCount() { - return 1; -} - constexpr inline ExperimentalFeature scopedEnum(YGExperimentalFeature unscoped) { return static_cast(unscoped); } diff --git a/yoga/enums/FlexDirection.h b/yoga/enums/FlexDirection.h index 45f6497ca4..d5ca99ab5b 100644 --- a/yoga/enums/FlexDirection.h +++ b/yoga/enums/FlexDirection.h @@ -27,11 +27,6 @@ constexpr inline int32_t ordinalCount() { return 4; } -template <> -constexpr inline int32_t bitCount() { - return 2; -} - constexpr inline FlexDirection scopedEnum(YGFlexDirection unscoped) { return static_cast(unscoped); } diff --git a/yoga/enums/Gutter.h b/yoga/enums/Gutter.h index 5c0f4a254e..81f2125da7 100644 --- a/yoga/enums/Gutter.h +++ b/yoga/enums/Gutter.h @@ -26,11 +26,6 @@ constexpr inline int32_t ordinalCount() { return 3; } -template <> -constexpr inline int32_t bitCount() { - return 2; -} - constexpr inline Gutter scopedEnum(YGGutter unscoped) { return static_cast(unscoped); } diff --git a/yoga/enums/Justify.h b/yoga/enums/Justify.h index 870a3cb2a7..1c9fd461c5 100644 --- a/yoga/enums/Justify.h +++ b/yoga/enums/Justify.h @@ -29,11 +29,6 @@ constexpr inline int32_t ordinalCount() { return 6; } -template <> -constexpr inline int32_t bitCount() { - return 3; -} - constexpr inline Justify scopedEnum(YGJustify unscoped) { return static_cast(unscoped); } diff --git a/yoga/enums/LogLevel.h b/yoga/enums/LogLevel.h index 45cac9fe39..150593d367 100644 --- a/yoga/enums/LogLevel.h +++ b/yoga/enums/LogLevel.h @@ -29,11 +29,6 @@ constexpr inline int32_t ordinalCount() { return 6; } -template <> -constexpr inline int32_t bitCount() { - return 3; -} - constexpr inline LogLevel scopedEnum(YGLogLevel unscoped) { return static_cast(unscoped); } diff --git a/yoga/enums/MeasureMode.h b/yoga/enums/MeasureMode.h index 80fbcc599f..62edc6a575 100644 --- a/yoga/enums/MeasureMode.h +++ b/yoga/enums/MeasureMode.h @@ -26,11 +26,6 @@ constexpr inline int32_t ordinalCount() { return 3; } -template <> -constexpr inline int32_t bitCount() { - return 2; -} - constexpr inline MeasureMode scopedEnum(YGMeasureMode unscoped) { return static_cast(unscoped); } diff --git a/yoga/enums/NodeType.h b/yoga/enums/NodeType.h index 782b163c2e..cf42785792 100644 --- a/yoga/enums/NodeType.h +++ b/yoga/enums/NodeType.h @@ -25,11 +25,6 @@ constexpr inline int32_t ordinalCount() { return 2; } -template <> -constexpr inline int32_t bitCount() { - return 1; -} - constexpr inline NodeType scopedEnum(YGNodeType unscoped) { return static_cast(unscoped); } diff --git a/yoga/enums/Overflow.h b/yoga/enums/Overflow.h index 1d29103e62..a676b960a9 100644 --- a/yoga/enums/Overflow.h +++ b/yoga/enums/Overflow.h @@ -26,11 +26,6 @@ constexpr inline int32_t ordinalCount() { return 3; } -template <> -constexpr inline int32_t bitCount() { - return 2; -} - constexpr inline Overflow scopedEnum(YGOverflow unscoped) { return static_cast(unscoped); } diff --git a/yoga/enums/PositionType.h b/yoga/enums/PositionType.h index bde2b1896f..90005fa2eb 100644 --- a/yoga/enums/PositionType.h +++ b/yoga/enums/PositionType.h @@ -26,11 +26,6 @@ constexpr inline int32_t ordinalCount() { return 3; } -template <> -constexpr inline int32_t bitCount() { - return 2; -} - constexpr inline PositionType scopedEnum(YGPositionType unscoped) { return static_cast(unscoped); } diff --git a/yoga/enums/Unit.h b/yoga/enums/Unit.h index 36efe95aaf..c5e5e39bdd 100644 --- a/yoga/enums/Unit.h +++ b/yoga/enums/Unit.h @@ -27,11 +27,6 @@ constexpr inline int32_t ordinalCount() { return 4; } -template <> -constexpr inline int32_t bitCount() { - return 2; -} - constexpr inline Unit scopedEnum(YGUnit unscoped) { return static_cast(unscoped); } diff --git a/yoga/enums/Wrap.h b/yoga/enums/Wrap.h index ae380a4448..7dc3e3b056 100644 --- a/yoga/enums/Wrap.h +++ b/yoga/enums/Wrap.h @@ -26,11 +26,6 @@ constexpr inline int32_t ordinalCount() { return 3; } -template <> -constexpr inline int32_t bitCount() { - return 2; -} - constexpr inline Wrap scopedEnum(YGWrap unscoped) { return static_cast(unscoped); } diff --git a/yoga/enums/YogaEnums.h b/yoga/enums/YogaEnums.h index a3e1191de1..4c2a2f2349 100644 --- a/yoga/enums/YogaEnums.h +++ b/yoga/enums/YogaEnums.h @@ -7,25 +7,44 @@ #pragma once +#include #include #include namespace facebook::yoga { +/** + * Concept for any enum/enum class + */ template +concept Enumeration = std::is_enum_v; + +/** + * Count of ordinals in a Yoga enum which is sequential + */ +template constexpr inline int32_t ordinalCount(); /** - * Count of bits needed to represent every ordinal + * Concept for a yoga enum which is sequential */ template -constexpr inline int32_t bitCount(); +concept HasOrdinality = (ordinalCount() > 0); + +/** + * Count of bits needed to represent every ordinal + */ +template +constexpr inline int32_t bitCount() { + return std::bit_width( + static_cast>(ordinalCount() - 1)); +} /** * Polyfill of C++ 23 to_underlying() * https://en.cppreference.com/w/cpp/utility/to_underlying */ -constexpr auto to_underlying(auto e) noexcept { +constexpr auto to_underlying(Enumeration auto e) noexcept { return static_cast>(e); } @@ -33,7 +52,7 @@ constexpr auto to_underlying(auto e) noexcept { * Convenience function to iterate through every value in a Yoga enum as part of * a range-based for loop. */ -template +template auto ordinals() { struct Iterator { EnumT e{}; diff --git a/yoga/numeric/Comparison.h b/yoga/numeric/Comparison.h index 3bf1037b9c..729589b934 100644 --- a/yoga/numeric/Comparison.h +++ b/yoga/numeric/Comparison.h @@ -10,27 +10,32 @@ #include #include #include +#include #include namespace facebook::yoga { -constexpr bool isUndefined(auto value) { +constexpr bool isUndefined(std::floating_point auto value) { return value != value; } -constexpr bool isDefined(auto value) { +constexpr bool isDefined(std::floating_point auto value) { return !isUndefined(value); } -constexpr auto maxOrDefined(auto a, auto b) { +constexpr auto maxOrDefined( + std::floating_point auto a, + std::floating_point auto b) { if (yoga::isDefined(a) && yoga::isDefined(b)) { return std::max(a, b); } return yoga::isUndefined(a) ? b : a; } -constexpr auto minOrDefined(auto a, auto b) { +constexpr auto minOrDefined( + std::floating_point auto a, + std::floating_point auto b) { if (yoga::isDefined(a) && yoga::isDefined(b)) { return std::min(a, b); } diff --git a/yoga/style/CompactValue.h b/yoga/style/CompactValue.h index c32dd9276f..d7884e1d6f 100644 --- a/yoga/style/CompactValue.h +++ b/yoga/style/CompactValue.h @@ -7,6 +7,7 @@ #pragma once +#include #include #include #include @@ -14,7 +15,6 @@ #include #include -#include #include static_assert( @@ -69,7 +69,7 @@ class YG_EXPORT CompactValue { } uint32_t unitBit = Unit == YGUnitPercent ? PERCENT_BIT : 0; - auto data = yoga::bit_cast(value); + auto data = std::bit_cast(value); data -= BIAS; data |= unitBit; return {data}; @@ -112,7 +112,7 @@ class YG_EXPORT CompactValue { return YGValue{0.0f, YGUnitPercent}; } - if (std::isnan(yoga::bit_cast(repr_))) { + if (std::isnan(std::bit_cast(repr_))) { return YGValueUndefined; } @@ -121,14 +121,14 @@ class YG_EXPORT CompactValue { data += BIAS; return YGValue{ - yoga::bit_cast(data), + std::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(yoga::bit_cast(repr_))); + repr_ != ZERO_BITS_PERCENT && std::isnan(std::bit_cast(repr_))); } bool isDefined() const noexcept {