Skip to content

Commit

Permalink
Change NaN with large number
Browse files Browse the repository at this point in the history
Reviewed By: emilsjolander

Differential Revision: D6969537

fbshipit-source-id: bdc09eaf703e0d313ca65c25a4fb44c99203d9bf
  • Loading branch information
priteshrnandgaonkar authored and facebook-github-bot committed Mar 1, 2018
1 parent af9d647 commit d174ab8
Show file tree
Hide file tree
Showing 11 changed files with 262 additions and 127 deletions.
21 changes: 19 additions & 2 deletions ReactAndroid/src/main/java/com/facebook/yoga/YogaConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,29 @@

public class YogaConstants {

public static final float UNDEFINED = Float.NaN;
/**
* Large positive number signifies that the property(float) is undefined. Earlier we used to have
* YGundefined as NAN, but the downside of this is that we can't use -ffast-math compiler flag as
* it assumes all floating-point calculation involve and result into finite numbers. For more
* information regarding -ffast-math compiler flag in clang, have a look at
* https://clang.llvm.org/docs/UsersManual.html#cmdoption-ffast-math
*/
public static final float UNDEFINED = (float) (10E20);

public static boolean shouldUseFastMath = false;

public static boolean isUndefined(float value) {
return Float.compare(value, UNDEFINED) == 0;
// Value of a float in the case of it being not defined is 10.1E20. Earlier it used to be NAN,
// the benefit of which
// was that if NAN is involved in any mathematical expression the result was NAN. But since we
// want to have `-ffast-math`
// flag being used by compiler which assumes that the floating point values are not NAN and Inf,
// we represent YGUndefined as 10.1E20.
// But now if YGUndefined is involved in any mathematical operations this value(10.1E20) would
// change.
// So the following check makes sure that if the value is outside a range (-10E8, 10E8) then it
// is undefined.
return (Float.compare(value, (float) 10E8) >= 0 || Float.compare(value, (float) -10E8) <= 0);
}

public static boolean isUndefined(YogaValue value) {
Expand Down
10 changes: 5 additions & 5 deletions ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -652,11 +652,11 @@ public final long measure(float width, int widthMode, float height, int heightMo
}

return mMeasureFunction.measure(
this,
width,
YogaMeasureMode.fromInt(widthMode),
height,
YogaMeasureMode.fromInt(heightMode));
this,
width,
YogaMeasureMode.fromInt(widthMode),
height,
YogaMeasureMode.fromInt(heightMode));
}

private native void jni_YGNodeSetHasBaselineFunc(long nativePointer, boolean hasMeasureFunc);
Expand Down
16 changes: 9 additions & 7 deletions ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,13 +337,15 @@ struct JYogaValue : public JavaClass<JYogaValue> {
}
};

#define YG_NODE_JNI_STYLE_PROP(javatype, type, name) \
javatype jni_YGNodeStyleGet##name(alias_ref<jobject>, jlong nativePointer) { \
return (javatype) YGNodeStyleGet##name(_jlong2YGNodeRef(nativePointer)); \
} \
\
void jni_YGNodeStyleSet##name(alias_ref<jobject>, jlong nativePointer, javatype value) { \
YGNodeStyleSet##name(_jlong2YGNodeRef(nativePointer), static_cast<type>(value)); \
#define YG_NODE_JNI_STYLE_PROP(javatype, type, name) \
javatype jni_YGNodeStyleGet##name(alias_ref<jobject>, jlong nativePointer) { \
return (javatype)YGNodeStyleGet##name(_jlong2YGNodeRef(nativePointer)); \
} \
\
void jni_YGNodeStyleSet##name( \
alias_ref<jobject>, jlong nativePointer, javatype value) { \
YGNodeStyleSet##name( \
_jlong2YGNodeRef(nativePointer), static_cast<type>(value)); \
}

#define YG_NODE_JNI_STYLE_UNIT_PROP(name) \
Expand Down
24 changes: 23 additions & 1 deletion ReactCommon/yoga/yoga/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,37 @@ YGFlexDirection YGFlexDirectionCross(
: YGFlexDirectionColumn;
}

float YGFloatMax(const float a, const float b) {
if (!YGFloatIsUndefined(a) && !YGFloatIsUndefined(b)) {
return fmaxf(a, b);
}
return YGFloatIsUndefined(a) ? b : a;
}

float YGFloatMin(const float a, const float b) {
if (!YGFloatIsUndefined(a) && !YGFloatIsUndefined(b)) {
return fminf(a, b);
}

return YGFloatIsUndefined(a) ? b : a;
}

bool YGValueEqual(const YGValue a, const YGValue b) {
if (a.unit != b.unit) {
return false;
}

if (a.unit == YGUnitUndefined ||
(std::isnan(a.value) && std::isnan(b.value))) {
(YGFloatIsUndefined(a.value) && YGFloatIsUndefined(b.value))) {
return true;
}

return fabs(a.value - b.value) < 0.0001f;
}

