Commit 6873f14b authored by leszeks's avatar leszeks Committed by Commit bot

[turbofan] Allow indexed access to node inputs/input_edges

Node::InputCount() and ::InputAt() have to check for inline/out-of-line
inputs every time they are called. The compiler doesn't seem to be very
good at caching the result of this check, meaning that it (and all its
jumps) would happen for every node access.

Previously we would get around this sometimes, by using Node::inputs(),
which returned a Node::Inputs iterable over node inputs. However,
sometimes node access is more convenient using an index, or we also
want to access the count. This patch adds an index accessor and 'count'
method to Node::Inputs, and replaces several uses of InputCount and
InputAt with this accessor.

Review-Url: https://codereview.chromium.org/2617123002
Cr-Commit-Position: refs/heads/master@{#42179}
parent 754736d2
...@@ -145,20 +145,27 @@ Reduction BranchElimination::ReduceLoop(Node* node) { ...@@ -145,20 +145,27 @@ Reduction BranchElimination::ReduceLoop(Node* node) {
Reduction BranchElimination::ReduceMerge(Node* node) { Reduction BranchElimination::ReduceMerge(Node* node) {
// Shortcut for the case when we do not know anything about some // Shortcut for the case when we do not know anything about some
// input. // input.
for (Node* input : node->inputs()) { Node::Inputs inputs = node->inputs();
for (Node* input : inputs) {
if (node_conditions_.Get(input) == nullptr) { if (node_conditions_.Get(input) == nullptr) {
return UpdateConditions(node, nullptr); return UpdateConditions(node, nullptr);
} }
} }
const ControlPathConditions* first = node_conditions_.Get(node->InputAt(0)); auto input_it = inputs.begin();
DCHECK_GT(inputs.count(), 0);
const ControlPathConditions* first = node_conditions_.Get(*input_it);
++input_it;
// Make a copy of the first input's conditions and merge with the conditions // Make a copy of the first input's conditions and merge with the conditions
// from other inputs. // from other inputs.
ControlPathConditions* conditions = ControlPathConditions* conditions =
new (zone_->New(sizeof(ControlPathConditions))) new (zone_->New(sizeof(ControlPathConditions)))
ControlPathConditions(*first); ControlPathConditions(*first);
for (int i = 1; i < node->InputCount(); i++) { auto input_end = inputs.end();
conditions->Merge(*(node_conditions_.Get(node->InputAt(i)))); for (; input_it != input_end; ++input_it) {
conditions->Merge(*(node_conditions_.Get(*input_it)));
} }
return UpdateConditions(node, conditions); return UpdateConditions(node, conditions);
......
...@@ -348,9 +348,10 @@ bool BytecodeGraphBuilder::Environment::StateValuesRequireUpdate( ...@@ -348,9 +348,10 @@ bool BytecodeGraphBuilder::Environment::StateValuesRequireUpdate(
if (*state_values == nullptr) { if (*state_values == nullptr) {
return true; return true;
} }
DCHECK_EQ((*state_values)->InputCount(), count); Node::Inputs inputs = (*state_values)->inputs();
DCHECK_EQ(inputs.count(), count);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
if ((*state_values)->InputAt(i) != values[i]) { if (inputs[i] != values[i]) {
return true; return true;
} }
} }
......
...@@ -195,15 +195,16 @@ Reduction CommonOperatorReducer::ReduceMerge(Node* node) { ...@@ -195,15 +195,16 @@ Reduction CommonOperatorReducer::ReduceMerge(Node* node) {
Reduction CommonOperatorReducer::ReduceEffectPhi(Node* node) { Reduction CommonOperatorReducer::ReduceEffectPhi(Node* node) {
DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode()); DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode());
int const input_count = node->InputCount() - 1; Node::Inputs inputs = node->inputs();
DCHECK_LE(1, input_count); int const effect_input_count = inputs.count() - 1;
Node* const merge = node->InputAt(input_count); DCHECK_LE(1, effect_input_count);
Node* const merge = inputs[effect_input_count];
DCHECK(IrOpcode::IsMergeOpcode(merge->opcode())); DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
DCHECK_EQ(input_count, merge->InputCount()); DCHECK_EQ(effect_input_count, merge->InputCount());
Node* const effect = node->InputAt(0); Node* const effect = inputs[0];
DCHECK_NE(node, effect); DCHECK_NE(node, effect);
for (int i = 1; i < input_count; ++i) { for (int i = 1; i < effect_input_count; ++i) {
Node* const input = node->InputAt(i); Node* const input = inputs[i];
if (input == node) { if (input == node) {
// Ignore redundant inputs. // Ignore redundant inputs.
DCHECK_EQ(IrOpcode::kLoop, merge->opcode()); DCHECK_EQ(IrOpcode::kLoop, merge->opcode());
...@@ -219,16 +220,18 @@ Reduction CommonOperatorReducer::ReduceEffectPhi(Node* node) { ...@@ -219,16 +220,18 @@ Reduction CommonOperatorReducer::ReduceEffectPhi(Node* node) {
Reduction CommonOperatorReducer::ReducePhi(Node* node) { Reduction CommonOperatorReducer::ReducePhi(Node* node) {
DCHECK_EQ(IrOpcode::kPhi, node->opcode()); DCHECK_EQ(IrOpcode::kPhi, node->opcode());
int const input_count = node->InputCount() - 1; Node::Inputs inputs = node->inputs();
DCHECK_LE(1, input_count); int const value_input_count = inputs.count() - 1;
Node* const merge = node->InputAt(input_count); DCHECK_LE(1, value_input_count);
Node* const merge = inputs[value_input_count];
DCHECK(IrOpcode::IsMergeOpcode(merge->opcode())); DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
DCHECK_EQ(input_count, merge->InputCount()); DCHECK_EQ(value_input_count, merge->InputCount());
if (input_count == 2) { if (value_input_count == 2) {
Node* vtrue = node->InputAt(0); Node* vtrue = inputs[0];
Node* vfalse = node->InputAt(1); Node* vfalse = inputs[1];
Node* if_true = merge->InputAt(0); Node::Inputs merge_inputs = merge->inputs();
Node* if_false = merge->InputAt(1); Node* if_true = merge_inputs[0];
Node* if_false = merge_inputs[1];
if (if_true->opcode() != IrOpcode::kIfTrue) { if (if_true->opcode() != IrOpcode::kIfTrue) {
std::swap(if_true, if_false); std::swap(if_true, if_false);
std::swap(vtrue, vfalse); std::swap(vtrue, vfalse);
...@@ -265,10 +268,10 @@ Reduction CommonOperatorReducer::ReducePhi(Node* node) { ...@@ -265,10 +268,10 @@ Reduction CommonOperatorReducer::ReducePhi(Node* node) {
} }
} }
} }
Node* const value = node->InputAt(0); Node* const value = inputs[0];
DCHECK_NE(node, value); DCHECK_NE(node, value);
for (int i = 1; i < input_count; ++i) { for (int i = 1; i < value_input_count; ++i) {
Node* const input = node->InputAt(i); Node* const input = inputs[i];
if (input == node) { if (input == node) {
// Ignore redundant inputs. // Ignore redundant inputs.
DCHECK_EQ(IrOpcode::kLoop, merge->opcode()); DCHECK_EQ(IrOpcode::kLoop, merge->opcode());
...@@ -300,20 +303,22 @@ Reduction CommonOperatorReducer::ReduceReturn(Node* node) { ...@@ -300,20 +303,22 @@ Reduction CommonOperatorReducer::ReduceReturn(Node* node) {
effect->opcode() == IrOpcode::kEffectPhi && effect->opcode() == IrOpcode::kEffectPhi &&
NodeProperties::GetControlInput(effect) == control && NodeProperties::GetControlInput(effect) == control &&
control->opcode() == IrOpcode::kMerge) { control->opcode() == IrOpcode::kMerge) {
int const control_input_count = control->InputCount(); Node::Inputs control_inputs = control->inputs();
DCHECK_NE(0, control_input_count); Node::Inputs value_inputs = value->inputs();
DCHECK_EQ(control_input_count, value->InputCount() - 1); Node::Inputs effect_inputs = effect->inputs();
DCHECK_EQ(control_input_count, effect->InputCount() - 1); DCHECK_NE(0, control_inputs.count());
DCHECK_EQ(control_inputs.count(), value_inputs.count() - 1);
DCHECK_EQ(control_inputs.count(), effect_inputs.count() - 1);
DCHECK_EQ(IrOpcode::kEnd, graph()->end()->opcode()); DCHECK_EQ(IrOpcode::kEnd, graph()->end()->opcode());
DCHECK_NE(0, graph()->end()->InputCount()); DCHECK_NE(0, graph()->end()->InputCount());
for (int i = 0; i < control_input_count; ++i) { for (int i = 0; i < control_inputs.count(); ++i) {
// Create a new {Return} and connect it to {end}. We don't need to mark // Create a new {Return} and connect it to {end}. We don't need to mark
// {end} as revisit, because we mark {node} as {Dead} below, which was // {end} as revisit, because we mark {node} as {Dead} below, which was
// previously connected to {end}, so we know for sure that at some point // previously connected to {end}, so we know for sure that at some point
// the reducer logic will visit {end} again. // the reducer logic will visit {end} again.
Node* ret = graph()->NewNode(common()->Return(), node->InputAt(0), Node* ret = graph()->NewNode(common()->Return(), node->InputAt(0),
value->InputAt(i), effect->InputAt(i), value_inputs[i], effect_inputs[i],
control->InputAt(i)); control_inputs[i]);
NodeProperties::MergeControlToEnd(graph(), common(), ret); NodeProperties::MergeControlToEnd(graph(), common(), ret);
} }
// Mark the merge {control} and return {node} as {dead}. // Mark the merge {control} and return {node} as {dead}.
......
...@@ -41,11 +41,11 @@ Reduction DeadCodeElimination::Reduce(Node* node) { ...@@ -41,11 +41,11 @@ Reduction DeadCodeElimination::Reduce(Node* node) {
Reduction DeadCodeElimination::ReduceEnd(Node* node) { Reduction DeadCodeElimination::ReduceEnd(Node* node) {
DCHECK_EQ(IrOpcode::kEnd, node->opcode()); DCHECK_EQ(IrOpcode::kEnd, node->opcode());
int const input_count = node->InputCount(); Node::Inputs inputs = node->inputs();
DCHECK_LE(1, input_count); DCHECK_LE(1, inputs.count());
int live_input_count = 0; int live_input_count = 0;
for (int i = 0; i < input_count; ++i) { for (int i = 0; i < inputs.count(); ++i) {
Node* const input = node->InputAt(i); Node* const input = inputs[i];
// Skip dead inputs. // Skip dead inputs.
if (input->opcode() == IrOpcode::kDead) continue; if (input->opcode() == IrOpcode::kDead) continue;
// Compact live inputs. // Compact live inputs.
...@@ -54,20 +54,20 @@ Reduction DeadCodeElimination::ReduceEnd(Node* node) { ...@@ -54,20 +54,20 @@ Reduction DeadCodeElimination::ReduceEnd(Node* node) {
} }
if (live_input_count == 0) { if (live_input_count == 0) {
return Replace(dead()); return Replace(dead());
} else if (live_input_count < input_count) { } else if (live_input_count < inputs.count()) {
node->TrimInputCount(live_input_count); node->TrimInputCount(live_input_count);
NodeProperties::ChangeOp(node, common()->End(live_input_count)); NodeProperties::ChangeOp(node, common()->End(live_input_count));
return Changed(node); return Changed(node);
} }
DCHECK_EQ(input_count, live_input_count); DCHECK_EQ(inputs.count(), live_input_count);
return NoChange(); return NoChange();
} }
Reduction DeadCodeElimination::ReduceLoopOrMerge(Node* node) { Reduction DeadCodeElimination::ReduceLoopOrMerge(Node* node) {
DCHECK(IrOpcode::IsMergeOpcode(node->opcode())); DCHECK(IrOpcode::IsMergeOpcode(node->opcode()));
int const input_count = node->InputCount(); Node::Inputs inputs = node->inputs();
DCHECK_LE(1, input_count); DCHECK_LE(1, inputs.count());
// Count the number of live inputs to {node} and compact them on the fly, also // Count the number of live inputs to {node} and compact them on the fly, also
// compacting the inputs of the associated {Phi} and {EffectPhi} uses at the // compacting the inputs of the associated {Phi} and {EffectPhi} uses at the
// same time. We consider {Loop}s dead even if only the first control input // same time. We consider {Loop}s dead even if only the first control input
...@@ -75,8 +75,8 @@ Reduction DeadCodeElimination::ReduceLoopOrMerge(Node* node) { ...@@ -75,8 +75,8 @@ Reduction DeadCodeElimination::ReduceLoopOrMerge(Node* node) {
int live_input_count = 0; int live_input_count = 0;
if (node->opcode() != IrOpcode::kLoop || if (node->opcode() != IrOpcode::kLoop ||
node->InputAt(0)->opcode() != IrOpcode::kDead) { node->InputAt(0)->opcode() != IrOpcode::kDead) {
for (int i = 0; i < input_count; ++i) { for (int i = 0; i < inputs.count(); ++i) {
Node* const input = node->InputAt(i); Node* const input = inputs[i];
// Skip dead inputs. // Skip dead inputs.
if (input->opcode() == IrOpcode::kDead) continue; if (input->opcode() == IrOpcode::kDead) continue;
// Compact live inputs. // Compact live inputs.
...@@ -84,7 +84,7 @@ Reduction DeadCodeElimination::ReduceLoopOrMerge(Node* node) { ...@@ -84,7 +84,7 @@ Reduction DeadCodeElimination::ReduceLoopOrMerge(Node* node) {
node->ReplaceInput(live_input_count, input); node->ReplaceInput(live_input_count, input);
for (Node* const use : node->uses()) { for (Node* const use : node->uses()) {
if (NodeProperties::IsPhi(use)) { if (NodeProperties::IsPhi(use)) {
DCHECK_EQ(input_count + 1, use->InputCount()); DCHECK_EQ(inputs.count() + 1, use->InputCount());
use->ReplaceInput(live_input_count, use->InputAt(i)); use->ReplaceInput(live_input_count, use->InputAt(i));
} }
} }
...@@ -110,9 +110,9 @@ Reduction DeadCodeElimination::ReduceLoopOrMerge(Node* node) { ...@@ -110,9 +110,9 @@ Reduction DeadCodeElimination::ReduceLoopOrMerge(Node* node) {
return Replace(node->InputAt(0)); return Replace(node->InputAt(0));
} }
DCHECK_LE(2, live_input_count); DCHECK_LE(2, live_input_count);
DCHECK_LE(live_input_count, input_count); DCHECK_LE(live_input_count, inputs.count());
// Trim input count for the {Merge} or {Loop} node. // Trim input count for the {Merge} or {Loop} node.
if (live_input_count < input_count) { if (live_input_count < inputs.count()) {
// Trim input counts for all phi uses and revisit them. // Trim input counts for all phi uses and revisit them.
for (Node* const use : node->uses()) { for (Node* const use : node->uses()) {
if (NodeProperties::IsPhi(use)) { if (NodeProperties::IsPhi(use)) {
......
...@@ -115,25 +115,21 @@ void GraphReducer::ReduceTop() { ...@@ -115,25 +115,21 @@ void GraphReducer::ReduceTop() {
if (node->IsDead()) return Pop(); // Node was killed while on stack. if (node->IsDead()) return Pop(); // Node was killed while on stack.
// Recurse on an input if necessary.
int start = entry.input_index < node->InputCount() ? entry.input_index : 0;
Node::Inputs node_inputs = node->inputs(); Node::Inputs node_inputs = node->inputs();
auto node_inputs_begin = node_inputs.begin();
auto node_inputs_end = node_inputs.end();
DCHECK(node_inputs_end == node_inputs_begin + node->InputCount());
for (auto it = node_inputs_begin + start; it != node_inputs_end; ++it) { // Recurse on an input if necessary.
Node* input = *it; int start = entry.input_index < node_inputs.count() ? entry.input_index : 0;
for (int i = start; i < node_inputs.count(); ++i) {
Node* input = node_inputs[i];
if (input != node && Recurse(input)) { if (input != node && Recurse(input)) {
entry.input_index = (it - node_inputs_begin) + 1; entry.input_index = i + 1;
return; return;
} }
} }
for (auto it = node_inputs_begin; it != node_inputs_begin + start; ++it) { for (int i = 0; i < start; ++i) {
Node* input = *it; Node* input = node_inputs[i];
if (input != node && Recurse(input)) { if (input != node && Recurse(input)) {
entry.input_index = (it - node_inputs_begin) + 1; entry.input_index = i + 1;
return; return;
} }
} }
...@@ -152,12 +148,10 @@ void GraphReducer::ReduceTop() { ...@@ -152,12 +148,10 @@ void GraphReducer::ReduceTop() {
if (replacement == node) { if (replacement == node) {
// In-place update of {node}, may need to recurse on an input. // In-place update of {node}, may need to recurse on an input.
Node::Inputs node_inputs = node->inputs(); Node::Inputs node_inputs = node->inputs();
auto node_inputs_begin = node_inputs.begin(); for (int i = 0; i < node_inputs.count(); ++i) {
auto node_inputs_end = node_inputs.end(); Node* input = node_inputs[i];
for (auto it = node_inputs_begin; it != node_inputs_end; ++it) {
Node* input = *it;
if (input != node && Recurse(input)) { if (input != node && Recurse(input)) {
entry.input_index = (it - node_inputs_begin) + 1; entry.input_index = i + 1;
return; return;
} }
} }
......
...@@ -404,9 +404,6 @@ Node::InputEdges::iterator Node::InputEdges::iterator::operator++(int n) { ...@@ -404,9 +404,6 @@ Node::InputEdges::iterator Node::InputEdges::iterator::operator++(int n) {
} }
bool Node::InputEdges::empty() const { return begin() == end(); }
Node::Inputs::const_iterator Node::Inputs::const_iterator::operator++(int n) { Node::Inputs::const_iterator Node::Inputs::const_iterator::operator++(int n) {
const_iterator result(*this); const_iterator result(*this);
++(*this); ++(*this);
...@@ -414,9 +411,6 @@ Node::Inputs::const_iterator Node::Inputs::const_iterator::operator++(int n) { ...@@ -414,9 +411,6 @@ Node::Inputs::const_iterator Node::Inputs::const_iterator::operator++(int n) {
} }
bool Node::Inputs::empty() const { return begin() == end(); }
Node::UseEdges::iterator Node::UseEdges::iterator::operator++(int n) { Node::UseEdges::iterator Node::UseEdges::iterator::operator++(int n) {
iterator result(*this); iterator result(*this);
++(*this); ++(*this);
......
...@@ -46,7 +46,7 @@ class V8_EXPORT_PRIVATE Node final { ...@@ -46,7 +46,7 @@ class V8_EXPORT_PRIVATE Node final {
Node* const* inputs, bool has_extensible_inputs); Node* const* inputs, bool has_extensible_inputs);
static Node* Clone(Zone* zone, NodeId id, const Node* node); static Node* Clone(Zone* zone, NodeId id, const Node* node);
bool IsDead() const { return InputCount() > 0 && !InputAt(0); } inline bool IsDead() const;
void Kill(); void Kill();
const Operator* op() const { return op_; } const Operator* op() const { return op_; }
...@@ -109,41 +109,11 @@ class V8_EXPORT_PRIVATE Node final { ...@@ -109,41 +109,11 @@ class V8_EXPORT_PRIVATE Node final {
int UseCount() const; int UseCount() const;
void ReplaceUses(Node* replace_to); void ReplaceUses(Node* replace_to);
class InputEdges final { class InputEdges;
public: inline InputEdges input_edges();
typedef Edge value_type;
class iterator;
inline iterator begin() const;
inline iterator end() const;
bool empty() const;
explicit InputEdges(Node* node) : node_(node) {}
private:
Node* node_;
};
InputEdges input_edges() { return InputEdges(this); }
class V8_EXPORT_PRIVATE Inputs final {
public:
typedef Node* value_type;
class const_iterator;
inline const_iterator begin() const;
inline const_iterator end() const;
bool empty() const;
explicit Inputs(Node* node) : node_(node) {}
private: class Inputs;
Node* node_; inline Inputs inputs() const;
};
Inputs inputs() { return Inputs(this); }
class UseEdges final { class UseEdges final {
public: public:
...@@ -345,6 +315,48 @@ static inline const T& OpParameter(const Node* node) { ...@@ -345,6 +315,48 @@ static inline const T& OpParameter(const Node* node) {
return OpParameter<T>(node->op()); return OpParameter<T>(node->op());
} }
class Node::InputEdges final {
public:
typedef Edge value_type;
class iterator;
inline iterator begin() const;
inline iterator end() const;
bool empty() const { return count_ == 0; }
int count() const { return count_; }
inline value_type operator[](int index) const;
InputEdges(Node** input_root, Use* use_root, int count)
: input_root_(input_root), use_root_(use_root), count_(count) {}
private:
Node** input_root_;
Use* use_root_;
int count_;
};
class V8_EXPORT_PRIVATE Node::Inputs final {
public:
typedef Node* value_type;
class const_iterator;
inline const_iterator begin() const;
inline const_iterator end() const;
bool empty() const { return count_ == 0; }
int count() const { return count_; }
inline value_type operator[](int index) const;
explicit Inputs(Node* const* input_root, int count)
: input_root_(input_root), count_(count) {}
private:
Node* const* input_root_;
int count_;
};
// An encapsulation for information associated with a single use of node as a // An encapsulation for information associated with a single use of node as a
// input from another node, allowing access to both the defining node and // input from another node, allowing access to both the defining node and
...@@ -373,6 +385,7 @@ class Edge final { ...@@ -373,6 +385,7 @@ class Edge final {
private: private:
friend class Node::UseEdges::iterator; friend class Node::UseEdges::iterator;
friend class Node::InputEdges;
friend class Node::InputEdges::iterator; friend class Node::InputEdges::iterator;
Edge(Node::Use* use, Node** input_ptr) : use_(use), input_ptr_(input_ptr) { Edge(Node::Use* use, Node** input_ptr) : use_(use), input_ptr_(input_ptr) {
...@@ -385,12 +398,37 @@ class Edge final { ...@@ -385,12 +398,37 @@ class Edge final {
Node** input_ptr_; Node** input_ptr_;
}; };
bool Node::IsDead() const {
Node::Inputs inputs = this->inputs();
return inputs.count() > 0 && inputs[0] == nullptr;
}
Node::InputEdges Node::input_edges() {
int inline_count = InlineCountField::decode(bit_field_);
if (inline_count != kOutlineMarker) {
return InputEdges(inputs_.inline_, reinterpret_cast<Use*>(this) - 1,
inline_count);
} else {
return InputEdges(inputs_.outline_->inputs_,
reinterpret_cast<Use*>(inputs_.outline_) - 1,
inputs_.outline_->count_);
}
}
Node::Inputs Node::inputs() const {
int inline_count = InlineCountField::decode(bit_field_);
if (inline_count != kOutlineMarker) {
return Inputs(inputs_.inline_, inline_count);
} else {
return Inputs(inputs_.outline_->inputs_, inputs_.outline_->count_);
}
}
// A forward iterator to visit the edges for the input dependencies of a node. // A forward iterator to visit the edges for the input dependencies of a node.
class Node::InputEdges::iterator final { class Node::InputEdges::iterator final {
public: public:
typedef std::forward_iterator_tag iterator_category; typedef std::forward_iterator_tag iterator_category;
typedef int difference_type; typedef std::ptrdiff_t difference_type;
typedef Edge value_type; typedef Edge value_type;
typedef Edge* pointer; typedef Edge* pointer;
typedef Edge& reference; typedef Edge& reference;
...@@ -419,15 +457,12 @@ class Node::InputEdges::iterator final { ...@@ -419,15 +457,12 @@ class Node::InputEdges::iterator final {
return iterator(use_ - offset, input_ptr_ + offset); return iterator(use_ - offset, input_ptr_ + offset);
} }
difference_type operator-(const iterator& other) const { difference_type operator-(const iterator& other) const {
return static_cast<difference_type>(input_ptr_ - other.input_ptr_); return input_ptr_ - other.input_ptr_;
} }
private: private:
friend class Node; friend class Node;
explicit iterator(Node* from, int index = 0)
: use_(from->GetUsePtr(index)), input_ptr_(from->GetInputPtr(index)) {}
explicit iterator(Use* use, Node** input_ptr) explicit iterator(Use* use, Node** input_ptr)
: use_(use), input_ptr_(input_ptr) {} : use_(use), input_ptr_(input_ptr) {}
...@@ -437,69 +472,71 @@ class Node::InputEdges::iterator final { ...@@ -437,69 +472,71 @@ class Node::InputEdges::iterator final {
Node::InputEdges::iterator Node::InputEdges::begin() const { Node::InputEdges::iterator Node::InputEdges::begin() const {
return Node::InputEdges::iterator(this->node_, 0); return Node::InputEdges::iterator(use_root_, input_root_);
} }
Node::InputEdges::iterator Node::InputEdges::end() const { Node::InputEdges::iterator Node::InputEdges::end() const {
return Node::InputEdges::iterator(this->node_, this->node_->InputCount()); return Node::InputEdges::iterator(use_root_ - count_, input_root_ + count_);
} }
Edge Node::InputEdges::operator[](int index) const {
return Edge(use_root_ + index, input_root_ + index);
}
// A forward iterator to visit the inputs of a node. // A forward iterator to visit the inputs of a node.
class Node::Inputs::const_iterator final { class Node::Inputs::const_iterator final {
public: public:
typedef std::forward_iterator_tag iterator_category; typedef std::forward_iterator_tag iterator_category;
typedef int difference_type; typedef std::ptrdiff_t difference_type;
typedef Node* value_type; typedef Node* value_type;
typedef Node** pointer; typedef const value_type* pointer;
typedef Node*& reference; typedef value_type& reference;
const_iterator(const const_iterator& other) : iter_(other.iter_) {} const_iterator(const const_iterator& other) : input_ptr_(other.input_ptr_) {}
Node* operator*() const { return (*iter_).to(); } Node* operator*() const { return *input_ptr_; }
bool operator==(const const_iterator& other) const { bool operator==(const const_iterator& other) const {
return iter_ == other.iter_; return input_ptr_ == other.input_ptr_;
} }
bool operator!=(const const_iterator& other) const { bool operator!=(const const_iterator& other) const {
return !(*this == other); return !(*this == other);
} }
const_iterator& operator++() { const_iterator& operator++() {
++iter_; ++input_ptr_;
return *this; return *this;
} }
const_iterator operator++(int); const_iterator operator++(int);
const_iterator& operator+=(difference_type offset) { const_iterator& operator+=(difference_type offset) {
iter_ += offset; input_ptr_ += offset;
return *this; return *this;
} }
const_iterator operator+(difference_type offset) const { const_iterator operator+(difference_type offset) const {
return const_iterator(iter_ + offset); return const_iterator(input_ptr_ + offset);
} }
difference_type operator-(const const_iterator& other) const { difference_type operator-(const const_iterator& other) const {
return iter_ - other.iter_; return input_ptr_ - other.input_ptr_;
} }
private: private:
friend class Node::Inputs; friend class Node::Inputs;
const_iterator(Node* node, int index) : iter_(node, index) {} explicit const_iterator(Node* const* input_ptr) : input_ptr_(input_ptr) {}
explicit const_iterator(Node::InputEdges::iterator iter) : iter_(iter) {}
Node::InputEdges::iterator iter_; Node* const* input_ptr_;
}; };
Node::Inputs::const_iterator Node::Inputs::begin() const { Node::Inputs::const_iterator Node::Inputs::begin() const {
return const_iterator(this->node_, 0); return const_iterator(input_root_);
} }
Node::Inputs::const_iterator Node::Inputs::end() const { Node::Inputs::const_iterator Node::Inputs::end() const {
return const_iterator(this->node_, this->node_->InputCount()); return const_iterator(input_root_ + count_);
} }
Node* Node::Inputs::operator[](int index) const { return input_root_[index]; }
// A forward iterator to visit the uses edges of a node. // A forward iterator to visit the uses edges of a node.
class Node::UseEdges::iterator final { class Node::UseEdges::iterator final {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment