FloatOptional GCC build fix and more constexpr (#1411)

Summary:
Pull Request resolved: https://github.com/facebook/yoga/pull/1411

X-link: https://github.com/facebook/react-native/pull/39796

Pull Request resolved: https://github.com/facebook/yoga/pull/1414

GCC flags that `isUndefined()` is not declared `constexpr` but that `unwrapOrDefault()` is. `std::isnan` is not constexpr until C++ 23 (because we cannot have nice things), so I made `yoga::isUndefined()` constexpr, using the same code `std::isnan()` boils down to. I then made `FloatOptional` depend on `Comparison.h` (instead of the other way around), so we can use it.

Note that the use of the `std::floating_point` concept here requires the libc++ bump in the previous diff in the stack.

Reviewed By: yungsters

Differential Revision: D49896837

fbshipit-source-id: 61e2bbbfedecffd007a12d42d998e43d3cf5119c
This commit is contained in:
Nick Gerleman
2023-10-06 13:04:39 -07:00
committed by Facebook GitHub Bot
parent f700e1335c
commit 7fe6e345a7
4 changed files with 40 additions and 44 deletions

View File

@@ -5,6 +5,8 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
#include <cmath>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <yoga/YGValue.h> #include <yoga/YGValue.h>

View File

@@ -563,10 +563,10 @@ static void measureNodeWithMeasureFunc(
// We want to make sure we don't call measure with negative size // We want to make sure we don't call measure with negative size
const float innerWidth = yoga::isUndefined(availableWidth) const float innerWidth = yoga::isUndefined(availableWidth)
? availableWidth ? availableWidth
: yoga::maxOrDefined(0, availableWidth - paddingAndBorderAxisRow); : yoga::maxOrDefined(0.0f, availableWidth - paddingAndBorderAxisRow);
const float innerHeight = yoga::isUndefined(availableHeight) const float innerHeight = yoga::isUndefined(availableHeight)
? availableHeight ? availableHeight
: yoga::maxOrDefined(0, availableHeight - paddingAndBorderAxisColumn); : yoga::maxOrDefined(0.0f, availableHeight - paddingAndBorderAxisColumn);
if (widthMeasureMode == MeasureMode::Exactly && if (widthMeasureMode == MeasureMode::Exactly &&
heightMeasureMode == MeasureMode::Exactly) { heightMeasureMode == MeasureMode::Exactly) {
@@ -1223,7 +1223,7 @@ static void justifyMainAxis(
const float occupiedSpaceByChildNodes = const float occupiedSpaceByChildNodes =
availableInnerMainDim - flexLine.layout.remainingFreeSpace; availableInnerMainDim - flexLine.layout.remainingFreeSpace;
flexLine.layout.remainingFreeSpace = yoga::maxOrDefined( flexLine.layout.remainingFreeSpace = yoga::maxOrDefined(
0, minAvailableMainDim - occupiedSpaceByChildNodes); 0.0f, minAvailableMainDim - occupiedSpaceByChildNodes);
} else { } else {
flexLine.layout.remainingFreeSpace = 0; flexLine.layout.remainingFreeSpace = 0;
} }
@@ -1260,7 +1260,7 @@ static void justifyMainAxis(
case Justify::SpaceBetween: case Justify::SpaceBetween:
if (flexLine.itemsInFlow.size() > 1) { if (flexLine.itemsInFlow.size() > 1) {
betweenMainDim += betweenMainDim +=
yoga::maxOrDefined(flexLine.layout.remainingFreeSpace, 0) / yoga::maxOrDefined(flexLine.layout.remainingFreeSpace, 0.0f) /
static_cast<float>(flexLine.itemsInFlow.size() - 1); static_cast<float>(flexLine.itemsInFlow.size() - 1);
} }
break; break;

View File

@@ -7,63 +7,49 @@
#pragma once #pragma once
#include <algorithm>
#include <array> #include <array>
#include <cmath>
#include <yoga/Yoga.h> #include <yoga/Yoga.h>
#include <yoga/numeric/FloatOptional.h>
namespace facebook::yoga { namespace facebook::yoga {
template <typename FloatT> constexpr bool isUndefined(auto value) {
inline bool isUndefined(FloatT value) { return value != value;
return std::isnan(value);
} }
inline float maxOrDefined(const float a, const float b) { constexpr auto maxOrDefined(auto a, auto b) {
if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) { if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) {
return fmaxf(a, b); return std::max(a, b);
} }
return yoga::isUndefined(a) ? b : a; return yoga::isUndefined(a) ? b : a;
} }
inline float minOrDefined(const float a, const float b) { constexpr auto minOrDefined(auto a, auto b) {
if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) { if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) {
return fminf(a, b); return std::min(a, b);
} }
return yoga::isUndefined(a) ? b : a; return yoga::isUndefined(a) ? b : a;
} }
inline FloatOptional maxOrDefined(FloatOptional op1, FloatOptional op2) {
if (op1 >= op2) {
return op1;
}
if (op2 > op1) {
return op2;
}
return op1.isUndefined() ? op2 : op1;
}
// Custom equality functions using a hardcoded epsilon of 0.0001f, or returning // Custom equality functions using a hardcoded epsilon of 0.0001f, or returning
// true if both floats are NaN. // true if both floats are NaN.
inline bool inexactEquals(const float a, const float b) { inline bool inexactEquals(float a, float b) {
if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) { if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) {
return fabs(a - b) < 0.0001f; return std::abs(a - b) < 0.0001f;
} }
return yoga::isUndefined(a) && yoga::isUndefined(b); return yoga::isUndefined(a) && yoga::isUndefined(b);
} }
inline bool inexactEquals(const double a, const double b) { inline bool inexactEquals(double a, double b) {
if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) { if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) {
return fabs(a - b) < 0.0001; return std::abs(a - b) < 0.0001;
} }
return yoga::isUndefined(a) && yoga::isUndefined(b); return yoga::isUndefined(a) && yoga::isUndefined(b);
} }
inline bool inexactEquals(const FloatOptional a, const FloatOptional b) {
return inexactEquals(a.unwrap(), b.unwrap());
}
inline bool inexactEquals(const YGValue& a, const YGValue& b) { inline bool inexactEquals(const YGValue& a, const YGValue& b) {
if (a.unit != b.unit) { if (a.unit != b.unit) {
return false; return false;

View File

@@ -7,7 +7,7 @@
#pragma once #pragma once
#include <cmath> #include <yoga/numeric/Comparison.h>
#include <limits> #include <limits>
namespace facebook::yoga { namespace facebook::yoga {
@@ -29,53 +29,61 @@ struct FloatOptional {
return isUndefined() ? defaultValue : value_; return isUndefined() ? defaultValue : value_;
} }
bool isUndefined() const { constexpr bool isUndefined() const {
return std::isnan(value_); return yoga::isUndefined(value_);
} }
}; };
// operators take FloatOptional by value, as it is a 32bit value // operators take FloatOptional by value, as it is a 32bit value
inline bool operator==(FloatOptional lhs, FloatOptional rhs) { constexpr bool operator==(FloatOptional lhs, FloatOptional rhs) {
return lhs.unwrap() == rhs.unwrap() || return lhs.unwrap() == rhs.unwrap() ||
(lhs.isUndefined() && rhs.isUndefined()); (lhs.isUndefined() && rhs.isUndefined());
} }
inline bool operator!=(FloatOptional lhs, FloatOptional rhs) { constexpr bool operator!=(FloatOptional lhs, FloatOptional rhs) {
return !(lhs == rhs); return !(lhs == rhs);
} }
inline bool operator==(FloatOptional lhs, float rhs) { constexpr bool operator==(FloatOptional lhs, float rhs) {
return lhs == FloatOptional{rhs}; return lhs == FloatOptional{rhs};
} }
inline bool operator!=(FloatOptional lhs, float rhs) { constexpr bool operator!=(FloatOptional lhs, float rhs) {
return !(lhs == rhs); return !(lhs == rhs);
} }
inline bool operator==(float lhs, FloatOptional rhs) { constexpr bool operator==(float lhs, FloatOptional rhs) {
return rhs == lhs; return rhs == lhs;
} }
inline bool operator!=(float lhs, FloatOptional rhs) { constexpr bool operator!=(float lhs, FloatOptional rhs) {
return !(lhs == rhs); return !(lhs == rhs);
} }
inline FloatOptional operator+(FloatOptional lhs, FloatOptional rhs) { constexpr FloatOptional operator+(FloatOptional lhs, FloatOptional rhs) {
return FloatOptional{lhs.unwrap() + rhs.unwrap()}; return FloatOptional{lhs.unwrap() + rhs.unwrap()};
} }
inline bool operator>(FloatOptional lhs, FloatOptional rhs) { constexpr bool operator>(FloatOptional lhs, FloatOptional rhs) {
return lhs.unwrap() > rhs.unwrap(); return lhs.unwrap() > rhs.unwrap();
} }
inline bool operator<(FloatOptional lhs, FloatOptional rhs) { constexpr bool operator<(FloatOptional lhs, FloatOptional rhs) {
return lhs.unwrap() < rhs.unwrap(); return lhs.unwrap() < rhs.unwrap();
} }
inline bool operator>=(FloatOptional lhs, FloatOptional rhs) { constexpr bool operator>=(FloatOptional lhs, FloatOptional rhs) {
return lhs > rhs || lhs == rhs; return lhs > rhs || lhs == rhs;
} }
inline bool operator<=(FloatOptional lhs, FloatOptional rhs) { constexpr bool operator<=(FloatOptional lhs, FloatOptional rhs) {
return lhs < rhs || lhs == rhs; return lhs < rhs || lhs == rhs;
} }
constexpr FloatOptional maxOrDefined(FloatOptional lhs, FloatOptional rhs) {
return FloatOptional{yoga::maxOrDefined(lhs.unwrap(), rhs.unwrap())};
}
inline bool inexactEquals(FloatOptional lhs, FloatOptional rhs) {
return yoga::inexactEquals(lhs.unwrap(), rhs.unwrap());
}
} // namespace facebook::yoga } // namespace facebook::yoga