bool YGFloatsEqual(const float a, const float b) {
if (!YGFloatIsUndefined(a) && !YGFloatIsUndefined(b)) {
return fabs(a - b) < 0.0001f;
}
return YGFloatIsUndefined(a) && YGFloatIsUndefined(b);
}
34 changes: 33 additions & 1 deletion ReactCommon/yoga/yoga/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,38 @@ struct YGCollectFlexItemsRowValues {

bool YGValueEqual(const YGValue a, const YGValue b);

// This custom float equality function returns true if either absolute
// difference between two floats is less than 0.0001f or both are undefined.
bool YGFloatsEqual(const float a, const float b);

// We need custom max function, since we want that, if one argument is
// YGUndefined then the max funtion should return the other argument as the max
// value. We wouldn't have needed a custom max function if YGUndefined was NAN
// as fmax has the same behaviour, but with NAN we cannot use `-ffast-math`
// compiler flag.
float YGFloatMax(const float a, const float b);

// We need custom min function, since we want that, if one argument is
// YGUndefined then the min funtion should return the other argument as the min
// value. We wouldn't have needed a custom min function if YGUndefined was NAN
// as fmin has the same behaviour, but with NAN we cannot use `-ffast-math`
// compiler flag.
float YGFloatMin(const float a, const float b);

// This custom float comparision function compares the array of float with
// YGFloatsEqual, as the default float comparision operator will not work(Look
// at the comments of YGFloatsEqual function).
template <std::size_t size>
bool YGFloatArrayEqual(
const std::array<float, size>& val1,
const std::array<float, size>& val2) {
bool areEqual = true;
for (std::size_t i = 0; i < size && areEqual; ++i) {
areEqual = YGFloatsEqual(val1[i], val2[i]);
}
return areEqual;
}

YGFlexDirection YGFlexDirectionCross(
const YGFlexDirection flexDirection,
const YGDirection direction);
Expand All @@ -71,7 +103,7 @@ inline float YGResolveValue(const YGValue value, const float parentSize) {
case YGUnitPoint:
return value.value;
case YGUnitPercent:
return value.value * parentSize / 100.0f;
return value.value * parentSize * 0.01;
}
return YGUndefined;
}
Expand Down
9 changes: 6 additions & 3 deletions ReactCommon/yoga/yoga/YGLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* of patent rights can be found in the PATENTS file in the same directory.
*/
#include "YGLayout.h"
#include "Utils.h"

const std::array<float, 2> kYGDefaultDimensionValues = {
{YGUndefined, YGUndefined}};
Expand All @@ -31,9 +32,11 @@ YGLayout::YGLayout()
doesLegacyStretchFlagAffectsLayout(false) {}

