Skip to content

Commit

Permalink
Remove BitUtils Usage in YGNode (microsoft#1250)
Browse files Browse the repository at this point in the history
Summary:
X-link: facebook/yoga#1250

Pull Request resolved: facebook#36988

BitUtils functions in Yoga are like bit fields, with more steps, and more error prone (you need to work with explicit offsets which can be tricky for anything variable length). Replace usage with a bitfield struct. Eventually I'd like to remove the BitUtils functions in general.

Changelog: [Internal]

Reviewed By: rshest

Differential Revision: D45133645

fbshipit-source-id: aa1430df5e2fb71ed9d2a5f5b1a35429b71c7069
  • Loading branch information
NickGerleman authored and facebook-github-bot committed Apr 21, 2023
1 parent 4260494 commit 4ae77c0
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 52 deletions.
36 changes: 15 additions & 21 deletions packages/react-native/ReactCommon/yoga/yoga/YGNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@
#include "YGNode.h"
#include <algorithm>
#include <iostream>
#include "CompactValue.h"
#include "Utils.h"

using namespace facebook;
using facebook::yoga::detail::CompactValue;

YGNode::YGNode(YGNode&& node) {
context_ = node.context_;
flags = node.flags;
flags_ = node.flags_;
measure_ = node.measure_;
baseline_ = node.baseline_;
print_ = node.print_;
Expand All @@ -42,7 +41,7 @@ YGNode::YGNode(const YGNode& node, YGConfigRef config) : YGNode{node} {

void YGNode::print(void* printContext) {
if (print_.noContext != nullptr) {
if (facebook::yoga::detail::getBooleanData(flags, printUsesContext_)) {
if (flags_.printUsesContext) {
print_.withContext(this, printContext);
} else {
print_.noContext(this);
Expand Down Expand Up @@ -202,14 +201,14 @@ YGSize YGNode::measure(
float height,
YGMeasureMode heightMode,
void* layoutContext) {
return facebook::yoga::detail::getBooleanData(flags, measureUsesContext_)
return flags_.measureUsesContext
? measure_.withContext(
this, width, widthMode, height, heightMode, layoutContext)
: measure_.noContext(this, width, widthMode, height, heightMode);
}

float YGNode::baseline(float width, float height, void* layoutContext) {
return facebook::yoga::detail::getBooleanData(flags, baselineUsesContext_)
return flags_.baselineUsesContext
? baseline_.withContext(this, width, height, layoutContext)
: baseline_.noContext(this, width, height);
}
Expand All @@ -236,14 +235,14 @@ void YGNode::setMeasureFunc(decltype(YGNode::measure_) measureFunc) {
}

void YGNode::setMeasureFunc(YGMeasureFunc measureFunc) {
facebook::yoga::detail::setBooleanData(flags, measureUsesContext_, false);
flags_.measureUsesContext = false;
decltype(YGNode::measure_) m;
m.noContext = measureFunc;
setMeasureFunc(m);
}

YOGA_EXPORT void YGNode::setMeasureFunc(MeasureWithContextFn measureFunc) {
facebook::yoga::detail::setBooleanData(flags, measureUsesContext_, true);
flags_.measureUsesContext = true;
decltype(YGNode::measure_) m;
m.withContext = measureFunc;
setMeasureFunc(m);
Expand All @@ -262,10 +261,10 @@ void YGNode::insertChild(YGNodeRef child, uint32_t index) {
}

void YGNode::setDirty(bool isDirty) {
if (isDirty == facebook::yoga::detail::getBooleanData(flags, isDirty_)) {
if (isDirty == flags_.isDirty) {
return;
}
facebook::yoga::detail::setBooleanData(flags, isDirty_, isDirty);
flags_.isDirty = isDirty;
if (isDirty && dirtied_) {
dirtied_(this);
}
Expand Down Expand Up @@ -408,9 +407,7 @@ YGValue YGNode::resolveFlexBasisPtr() const {
return flexBasis;
}
if (!style_.flex().isUndefined() && style_.flex().unwrap() > 0.0f) {
return facebook::yoga::detail::getBooleanData(flags, useWebDefaults_)
? YGValueAuto
: YGValueZero;
return flags_.useWebDefaults ? YGValueAuto : YGValueZero;
}
return YGValueAuto;
}
Expand Down Expand Up @@ -449,7 +446,7 @@ void YGNode::cloneChildrenIfNeeded(void* cloneContext) {
}

void YGNode::markDirtyAndPropagate() {
if (!facebook::yoga::detail::getBooleanData(flags, isDirty_)) {
if (!flags_.isDirty) {
setDirty(true);
setLayoutComputedFlexBasis(YGFloatOptional());
if (owner_) {
Expand All @@ -459,7 +456,7 @@ void YGNode::markDirtyAndPropagate() {
}

void YGNode::markDirtyAndPropagateDownwards() {
facebook::yoga::detail::setBooleanData(flags, isDirty_, true);
flags_.isDirty = true;
for_each(children_.begin(), children_.end(), [](YGNodeRef childNode) {
childNode->markDirtyAndPropagateDownwards();
});
Expand All @@ -486,13 +483,11 @@ float YGNode::resolveFlexShrink() const {
if (!style_.flexShrink().isUndefined()) {
return style_.flexShrink().unwrap();
}
if (!facebook::yoga::detail::getBooleanData(flags, useWebDefaults_) &&
!style_.flex().isUndefined() && style_.flex().unwrap() < 0.0f) {
if (!flags_.useWebDefaults && !style_.flex().isUndefined() &&
style_.flex().unwrap() < 0.0f) {
return -style_.flex().unwrap();
}
return facebook::yoga::detail::getBooleanData(flags, useWebDefaults_)
? kWebDefaultFlexShrink
: kDefaultFlexShrink;
return flags_.useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink;
}

bool YGNode::isNodeFlexible() {
Expand Down Expand Up @@ -570,8 +565,7 @@ void YGNode::reset() {

clearChildren();

auto webDefaults =
facebook::yoga::detail::getBooleanData(flags, useWebDefaults_);
auto webDefaults = flags_.useWebDefaults;
*this = YGNode{getConfig()};
if (webDefaults) {
useWebDefaults();
Expand Down
60 changes: 29 additions & 31 deletions packages/react-native/ReactCommon/yoga/yoga/YGNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

#include <cstdint>
#include <stdio.h>
#include "BitUtils.h"
#include "CompactValue.h"
#include "YGConfig.h"
#include "YGLayout.h"
Expand All @@ -20,24 +19,29 @@

YGConfigRef YGConfigGetDefault();

#pragma pack(push)
#pragma pack(1)
struct YGNodeFlags {
bool hasNewLayout : 1;
bool isReferenceBaseline : 1;
bool isDirty : 1;
uint8_t nodeType : 1;
bool measureUsesContext : 1;
bool baselineUsesContext : 1;
bool printUsesContext : 1;
bool useWebDefaults : 1;
};
#pragma pack(pop)

struct YOGA_EXPORT YGNode {
using MeasureWithContextFn =
YGSize (*)(YGNode*, float, YGMeasureMode, float, YGMeasureMode, void*);
using BaselineWithContextFn = float (*)(YGNode*, float, float, void*);
using PrintWithContextFn = void (*)(YGNode*, void*);

private:
static constexpr size_t hasNewLayout_ = 0;
static constexpr size_t isReferenceBaseline_ = 1;
static constexpr size_t isDirty_ = 2;
static constexpr size_t nodeType_ = 3;
static constexpr size_t measureUsesContext_ = 4;
static constexpr size_t baselineUsesContext_ = 5;
static constexpr size_t printUsesContext_ = 6;
static constexpr size_t useWebDefaults_ = 7;

void* context_ = nullptr;
uint8_t flags = 1;
YGNodeFlags flags_ = {};
uint8_t reserved_ = 0;
union {
YGMeasureFunc noContext;
Expand Down Expand Up @@ -69,7 +73,7 @@ struct YOGA_EXPORT YGNode {
void setBaselineFunc(decltype(baseline_));

void useWebDefaults() {
facebook::yoga::detail::setBooleanData(flags, useWebDefaults_, true);
flags_.useWebDefaults = true;
style_.flexDirection() = YGFlexDirectionRow;
style_.alignContent() = YGAlignStretch;
}
Expand All @@ -86,6 +90,8 @@ struct YOGA_EXPORT YGNode {
public:
YGNode() : YGNode{YGConfigGetDefault()} {}
explicit YGNode(const YGConfigRef config) : config_{config} {
flags_.hasNewLayout = true;

if (config->useWebDefaults) {
useWebDefaults();
}
Expand Down Expand Up @@ -113,12 +119,10 @@ struct YOGA_EXPORT YGNode {

void print(void*);

bool getHasNewLayout() const {
return facebook::yoga::detail::getBooleanData(flags, hasNewLayout_);
}
bool getHasNewLayout() const { return flags_.hasNewLayout; }

YGNodeType getNodeType() const {
return facebook::yoga::detail::getEnumData<YGNodeType>(flags, nodeType_);
return static_cast<YGNodeType>(flags_.nodeType);
}

bool hasMeasureFunc() const noexcept { return measure_.noContext != nullptr; }
Expand All @@ -145,9 +149,7 @@ struct YOGA_EXPORT YGNode {

uint32_t getLineIndex() const { return lineIndex_; }

bool isReferenceBaseline() {
return facebook::yoga::detail::getBooleanData(flags, isReferenceBaseline_);
}
bool isReferenceBaseline() { return flags_.isReferenceBaseline; }

// returns the YGNodeRef that owns this YGNode. An owner is used to identify
// the YogaTree that a YGNode belongs to. This method will return the parent
Expand Down Expand Up @@ -180,9 +182,7 @@ struct YOGA_EXPORT YGNode {

YGConfigRef getConfig() const { return config_; }

bool isDirty() const {
return facebook::yoga::detail::getBooleanData(flags, isDirty_);
}
bool isDirty() const { return flags_.isDirty; }

std::array<YGValue, 2> getResolvedDimensions() const {
return resolvedDimensions_;
Expand Down Expand Up @@ -252,21 +252,20 @@ struct YOGA_EXPORT YGNode {

void setPrintFunc(YGPrintFunc printFunc) {
print_.noContext = printFunc;
facebook::yoga::detail::setBooleanData(flags, printUsesContext_, false);
flags_.printUsesContext = false;
}
void setPrintFunc(PrintWithContextFn printFunc) {
print_.withContext = printFunc;
facebook::yoga::detail::setBooleanData(flags, printUsesContext_, true);
flags_.printUsesContext = true;
}
void setPrintFunc(std::nullptr_t) { setPrintFunc(YGPrintFunc{nullptr}); }

void setHasNewLayout(bool hasNewLayout) {
facebook::yoga::detail::setBooleanData(flags, hasNewLayout_, hasNewLayout);
flags_.hasNewLayout = hasNewLayout;
}

void setNodeType(YGNodeType nodeType) {
return facebook::yoga::detail::setEnumData<YGNodeType>(
flags, nodeType_, nodeType);
flags_.nodeType = static_cast<uint8_t>(nodeType);
}

void setMeasureFunc(YGMeasureFunc measureFunc);
Expand All @@ -276,11 +275,11 @@ struct YOGA_EXPORT YGNode {
}

void setBaselineFunc(YGBaselineFunc baseLineFunc) {
facebook::yoga::detail::setBooleanData(flags, baselineUsesContext_, false);
flags_.baselineUsesContext = false;
baseline_.noContext = baseLineFunc;
}
void setBaselineFunc(BaselineWithContextFn baseLineFunc) {
facebook::yoga::detail::setBooleanData(flags, baselineUsesContext_, true);
flags_.baselineUsesContext = true;
baseline_.withContext = baseLineFunc;
}
void setBaselineFunc(std::nullptr_t) {
Expand All @@ -296,8 +295,7 @@ struct YOGA_EXPORT YGNode {
void setLineIndex(uint32_t lineIndex) { lineIndex_ = lineIndex; }

void setIsReferenceBaseline(bool isReferenceBaseline) {
facebook::yoga::detail::setBooleanData(
flags, isReferenceBaseline_, isReferenceBaseline);
flags_.isReferenceBaseline = isReferenceBaseline;
}

void setOwner(YGNodeRef owner) { owner_ = owner; }
Expand Down

0 comments on commit 4ae77c0

Please sign in to comment.