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.
*/
#include <cmath>
#include <gtest/gtest.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
const float innerWidth = yoga::isUndefined(availableWidth)
? availableWidth
: yoga::maxOrDefined(0, availableWidth - paddingAndBorderAxisRow);
: yoga::maxOrDefined(0.0f, availableWidth - paddingAndBorderAxisRow);
const float innerHeight = yoga::isUndefined(availableHeight)
? availableHeight
: yoga::maxOrDefined(0, availableHeight - paddingAndBorderAxisColumn);
: yoga::maxOrDefined(0.0f, availableHeight - paddingAndBorderAxisColumn);
if (widthMeasureMode == MeasureMode::Exactly &&
heightMeasureMode == MeasureMode::Exactly) {
@@ -1223,7 +1223,7 @@ static void justifyMainAxis(
const float occupiedSpaceByChildNodes =
availableInnerMainDim - flexLine.layout.remainingFreeSpace;
flexLine.layout.remainingFreeSpace = yoga::maxOrDefined(
0, minAvailableMainDim - occupiedSpaceByChildNodes);
0.0f, minAvailableMainDim - occupiedSpaceByChildNodes);
} else {
flexLine.layout.remainingFreeSpace = 0;
}
@@ -1260,7 +1260,7 @@ static void justifyMainAxis(
case Justify::SpaceBetween:
if (flexLine.itemsInFlow.size() > 1) {
betweenMainDim +=
yoga::maxOrDefined(flexLine.layout.remainingFreeSpace, 0) /
yoga::maxOrDefined(flexLine.layout.remainingFreeSpace, 0.0f) /
static_cast<float>(flexLine.itemsInFlow.size() - 1);
}
break;

View File

@@ -7,63 +7,49 @@
#pragma once
#include <algorithm>
#include <array>
#include <cmath>
#include <yoga/Yoga.h>
#include <yoga/numeric/FloatOptional.h>
namespace facebook::yoga {
template <typename FloatT>
inline bool isUndefined(FloatT value) {
return std::isnan(value);
constexpr bool isUndefined(auto value) {
return value != value;
}
inline float maxOrDefined(const float a, const float b) {
constexpr auto maxOrDefined(auto a, auto b) {
if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) {
return fmaxf(a, b);
return std::max(a, b);
}
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)) {
return fminf(a, b);
return std::min(a, b);
}
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
// 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)) {
return fabs(a - b) < 0.0001f;
return std::abs(a - b) < 0.0001f;
}
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)) {
return fabs(a - b) < 0.0001;
return std::abs(a - b) < 0.0001;
}
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) {
if (a.unit != b.unit) {
return false;

View File

@@ -7,7 +7,7 @@
#pragma once
#include <cmath>
#include <yoga/numeric/Comparison.h>
#include <limits>
namespace facebook::yoga {
@@ -29,53 +29,61 @@ struct FloatOptional {
return isUndefined() ? defaultValue : value_;
}
bool isUndefined() const {
return std::isnan(value_);
constexpr bool isUndefined() const {
return yoga::isUndefined(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() ||
(lhs.isUndefined() && rhs.isUndefined());
}
inline bool operator!=(FloatOptional lhs, FloatOptional rhs) {
constexpr bool operator!=(FloatOptional lhs, FloatOptional rhs) {
return !(lhs == rhs);
}
inline bool operator==(FloatOptional lhs, float rhs) {
constexpr bool operator==(FloatOptional lhs, float rhs) {
return lhs == FloatOptional{rhs};
}
inline bool operator!=(FloatOptional lhs, float rhs) {
constexpr bool operator!=(FloatOptional lhs, float rhs) {
return !(lhs == rhs);
}
inline bool operator==(float lhs, FloatOptional rhs) {
constexpr bool operator==(float lhs, FloatOptional rhs) {
return rhs == lhs;
}
inline bool operator!=(float lhs, FloatOptional rhs) {
constexpr bool operator!=(float lhs, FloatOptional rhs) {
return !(lhs == rhs);
}
inline FloatOptional operator+(FloatOptional lhs, FloatOptional rhs) {
constexpr FloatOptional operator+(FloatOptional lhs, FloatOptional rhs) {
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();
}
inline bool operator<(FloatOptional lhs, FloatOptional rhs) {
constexpr bool operator<(FloatOptional lhs, FloatOptional rhs) {
return lhs.unwrap() < rhs.unwrap();
}
inline bool operator>=(FloatOptional lhs, FloatOptional rhs) {
constexpr bool operator>=(FloatOptional lhs, FloatOptional 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;
}
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