bool YGLayout::operator==(YGLayout layout) const {
bool isEqual = position == layout.position &&
dimensions == layout.dimensions && margin == layout.margin &&
border == layout.border && padding == layout.padding &&
bool isEqual = YGFloatArrayEqual(position, layout.position) &&
YGFloatArrayEqual(dimensions, layout.dimensions) &&
YGFloatArrayEqual(margin, layout.margin) &&
YGFloatArrayEqual(border, layout.border) &&
YGFloatArrayEqual(padding, layout.padding) &&
direction == layout.direction && hadOverflow == layout.hadOverflow &&
lastParentDirection == layout.lastParentDirection &&
nextCachedMeasurementsIndex == layout.nextCachedMeasurementsIndex &&
Expand Down
41 changes: 24 additions & 17 deletions ReactCommon/yoga/yoga/YGNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -624,56 +624,63 @@ bool YGNode::isNodeFlexible() {
float YGNode::getLeadingBorder(const YGFlexDirection axis) {
if (YGFlexDirectionIsRow(axis) &&
style_.border[YGEdgeStart].unit != YGUnitUndefined &&
!YGFloatIsUndefined(style_.border[YGEdgeStart].value) &&
style_.border[YGEdgeStart].value >= 0.0f) {
return style_.border[YGEdgeStart].value;
}

return fmaxf(
YGComputedEdgeValue(style_.border, leading[axis], &YGValueZero)->value,
0.0f);
float computedEdgeValue =
YGComputedEdgeValue(style_.border, leading[axis], &YGValueZero)->value;
return YGFloatMax(computedEdgeValue, 0.0f);
}

float YGNode::getTrailingBorder(const YGFlexDirection flexDirection) {
if (YGFlexDirectionIsRow(flexDirection) &&
style_.border[YGEdgeEnd].unit != YGUnitUndefined &&
!YGFloatIsUndefined(style_.border[YGEdgeEnd].value) &&
style_.border[YGEdgeEnd].value >= 0.0f) {
return style_.border[YGEdgeEnd].value;
}

return fmaxf(
float computedEdgeValue =
YGComputedEdgeValue(style_.border, trailing[flexDirection], &YGValueZero)
->value,
0.0f);
->value;
return YGFloatMax(computedEdgeValue, 0.0f);
}

float YGNode::getLeadingPadding(
const YGFlexDirection axis,
const float widthSize) {
if (YGFlexDirectionIsRow(axis) &&
style_.padding[YGEdgeStart].unit != YGUnitUndefined &&
YGResolveValue(style_.padding[YGEdgeStart], widthSize) >= 0.0f) {
!YGFloatIsUndefined(
YGResolveValue(style_.padding[YGEdgeStart], widthSize)) &&
YGResolveValue(style_.padding[YGEdgeStart], widthSize) > 0.0f) {
return YGResolveValue(style_.padding[YGEdgeStart], widthSize);
}
return fmaxf(
YGResolveValue(
*YGComputedEdgeValue(style_.padding, leading[axis], &YGValueZero),
widthSize),
0.0f);

float resolvedValue = YGResolveValue(
*YGComputedEdgeValue(style_.padding, leading[axis], &YGValueZero),
widthSize);
return YGFloatMax(resolvedValue, 0.0f);
}

float YGNode::getTrailingPadding(
const YGFlexDirection axis,
const float widthSize) {
if (YGFlexDirectionIsRow(axis) &&
style_.padding[YGEdgeEnd].unit != YGUnitUndefined &&
!YGFloatIsUndefined(
YGResolveValue(style_.padding[YGEdgeEnd], widthSize)) &&
YGResolveValue(style_.padding[YGEdgeEnd], widthSize) >= 0.0f) {
return YGResolveValue(style_.padding[YGEdgeEnd], widthSize);
}
return fmaxf(
YGResolveValue(
*YGComputedEdgeValue(style_.padding, trailing[axis], &YGValueZero),
widthSize),
0.0f);

float resolvedValue = YGResolveValue(
*YGComputedEdgeValue(style_.padding, trailing[axis], &YGValueZero),
widthSize);

return YGFloatMax(resolvedValue, 0.0f);
}

float YGNode::getLeadingPaddingAndBorder(
Expand Down
10 changes: 6 additions & 4 deletions ReactCommon/yoga/yoga/YGStyle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,21 +70,23 @@ bool YGStyle::operator==(const YGStyle& style) {
YGValueArrayEqual(minDimensions, style.minDimensions) &&
YGValueArrayEqual(maxDimensions, style.maxDimensions);

if (!(std::isnan(flex) && std::isnan(style.flex))) {
if (!(YGFloatIsUndefined(flex) && YGFloatIsUndefined(style.flex))) {
areNonFloatValuesEqual = areNonFloatValuesEqual && flex == style.flex;
}

if (!(std::isnan(flexGrow) && std::isnan(style.flexGrow))) {
if (!(YGFloatIsUndefined(flexGrow) && YGFloatIsUndefined(style.flexGrow))) {
areNonFloatValuesEqual =
areNonFloatValuesEqual && flexGrow == style.flexGrow;
}

if (!(std::isnan(flexShrink) && std::isnan(style.flexShrink))) {
if (!(YGFloatIsUndefined(flexShrink) &&
YGFloatIsUndefined(style.flexShrink))) {
areNonFloatValuesEqual =
areNonFloatValuesEqual && flexShrink == style.flexShrink;
}

if (!(std::isnan(aspectRatio) && std::isnan(style.aspectRatio))) {
if (!(YGFloatIsUndefined(aspectRatio) &&
YGFloatIsUndefined(style.aspectRatio))) {
areNonFloatValuesEqual =
areNonFloatValuesEqual && aspectRatio == style.aspectRatio;
}
Expand Down
15 changes: 8 additions & 7 deletions ReactCommon/yoga/yoga/Yoga-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,20 @@ struct YGCachedMeasurement {
bool isEqual = widthMeasureMode == measurement.widthMeasureMode &&
heightMeasureMode == measurement.heightMeasureMode;

if (!std::isnan(availableWidth) ||
!std::isnan(measurement.availableWidth)) {
if (!YGFloatIsUndefined(availableWidth) ||
!YGFloatIsUndefined(measurement.availableWidth)) {
isEqual = isEqual && availableWidth == measurement.availableWidth;
}
if (!std::isnan(availableHeight) ||
!std::isnan(measurement.availableHeight)) {
if (!YGFloatIsUndefined(availableHeight) ||
!YGFloatIsUndefined(measurement.availableHeight)) {
isEqual = isEqual && availableHeight == measurement.availableHeight;
}
if (!std::isnan(computedWidth) || !std::isnan(measurement.computedWidth)) {
if (!YGFloatIsUndefined(computedWidth) ||
!YGFloatIsUndefined(measurement.computedWidth)) {
isEqual = isEqual && computedWidth == measurement.computedWidth;
}
if (!std::isnan(computedHeight) ||
!std::isnan(measurement.computedHeight)) {
if (!YGFloatIsUndefined(computedHeight) ||
!YGFloatIsUndefined(measurement.computedHeight)) {
isEqual = isEqual && computedHeight == measurement.computedHeight;
}

Expand Down
Loading

0 comments on commit d174ab8

Please sign in to comment.