Files
yoga/yoga/YGNode.h
David Aurelio a935a222b5 YGNode remove assignment operators
Summary:
@public

Having assignment operators for `YGNode` means that existing children on the node assigned to would have to be handled somehow.

Deallocating might be incorrect. Ignoring might leak.

Here, we `delete` copy assignment, and make move assignment private (it is used in `YGNode::reset()`).

Copy and move constructors *can* be implemented. The move constructor has to take ownership of the children, while the copy constructor leaves ownership untouched. Since children are copied lazily during layout, this does not expose true value semantics. We should consider removing the copy constructor, too.

Reviewed By: SidharthGuglani

Differential Revision: D14241663

fbshipit-source-id: 39ffdb07f1028bfcf2710c0674a06cdebf3bd650
2019-03-01 04:22:04 -08:00

362 lines
10 KiB
C++

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
#pragma once
#include <stdio.h>
#include "YGConfig.h"
#include "YGLayout.h"
#include "YGStyle.h"
#include "Yoga-internal.h"
struct YGNode {
using MeasureWithContextFn =
YGSize (*)(YGNode*, float, YGMeasureMode, float, YGMeasureMode, void*);
using BaselineWithContextFn = float (*)(YGNode*, float, float, void*);
using PrintWithContextFn = void (*)(YGNode*, void*);
private:
void* context_ = nullptr;
bool hasNewLayout_ : 1;
bool isReferenceBaseline_ : 1;
bool isDirty_ : 1;
YGNodeType nodeType_ : 1;
bool measureUsesContext_ : 1;
bool baselineUsesContext_ : 1;
bool printUsesContext_ : 1;
union {
YGMeasureFunc noContext;
MeasureWithContextFn withContext;
} measure_ = {nullptr};
union {
YGBaselineFunc noContext;
BaselineWithContextFn withContext;
} baseline_ = {nullptr};
union {
YGPrintFunc noContext;
PrintWithContextFn withContext;
} print_ = {nullptr};
YGDirtiedFunc dirtied_ = nullptr;
YGStyle style_ = {};
YGLayout layout_ = {};
uint32_t lineIndex_ = 0;
YGNodeRef owner_ = nullptr;
YGVector children_ = {};
YGConfigRef config_ = nullptr;
std::array<YGValue, 2> resolvedDimensions_ = {
{YGValueUndefined, YGValueUndefined}};
YGFloatOptional relativePosition(
const YGFlexDirection axis,
const float axisSize) const;
void setMeasureFunc(decltype(measure_));
void setBaselineFunc(decltype(baseline_));
// DANGER DANGER DANGER!
// If the the node assigned to has children, we'd either have to deallocate
// them (potentially incorrect) or ignore them (danger of leaks). Only ever
// use this after checking that there are no children.
// DO NOT CHANGE THE VISIBILITY OF THIS METHOD!
YGNode& operator=(YGNode&&) = default;
public:
YGNode()
: hasNewLayout_{true},
isReferenceBaseline_{false},
isDirty_{false},
nodeType_{YGNodeTypeDefault},
measureUsesContext_{false},
baselineUsesContext_{false},
printUsesContext_{false} {}
~YGNode() = default; // cleanup of owner/children relationships in YGNodeFree
explicit YGNode(const YGConfigRef newConfig) : config_(newConfig){};
YGNode(YGNode&&);
// Does not expose true value semantics, as children are not cloned eagerly.
// Should we remove this?
YGNode(const YGNode& node) = default;
// assignment means potential leaks of existing children, or alternatively
// freeing unowned memory, double free, or freeing stack memory.
YGNode& operator=(const YGNode&) = delete;
// Getters
void* getContext() const {
return context_;
}
void print(void*);
bool getHasNewLayout() const {
return hasNewLayout_;
}
YGNodeType getNodeType() const {
return nodeType_;
}
bool hasMeasureFunc() const noexcept {
return measure_.noContext != nullptr;
}
YGSize measure(float, YGMeasureMode, float, YGMeasureMode, void*);
bool hasBaselineFunc() const noexcept {
return baseline_.noContext != nullptr;
}
float baseline(float width, float height, void* layoutContext);
YGDirtiedFunc getDirtied() const {
return dirtied_;
}
// For Performance reasons passing as reference.
YGStyle& getStyle() {
return style_;
}
const YGStyle& getStyle() const {
return style_;
}
// For Performance reasons passing as reference.
YGLayout& getLayout() {
return layout_;
}
const YGLayout& getLayout() const {
return layout_;
}
uint32_t getLineIndex() const {
return lineIndex_;
}
bool isReferenceBaseline() {
return 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
// of the YGNode when a YGNode only belongs to one YogaTree or nullptr when
// the YGNode is shared between two or more YogaTrees.
YGNodeRef getOwner() const {
return owner_;
}
// Deprecated, use getOwner() instead.
YGNodeRef getParent() const {
return getOwner();
}
const YGVector& getChildren() const {
return children_;
}
// Applies a callback to all children, after cloning them if they are not
// owned.
template <typename T>
void iterChildrenAfterCloningIfNeeded(T callback, void* cloneContext) {
int i = 0;
for (YGNodeRef& child : children_) {
if (child->getOwner() != this) {
child = config_->cloneNode(child, this, i, cloneContext);
child->setOwner(this);
}
i += 1;
callback(child, cloneContext);
}
}
YGNodeRef getChild(uint32_t index) const {
return children_.at(index);
}
YGConfigRef getConfig() const {
return config_;
}
bool isDirty() const {
return isDirty_;
}
std::array<YGValue, 2> getResolvedDimensions() const {
return resolvedDimensions_;
}
YGValue getResolvedDimension(int index) const {
return resolvedDimensions_[index];
}
// Methods related to positions, margin, padding and border
YGFloatOptional getLeadingPosition(
const YGFlexDirection axis,
const float axisSize) const;
bool isLeadingPositionDefined(const YGFlexDirection axis) const;
bool isTrailingPosDefined(const YGFlexDirection axis) const;
YGFloatOptional getTrailingPosition(
const YGFlexDirection axis,
const float axisSize) const;
YGFloatOptional getLeadingMargin(
const YGFlexDirection axis,
const float widthSize) const;
YGFloatOptional getTrailingMargin(
const YGFlexDirection axis,
const float widthSize) const;
float getLeadingBorder(const YGFlexDirection flexDirection) const;
float getTrailingBorder(const YGFlexDirection flexDirection) const;
YGFloatOptional getLeadingPadding(
const YGFlexDirection axis,
const float widthSize) const;
YGFloatOptional getTrailingPadding(
const YGFlexDirection axis,
const float widthSize) const;
YGFloatOptional getLeadingPaddingAndBorder(
const YGFlexDirection axis,
const float widthSize) const;
YGFloatOptional getTrailingPaddingAndBorder(
const YGFlexDirection axis,
const float widthSize) const;
YGFloatOptional getMarginForAxis(
const YGFlexDirection axis,
const float widthSize) const;
// Setters
void setContext(void* context) {
context_ = context;
}
void setPrintFunc(YGPrintFunc printFunc) {
print_.noContext = printFunc;
printUsesContext_ = false;
}
void setPrintFunc(PrintWithContextFn printFunc) {
print_.withContext = printFunc;
printUsesContext_ = true;
}
void setPrintFunc(std::nullptr_t) {
setPrintFunc(YGPrintFunc{nullptr});
}
void setHasNewLayout(bool hasNewLayout) {
hasNewLayout_ = hasNewLayout;
}
void setNodeType(YGNodeType nodeType) {
nodeType_ = nodeType;
}
void setStyleFlexDirection(YGFlexDirection direction) {
style_.flexDirection = direction;
}
void setStyleAlignContent(YGAlign alignContent) {
style_.alignContent = alignContent;
}
void setMeasureFunc(YGMeasureFunc measureFunc);
void setMeasureFunc(MeasureWithContextFn);
void setMeasureFunc(std::nullptr_t) {
return setMeasureFunc(YGMeasureFunc{nullptr});
}
void setBaselineFunc(YGBaselineFunc baseLineFunc) {
baselineUsesContext_ = false;
baseline_.noContext = baseLineFunc;
}
void setBaselineFunc(BaselineWithContextFn baseLineFunc) {
baselineUsesContext_ = true;
baseline_.withContext = baseLineFunc;
}
void setBaselineFunc(std::nullptr_t) {
return setBaselineFunc(YGBaselineFunc{nullptr});
}
void setDirtiedFunc(YGDirtiedFunc dirtiedFunc) {
dirtied_ = dirtiedFunc;
}
void setStyle(const YGStyle& style) {
style_ = style;
}
void setLayout(const YGLayout& layout) {
layout_ = layout;
}
void setLineIndex(uint32_t lineIndex) {
lineIndex_ = lineIndex;
}
void setIsReferenceBaseline(bool isReferenceBaseline) {
isReferenceBaseline_ = isReferenceBaseline;
}
void setOwner(YGNodeRef owner) {
owner_ = owner;
}
void setChildren(const YGVector& children) {
children_ = children;
}
// TODO: rvalue override for setChildren
void setConfig(YGConfigRef config) {
config_ = config;
}
void setDirty(bool isDirty);
void setLayoutLastOwnerDirection(YGDirection direction);
void setLayoutComputedFlexBasis(const YGFloatOptional computedFlexBasis);
void setLayoutComputedFlexBasisGeneration(
uint32_t computedFlexBasisGeneration);
void setLayoutMeasuredDimension(float measuredDimension, int index);
void setLayoutHadOverflow(bool hadOverflow);
void setLayoutDimension(float dimension, int index);
void setLayoutDirection(YGDirection direction);
void setLayoutMargin(float margin, int index);
void setLayoutBorder(float border, int index);
void setLayoutPadding(float padding, int index);
void setLayoutPosition(float position, int index);
void setPosition(
const YGDirection direction,
const float mainSize,
const float crossSize,
const float ownerWidth);
void setAndPropogateUseLegacyFlag(bool useLegacyFlag);
void setLayoutDoesLegacyFlagAffectsLayout(bool doesLegacyFlagAffectsLayout);
void setLayoutDidUseLegacyFlag(bool didUseLegacyFlag);
void markDirtyAndPropogateDownwards();
// Other methods
YGValue marginLeadingValue(const YGFlexDirection axis) const;
YGValue marginTrailingValue(const YGFlexDirection axis) const;
YGValue resolveFlexBasisPtr() const;
void resolveDimension();
YGDirection resolveDirection(const YGDirection ownerDirection);
void clearChildren();
/// Replaces the occurrences of oldChild with newChild
void replaceChild(YGNodeRef oldChild, YGNodeRef newChild);
void replaceChild(YGNodeRef child, uint32_t index);
void insertChild(YGNodeRef child, uint32_t index);
/// Removes the first occurrence of child
bool removeChild(YGNodeRef child);
void removeChild(uint32_t index);
void cloneChildrenIfNeeded(void*);
void markDirtyAndPropogate();
float resolveFlexGrow();
float resolveFlexShrink();
bool isNodeFlexible();
bool didUseLegacyFlag();
bool isLayoutTreeEqualToNode(const YGNode& node) const;
void reset();
};