From 0a4f7bd55825eb9beb4e2c75fe4c5ef6ec801bed Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Wed, 1 May 2019 06:47:30 -0700 Subject: [PATCH] `YGStyle`: mutable accessors return `Ref` instances Summary: @public Change style property accessors to return `Ref` instances instead of references to `CompactValue`. This will allow to track assignments to properties later on, e.g. for instrumentation or dynamic property storage. Reviewed By: SidharthGuglani Differential Revision: D15078961 fbshipit-source-id: 259f05f7d30f093c04bf333c5bd4fb3601b8e933 --- tests/YGStyleAccessorsTest.cpp | 13 +++- yoga/YGStyle.h | 130 ++++++++++++++++++++----------- yoga/Yoga.cpp | 136 +++++++++++++++++++-------------- 3 files changed, 174 insertions(+), 105 deletions(-) diff --git a/tests/YGStyleAccessorsTest.cpp b/tests/YGStyleAccessorsTest.cpp index 9e65ad55..1123ea6e 100644 --- a/tests/YGStyleAccessorsTest.cpp +++ b/tests/YGStyleAccessorsTest.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #define ACCESSOR_TESTS_1(NAME, X) \ style.NAME() = X; \ @@ -29,9 +29,14 @@ #define ACCESSOR_TESTS_N(a, b, c, d, e, COUNT, ...) ACCESSOR_TESTS_##COUNT #define ACCESSOR_TESTS(...) ACCESSOR_TESTS_N(__VA_ARGS__, 5, 4, 3, 2, 1) -#define INDEX_ACCESSOR_TESTS_1(NAME, IDX, X) \ - style.NAME()[IDX] = X; \ - ASSERT_EQ(style.NAME()[IDX], X); +#define INDEX_ACCESSOR_TESTS_1(NAME, IDX, X) \ + { \ + style.NAME()[IDX] = X; \ + ASSERT_EQ(style.NAME()[IDX], X); \ + auto asArray = decltype(std::declval().NAME()){X}; \ + style.NAME() = asArray; \ + ASSERT_EQ(static_cast(style.NAME()), asArray); \ + } #define INDEX_ACCESSOR_TESTS_2(NAME, IDX, X, Y) \ INDEX_ACCESSOR_TESTS_1(NAME, IDX, X) \ diff --git a/yoga/YGStyle.h b/yoga/YGStyle.h index 953c6ae8..849fa0e7 100644 --- a/yoga/YGStyle.h +++ b/yoga/YGStyle.h @@ -28,12 +28,47 @@ { *this, &YGStyle::get_##FIELD, &YGStyle::set_##FIELD } class YGStyle { + template + using Values = + facebook::yoga::detail::Values()>; using CompactValue = facebook::yoga::detail::CompactValue; public: - using Dimensions = facebook::yoga::detail::Values<2>; - using Edges = - facebook::yoga::detail::Values()>; + using Dimensions = Values; + using Edges = Values; + + template + struct Ref { + YGStyle& style; + operator T() const { return style.*Prop; } + Ref& operator=(T value) { + style.*Prop = value; + return *this; + } + }; + + template YGStyle::*Prop> + struct IdxRef { + struct Ref { + YGStyle& style; + Idx idx; + operator CompactValue() const { return (style.*Prop)[idx]; } + operator YGValue() const { return (style.*Prop)[idx]; } + Ref& operator=(CompactValue value) { + (style.*Prop)[idx] = value; + return *this; + } + }; + + YGStyle& style; + IdxRef& operator=(const Values& values) { + style.*Prop = values; + return *this; + } + operator const Values&() const { return style.*Prop; } + Ref operator[](Idx idx) { return {style, idx}; } + CompactValue operator[](Idx idx) const { return (style.*Prop)[idx]; } + }; template struct BitfieldRef { @@ -61,6 +96,37 @@ public: display_(YGDisplayFlex) {} ~YGStyle() = default; +private: + /* Some platforms don't support enum bitfields, + so please use BITFIELD_ENUM_SIZED(BITS_COUNT) */ + YGDirection direction_ BITFIELD_ENUM_SIZED(2); + YGFlexDirection flexDirection_ BITFIELD_ENUM_SIZED(2); + YGJustify justifyContent_ BITFIELD_ENUM_SIZED(3); + YGAlign alignContent_ BITFIELD_ENUM_SIZED(3); + YGAlign alignItems_ BITFIELD_ENUM_SIZED(3); + YGAlign alignSelf_ BITFIELD_ENUM_SIZED(3); + YGPositionType positionType_ BITFIELD_ENUM_SIZED(1); + YGWrap flexWrap_ BITFIELD_ENUM_SIZED(2); + YGOverflow overflow_ BITFIELD_ENUM_SIZED(2); + YGDisplay display_ BITFIELD_ENUM_SIZED(1); + YGFloatOptional flex_ = {}; + YGFloatOptional flexGrow_ = {}; + YGFloatOptional flexShrink_ = {}; + CompactValue flexBasis_ = CompactValue::ofAuto(); + Edges margin_ = {}; + Edges position_ = {}; + Edges padding_ = {}; + Edges border_ = {}; + Dimensions dimensions_{CompactValue::ofAuto()}; + Dimensions minDimensions_ = {}; + Dimensions maxDimensions_ = {}; + // Yoga specific properties, not compatible with flexbox specification + YGFloatOptional aspectRatio_ = {}; + +public: + // for library users needing a type + using ValueRepr = std::remove_reference::type; + YGDirection direction() const { return direction_; } BitfieldRef direction() { return BITFIELD_REF(direction); } @@ -98,69 +164,47 @@ public: BitfieldRef display() { return BITFIELD_REF(display); } YGFloatOptional flex() const { return flex_; } - YGFloatOptional& flex() { return flex_; } + Ref flex() { return {*this}; } YGFloatOptional flexGrow() const { return flexGrow_; } - YGFloatOptional& flexGrow() { return flexGrow_; } + Ref flexGrow() { return {*this}; } YGFloatOptional flexShrink() const { return flexShrink_; } - YGFloatOptional& flexShrink() { return flexShrink_; } + Ref flexShrink() { return {*this}; } CompactValue flexBasis() const { return flexBasis_; } - CompactValue& flexBasis() { return flexBasis_; } + Ref flexBasis() { return {*this}; } const Edges& margin() const { return margin_; } - Edges& margin() { return margin_; } + IdxRef margin() { return {*this}; } const Edges& position() const { return position_; } - Edges& position() { return position_; } + IdxRef position() { return {*this}; } const Edges& padding() const { return padding_; } - Edges& padding() { return padding_; } + IdxRef padding() { return {*this}; } const Edges& border() const { return border_; } - Edges& border() { return border_; } + IdxRef border() { return {*this}; } const Dimensions& dimensions() const { return dimensions_; } - Dimensions& dimensions() { return dimensions_; } + IdxRef dimensions() { return {*this}; } const Dimensions& minDimensions() const { return minDimensions_; } - Dimensions& minDimensions() { return minDimensions_; } + IdxRef minDimensions() { + return {*this}; + } const Dimensions& maxDimensions() const { return maxDimensions_; } - Dimensions& maxDimensions() { return maxDimensions_; } + IdxRef maxDimensions() { + return {*this}; + } // Yoga specific properties, not compatible with flexbox specification YGFloatOptional aspectRatio() const { return aspectRatio_; } - YGFloatOptional& aspectRatio() { return aspectRatio_; } + Ref aspectRatio() { return {*this}; } private: - /* Some platforms don't support enum bitfields, - so please use BITFIELD_ENUM_SIZED(BITS_COUNT) */ - YGDirection direction_ BITFIELD_ENUM_SIZED(2); - YGFlexDirection flexDirection_ BITFIELD_ENUM_SIZED(2); - YGJustify justifyContent_ BITFIELD_ENUM_SIZED(3); - YGAlign alignContent_ BITFIELD_ENUM_SIZED(3); - YGAlign alignItems_ BITFIELD_ENUM_SIZED(3); - YGAlign alignSelf_ BITFIELD_ENUM_SIZED(3); - YGPositionType positionType_ BITFIELD_ENUM_SIZED(1); - YGWrap flexWrap_ BITFIELD_ENUM_SIZED(2); - YGOverflow overflow_ BITFIELD_ENUM_SIZED(2); - YGDisplay display_ BITFIELD_ENUM_SIZED(1); - YGFloatOptional flex_ = {}; - YGFloatOptional flexGrow_ = {}; - YGFloatOptional flexShrink_ = {}; - CompactValue flexBasis_ = CompactValue::ofAuto(); - Edges margin_ = {}; - Edges position_ = {}; - Edges padding_ = {}; - Edges border_ = {}; - Dimensions dimensions_{CompactValue::ofAuto()}; - Dimensions minDimensions_ = {}; - Dimensions maxDimensions_ = {}; - // Yoga specific properties, not compatible with flexbox specification - YGFloatOptional aspectRatio_ = {}; - BITFIELD_ACCESSORS(direction) BITFIELD_ACCESSORS(flexDirection) BITFIELD_ACCESSORS(justifyContent) @@ -171,10 +215,6 @@ private: BITFIELD_ACCESSORS(flexWrap); BITFIELD_ACCESSORS(overflow); BITFIELD_ACCESSORS(display); - -public: - // for library users needing a type - using ValueRepr = std::remove_reference::type; }; bool operator==(const YGStyle& lhs, const YGStyle& rhs); diff --git a/yoga/Yoga.cpp b/yoga/Yoga.cpp index 39d0a767..745188a4 100644 --- a/yoga/Yoga.cpp +++ b/yoga/Yoga.cpp @@ -558,36 +558,27 @@ void updateStyle(YGNode* node, T value) { [](YGStyle& s, T x) { (s.*Prop)() = x; }); } -template -void updateStyle(YGNode* node, T value) { +template +void updateStyle(YGNode* node, Ref (YGStyle::*prop)(), T value) { updateStyle( node, value, - [](YGStyle& s, T x) { return (s.*Prop)() != x; }, - [](YGStyle& s, T x) { (s.*Prop)() = x; }); + [prop](YGStyle& s, T x) { return (s.*prop)() != x; }, + [prop](YGStyle& s, T x) { (s.*prop)() = x; }); } -template ()>& (YGStyle::*Prop)()> -void updateIndexedStyleProp(YGNode* node, Idx idx, detail::CompactValue value) { +template +void updateIndexedStyleProp( + YGNode* node, + Ref (YGStyle::*prop)(), + Idx idx, + detail::CompactValue value) { using detail::CompactValue; updateStyle( node, value, - [idx](YGStyle& s, CompactValue x) { return (s.*Prop)()[idx] != x; }, - [idx](YGStyle& s, CompactValue x) { (s.*Prop)()[idx] = x; }); -} - -template -void updateEdgeProp(YGNode* node, YGEdge edge, detail::CompactValue value) { - updateIndexedStyleProp(node, edge, value); -} - -template -void updateDimensionProp( - YGNode* node, - YGDimension dimension, - detail::CompactValue value) { - updateIndexedStyleProp(node, dimension, value); + [idx, prop](YGStyle& s, CompactValue x) { return (s.*prop)()[idx] != x; }, + [idx, prop](YGStyle& s, CompactValue x) { (s.*prop)()[idx] = x; }); } } // namespace @@ -670,9 +661,16 @@ YGDisplay YGNodeStyleGetDisplay(const YGNodeConstRef node) { return node->getStyle().display(); } +// MSVC has trouble inferring the return type of pointer to member functions +// with const and non-const overloads, instead of preferring the non-const +// overload like clang and GCC. For the purposes of updateStyle(), we can help +// MSVC by specifying that return type explicitely. In combination with +// decltype, MSVC will prefer the non-const version. +#define MSVC_HINT(PROP) decltype(YGStyle{}.PROP()) + // TODO(T26792433): Change the API to accept YGFloatOptional. void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) { - updateStyle(node, YGFloatOptional{flex}); + updateStyle(node, &YGStyle::flex, YGFloatOptional{flex}); } // TODO(T26792433): Change the API to accept YGFloatOptional. @@ -684,14 +682,14 @@ float YGNodeStyleGetFlex(const YGNodeConstRef node) { // TODO(T26792433): Change the API to accept YGFloatOptional. void YGNodeStyleSetFlexGrow(const YGNodeRef node, const float flexGrow) { - updateStyle( - node, YGFloatOptional{flexGrow}); + updateStyle( + node, &YGStyle::flexGrow, YGFloatOptional{flexGrow}); } // TODO(T26792433): Change the API to accept YGFloatOptional. void YGNodeStyleSetFlexShrink(const YGNodeRef node, const float flexShrink) { - updateStyle( - node, YGFloatOptional{flexShrink}); + updateStyle( + node, &YGStyle::flexShrink, YGFloatOptional{flexShrink}); } YGValue YGNodeStyleGetFlexBasis(const YGNodeConstRef node) { @@ -705,28 +703,30 @@ YGValue YGNodeStyleGetFlexBasis(const YGNodeConstRef node) { void YGNodeStyleSetFlexBasis(const YGNodeRef node, const float flexBasis) { auto value = detail::CompactValue::ofMaybe(flexBasis); - updateStyle(node, value); + updateStyle(node, &YGStyle::flexBasis, value); } void YGNodeStyleSetFlexBasisPercent( const YGNodeRef node, const float flexBasisPercent) { auto value = detail::CompactValue::ofMaybe(flexBasisPercent); - updateStyle(node, value); + updateStyle(node, &YGStyle::flexBasis, value); } void YGNodeStyleSetFlexBasisAuto(const YGNodeRef node) { - updateStyle( - node, detail::CompactValue::ofAuto()); + updateStyle( + node, &YGStyle::flexBasis, detail::CompactValue::ofAuto()); } void YGNodeStyleSetPosition(YGNodeRef node, YGEdge edge, float points) { auto value = detail::CompactValue::ofMaybe(points); - updateEdgeProp<&YGStyle::position>(node, edge, value); + updateIndexedStyleProp( + node, &YGStyle::position, edge, value); } void YGNodeStyleSetPositionPercent(YGNodeRef node, YGEdge edge, float percent) { auto value = detail::CompactValue::ofMaybe(percent); - updateEdgeProp<&YGStyle::position>(node, edge, value); + updateIndexedStyleProp( + node, &YGStyle::position, edge, value); } YGValue YGNodeStyleGetPosition(YGNodeConstRef node, YGEdge edge) { return node->getStyle().position()[edge]; @@ -734,14 +734,17 @@ YGValue YGNodeStyleGetPosition(YGNodeConstRef node, YGEdge edge) { void YGNodeStyleSetMargin(YGNodeRef node, YGEdge edge, float points) { auto value = detail::CompactValue::ofMaybe(points); - updateEdgeProp<&YGStyle::margin>(node, edge, value); + updateIndexedStyleProp( + node, &YGStyle::margin, edge, value); } void YGNodeStyleSetMarginPercent(YGNodeRef node, YGEdge edge, float percent) { auto value = detail::CompactValue::ofMaybe(percent); - updateEdgeProp<&YGStyle::margin>(node, edge, value); + updateIndexedStyleProp( + node, &YGStyle::margin, edge, value); } void YGNodeStyleSetMarginAuto(YGNodeRef node, YGEdge edge) { - updateEdgeProp<&YGStyle::margin>(node, edge, detail::CompactValue::ofAuto()); + updateIndexedStyleProp( + node, &YGStyle::margin, edge, detail::CompactValue::ofAuto()); } YGValue YGNodeStyleGetMargin(YGNodeConstRef node, YGEdge edge) { return node->getStyle().margin()[edge]; @@ -749,11 +752,13 @@ YGValue YGNodeStyleGetMargin(YGNodeConstRef node, YGEdge edge) { void YGNodeStyleSetPadding(YGNodeRef node, YGEdge edge, float points) { auto value = detail::CompactValue::ofMaybe(points); - updateEdgeProp<&YGStyle::padding>(node, edge, value); + updateIndexedStyleProp( + node, &YGStyle::padding, edge, value); } void YGNodeStyleSetPaddingPercent(YGNodeRef node, YGEdge edge, float percent) { auto value = detail::CompactValue::ofMaybe(percent); - updateEdgeProp<&YGStyle::padding>(node, edge, value); + updateIndexedStyleProp( + node, &YGStyle::padding, edge, value); } YGValue YGNodeStyleGetPadding(YGNodeConstRef node, YGEdge edge) { return node->getStyle().padding()[edge]; @@ -765,7 +770,8 @@ void YGNodeStyleSetBorder( const YGEdge edge, const float border) { auto value = detail::CompactValue::ofMaybe(border); - updateEdgeProp<&YGStyle::border>(node, edge, value); + updateIndexedStyleProp( + node, &YGStyle::border, edge, value); } float YGNodeStyleGetBorder(const YGNodeConstRef node, const YGEdge edge) { @@ -789,21 +795,26 @@ float YGNodeStyleGetAspectRatio(const YGNodeConstRef node) { // TODO(T26792433): Change the API to accept YGFloatOptional. void YGNodeStyleSetAspectRatio(const YGNodeRef node, const float aspectRatio) { - updateStyle( - node, YGFloatOptional{aspectRatio}); + updateStyle( + node, &YGStyle::aspectRatio, YGFloatOptional{aspectRatio}); } void YGNodeStyleSetWidth(YGNodeRef node, float points) { auto value = detail::CompactValue::ofMaybe(points); - updateDimensionProp<&YGStyle::dimensions>(node, YGDimensionWidth, value); + updateIndexedStyleProp( + node, &YGStyle::dimensions, YGDimensionWidth, value); } void YGNodeStyleSetWidthPercent(YGNodeRef node, float percent) { auto value = detail::CompactValue::ofMaybe(percent); - updateDimensionProp<&YGStyle::dimensions>(node, YGDimensionWidth, value); + updateIndexedStyleProp( + node, &YGStyle::dimensions, YGDimensionWidth, value); } void YGNodeStyleSetWidthAuto(YGNodeRef node) { - updateDimensionProp<&YGStyle::dimensions>( - node, YGDimensionWidth, detail::CompactValue::ofAuto()); + updateIndexedStyleProp( + node, + &YGStyle::dimensions, + YGDimensionWidth, + detail::CompactValue::ofAuto()); } YGValue YGNodeStyleGetWidth(YGNodeConstRef node) { return node->getStyle().dimensions()[YGDimensionWidth]; @@ -811,15 +822,20 @@ YGValue YGNodeStyleGetWidth(YGNodeConstRef node) { void YGNodeStyleSetHeight(YGNodeRef node, float points) { auto value = detail::CompactValue::ofMaybe(points); - updateDimensionProp<&YGStyle::dimensions>(node, YGDimensionHeight, value); + updateIndexedStyleProp( + node, &YGStyle::dimensions, YGDimensionHeight, value); } void YGNodeStyleSetHeightPercent(YGNodeRef node, float percent) { auto value = detail::CompactValue::ofMaybe(percent); - updateDimensionProp<&YGStyle::dimensions>(node, YGDimensionHeight, value); + updateIndexedStyleProp( + node, &YGStyle::dimensions, YGDimensionHeight, value); } void YGNodeStyleSetHeightAuto(YGNodeRef node) { - updateDimensionProp<&YGStyle::dimensions>( - node, YGDimensionHeight, detail::CompactValue::ofAuto()); + updateIndexedStyleProp( + node, + &YGStyle::dimensions, + YGDimensionHeight, + detail::CompactValue::ofAuto()); } YGValue YGNodeStyleGetHeight(YGNodeConstRef node) { return node->getStyle().dimensions()[YGDimensionHeight]; @@ -827,11 +843,13 @@ YGValue YGNodeStyleGetHeight(YGNodeConstRef node) { void YGNodeStyleSetMinWidth(const YGNodeRef node, const float minWidth) { auto value = detail::CompactValue::ofMaybe(minWidth); - updateDimensionProp<&YGStyle::minDimensions>(node, YGDimensionWidth, value); + updateIndexedStyleProp( + node, &YGStyle::minDimensions, YGDimensionWidth, value); } void YGNodeStyleSetMinWidthPercent(const YGNodeRef node, const float minWidth) { auto value = detail::CompactValue::ofMaybe(minWidth); - updateDimensionProp<&YGStyle::minDimensions>(node, YGDimensionWidth, value); + updateIndexedStyleProp( + node, &YGStyle::minDimensions, YGDimensionWidth, value); } YGValue YGNodeStyleGetMinWidth(const YGNodeConstRef node) { return node->getStyle().minDimensions()[YGDimensionWidth]; @@ -839,13 +857,15 @@ YGValue YGNodeStyleGetMinWidth(const YGNodeConstRef node) { void YGNodeStyleSetMinHeight(const YGNodeRef node, const float minHeight) { auto value = detail::CompactValue::ofMaybe(minHeight); - updateDimensionProp<&YGStyle::minDimensions>(node, YGDimensionHeight, value); + updateIndexedStyleProp( + node, &YGStyle::minDimensions, YGDimensionHeight, value); } void YGNodeStyleSetMinHeightPercent( const YGNodeRef node, const float minHeight) { auto value = detail::CompactValue::ofMaybe(minHeight); - updateDimensionProp<&YGStyle::minDimensions>(node, YGDimensionHeight, value); + updateIndexedStyleProp( + node, &YGStyle::minDimensions, YGDimensionHeight, value); } YGValue YGNodeStyleGetMinHeight(const YGNodeConstRef node) { return node->getStyle().minDimensions()[YGDimensionHeight]; @@ -853,11 +873,13 @@ YGValue YGNodeStyleGetMinHeight(const YGNodeConstRef node) { void YGNodeStyleSetMaxWidth(const YGNodeRef node, const float maxWidth) { auto value = detail::CompactValue::ofMaybe(maxWidth); - updateDimensionProp<&YGStyle::maxDimensions>(node, YGDimensionWidth, value); + updateIndexedStyleProp( + node, &YGStyle::maxDimensions, YGDimensionWidth, value); } void YGNodeStyleSetMaxWidthPercent(const YGNodeRef node, const float maxWidth) { auto value = detail::CompactValue::ofMaybe(maxWidth); - updateDimensionProp<&YGStyle::maxDimensions>(node, YGDimensionWidth, value); + updateIndexedStyleProp( + node, &YGStyle::maxDimensions, YGDimensionWidth, value); } YGValue YGNodeStyleGetMaxWidth(const YGNodeConstRef node) { return node->getStyle().maxDimensions()[YGDimensionWidth]; @@ -865,13 +887,15 @@ YGValue YGNodeStyleGetMaxWidth(const YGNodeConstRef node) { void YGNodeStyleSetMaxHeight(const YGNodeRef node, const float maxHeight) { auto value = detail::CompactValue::ofMaybe(maxHeight); - updateDimensionProp<&YGStyle::maxDimensions>(node, YGDimensionHeight, value); + updateIndexedStyleProp( + node, &YGStyle::maxDimensions, YGDimensionHeight, value); } void YGNodeStyleSetMaxHeightPercent( const YGNodeRef node, const float maxHeight) { auto value = detail::CompactValue::ofMaybe(maxHeight); - updateDimensionProp<&YGStyle::maxDimensions>(node, YGDimensionHeight, value); + updateIndexedStyleProp( + node, &YGStyle::maxDimensions, YGDimensionHeight, value); } YGValue YGNodeStyleGetMaxHeight(const YGNodeConstRef node) { return node->getStyle().maxDimensions()[YGDimensionHeight];