Bug 1226920 - Allow calling ForEachNode() with an action returning void r=botond

This commit is contained in:
Kevin Wern 2015-11-23 13:06:01 -05:00
parent 741c3408b7
commit 7e0f8f630c
2 changed files with 67 additions and 9 deletions

View File

@ -92,18 +92,15 @@ Node* DepthFirstSearch(Node* aRoot, const Condition& aCondition)
/*
* Do a depth-first traversal of the tree rooted at |aRoot|, performing
* |aAction| for each node, returning a TraversalFlag to determine behavior for
* that node's children. If a node is determined to be ineligible (by |aAction|
* returning TraversalFlag::Skip), its children are skipped by the function.
* |aAction| for each node. |aAction| can return a TraversalFlag to determine
* whether or not to omit the children of a particular node.
*
* |Node| should have methods GetLastChild() and GetPrevSibling().
* |aAction| must return a TraversalFlag. Bear in mind that the TraversalFlag
* only dictates the behavior for children of a node, not the node itself. To
* skip the node itself, the logic returning TraversalFlag::Skip should be
* performed before the node is manipulated in any way.
* If |aAction| does not return a TraversalFlag, it must return nothing. There
* is no ForEachNode instance handling types other than void or TraversalFlag.
*/
template <typename Node, typename Action>
void ForEachNode(Node* aRoot, const Action& aAction)
auto ForEachNode(Node* aRoot, const Action& aAction) ->
typename EnableIf<IsSame<decltype(aAction(aRoot)), TraversalFlag>::value, void>::Type
{
if (!aRoot) {
return;
@ -128,6 +125,31 @@ void ForEachNode(Node* aRoot, const Action& aAction)
}
}
template <typename Node, typename Action>
auto ForEachNode(Node* aRoot, const Action& aAction) ->
typename EnableIf<IsSame<decltype(aAction(aRoot)), void>::value, void>::Type
{
if (!aRoot) {
return;
}
std::stack<Node*> stack;
stack.push(aRoot);
while (!stack.empty()) {
Node* node = stack.top();
stack.pop();
aAction(node);
for (Node* child = node->GetLastChild();
child;
child = child->GetPrevSibling()) {
stack.push(child);
}
}
}
}
}

View File

@ -502,3 +502,39 @@ TEST(TreeTraversal, ForEachNodeLeavesIneligible)
<< "Node at index " << i << " was hit out of order.";
}
}
TEST(TreeTraversal, ForEachNodeLambdaReturnsVoid)
{
std::vector<RefPtr<ForEachTestNode>> nodeList;
int visitCount = 0;
for (int i = 0; i < 10; i++)
{
nodeList.push_back(new ForEachTestNode(ForEachNodeType::Continue,i));
}
RefPtr<ForEachTestNode> root = nodeList[0];
nodeList[0]->AddChild(nodeList[1]);
nodeList[0]->AddChild(nodeList[4]);
nodeList[1]->AddChild(nodeList[2]);
nodeList[1]->AddChild(nodeList[3]);
nodeList[4]->AddChild(nodeList[5]);
nodeList[4]->AddChild(nodeList[6]);
nodeList[6]->AddChild(nodeList[7]);
nodeList[7]->AddChild(nodeList[8]);
nodeList[7]->AddChild(nodeList[9]);
ForEachNode(root.get(),
[&visitCount](ForEachTestNode* aNode)
{
aNode->SetActualTraversalRank(visitCount);
visitCount++;
});
for (size_t i = 0; i < nodeList.size(); i++)
{
ASSERT_EQ(nodeList[i]->GetExpectedTraversalRank(),
nodeList[i]->GetActualTraversalRank())
<< "Node at index " << i << " was hit out of order.";
}
}