Skip to content

Commit

Permalink
FloatOptional GCC build fix and more constexpr (#1411)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #1411

X-link: facebook/react-native#39796

Pull Request resolved: #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
  • Loading branch information
NickGerleman authored and facebook-github-bot committed Oct 6, 2023
1 parent f700e13 commit 7fe6e34
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 44 deletions.
2 changes: 2 additions & 0 deletions tests/FloatOptionalTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
* LICENSE file in the root directory of this source tree.
*/

#include <cmath>

#include <gtest/gtest.h>

#include <yoga/YGValue.h>
Expand Down
8 changes: 4 additions & 4 deletions yoga/algorithm/CalculateLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down
38 changes: 12 additions & 26 deletions yoga/numeric/Comparison.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
36 changes: 22 additions & 14 deletions yoga/numeric/FloatOptional.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

#pragma once

#include <cmath>
#include <yoga/numeric/Comparison.h>
#include <limits>

namespace facebook::yoga {
Expand All @@ -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

0 comments on commit 7fe6e34

Please sign in to comment.