From 2eb6444218408aac489eb68e3e265e09ba09e658 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Tue, 29 Aug 2023 18:57:51 -0700 Subject: [PATCH] C++ Cleanup 6/N: YGFloatOptional (#1356) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Pull Request resolved: https://github.com/facebook/yoga/pull/1356 X-link: https://github.com/facebook/react-native/pull/39196 ## This diff This renames YGFloatOptional to FloatOptional, adds it to a namespace, and moves it to a subdirectory. This needs Fabric updates because Fabric uses Yoga internals for props storage. ## This stack The organization of the C++ internals of Yoga are in need of attention. 1. Some of the C++ internals are namespaced, but others not. 2. Some of the namespaces include `detail`, but are meant to be used outside of the translation unit (FB Clang Tidy rules warn on any usage of these) 2. Most of the files are in a flat hierarchy, except for event tracing in its own folder 3. Some files and functions begin with YG, others don’t 4. Some functions are uppercase, others are not 5. Almost all of the interesting logic is in Yoga.cpp, and the file is too large to reason about 6. There are multiple grab bag files where folks put random functions they need in (Utils, BitUtils, Yoga-Internal.h) 7. There is no clear indication from file structure or type naming what is private vs not 8. Handles like `YGNodeRef` and `YGConfigRef` can be used to access internals just by importing headers This stack does some much needed spring cleaning: 1. All non-public headers and C++ implementation details are in separate folders from the root level `yoga`. This will give us room to split up logic and add more files without too large a flat hierarchy 3. All private C++ internals are under the `facebook::yoga` namespace. Details namespaces are only ever used within the same header, as they are intended 4. Utils files are split 5. Most C++ internals drop the YG prefix 6. Most C++ internal function names are all lower camel case 7. We start to split up Yoga.cpp 8. Every header beginning with YG or at the top-level directory is public and C only, with the exception of Yoga-Internal.h which has non-public functions for bindings 9. It is not possible to use private APIs without static casting handles to internal classes This will give us more leeway to continue splitting monolithic files, and consistent guidelines for style in new files as well. These changes should not be breaking to any project using only public Yoga headers. This includes every usage of Yoga in fbsource except for RN Fabric which is currently tied to internals. This refactor should make that boundary clearer. Changelog: [Internal] Reviewed By: rshest Differential Revision: D48767992 fbshipit-source-id: 5a41724a6d84173363977ff92a601b57e0e8b59e --- ...OptionalTest.cpp => FloatOptionalTest.cpp} | 59 +++++++-------- tests/YGStyleAccessorsTest.cpp | 34 ++++----- yoga/YGFloatOptional.h | 70 ------------------ yoga/Yoga.cpp | 69 +++++++++-------- yoga/algorithm/ResolveValue.h | 14 ++-- yoga/debug/NodeToString.cpp | 2 +- yoga/node/LayoutResults.h | 4 +- yoga/node/Node.cpp | 46 ++++++------ yoga/node/Node.h | 27 ++++--- yoga/numeric/Comparison.h | 4 +- yoga/numeric/FloatOptional.h | 74 +++++++++++++++++++ yoga/style/Style.h | 26 +++---- 12 files changed, 215 insertions(+), 214 deletions(-) rename tests/{YGFloatOptionalTest.cpp => FloatOptionalTest.cpp} (76%) delete mode 100644 yoga/YGFloatOptional.h create mode 100644 yoga/numeric/FloatOptional.h diff --git a/tests/YGFloatOptionalTest.cpp b/tests/FloatOptionalTest.cpp similarity index 76% rename from tests/YGFloatOptionalTest.cpp rename to tests/FloatOptionalTest.cpp index 656c81f786..95a3f3da94 100644 --- a/tests/YGFloatOptionalTest.cpp +++ b/tests/FloatOptionalTest.cpp @@ -8,18 +8,19 @@ #include #include -#include +#include #include using namespace facebook; +using namespace facebook::yoga; -constexpr auto empty = YGFloatOptional{}; -constexpr auto zero = YGFloatOptional{0.0f}; -constexpr auto one = YGFloatOptional{1.0f}; -constexpr auto positive = YGFloatOptional{1234.5f}; -constexpr auto negative = YGFloatOptional{-9876.5f}; +constexpr auto empty = FloatOptional{}; +constexpr auto zero = FloatOptional{0.0f}; +constexpr auto one = FloatOptional{1.0f}; +constexpr auto positive = FloatOptional{1234.5f}; +constexpr auto negative = FloatOptional{-9876.5f}; -TEST(YGFloatOptional, value) { +TEST(FloatOptional, value) { ASSERT_TRUE(YGFloatIsUndefined(empty.unwrap())); ASSERT_EQ(zero.unwrap(), 0.0f); ASSERT_EQ(one.unwrap(), 1.0f); @@ -33,7 +34,7 @@ TEST(YGFloatOptional, value) { ASSERT_FALSE(negative.isUndefined()); } -TEST(YGFloatOptional, equality) { +TEST(FloatOptional, equality) { ASSERT_TRUE(empty == empty); ASSERT_TRUE(empty == YGUndefined); ASSERT_FALSE(empty == zero); @@ -58,7 +59,7 @@ TEST(YGFloatOptional, equality) { ASSERT_FALSE(negative == zero); } -TEST(YGFloatOptional, inequality) { +TEST(FloatOptional, inequality) { ASSERT_FALSE(empty != empty); ASSERT_FALSE(empty != YGUndefined); ASSERT_TRUE(empty != zero); @@ -83,7 +84,7 @@ TEST(YGFloatOptional, inequality) { ASSERT_TRUE(negative != zero); } -TEST(YGFloatOptional, greater_than_with_undefined) { +TEST(FloatOptional, greater_than_with_undefined) { ASSERT_FALSE(empty > empty); ASSERT_FALSE(empty > zero); ASSERT_FALSE(empty > one); @@ -95,7 +96,7 @@ TEST(YGFloatOptional, greater_than_with_undefined) { ASSERT_FALSE(negative > empty); } -TEST(YGFloatOptional, greater_than) { +TEST(FloatOptional, greater_than) { ASSERT_TRUE(zero > negative); ASSERT_FALSE(zero > zero); ASSERT_FALSE(zero > positive); @@ -105,10 +106,10 @@ TEST(YGFloatOptional, greater_than) { ASSERT_TRUE(one > zero); ASSERT_FALSE(one > positive); - ASSERT_TRUE(negative > YGFloatOptional{-INFINITY}); + ASSERT_TRUE(negative > FloatOptional{-INFINITY}); } -TEST(YGFloatOptional, less_than_with_undefined) { +TEST(FloatOptional, less_than_with_undefined) { ASSERT_FALSE(empty < empty); ASSERT_FALSE(zero < empty); ASSERT_FALSE(one < empty); @@ -120,7 +121,7 @@ TEST(YGFloatOptional, less_than_with_undefined) { ASSERT_FALSE(empty < negative); } -TEST(YGFloatOptional, less_than) { +TEST(FloatOptional, less_than) { ASSERT_TRUE(negative < zero); ASSERT_FALSE(zero < zero); ASSERT_FALSE(positive < zero); @@ -130,10 +131,10 @@ TEST(YGFloatOptional, less_than) { ASSERT_TRUE(zero < one); ASSERT_FALSE(positive < one); - ASSERT_TRUE(YGFloatOptional{-INFINITY} < negative); + ASSERT_TRUE(FloatOptional{-INFINITY} < negative); } -TEST(YGFloatOptional, greater_than_equals_with_undefined) { +TEST(FloatOptional, greater_than_equals_with_undefined) { ASSERT_TRUE(empty >= empty); ASSERT_FALSE(empty >= zero); ASSERT_FALSE(empty >= one); @@ -145,7 +146,7 @@ TEST(YGFloatOptional, greater_than_equals_with_undefined) { ASSERT_FALSE(negative >= empty); } -TEST(YGFloatOptional, greater_than_equals) { +TEST(FloatOptional, greater_than_equals) { ASSERT_TRUE(zero >= negative); ASSERT_TRUE(zero >= zero); ASSERT_FALSE(zero >= positive); @@ -155,10 +156,10 @@ TEST(YGFloatOptional, greater_than_equals) { ASSERT_TRUE(one >= zero); ASSERT_FALSE(one >= positive); - ASSERT_TRUE(negative >= YGFloatOptional{-INFINITY}); + ASSERT_TRUE(negative >= FloatOptional{-INFINITY}); } -TEST(YGFloatOptional, less_than_equals_with_undefined) { +TEST(FloatOptional, less_than_equals_with_undefined) { ASSERT_TRUE(empty <= empty); ASSERT_FALSE(zero <= empty); ASSERT_FALSE(one <= empty); @@ -170,7 +171,7 @@ TEST(YGFloatOptional, less_than_equals_with_undefined) { ASSERT_FALSE(empty <= negative); } -TEST(YGFloatOptional, less_than_equals) { +TEST(FloatOptional, less_than_equals) { ASSERT_TRUE(negative <= zero); ASSERT_TRUE(zero <= zero); ASSERT_FALSE(positive <= zero); @@ -180,32 +181,32 @@ TEST(YGFloatOptional, less_than_equals) { ASSERT_TRUE(zero <= one); ASSERT_FALSE(positive <= one); - ASSERT_TRUE(YGFloatOptional{-INFINITY} <= negative); + ASSERT_TRUE(FloatOptional{-INFINITY} <= negative); } -TEST(YGFloatOptional, addition) { +TEST(FloatOptional, addition) { auto n = negative.unwrap(); auto p = positive.unwrap(); ASSERT_EQ(zero + one, one); - ASSERT_EQ(negative + positive, YGFloatOptional{n + p}); + ASSERT_EQ(negative + positive, FloatOptional{n + p}); ASSERT_EQ(empty + zero, empty); ASSERT_EQ(empty + empty, empty); ASSERT_EQ(negative + empty, empty); } -TEST(YGFloatOptionalTest, maxOrDefined) { +TEST(YGFloatOptiona, maxOrDefined) { ASSERT_EQ(yoga::maxOrDefined(empty, empty), empty); ASSERT_EQ(yoga::maxOrDefined(empty, positive), positive); ASSERT_EQ(yoga::maxOrDefined(negative, empty), negative); - ASSERT_EQ(yoga::maxOrDefined(negative, YGFloatOptional{-INFINITY}), negative); + ASSERT_EQ(yoga::maxOrDefined(negative, FloatOptional{-INFINITY}), negative); ASSERT_EQ( - yoga::maxOrDefined(YGFloatOptional{1.0f}, YGFloatOptional{1.125f}), - YGFloatOptional{1.125f}); + yoga::maxOrDefined(FloatOptional{1.0f}, FloatOptional{1.125f}), + FloatOptional{1.125f}); } -TEST(YGFloatOptionalTest, unwrap) { +TEST(FloatOptional, unwrap) { ASSERT_TRUE(YGFloatIsUndefined(empty.unwrap())); ASSERT_EQ(zero.unwrap(), 0.0f); - ASSERT_EQ(YGFloatOptional{123456.78f}.unwrap(), 123456.78f); + ASSERT_EQ(FloatOptional{123456.78f}.unwrap(), 123456.78f); } diff --git a/tests/YGStyleAccessorsTest.cpp b/tests/YGStyleAccessorsTest.cpp index 49671bccc0..390743e38b 100644 --- a/tests/YGStyleAccessorsTest.cpp +++ b/tests/YGStyleAccessorsTest.cpp @@ -154,24 +154,24 @@ ACCESSOR_TEST(display, YGDisplayFlex, YGDisplayNone, YGDisplayFlex) ACCESSOR_TEST( flex, - YGFloatOptional{}, - YGFloatOptional{123.45f}, - YGFloatOptional{-9.87f}, - YGFloatOptional{}) + FloatOptional{}, + FloatOptional{123.45f}, + FloatOptional{-9.87f}, + FloatOptional{}) ACCESSOR_TEST( flexGrow, - YGFloatOptional{}, - YGFloatOptional{123.45f}, - YGFloatOptional{-9.87f}, - YGFloatOptional{}) + FloatOptional{}, + FloatOptional{123.45f}, + FloatOptional{-9.87f}, + FloatOptional{}) ACCESSOR_TEST( flexShrink, - YGFloatOptional{}, - YGFloatOptional{123.45f}, - YGFloatOptional{-9.87f}, - YGFloatOptional{}) + FloatOptional{}, + FloatOptional{123.45f}, + FloatOptional{-9.87f}, + FloatOptional{}) ACCESSOR_TEST( flexBasis, @@ -243,11 +243,11 @@ INDEX_ACCESSOR_TEST( ACCESSOR_TEST( aspectRatio, - YGFloatOptional{}, - YGFloatOptional{-123.45f}, - YGFloatOptional{9876.5f}, - YGFloatOptional{0.0f}, - YGFloatOptional{}); + FloatOptional{}, + FloatOptional{-123.45f}, + FloatOptional{9876.5f}, + FloatOptional{0.0f}, + FloatOptional{}); #endif diff --git a/yoga/YGFloatOptional.h b/yoga/YGFloatOptional.h deleted file mode 100644 index c4c18311d5..0000000000 --- a/yoga/YGFloatOptional.h +++ /dev/null @@ -1,70 +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 -#include - -struct YGFloatOptional { -private: - float value_ = std::numeric_limits::quiet_NaN(); - -public: - explicit constexpr YGFloatOptional(float value) : value_(value) {} - constexpr YGFloatOptional() = default; - - // returns the wrapped value, or a value x with YGIsUndefined(x) == true - constexpr float unwrap() const { return value_; } - - bool isUndefined() const { return std::isnan(value_); } -}; - -// operators take YGFloatOptional by value, as it is a 32bit value - -inline bool operator==(YGFloatOptional lhs, YGFloatOptional rhs) { - return lhs.unwrap() == rhs.unwrap() || - (lhs.isUndefined() && rhs.isUndefined()); -} -inline bool operator!=(YGFloatOptional lhs, YGFloatOptional rhs) { - return !(lhs == rhs); -} - -inline bool operator==(YGFloatOptional lhs, float rhs) { - return lhs == YGFloatOptional{rhs}; -} -inline bool operator!=(YGFloatOptional lhs, float rhs) { - return !(lhs == rhs); -} - -inline bool operator==(float lhs, YGFloatOptional rhs) { - return rhs == lhs; -} -inline bool operator!=(float lhs, YGFloatOptional rhs) { - return !(lhs == rhs); -} - -inline YGFloatOptional operator+(YGFloatOptional lhs, YGFloatOptional rhs) { - return YGFloatOptional{lhs.unwrap() + rhs.unwrap()}; -} - -inline bool operator>(YGFloatOptional lhs, YGFloatOptional rhs) { - return lhs.unwrap() > rhs.unwrap(); -} - -inline bool operator<(YGFloatOptional lhs, YGFloatOptional rhs) { - return lhs.unwrap() < rhs.unwrap(); -} - -inline bool operator>=(YGFloatOptional lhs, YGFloatOptional rhs) { - return lhs > rhs || lhs == rhs; -} - -inline bool operator<=(YGFloatOptional lhs, YGFloatOptional rhs) { - return lhs < rhs || lhs == rhs; -} diff --git a/yoga/Yoga.cpp b/yoga/Yoga.cpp index 1179e7a760..dd65a264e4 100644 --- a/yoga/Yoga.cpp +++ b/yoga/Yoga.cpp @@ -636,12 +636,12 @@ YOGA_EXPORT YGDisplay YGNodeStyleGetDisplay(const YGNodeConstRef node) { return static_cast(node)->getStyle().display(); } -// TODO(T26792433): Change the API to accept YGFloatOptional. +// TODO(T26792433): Change the API to accept FloatOptional. YOGA_EXPORT void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) { - updateStyle(node, &Style::flex, YGFloatOptional{flex}); + updateStyle(node, &Style::flex, FloatOptional{flex}); } -// TODO(T26792433): Change the API to accept YGFloatOptional. +// TODO(T26792433): Change the API to accept FloatOptional. YOGA_EXPORT float YGNodeStyleGetFlex(const YGNodeConstRef nodeRef) { auto node = static_cast(nodeRef); return node->getStyle().flex().isUndefined() @@ -649,20 +649,20 @@ YOGA_EXPORT float YGNodeStyleGetFlex(const YGNodeConstRef nodeRef) { : node->getStyle().flex().unwrap(); } -// TODO(T26792433): Change the API to accept YGFloatOptional. +// TODO(T26792433): Change the API to accept FloatOptional. YOGA_EXPORT void YGNodeStyleSetFlexGrow( const YGNodeRef node, const float flexGrow) { updateStyle( - node, &Style::flexGrow, YGFloatOptional{flexGrow}); + node, &Style::flexGrow, FloatOptional{flexGrow}); } -// TODO(T26792433): Change the API to accept YGFloatOptional. +// TODO(T26792433): Change the API to accept FloatOptional. YOGA_EXPORT void YGNodeStyleSetFlexShrink( const YGNodeRef node, const float flexShrink) { updateStyle( - node, &Style::flexShrink, YGFloatOptional{flexShrink}); + node, &Style::flexShrink, FloatOptional{flexShrink}); } YOGA_EXPORT YGValue YGNodeStyleGetFlexBasis(const YGNodeConstRef node) { @@ -756,7 +756,7 @@ YOGA_EXPORT YGValue YGNodeStyleGetPadding(YGNodeConstRef node, YGEdge edge) { return static_cast(node)->getStyle().padding()[edge]; } -// TODO(T26792433): Change the API to accept YGFloatOptional. +// TODO(T26792433): Change the API to accept FloatOptional. YOGA_EXPORT void YGNodeStyleSetBorder( const YGNodeRef node, const YGEdge edge, @@ -771,7 +771,7 @@ YOGA_EXPORT float YGNodeStyleGetBorder( auto border = static_cast(node)->getStyle().border()[edge]; if (border.isUndefined() || border.isAuto()) { // TODO(T26792433): Rather than returning YGUndefined, change the api to - // return YGFloatOptional. + // return FloatOptional. return YGUndefined; } @@ -793,7 +793,7 @@ YOGA_EXPORT float YGNodeStyleGetGap( static_cast(node)->getStyle().gap()[gutter]; if (gapLength.isUndefined() || gapLength.isAuto()) { // TODO(T26792433): Rather than returning YGUndefined, change the api to - // return YGFloatOptional. + // return FloatOptional. return YGUndefined; } @@ -802,19 +802,19 @@ YOGA_EXPORT float YGNodeStyleGetGap( // Yoga specific properties, not compatible with flexbox specification -// TODO(T26792433): Change the API to accept YGFloatOptional. +// TODO(T26792433): Change the API to accept FloatOptional. YOGA_EXPORT float YGNodeStyleGetAspectRatio(const YGNodeConstRef node) { - const YGFloatOptional op = + const FloatOptional op = static_cast(node)->getStyle().aspectRatio(); return op.isUndefined() ? YGUndefined : op.unwrap(); } -// TODO(T26792433): Change the API to accept YGFloatOptional. +// TODO(T26792433): Change the API to accept FloatOptional. YOGA_EXPORT void YGNodeStyleSetAspectRatio( const YGNodeRef node, const float aspectRatio) { updateStyle( - node, &Style::aspectRatio, YGFloatOptional{aspectRatio}); + node, &Style::aspectRatio, FloatOptional{aspectRatio}); } YOGA_EXPORT void YGNodeStyleSetWidth(YGNodeRef node, float points) { @@ -1150,13 +1150,13 @@ static inline bool YGNodeIsLayoutDimDefined( return !YGFloatIsUndefined(value) && value >= 0.0f; } -static YGFloatOptional YGNodeBoundAxisWithinMinAndMax( +static FloatOptional YGNodeBoundAxisWithinMinAndMax( const yoga::Node* const node, const YGFlexDirection axis, - const YGFloatOptional value, + const FloatOptional value, const float axisSize) { - YGFloatOptional min; - YGFloatOptional max; + FloatOptional min; + FloatOptional max; if (isColumn(axis)) { min = yoga::resolveValue( @@ -1170,11 +1170,11 @@ static YGFloatOptional YGNodeBoundAxisWithinMinAndMax( node->getStyle().maxDimensions()[YGDimensionWidth], axisSize); } - if (max >= YGFloatOptional{0} && value > max) { + if (max >= FloatOptional{0} && value > max) { return max; } - if (min >= YGFloatOptional{0} && value < min) { + if (min >= FloatOptional{0} && value < min) { return min; } @@ -1190,8 +1190,7 @@ static inline float YGNodeBoundAxis( const float axisSize, const float widthSize) { return yoga::maxOrDefined( - YGNodeBoundAxisWithinMinAndMax( - node, axis, YGFloatOptional{value}, axisSize) + YGNodeBoundAxisWithinMinAndMax(node, axis, FloatOptional{value}, axisSize) .unwrap(), YGNodePaddingAndBorderForAxis(node, axis, widthSize)); } @@ -1214,10 +1213,10 @@ static void YGConstrainMaxSizeForMode( const float ownerWidth, YGMeasureMode* mode, float* size) { - const YGFloatOptional maxSize = + const FloatOptional maxSize = yoga::resolveValue( node->getStyle().maxDimensions()[dim[axis]], ownerAxisSize) + - YGFloatOptional(node->getMarginForAxis(axis, ownerWidth)); + FloatOptional(node->getMarginForAxis(axis, ownerWidth)); switch (*mode) { case YGMeasureModeExactly: case YGMeasureModeAtMost: @@ -1260,7 +1259,7 @@ static void YGNodeComputeFlexBasisForChild( YGMeasureMode childWidthMeasureMode; YGMeasureMode childHeightMeasureMode; - const YGFloatOptional resolvedFlexBasis = + const FloatOptional resolvedFlexBasis = yoga::resolveValue(child->resolveFlexBasisPtr(), mainAxisownerSize); const bool isRowStyleDimDefined = YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, ownerWidth); @@ -1272,14 +1271,14 @@ static void YGNodeComputeFlexBasisForChild( (child->getConfig()->isExperimentalFeatureEnabled( YGExperimentalFeatureWebFlexBasis) && child->getLayout().computedFlexBasisGeneration != generationCount)) { - const YGFloatOptional paddingAndBorder = YGFloatOptional( + const FloatOptional paddingAndBorder = FloatOptional( YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth)); child->setLayoutComputedFlexBasis( yoga::maxOrDefined(resolvedFlexBasis, paddingAndBorder)); } } else if (isMainAxisRow && isRowStyleDimDefined) { // The width is definite, so use that as the flex basis. - const YGFloatOptional paddingAndBorder = YGFloatOptional( + const FloatOptional paddingAndBorder = FloatOptional( YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow, ownerWidth)); child->setLayoutComputedFlexBasis(yoga::maxOrDefined( @@ -1288,8 +1287,8 @@ static void YGNodeComputeFlexBasisForChild( paddingAndBorder)); } else if (!isMainAxisRow && isColumnStyleDimDefined) { // The height is definite, so use that as the flex basis. - const YGFloatOptional paddingAndBorder = - YGFloatOptional(YGNodePaddingAndBorderForAxis( + const FloatOptional paddingAndBorder = + FloatOptional(YGNodePaddingAndBorderForAxis( child, YGFlexDirectionColumn, ownerWidth)); child->setLayoutComputedFlexBasis(yoga::maxOrDefined( yoga::resolveValue( @@ -1426,7 +1425,7 @@ static void YGNodeComputeFlexBasisForChild( depth, generationCount); - child->setLayoutComputedFlexBasis(YGFloatOptional(yoga::maxOrDefined( + child->setLayoutComputedFlexBasis(FloatOptional(yoga::maxOrDefined( child->getLayout().measuredDimensions[dim[mainAxis]], YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth)))); } @@ -1876,13 +1875,13 @@ static float YGNodeCalculateAvailableInnerDim( if (!YGFloatIsUndefined(availableInnerDim)) { // We want to make sure our available height does not violate min and max // constraints - const YGFloatOptional minDimensionOptional = yoga::resolveValue( + const FloatOptional minDimensionOptional = yoga::resolveValue( node->getStyle().minDimensions()[dimension], ownerDim); const float minInnerDim = minDimensionOptional.isUndefined() ? 0.0f : minDimensionOptional.unwrap() - paddingAndBorder; - const YGFloatOptional maxDimensionOptional = yoga::resolveValue( + const FloatOptional maxDimensionOptional = yoga::resolveValue( node->getStyle().maxDimensions()[dimension], ownerDim); const float maxInnerDim = maxDimensionOptional.isUndefined() @@ -1958,7 +1957,7 @@ static float YGNodeComputeFlexBasisForChildren( } if (child == singleFlexChild) { child->setLayoutComputedFlexBasisGeneration(generationCount); - child->setLayoutComputedFlexBasis(YGFloatOptional(0)); + child->setLayoutComputedFlexBasis(FloatOptional(0)); } else { YGNodeComputeFlexBasisForChild( node, @@ -3522,7 +3521,7 @@ static void YGNodelayoutImpl( YGNodeBoundAxisWithinMinAndMax( node, mainAxis, - YGFloatOptional{maxLineMainDim}, + FloatOptional{maxLineMainDim}, mainAxisownerSize) .unwrap()), paddingAndBorderAxisMain), @@ -3553,7 +3552,7 @@ static void YGNodelayoutImpl( YGNodeBoundAxisWithinMinAndMax( node, crossAxis, - YGFloatOptional{ + FloatOptional{ totalLineCrossDim + paddingAndBorderAxisCross}, crossAxisownerSize) .unwrap()), diff --git a/yoga/algorithm/ResolveValue.h b/yoga/algorithm/ResolveValue.h index 033a2420a1..2ba4bfef5b 100644 --- a/yoga/algorithm/ResolveValue.h +++ b/yoga/algorithm/ResolveValue.h @@ -8,24 +8,22 @@ #pragma once #include -#include +#include namespace facebook::yoga { -inline YGFloatOptional resolveValue( - const YGValue value, - const float ownerSize) { +inline FloatOptional resolveValue(const YGValue value, const float ownerSize) { switch (value.unit) { case YGUnitPoint: - return YGFloatOptional{value.value}; + return FloatOptional{value.value}; case YGUnitPercent: - return YGFloatOptional{value.value * ownerSize * 0.01f}; + return FloatOptional{value.value * ownerSize * 0.01f}; default: - return YGFloatOptional{}; + return FloatOptional{}; } } -inline YGFloatOptional resolveValue(CompactValue value, float ownerSize) { +inline FloatOptional resolveValue(CompactValue value, float ownerSize) { return resolveValue((YGValue) value, ownerSize); } diff --git a/yoga/debug/NodeToString.cpp b/yoga/debug/NodeToString.cpp index 0a033cdba5..1b6d01d380 100644 --- a/yoga/debug/NodeToString.cpp +++ b/yoga/debug/NodeToString.cpp @@ -45,7 +45,7 @@ static void appendFormattedString(std::string& str, const char* fmt, ...) { static void appendFloatOptionalIfDefined( std::string& base, const std::string key, - const YGFloatOptional num) { + const FloatOptional num) { if (!num.isUndefined()) { appendFormattedString(base, "%s: %g; ", key.c_str(), num.unwrap()); } diff --git a/yoga/node/LayoutResults.h b/yoga/node/LayoutResults.h index 18cc135f2c..d920e9a24c 100644 --- a/yoga/node/LayoutResults.h +++ b/yoga/node/LayoutResults.h @@ -8,7 +8,7 @@ #pragma once #include -#include +#include #include namespace facebook::yoga { @@ -28,7 +28,7 @@ struct LayoutResults { public: uint32_t computedFlexBasisGeneration = 0; - YGFloatOptional computedFlexBasis = {}; + FloatOptional computedFlexBasis = {}; // Instead of recomputing the entire layout every single time, we cache some // information to break early when nothing changed diff --git a/yoga/node/Node.cpp b/yoga/node/Node.cpp index c30ee78e7e..82132f54cb 100644 --- a/yoga/node/Node.cpp +++ b/yoga/node/Node.cpp @@ -110,7 +110,7 @@ CompactValue Node::computeColumnGap( } } -YGFloatOptional Node::getLeadingPosition( +FloatOptional Node::getLeadingPosition( const YGFlexDirection axis, const float axisSize) const { auto leadingPosition = isRow(axis) @@ -124,7 +124,7 @@ YGFloatOptional Node::getLeadingPosition( return yoga::resolveValue(leadingPosition, axisSize); } -YGFloatOptional Node::getTrailingPosition( +FloatOptional Node::getTrailingPosition( const YGFlexDirection axis, const float axisSize) const { auto trailingPosition = isRow(axis) @@ -162,7 +162,7 @@ bool Node::isTrailingPosDefined(const YGFlexDirection axis) const { return !trailingPosition.isUndefined(); } -YGFloatOptional Node::getLeadingMargin( +FloatOptional Node::getLeadingMargin( const YGFlexDirection axis, const float widthSize) const { auto leadingMargin = isRow(axis) @@ -170,11 +170,11 @@ YGFloatOptional Node::getLeadingMargin( style_.margin(), YGEdgeStart, leading[axis], CompactValue::ofZero()) : computeEdgeValueForColumn( style_.margin(), leading[axis], CompactValue::ofZero()); - return leadingMargin.isAuto() ? YGFloatOptional{0} + return leadingMargin.isAuto() ? FloatOptional{0} : yoga::resolveValue(leadingMargin, widthSize); } -YGFloatOptional Node::getTrailingMargin( +FloatOptional Node::getTrailingMargin( const YGFlexDirection axis, const float widthSize) const { auto trailingMargin = isRow(axis) @@ -183,17 +183,17 @@ YGFloatOptional Node::getTrailingMargin( : computeEdgeValueForColumn( style_.margin(), trailing[axis], CompactValue::ofZero()); return trailingMargin.isAuto() - ? YGFloatOptional{0} + ? FloatOptional{0} : yoga::resolveValue(trailingMargin, widthSize); } -YGFloatOptional Node::getMarginForAxis( +FloatOptional Node::getMarginForAxis( const YGFlexDirection axis, const float widthSize) const { return getLeadingMargin(axis, widthSize) + getTrailingMargin(axis, widthSize); } -YGFloatOptional Node::getGapForAxis( +FloatOptional Node::getGapForAxis( const YGFlexDirection axis, const float widthSize) const { auto gap = isRow(axis) @@ -325,7 +325,7 @@ void Node::setLayoutLastOwnerDirection(YGDirection direction) { layout_.lastOwnerDirection = direction; } -void Node::setLayoutComputedFlexBasis(const YGFloatOptional computedFlexBasis) { +void Node::setLayoutComputedFlexBasis(const FloatOptional computedFlexBasis) { layout_.computedFlexBasis = computedFlexBasis; } @@ -352,16 +352,16 @@ void Node::setLayoutDimension(float dimension, int index) { // If both left and right are defined, then use left. Otherwise return +left or // -right depending on which is defined. -YGFloatOptional Node::relativePosition( +FloatOptional Node::relativePosition( const YGFlexDirection axis, const float axisSize) const { if (isLeadingPositionDefined(axis)) { return getLeadingPosition(axis, axisSize); } - YGFloatOptional trailingPosition = getTrailingPosition(axis, axisSize); + FloatOptional trailingPosition = getTrailingPosition(axis, axisSize); if (!trailingPosition.isUndefined()) { - trailingPosition = YGFloatOptional{-1 * trailingPosition.unwrap()}; + trailingPosition = FloatOptional{-1 * trailingPosition.unwrap()}; } return trailingPosition; } @@ -383,9 +383,9 @@ void Node::setPosition( // Here we should check for `YGPositionTypeStatic` and in this case zero inset // properties (left, right, top, bottom, begin, end). // https://www.w3.org/TR/css-position-3/#valdef-position-static - const YGFloatOptional relativePositionMain = + const FloatOptional relativePositionMain = relativePosition(mainAxis, mainSize); - const YGFloatOptional relativePositionCross = + const FloatOptional relativePositionCross = relativePosition(crossAxis, crossSize); setLayoutPosition( @@ -468,7 +468,7 @@ void Node::cloneChildrenIfNeeded(void* cloneContext) { void Node::markDirtyAndPropagate() { if (!flags_.isDirty) { setDirty(true); - setLayoutComputedFlexBasis(YGFloatOptional()); + setLayoutComputedFlexBasis(FloatOptional()); if (owner_) { owner_->markDirtyAndPropagate(); } @@ -534,7 +534,7 @@ float Node::getTrailingBorder(const YGFlexDirection axis) const { return fmaxf(trailingBorder.value, 0.0f); } -YGFloatOptional Node::getLeadingPadding( +FloatOptional Node::getLeadingPadding( const YGFlexDirection axis, const float widthSize) const { auto leadingPadding = isRow(axis) @@ -546,10 +546,10 @@ YGFloatOptional Node::getLeadingPadding( : computeEdgeValueForColumn( style_.padding(), leading[axis], CompactValue::ofZero()); return yoga::maxOrDefined( - yoga::resolveValue(leadingPadding, widthSize), YGFloatOptional(0.0f)); + yoga::resolveValue(leadingPadding, widthSize), FloatOptional(0.0f)); } -YGFloatOptional Node::getTrailingPadding( +FloatOptional Node::getTrailingPadding( const YGFlexDirection axis, const float widthSize) const { auto trailingPadding = isRow(axis) @@ -558,21 +558,21 @@ YGFloatOptional Node::getTrailingPadding( : computeEdgeValueForColumn( style_.padding(), trailing[axis], CompactValue::ofZero()); return yoga::maxOrDefined( - yoga::resolveValue(trailingPadding, widthSize), YGFloatOptional(0.0f)); + yoga::resolveValue(trailingPadding, widthSize), FloatOptional(0.0f)); } -YGFloatOptional Node::getLeadingPaddingAndBorder( +FloatOptional Node::getLeadingPaddingAndBorder( const YGFlexDirection axis, const float widthSize) const { return getLeadingPadding(axis, widthSize) + - YGFloatOptional(getLeadingBorder(axis)); + FloatOptional(getLeadingBorder(axis)); } -YGFloatOptional Node::getTrailingPaddingAndBorder( +FloatOptional Node::getTrailingPaddingAndBorder( const YGFlexDirection axis, const float widthSize) const { return getTrailingPadding(axis, widthSize) + - YGFloatOptional(getTrailingBorder(axis)); + FloatOptional(getTrailingBorder(axis)); } void Node::reset() { diff --git a/yoga/node/Node.h b/yoga/node/Node.h index abb1535aed..542d7c08ea 100644 --- a/yoga/node/Node.h +++ b/yoga/node/Node.h @@ -66,7 +66,7 @@ class YOGA_EXPORT Node : public ::YGNode { std::array resolvedDimensions_ = { {YGValueUndefined, YGValueUndefined}}; - YGFloatOptional relativePosition( + FloatOptional relativePosition( const YGFlexDirection axis, const float axisSize) const; @@ -203,40 +203,39 @@ class YOGA_EXPORT Node : public ::YGNode { CompactValue defaultValue); // Methods related to positions, margin, padding and border - YGFloatOptional getLeadingPosition( + FloatOptional getLeadingPosition( const YGFlexDirection axis, const float axisSize) const; bool isLeadingPositionDefined(const YGFlexDirection axis) const; bool isTrailingPosDefined(const YGFlexDirection axis) const; - YGFloatOptional getTrailingPosition( + FloatOptional getTrailingPosition( const YGFlexDirection axis, const float axisSize) const; - YGFloatOptional getLeadingMargin( + FloatOptional getLeadingMargin( const YGFlexDirection axis, const float widthSize) const; - YGFloatOptional getTrailingMargin( + FloatOptional getTrailingMargin( const YGFlexDirection axis, const float widthSize) const; float getLeadingBorder(const YGFlexDirection flexDirection) const; float getTrailingBorder(const YGFlexDirection flexDirection) const; - YGFloatOptional getLeadingPadding( + FloatOptional getLeadingPadding( const YGFlexDirection axis, const float widthSize) const; - YGFloatOptional getTrailingPadding( + FloatOptional getTrailingPadding( const YGFlexDirection axis, const float widthSize) const; - YGFloatOptional getLeadingPaddingAndBorder( + FloatOptional getLeadingPaddingAndBorder( const YGFlexDirection axis, const float widthSize) const; - YGFloatOptional getTrailingPaddingAndBorder( + FloatOptional getTrailingPaddingAndBorder( const YGFlexDirection axis, const float widthSize) const; - YGFloatOptional getMarginForAxis( - const YGFlexDirection axis, - const float widthSize) const; - YGFloatOptional getGapForAxis( + FloatOptional getMarginForAxis( const YGFlexDirection axis, const float widthSize) const; + FloatOptional getGapForAxis(const YGFlexDirection axis, const float widthSize) + const; // Setters void setContext(void* context) { context_ = context; } @@ -299,7 +298,7 @@ class YOGA_EXPORT Node : public ::YGNode { void setDirty(bool isDirty); void setLayoutLastOwnerDirection(YGDirection direction); - void setLayoutComputedFlexBasis(const YGFloatOptional computedFlexBasis); + void setLayoutComputedFlexBasis(const FloatOptional computedFlexBasis); void setLayoutComputedFlexBasisGeneration( uint32_t computedFlexBasisGeneration); void setLayoutMeasuredDimension(float measuredDimension, int index); diff --git a/yoga/numeric/Comparison.h b/yoga/numeric/Comparison.h index 4e9b35151f..86ed16fa50 100644 --- a/yoga/numeric/Comparison.h +++ b/yoga/numeric/Comparison.h @@ -10,7 +10,7 @@ #include #include -#include +#include #include namespace facebook::yoga { @@ -30,7 +30,7 @@ inline float minOrDefined(const float a, const float b) { return std::isnan(a) ? b : a; } -inline YGFloatOptional maxOrDefined(YGFloatOptional op1, YGFloatOptional op2) { +inline FloatOptional maxOrDefined(FloatOptional op1, FloatOptional op2) { if (op1 >= op2) { return op1; } diff --git a/yoga/numeric/FloatOptional.h b/yoga/numeric/FloatOptional.h new file mode 100644 index 0000000000..89eff3b882 --- /dev/null +++ b/yoga/numeric/FloatOptional.h @@ -0,0 +1,74 @@ +/* + * 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 +#include + +namespace facebook::yoga { + +struct FloatOptional { +private: + float value_ = std::numeric_limits::quiet_NaN(); + +public: + explicit constexpr FloatOptional(float value) : value_(value) {} + constexpr FloatOptional() = default; + + // returns the wrapped value, or a value x with YGIsUndefined(x) == true + constexpr float unwrap() const { return value_; } + + bool isUndefined() const { return std::isnan(value_); } +}; + +// operators take FloatOptional by value, as it is a 32bit value + +inline bool operator==(FloatOptional lhs, FloatOptional rhs) { + return lhs.unwrap() == rhs.unwrap() || + (lhs.isUndefined() && rhs.isUndefined()); +} +inline bool operator!=(FloatOptional lhs, FloatOptional rhs) { + return !(lhs == rhs); +} + +inline bool operator==(FloatOptional lhs, float rhs) { + return lhs == FloatOptional{rhs}; +} +inline bool operator!=(FloatOptional lhs, float rhs) { + return !(lhs == rhs); +} + +inline bool operator==(float lhs, FloatOptional rhs) { + return rhs == lhs; +} +inline bool operator!=(float lhs, FloatOptional rhs) { + return !(lhs == rhs); +} + +inline FloatOptional operator+(FloatOptional lhs, FloatOptional rhs) { + return FloatOptional{lhs.unwrap() + rhs.unwrap()}; +} + +inline bool operator>(FloatOptional lhs, FloatOptional rhs) { + return lhs.unwrap() > rhs.unwrap(); +} + +inline bool operator<(FloatOptional lhs, FloatOptional rhs) { + return lhs.unwrap() < rhs.unwrap(); +} + +inline bool operator>=(FloatOptional lhs, FloatOptional rhs) { + return lhs > rhs || lhs == rhs; +} + +inline bool operator<=(FloatOptional lhs, FloatOptional rhs) { + return lhs < rhs || lhs == rhs; +} + +} // namespace facebook::yoga diff --git a/yoga/style/Style.h b/yoga/style/Style.h index c323346e45..49bb8ece67 100644 --- a/yoga/style/Style.h +++ b/yoga/style/Style.h @@ -13,10 +13,10 @@ #include #include -#include #include #include +#include #include namespace facebook::yoga { @@ -105,9 +105,9 @@ class YOGA_EXPORT Style { uint32_t flags = 0; - YGFloatOptional flex_ = {}; - YGFloatOptional flexGrow_ = {}; - YGFloatOptional flexShrink_ = {}; + FloatOptional flex_ = {}; + FloatOptional flexGrow_ = {}; + FloatOptional flexShrink_ = {}; CompactValue flexBasis_ = CompactValue::ofAuto(); Edges margin_ = {}; Edges position_ = {}; @@ -118,7 +118,7 @@ class YOGA_EXPORT Style { Dimensions minDimensions_ = {}; Dimensions maxDimensions_ = {}; // Yoga specific properties, not compatible with flexbox specification - YGFloatOptional aspectRatio_ = {}; + FloatOptional aspectRatio_ = {}; public: // for library users needing a type @@ -187,14 +187,14 @@ class YOGA_EXPORT Style { } BitfieldRef display() { return {*this, displayOffset}; } - YGFloatOptional flex() const { return flex_; } - Ref flex() { return {*this}; } + FloatOptional flex() const { return flex_; } + Ref flex() { return {*this}; } - YGFloatOptional flexGrow() const { return flexGrow_; } - Ref flexGrow() { return {*this}; } + FloatOptional flexGrow() const { return flexGrow_; } + Ref flexGrow() { return {*this}; } - YGFloatOptional flexShrink() const { return flexShrink_; } - Ref flexShrink() { return {*this}; } + FloatOptional flexShrink() const { return flexShrink_; } + Ref flexShrink() { return {*this}; } CompactValue flexBasis() const { return flexBasis_; } Ref flexBasis() { return {*this}; } @@ -228,8 +228,8 @@ class YOGA_EXPORT Style { } // Yoga specific properties, not compatible with flexbox specification - YGFloatOptional aspectRatio() const { return aspectRatio_; } - Ref aspectRatio() { return {*this}; } + FloatOptional aspectRatio() const { return aspectRatio_; } + Ref aspectRatio() { return {*this}; } }; YOGA_EXPORT bool operator==(const Style& lhs, const Style& rhs);