mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1226920 - Allow calling ForEachNode() with an action returning void r=botond
This commit is contained in:
parent
741c3408b7
commit
7e0f8f630c
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.";
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user