summaryrefslogtreecommitdiffstats
path: root/gfx/tests/gtest/TestTreeTraversal.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/tests/gtest/TestTreeTraversal.cpp')
-rw-r--r--gfx/tests/gtest/TestTreeTraversal.cpp2225
1 files changed, 2225 insertions, 0 deletions
diff --git a/gfx/tests/gtest/TestTreeTraversal.cpp b/gfx/tests/gtest/TestTreeTraversal.cpp
new file mode 100644
index 000000000..043e28fd5
--- /dev/null
+++ b/gfx/tests/gtest/TestTreeTraversal.cpp
@@ -0,0 +1,2225 @@
+#include <vector>
+#include "mozilla/RefPtr.h"
+#include "gtest/gtest.h"
+#include "gtest/MozGTestBench.h"
+#include "nsRegion.h"
+#include "nsRect.h"
+#include "TreeTraversal.h"
+#include <stack>
+#include <queue>
+
+const int PERFORMANCE_TREE_DEPTH = 20;
+const int PERFORMANCE_TREE_CHILD_COUNT = 2;
+const int PERFORMANCE_TREE_LEAF_COUNT = 1048576; // 2 ** 20
+const int PERFORMANCE_REGION_XWRAP = 1024;
+
+using namespace mozilla::layers;
+using namespace mozilla;
+
+enum class SearchNodeType {Needle, Hay};
+enum class ForEachNodeType {Continue, Skip};
+
+template <class T>
+class TestNodeBase {
+ public:
+ NS_INLINE_DECL_REFCOUNTING(TestNodeBase<T>);
+ explicit TestNodeBase(T aType, int aExpectedTraversalRank = -1);
+ explicit TestNodeBase();
+ void SetActualTraversalRank(int aRank);
+ void SetValue(int aValue);
+ void SetType(T aType);
+ void SetRegion(nsRegion aRegion);
+ int GetExpectedTraversalRank();
+ int GetActualTraversalRank();
+ int GetValue();
+ T GetType();
+ nsRegion GetRegion();
+ virtual bool IsLeaf() = 0;
+ private:
+ MOZ_INIT_OUTSIDE_CTOR int mExpectedTraversalRank;
+ MOZ_INIT_OUTSIDE_CTOR int mActualTraversalRank;
+ MOZ_INIT_OUTSIDE_CTOR int mValue;
+ MOZ_INIT_OUTSIDE_CTOR nsRegion mRegion;
+ MOZ_INIT_OUTSIDE_CTOR T mType;
+ protected:
+ virtual ~TestNodeBase<T>() {};
+};
+
+template <class T>
+class TestNodeReverse : public TestNodeBase<T> {
+ public:
+ explicit TestNodeReverse(T aType, int aExpectedTraversalRank = -1);
+ explicit TestNodeReverse();
+ void AddChild(RefPtr<TestNodeReverse<T>> aNode);
+ TestNodeReverse<T>* GetLastChild();
+ TestNodeReverse<T>* GetPrevSibling();
+ bool IsLeaf();
+ private:
+ void SetPrevSibling(RefPtr<TestNodeReverse<T>> aNode);
+ void SetLastChild(RefPtr<TestNodeReverse<T>> aNode);
+ RefPtr<TestNodeReverse<T>> mSiblingNode;
+ RefPtr<TestNodeReverse<T>> mLastChildNode;
+ ~TestNodeReverse<T>() {};
+};
+
+template <class T>
+class TestNodeForward : public TestNodeBase<T> {
+ public:
+ explicit TestNodeForward(T aType, int aExpectedTraversalRank = -1);
+ explicit TestNodeForward();
+ void AddChild(RefPtr<TestNodeForward<T>> aNode);
+ TestNodeForward<T>* GetFirstChild();
+ TestNodeForward<T>* GetNextSibling();
+ bool IsLeaf();
+ private:
+ void SetNextSibling(RefPtr<TestNodeForward<T>> aNode);
+ void SetLastChild(RefPtr<TestNodeForward<T>> aNode);
+ void SetFirstChild(RefPtr<TestNodeForward<T>> aNode);
+ RefPtr<TestNodeForward<T>> mSiblingNode = nullptr;
+ RefPtr<TestNodeForward<T>> mFirstChildNode = nullptr;
+ // Track last child to facilitate appending children
+ RefPtr<TestNodeForward<T>> mLastChildNode = nullptr;
+ ~TestNodeForward<T>() {};
+};
+
+template <class T>
+TestNodeReverse<T>::TestNodeReverse(T aType, int aExpectedTraversalRank) :
+ TestNodeBase<T>(aType, aExpectedTraversalRank)
+{
+
+}
+
+template <class T>
+TestNodeReverse<T>::TestNodeReverse() :
+ TestNodeBase<T>()
+{
+
+}
+
+template <class T>
+void TestNodeReverse<T>::SetLastChild(RefPtr<TestNodeReverse<T>> aNode)
+{
+ mLastChildNode = aNode;
+}
+
+template <class T>
+void TestNodeReverse<T>::AddChild(RefPtr<TestNodeReverse<T>> aNode)
+{
+ aNode->SetPrevSibling(mLastChildNode);
+ SetLastChild(aNode);
+}
+
+template <class T>
+void TestNodeReverse<T>::SetPrevSibling(RefPtr<TestNodeReverse<T>> aNode)
+{
+ mSiblingNode = aNode;
+}
+
+template <class T>
+TestNodeReverse<T>* TestNodeReverse<T>::GetLastChild()
+{
+ return mLastChildNode;
+}
+
+template <class T>
+TestNodeReverse<T>* TestNodeReverse<T>::GetPrevSibling()
+{
+ return mSiblingNode;
+}
+
+template <class T>
+bool TestNodeReverse<T>::IsLeaf()
+{
+ return !mLastChildNode;
+}
+
+template <class T>
+TestNodeForward<T>::TestNodeForward(T aType, int aExpectedTraversalRank) :
+ TestNodeBase<T>(aType, aExpectedTraversalRank)
+{
+
+}
+
+template <class T>
+TestNodeForward<T>::TestNodeForward() :
+ TestNodeBase<T>()
+{
+
+}
+
+template <class T>
+void TestNodeForward<T>::AddChild(RefPtr<TestNodeForward<T>> aNode)
+{
+ if (mFirstChildNode == nullptr) {
+ SetFirstChild(aNode);
+ SetLastChild(aNode);
+ }
+ else {
+ mLastChildNode->SetNextSibling(aNode);
+ SetLastChild(aNode);
+ }
+}
+
+template <class T>
+void TestNodeForward<T>::SetLastChild(RefPtr<TestNodeForward<T>> aNode)
+{
+ mLastChildNode = aNode;
+}
+
+template <class T>
+void TestNodeForward<T>::SetFirstChild(RefPtr<TestNodeForward<T>> aNode)
+{
+ mFirstChildNode = aNode;
+}
+
+template <class T>
+void TestNodeForward<T>::SetNextSibling(RefPtr<TestNodeForward<T>> aNode)
+{
+ mSiblingNode = aNode;
+}
+
+template <class T>
+bool TestNodeForward<T>::IsLeaf()
+{
+ return !mFirstChildNode;
+}
+
+template <class T>
+TestNodeForward<T>* TestNodeForward<T>::GetFirstChild()
+{
+ return mFirstChildNode;
+}
+
+template <class T>
+TestNodeForward<T>* TestNodeForward<T>::GetNextSibling()
+{
+ return mSiblingNode;
+}
+
+template <class T>
+TestNodeBase<T>::TestNodeBase(T aType, int aExpectedTraversalRank):
+ mExpectedTraversalRank(aExpectedTraversalRank),
+ mActualTraversalRank(-1),
+ mType(aType)
+{
+}
+
+template <class T>
+TestNodeBase<T>::TestNodeBase()
+{
+}
+
+template <class T>
+int TestNodeBase<T>::GetActualTraversalRank()
+{
+ return mActualTraversalRank;
+}
+
+template <class T>
+void TestNodeBase<T>::SetActualTraversalRank(int aRank)
+{
+ mActualTraversalRank = aRank;
+}
+
+template <class T>
+int TestNodeBase<T>::GetExpectedTraversalRank()
+{
+ return mExpectedTraversalRank;
+}
+
+template <class T>
+T TestNodeBase<T>::GetType()
+{
+ return mType;
+}
+
+template <class T>
+void TestNodeBase<T>::SetType(T aType)
+{
+ mType = aType;
+}
+
+template <class T>
+nsRegion TestNodeBase<T>::GetRegion()
+{
+ return mRegion;
+}
+
+template <class T>
+void TestNodeBase<T>::SetRegion(nsRegion aRegion)
+{
+ mRegion = aRegion;
+}
+
+template <class T>
+int TestNodeBase<T>::GetValue()
+{
+ return mValue;
+}
+
+template <class T>
+void TestNodeBase<T>::SetValue(int aValue)
+{
+ mValue = aValue;
+}
+
+typedef TestNodeBase<SearchNodeType> SearchTestNode;
+typedef TestNodeBase<ForEachNodeType> ForEachTestNode;
+typedef TestNodeReverse<SearchNodeType> SearchTestNodeReverse;
+typedef TestNodeReverse<ForEachNodeType> ForEachTestNodeReverse;
+typedef TestNodeForward<SearchNodeType> SearchTestNodeForward;
+typedef TestNodeForward<ForEachNodeType> ForEachTestNodeForward;
+
+template <typename Node, typename Action>
+void CreateBenchmarkTreeRecursive(RefPtr<Node> aNode, int aDepth, int aChildrenCount, Action aAction)
+{
+ if (aDepth > 0) {
+ for (int i = 0; i < aChildrenCount; i++) {
+ RefPtr<Node> newNode = new Node();
+ aNode->AddChild(newNode);
+ CreateBenchmarkTreeRecursive(newNode, aDepth-1, aChildrenCount, aAction);
+ }
+ }
+ aAction(aNode);
+}
+
+template <typename Node, typename Action>
+RefPtr<Node> CreateBenchmarkTree(int aDepth, int aChildrenCount, Action aAction)
+{
+ RefPtr<Node> rootNode = new Node();
+ CreateBenchmarkTreeRecursive(rootNode, aDepth, aChildrenCount, aAction);
+ return rootNode;
+}
+
+TEST(TreeTraversal, DepthFirstSearchNull)
+{
+ RefPtr<SearchTestNodeReverse> nullNode;
+ RefPtr<SearchTestNodeReverse> result = DepthFirstSearch<layers::ReverseIterator>(nullNode.get(),
+ [](SearchTestNodeReverse* aNode)
+ {
+ return aNode->GetType() == SearchNodeType::Needle;
+ });
+ ASSERT_EQ(result.get(), nullptr) << "Null root did not return null search result.";
+}
+
+TEST(TreeTraversal, DepthFirstSearchValueExists)
+{
+ int visitCount = 0;
+ size_t expectedNeedleTraversalRank = 7;
+ RefPtr<SearchTestNodeForward> needleNode;
+ std::vector<RefPtr<SearchTestNodeForward>> nodeList;
+ for (size_t i = 0; i < 10; i++)
+ {
+ if (i == expectedNeedleTraversalRank) {
+ needleNode = new SearchTestNodeForward(SearchNodeType::Needle, i);
+ nodeList.push_back(needleNode);
+ } else if (i < expectedNeedleTraversalRank) {
+ nodeList.push_back(new SearchTestNodeForward(SearchNodeType::Hay, i));
+ } else {
+ nodeList.push_back(new SearchTestNodeForward(SearchNodeType::Hay));
+ }
+ }
+
+ RefPtr<SearchTestNodeForward> 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]);
+
+ RefPtr<SearchTestNodeForward> foundNode = DepthFirstSearch<layers::ForwardIterator>(root.get(),
+ [&visitCount](SearchTestNodeForward* aNode)
+ {
+ aNode->SetActualTraversalRank(visitCount);
+ visitCount++;
+ return aNode->GetType() == SearchNodeType::Needle;
+ });
+
+ 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.";
+ }
+
+ ASSERT_EQ(foundNode, needleNode) << "Search did not return expected node.";
+ ASSERT_EQ(foundNode->GetType(), SearchNodeType::Needle)
+ << "Returned node does not match expected value (something odd happened).";
+}
+
+TEST(TreeTraversal, DepthFirstSearchValueExistsReverse)
+{
+ int visitCount = 0;
+ size_t expectedNeedleTraversalRank = 7;
+ RefPtr<SearchTestNodeReverse> needleNode;
+ std::vector<RefPtr<SearchTestNodeReverse>> nodeList;
+ for (size_t i = 0; i < 10; i++)
+ {
+ if (i == expectedNeedleTraversalRank) {
+ needleNode = new SearchTestNodeReverse(SearchNodeType::Needle, i);
+ nodeList.push_back(needleNode);
+ } else if (i < expectedNeedleTraversalRank) {
+ nodeList.push_back(new SearchTestNodeReverse(SearchNodeType::Hay, i));
+ } else {
+ nodeList.push_back(new SearchTestNodeReverse(SearchNodeType::Hay));
+ }
+ }
+
+ RefPtr<SearchTestNodeReverse> root = nodeList[0];
+ nodeList[0]->AddChild(nodeList[4]);
+ nodeList[0]->AddChild(nodeList[1]);
+ nodeList[1]->AddChild(nodeList[3]);
+ nodeList[1]->AddChild(nodeList[2]);
+ nodeList[4]->AddChild(nodeList[6]);
+ nodeList[4]->AddChild(nodeList[5]);
+ nodeList[6]->AddChild(nodeList[7]);
+ nodeList[7]->AddChild(nodeList[9]);
+ nodeList[7]->AddChild(nodeList[8]);
+
+ RefPtr<SearchTestNodeReverse> foundNode = DepthFirstSearch<layers::ReverseIterator>(root.get(),
+ [&visitCount](SearchTestNodeReverse* aNode)
+ {
+ aNode->SetActualTraversalRank(visitCount);
+ visitCount++;
+ return aNode->GetType() == SearchNodeType::Needle;
+ });
+
+ 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.";
+ }
+
+ ASSERT_EQ(foundNode, needleNode) << "Search did not return expected node.";
+ ASSERT_EQ(foundNode->GetType(), SearchNodeType::Needle)
+ << "Returned node does not match expected value (something odd happened).";
+}
+
+TEST(TreeTraversal, DepthFirstSearchRootIsNeedle)
+{
+ RefPtr<SearchTestNodeReverse> root = new SearchTestNodeReverse(SearchNodeType::Needle, 0);
+ RefPtr<SearchTestNodeReverse> childNode1= new SearchTestNodeReverse(SearchNodeType::Hay);
+ RefPtr<SearchTestNodeReverse> childNode2 = new SearchTestNodeReverse(SearchNodeType::Hay);
+ int visitCount = 0;
+ RefPtr<SearchTestNodeReverse> result = DepthFirstSearch<layers::ReverseIterator>(root.get(),
+ [&visitCount](SearchTestNodeReverse* aNode)
+ {
+ aNode->SetActualTraversalRank(visitCount);
+ visitCount++;
+ return aNode->GetType() == SearchNodeType::Needle;
+ });
+ ASSERT_EQ(result, root) << "Search starting at needle did not return needle.";
+ ASSERT_EQ(root->GetExpectedTraversalRank(), root->GetActualTraversalRank())
+ << "Search starting at needle did not return needle.";
+ ASSERT_EQ(childNode1->GetExpectedTraversalRank(),
+ childNode1->GetActualTraversalRank())
+ << "Search starting at needle continued past needle.";
+ ASSERT_EQ(childNode2->GetExpectedTraversalRank(),
+ childNode2->GetActualTraversalRank())
+ << "Search starting at needle continued past needle.";
+}
+
+TEST(TreeTraversal, DepthFirstSearchValueDoesNotExist)
+{
+ int visitCount = 0;
+ std::vector<RefPtr<SearchTestNodeForward>> nodeList;
+ for (int i = 0; i < 10; i++)
+ {
+ nodeList.push_back(new SearchTestNodeForward(SearchNodeType::Hay, i));
+ }
+
+ RefPtr<SearchTestNodeForward> 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]);
+
+
+ RefPtr<SearchTestNodeForward> foundNode = DepthFirstSearch<layers::ForwardIterator>(root.get(),
+ [&visitCount](SearchTestNodeForward* aNode)
+ {
+ aNode->SetActualTraversalRank(visitCount);
+ visitCount++;
+ return aNode->GetType() == SearchNodeType::Needle;
+ });
+
+ for (int i = 0; i < 10; i++)
+ {
+ ASSERT_EQ(nodeList[i]->GetExpectedTraversalRank(),
+ nodeList[i]->GetActualTraversalRank())
+ << "Node at index " << i << " was hit out of order.";
+ }
+
+ ASSERT_EQ(foundNode.get(), nullptr)
+ << "Search found something that should not exist.";
+}
+
+TEST(TreeTraversal, DepthFirstSearchValueDoesNotExistReverse)
+{
+ int visitCount = 0;
+ std::vector<RefPtr<SearchTestNodeReverse>> nodeList;
+ for (int i = 0; i < 10; i++)
+ {
+ nodeList.push_back(new SearchTestNodeReverse(SearchNodeType::Hay, i));
+ }
+
+ RefPtr<SearchTestNodeReverse> root = nodeList[0];
+ nodeList[0]->AddChild(nodeList[4]);
+ nodeList[0]->AddChild(nodeList[1]);
+ nodeList[1]->AddChild(nodeList[3]);
+ nodeList[1]->AddChild(nodeList[2]);
+ nodeList[4]->AddChild(nodeList[6]);
+ nodeList[4]->AddChild(nodeList[5]);
+ nodeList[6]->AddChild(nodeList[7]);
+ nodeList[7]->AddChild(nodeList[9]);
+ nodeList[7]->AddChild(nodeList[8]);
+
+
+ RefPtr<SearchTestNodeReverse> foundNode = DepthFirstSearch<layers::ReverseIterator>(root.get(),
+ [&visitCount](SearchTestNodeReverse* aNode)
+ {
+ aNode->SetActualTraversalRank(visitCount);
+ visitCount++;
+ return aNode->GetType() == SearchNodeType::Needle;
+ });
+
+ for (int i = 0; i < 10; i++)
+ {
+ ASSERT_EQ(nodeList[i]->GetExpectedTraversalRank(),
+ nodeList[i]->GetActualTraversalRank())
+ << "Node at index " << i << " was hit out of order.";
+ }
+
+ ASSERT_EQ(foundNode.get(), nullptr)
+ << "Search found something that should not exist.";
+}
+
+TEST(TreeTraversal, DepthFirstSearchPostOrderNull)
+{
+ RefPtr<SearchTestNodeReverse> nullNode;
+ RefPtr<SearchTestNodeReverse> result = DepthFirstSearchPostOrder<layers::ReverseIterator>(nullNode.get(),
+ [](SearchTestNodeReverse* aNode)
+ {
+ return aNode->GetType() == SearchNodeType::Needle;
+ });
+ ASSERT_EQ(result.get(), nullptr) << "Null root did not return null search result.";
+}
+
+TEST(TreeTraversal, DepthFirstSearchPostOrderValueExists)
+{
+ int visitCount = 0;
+ size_t expectedNeedleTraversalRank = 7;
+ RefPtr<SearchTestNodeForward> needleNode;
+ std::vector<RefPtr<SearchTestNodeForward>> nodeList;
+ for (size_t i = 0; i < 10; i++)
+ {
+ if (i == expectedNeedleTraversalRank) {
+ needleNode = new SearchTestNodeForward(SearchNodeType::Needle, i);
+ nodeList.push_back(needleNode);
+ } else if (i < expectedNeedleTraversalRank) {
+ nodeList.push_back(new SearchTestNodeForward(SearchNodeType::Hay, i));
+ } else {
+ nodeList.push_back(new SearchTestNodeForward(SearchNodeType::Hay));
+ }
+ }
+
+ RefPtr<SearchTestNodeForward> root = nodeList[9];
+ nodeList[9]->AddChild(nodeList[2]);
+ nodeList[9]->AddChild(nodeList[8]);
+ nodeList[2]->AddChild(nodeList[0]);
+ nodeList[2]->AddChild(nodeList[1]);
+ nodeList[8]->AddChild(nodeList[6]);
+ nodeList[8]->AddChild(nodeList[7]);
+ nodeList[6]->AddChild(nodeList[5]);
+ nodeList[5]->AddChild(nodeList[3]);
+ nodeList[5]->AddChild(nodeList[4]);
+
+ RefPtr<SearchTestNodeForward> foundNode = DepthFirstSearchPostOrder<layers::ForwardIterator>(root.get(),
+ [&visitCount](SearchTestNodeForward* aNode)
+ {
+ aNode->SetActualTraversalRank(visitCount);
+ visitCount++;
+ return aNode->GetType() == SearchNodeType::Needle;
+ });
+
+ 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.";
+ }
+
+ ASSERT_EQ(foundNode, needleNode) << "Search did not return expected node.";
+ ASSERT_EQ(foundNode->GetType(), SearchNodeType::Needle)
+ << "Returned node does not match expected value (something odd happened).";
+}
+
+TEST(TreeTraversal, DepthFirstSearchPostOrderValueExistsReverse)
+{
+ int visitCount = 0;
+ size_t expectedNeedleTraversalRank = 7;
+ RefPtr<SearchTestNodeReverse> needleNode;
+ std::vector<RefPtr<SearchTestNodeReverse>> nodeList;
+ for (size_t i = 0; i < 10; i++)
+ {
+ if (i == expectedNeedleTraversalRank) {
+ needleNode = new SearchTestNodeReverse(SearchNodeType::Needle, i);
+ nodeList.push_back(needleNode);
+ } else if (i < expectedNeedleTraversalRank) {
+ nodeList.push_back(new SearchTestNodeReverse(SearchNodeType::Hay, i));
+ } else {
+ nodeList.push_back(new SearchTestNodeReverse(SearchNodeType::Hay));
+ }
+ }
+
+ RefPtr<SearchTestNodeReverse> root = nodeList[9];
+ nodeList[9]->AddChild(nodeList[8]);
+ nodeList[9]->AddChild(nodeList[2]);
+ nodeList[2]->AddChild(nodeList[1]);
+ nodeList[2]->AddChild(nodeList[0]);
+ nodeList[8]->AddChild(nodeList[7]);
+ nodeList[8]->AddChild(nodeList[6]);
+ nodeList[6]->AddChild(nodeList[5]);
+ nodeList[5]->AddChild(nodeList[4]);
+ nodeList[5]->AddChild(nodeList[3]);
+
+ RefPtr<SearchTestNodeReverse> foundNode = DepthFirstSearchPostOrder<layers::ReverseIterator>(root.get(),
+ [&visitCount](SearchTestNodeReverse* aNode)
+ {
+ aNode->SetActualTraversalRank(visitCount);
+ visitCount++;
+ return aNode->GetType() == SearchNodeType::Needle;
+ });
+
+ 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.";
+ }
+
+ ASSERT_EQ(foundNode, needleNode) << "Search did not return expected node.";
+ ASSERT_EQ(foundNode->GetType(), SearchNodeType::Needle)
+ << "Returned node does not match expected value (something odd happened).";
+}
+
+TEST(TreeTraversal, DepthFirstSearchPostOrderRootIsNeedle)
+{
+ RefPtr<SearchTestNodeReverse> root = new SearchTestNodeReverse(SearchNodeType::Needle, 0);
+ RefPtr<SearchTestNodeReverse> childNode1= new SearchTestNodeReverse(SearchNodeType::Hay);
+ RefPtr<SearchTestNodeReverse> childNode2 = new SearchTestNodeReverse(SearchNodeType::Hay);
+ int visitCount = 0;
+ RefPtr<SearchTestNodeReverse> result = DepthFirstSearchPostOrder<layers::ReverseIterator>(root.get(),
+ [&visitCount](SearchTestNodeReverse* aNode)
+ {
+ aNode->SetActualTraversalRank(visitCount);
+ visitCount++;
+ return aNode->GetType() == SearchNodeType::Needle;
+ });
+ ASSERT_EQ(result, root) << "Search starting at needle did not return needle.";
+ ASSERT_EQ(root->GetExpectedTraversalRank(), root->GetActualTraversalRank())
+ << "Search starting at needle did not return needle.";
+ ASSERT_EQ(childNode1->GetExpectedTraversalRank(),
+ childNode1->GetActualTraversalRank())
+ << "Search starting at needle continued past needle.";
+ ASSERT_EQ(childNode2->GetExpectedTraversalRank(),
+ childNode2->GetActualTraversalRank())
+ << "Search starting at needle continued past needle.";
+}
+
+TEST(TreeTraversal, DepthFirstSearchPostOrderValueDoesNotExist)
+{
+ int visitCount = 0;
+ std::vector<RefPtr<SearchTestNodeForward>> nodeList;
+ for (int i = 0; i < 10; i++)
+ {
+ nodeList.push_back(new SearchTestNodeForward(SearchNodeType::Hay, i));
+ }
+
+ RefPtr<SearchTestNodeForward> root = nodeList[9];
+ nodeList[9]->AddChild(nodeList[2]);
+ nodeList[9]->AddChild(nodeList[8]);
+ nodeList[2]->AddChild(nodeList[0]);
+ nodeList[2]->AddChild(nodeList[1]);
+ nodeList[8]->AddChild(nodeList[6]);
+ nodeList[8]->AddChild(nodeList[7]);
+ nodeList[6]->AddChild(nodeList[5]);
+ nodeList[5]->AddChild(nodeList[3]);
+ nodeList[5]->AddChild(nodeList[4]);
+
+ RefPtr<SearchTestNodeForward> foundNode = DepthFirstSearchPostOrder<layers::ForwardIterator>(root.get(),
+ [&visitCount](SearchTestNodeForward* aNode)
+ {
+ aNode->SetActualTraversalRank(visitCount);
+ visitCount++;
+ return aNode->GetType() == SearchNodeType::Needle;
+ });
+
+ for (int i = 0; i < 10; i++)
+ {
+ ASSERT_EQ(nodeList[i]->GetExpectedTraversalRank(),
+ nodeList[i]->GetActualTraversalRank())
+ << "Node at index " << i << " was hit out of order.";
+ }
+
+ ASSERT_EQ(foundNode.get(), nullptr)
+ << "Search found something that should not exist.";
+}
+
+TEST(TreeTraversal, DepthFirstSearchPostOrderValueDoesNotExistReverse)
+{
+ int visitCount = 0;
+ std::vector<RefPtr<SearchTestNodeReverse>> nodeList;
+ for (int i = 0; i < 10; i++)
+ {
+ nodeList.push_back(new SearchTestNodeReverse(SearchNodeType::Hay, i));
+ }
+
+ RefPtr<SearchTestNodeReverse> root = nodeList[9];
+ nodeList[9]->AddChild(nodeList[8]);
+ nodeList[9]->AddChild(nodeList[2]);
+ nodeList[2]->AddChild(nodeList[1]);
+ nodeList[2]->AddChild(nodeList[0]);
+ nodeList[8]->AddChild(nodeList[7]);
+ nodeList[8]->AddChild(nodeList[6]);
+ nodeList[6]->AddChild(nodeList[5]);
+ nodeList[5]->AddChild(nodeList[4]);
+ nodeList[5]->AddChild(nodeList[3]);
+
+ RefPtr<SearchTestNodeReverse> foundNode = DepthFirstSearchPostOrder<layers::ReverseIterator>(root.get(),
+ [&visitCount](SearchTestNodeReverse* aNode)
+ {
+ aNode->SetActualTraversalRank(visitCount);
+ visitCount++;
+ return aNode->GetType() == SearchNodeType::Needle;
+ });
+
+ for (int i = 0; i < 10; i++)
+ {
+ ASSERT_EQ(nodeList[i]->GetExpectedTraversalRank(),
+ nodeList[i]->GetActualTraversalRank())
+ << "Node at index " << i << " was hit out of order.";
+ }
+
+ ASSERT_EQ(foundNode.get(), nullptr)
+ << "Search found something that should not exist.";
+}
+
+TEST(TreeTraversal, BreadthFirstSearchNull)
+{
+ RefPtr<SearchTestNodeReverse> nullNode;
+ RefPtr<SearchTestNodeReverse> result = BreadthFirstSearch<layers::ReverseIterator>(nullNode.get(),
+ [](SearchTestNodeReverse* aNode)
+ {
+ return aNode->GetType() == SearchNodeType::Needle;
+ });
+ ASSERT_EQ(result.get(), nullptr) << "Null root did not return null search result.";
+}
+
+TEST(TreeTraversal, BreadthFirstSearchRootIsNeedle)
+{
+ RefPtr<SearchTestNodeReverse> root = new SearchTestNodeReverse(SearchNodeType::Needle, 0);
+ RefPtr<SearchTestNodeReverse> childNode1= new SearchTestNodeReverse(SearchNodeType::Hay);
+ RefPtr<SearchTestNodeReverse> childNode2 = new SearchTestNodeReverse(SearchNodeType::Hay);
+ int visitCount = 0;
+ RefPtr<SearchTestNodeReverse> result = BreadthFirstSearch<layers::ReverseIterator>(root.get(),
+ [&visitCount](SearchTestNodeReverse* aNode)
+ {
+ aNode->SetActualTraversalRank(visitCount);
+ visitCount++;
+ return aNode->GetType() == SearchNodeType::Needle;
+ });
+ ASSERT_EQ(result, root) << "Search starting at needle did not return needle.";
+ ASSERT_EQ(root->GetExpectedTraversalRank(), root->GetActualTraversalRank())
+ << "Search starting at needle did not return needle.";
+ ASSERT_EQ(childNode1->GetExpectedTraversalRank(),
+ childNode1->GetActualTraversalRank())
+ << "Search starting at needle continued past needle.";
+ ASSERT_EQ(childNode2->GetExpectedTraversalRank(),
+ childNode2->GetActualTraversalRank())
+ << "Search starting at needle continued past needle.";
+}
+
+TEST(TreeTraversal, BreadthFirstSearchValueExists)
+{
+ int visitCount = 0;
+ size_t expectedNeedleTraversalRank = 7;
+ RefPtr<SearchTestNodeForward> needleNode;
+ std::vector<RefPtr<SearchTestNodeForward>> nodeList;
+ for (size_t i = 0; i < 10; i++)
+ {
+ if (i == expectedNeedleTraversalRank) {
+ needleNode = new SearchTestNodeForward(SearchNodeType::Needle, i);
+ nodeList.push_back(needleNode);
+ } else if (i < expectedNeedleTraversalRank) {
+ nodeList.push_back(new SearchTestNodeForward(SearchNodeType::Hay, i));
+ } else {
+ nodeList.push_back(new SearchTestNodeForward(SearchNodeType::Hay));
+ }
+ }
+
+ RefPtr<SearchTestNodeForward> root = nodeList[0];
+ nodeList[0]->AddChild(nodeList[1]);
+ nodeList[0]->AddChild(nodeList[2]);
+ nodeList[1]->AddChild(nodeList[3]);
+ nodeList[1]->AddChild(nodeList[4]);
+ nodeList[2]->AddChild(nodeList[5]);
+ nodeList[2]->AddChild(nodeList[6]);
+ nodeList[6]->AddChild(nodeList[7]);
+ nodeList[7]->AddChild(nodeList[8]);
+ nodeList[7]->AddChild(nodeList[9]);
+
+ RefPtr<SearchTestNodeForward> foundNode = BreadthFirstSearch<layers::ForwardIterator>(root.get(),
+ [&visitCount](SearchTestNodeForward* aNode)
+ {
+ aNode->SetActualTraversalRank(visitCount);
+ visitCount++;
+ return aNode->GetType() == SearchNodeType::Needle;
+ });
+
+ 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.";
+ }
+
+ ASSERT_EQ(foundNode, needleNode) << "Search did not return expected node.";
+ ASSERT_EQ(foundNode->GetType(), SearchNodeType::Needle)
+ << "Returned node does not match expected value (something odd happened).";
+}
+
+TEST(TreeTraversal, BreadthFirstSearchValueExistsReverse)
+{
+ int visitCount = 0;
+ size_t expectedNeedleTraversalRank = 7;
+ RefPtr<SearchTestNodeReverse> needleNode;
+ std::vector<RefPtr<SearchTestNodeReverse>> nodeList;
+ for (size_t i = 0; i < 10; i++)
+ {
+ if (i == expectedNeedleTraversalRank) {
+ needleNode = new SearchTestNodeReverse(SearchNodeType::Needle, i);
+ nodeList.push_back(needleNode);
+ } else if (i < expectedNeedleTraversalRank) {
+ nodeList.push_back(new SearchTestNodeReverse(SearchNodeType::Hay, i));
+ } else {
+ nodeList.push_back(new SearchTestNodeReverse(SearchNodeType::Hay));
+ }
+ }
+
+ RefPtr<SearchTestNodeReverse> root = nodeList[0];
+ nodeList[0]->AddChild(nodeList[2]);
+ nodeList[0]->AddChild(nodeList[1]);
+ nodeList[1]->AddChild(nodeList[4]);
+ nodeList[1]->AddChild(nodeList[3]);
+ nodeList[2]->AddChild(nodeList[6]);
+ nodeList[2]->AddChild(nodeList[5]);
+ nodeList[6]->AddChild(nodeList[7]);
+ nodeList[7]->AddChild(nodeList[9]);
+ nodeList[7]->AddChild(nodeList[8]);
+
+ RefPtr<SearchTestNodeReverse> foundNode = BreadthFirstSearch<layers::ReverseIterator>(root.get(),
+ [&visitCount](SearchTestNodeReverse* aNode)
+ {
+ aNode->SetActualTraversalRank(visitCount);
+ visitCount++;
+ return aNode->GetType() == SearchNodeType::Needle;
+ });
+
+ 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.";
+ }
+
+ ASSERT_EQ(foundNode, needleNode) << "Search did not return expected node.";
+ ASSERT_EQ(foundNode->GetType(), SearchNodeType::Needle)
+ << "Returned node does not match expected value (something odd happened).";
+}
+
+TEST(TreeTraversal, BreadthFirstSearchValueDoesNotExist)
+{
+ int visitCount = 0;
+ std::vector<RefPtr<SearchTestNodeForward>> nodeList;
+ for (int i = 0; i < 10; i++)
+ {
+ nodeList.push_back(new SearchTestNodeForward(SearchNodeType::Hay, i));
+ }
+
+ RefPtr<SearchTestNodeForward> root = nodeList[0];
+ nodeList[0]->AddChild(nodeList[1]);
+ nodeList[0]->AddChild(nodeList[2]);
+ nodeList[1]->AddChild(nodeList[3]);
+ nodeList[1]->AddChild(nodeList[4]);
+ nodeList[2]->AddChild(nodeList[5]);
+ nodeList[2]->AddChild(nodeList[6]);
+ nodeList[6]->AddChild(nodeList[7]);
+ nodeList[7]->AddChild(nodeList[8]);
+ nodeList[7]->AddChild(nodeList[9]);
+
+
+ RefPtr<SearchTestNodeForward> foundNode = BreadthFirstSearch<layers::ForwardIterator>(root.get(),
+ [&visitCount](SearchTestNodeForward* aNode)
+ {
+ aNode->SetActualTraversalRank(visitCount);
+ visitCount++;
+ return aNode->GetType() == SearchNodeType::Needle;
+ });
+
+ 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.";
+ }
+
+ ASSERT_EQ(foundNode.get(), nullptr)
+ << "Search found something that should not exist.";
+}
+
+TEST(TreeTraversal, BreadthFirstSearchValueDoesNotExistReverse)
+{
+ int visitCount = 0;
+ std::vector<RefPtr<SearchTestNodeReverse>> nodeList;
+ for (int i = 0; i < 10; i++)
+ {
+ nodeList.push_back(new SearchTestNodeReverse(SearchNodeType::Hay, i));
+ }
+
+ RefPtr<SearchTestNodeReverse> root = nodeList[0];
+ nodeList[0]->AddChild(nodeList[2]);
+ nodeList[0]->AddChild(nodeList[1]);
+ nodeList[1]->AddChild(nodeList[4]);
+ nodeList[1]->AddChild(nodeList[3]);
+ nodeList[2]->AddChild(nodeList[6]);
+ nodeList[2]->AddChild(nodeList[5]);
+ nodeList[6]->AddChild(nodeList[7]);
+ nodeList[7]->AddChild(nodeList[9]);
+ nodeList[7]->AddChild(nodeList[8]);
+
+
+ RefPtr<SearchTestNodeReverse> foundNode = BreadthFirstSearch<layers::ReverseIterator>(root.get(),
+ [&visitCount](SearchTestNodeReverse* aNode)
+ {
+ aNode->SetActualTraversalRank(visitCount);
+ visitCount++;
+ return aNode->GetType() == SearchNodeType::Needle;
+ });
+
+ 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.";
+ }
+
+ ASSERT_EQ(foundNode.get(), nullptr)
+ << "Search found something that should not exist.";
+}
+
+TEST(TreeTraversal, ForEachNodeNullStillRuns)
+{
+ RefPtr<ForEachTestNodeReverse> nullNode;
+ ForEachNode<layers::ReverseIterator>(nullNode.get(),
+ [](ForEachTestNodeReverse* aNode)
+ {
+ return TraversalFlag::Continue;
+ });
+}
+
+TEST(TreeTraversal, ForEachNodeAllEligible)
+{
+ std::vector<RefPtr<ForEachTestNodeForward>> nodeList;
+ int visitCount = 0;
+ for (int i = 0; i < 10; i++)
+ {
+ nodeList.push_back(new ForEachTestNodeForward(ForEachNodeType::Continue,i));
+ }
+
+ RefPtr<ForEachTestNodeForward> 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<layers::ForwardIterator>(root.get(),
+ [&visitCount](ForEachTestNodeForward* aNode)
+ {
+ aNode->SetActualTraversalRank(visitCount);
+ visitCount++;
+ return aNode->GetType() == ForEachNodeType::Continue
+ ? TraversalFlag::Continue : TraversalFlag::Skip;
+ });
+
+ 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.";
+ }
+}
+
+TEST(TreeTraversal, ForEachNodeAllEligibleReverse)
+{
+ std::vector<RefPtr<ForEachTestNodeReverse>> nodeList;
+ int visitCount = 0;
+ for (int i = 0; i < 10; i++)
+ {
+ nodeList.push_back(new ForEachTestNodeReverse(ForEachNodeType::Continue,i));
+ }
+
+ RefPtr<ForEachTestNodeReverse> root = nodeList[0];
+ nodeList[0]->AddChild(nodeList[4]);
+ nodeList[0]->AddChild(nodeList[1]);
+ nodeList[1]->AddChild(nodeList[3]);
+ nodeList[1]->AddChild(nodeList[2]);
+ nodeList[4]->AddChild(nodeList[6]);
+ nodeList[4]->AddChild(nodeList[5]);
+ nodeList[6]->AddChild(nodeList[7]);
+ nodeList[7]->AddChild(nodeList[9]);
+ nodeList[7]->AddChild(nodeList[8]);
+
+
+ ForEachNode<layers::ReverseIterator>(root.get(),
+ [&visitCount](ForEachTestNodeReverse* aNode)
+ {
+ aNode->SetActualTraversalRank(visitCount);
+ visitCount++;
+ return aNode->GetType() == ForEachNodeType::Continue
+ ? TraversalFlag::Continue : TraversalFlag::Skip;
+ });
+
+ 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.";
+ }
+}
+
+TEST(TreeTraversal, ForEachNodeSomeIneligibleNodes)
+{
+ std::vector<RefPtr<ForEachTestNodeForward>> expectedVisitedNodeList;
+ std::vector<RefPtr<ForEachTestNodeForward>> expectedSkippedNodeList;
+ int visitCount = 0;
+
+ expectedVisitedNodeList.push_back(new ForEachTestNodeForward(ForEachNodeType::Continue, 0));
+ expectedVisitedNodeList.push_back(new ForEachTestNodeForward(ForEachNodeType::Skip, 1));
+ expectedVisitedNodeList.push_back(new ForEachTestNodeForward(ForEachNodeType::Continue, 2));
+ expectedVisitedNodeList.push_back(new ForEachTestNodeForward(ForEachNodeType::Skip, 3));
+
+ expectedSkippedNodeList.push_back(new ForEachTestNodeForward(ForEachNodeType::Continue));
+ expectedSkippedNodeList.push_back(new ForEachTestNodeForward(ForEachNodeType::Continue));
+ expectedSkippedNodeList.push_back(new ForEachTestNodeForward(ForEachNodeType::Skip));
+ expectedSkippedNodeList.push_back(new ForEachTestNodeForward(ForEachNodeType::Skip));
+
+ RefPtr<ForEachTestNodeForward> root = expectedVisitedNodeList[0];
+ expectedVisitedNodeList[0]->AddChild(expectedVisitedNodeList[1]);
+ expectedVisitedNodeList[0]->AddChild(expectedVisitedNodeList[2]);
+ expectedVisitedNodeList[1]->AddChild(expectedSkippedNodeList[0]);
+ expectedVisitedNodeList[1]->AddChild(expectedSkippedNodeList[1]);
+ expectedVisitedNodeList[2]->AddChild(expectedVisitedNodeList[3]);
+ expectedVisitedNodeList[3]->AddChild(expectedSkippedNodeList[2]);
+ expectedVisitedNodeList[3]->AddChild(expectedSkippedNodeList[3]);
+
+ ForEachNode<layers::ForwardIterator>(root.get(),
+ [&visitCount](ForEachTestNodeForward* aNode)
+ {
+ aNode->SetActualTraversalRank(visitCount);
+ visitCount++;
+ return aNode->GetType() == ForEachNodeType::Continue
+ ? TraversalFlag::Continue : TraversalFlag::Skip;
+ });
+
+ for (size_t i = 0; i < expectedVisitedNodeList.size(); i++)
+ {
+ ASSERT_EQ(expectedVisitedNodeList[i]->GetExpectedTraversalRank(),
+ expectedVisitedNodeList[i]->GetActualTraversalRank())
+ << "Node at index " << i << " was hit out of order.";
+ }
+
+ for (size_t i = 0; i < expectedSkippedNodeList.size(); i++)
+ {
+ ASSERT_EQ(expectedSkippedNodeList[i]->GetExpectedTraversalRank(),
+ expectedSkippedNodeList[i]->GetActualTraversalRank())
+ << "Node at index " << i << "was not expected to be hit.";
+ }
+}
+
+TEST(TreeTraversal, ForEachNodeSomeIneligibleNodesReverse)
+{
+ std::vector<RefPtr<ForEachTestNodeReverse>> expectedVisitedNodeList;
+ std::vector<RefPtr<ForEachTestNodeReverse>> expectedSkippedNodeList;
+ int visitCount = 0;
+
+ expectedVisitedNodeList.push_back(new ForEachTestNodeReverse(ForEachNodeType::Continue, 0));
+ expectedVisitedNodeList.push_back(new ForEachTestNodeReverse(ForEachNodeType::Skip, 1));
+ expectedVisitedNodeList.push_back(new ForEachTestNodeReverse(ForEachNodeType::Continue, 2));
+ expectedVisitedNodeList.push_back(new ForEachTestNodeReverse(ForEachNodeType::Skip, 3));
+
+ expectedSkippedNodeList.push_back(new ForEachTestNodeReverse(ForEachNodeType::Continue));
+ expectedSkippedNodeList.push_back(new ForEachTestNodeReverse(ForEachNodeType::Continue));
+ expectedSkippedNodeList.push_back(new ForEachTestNodeReverse(ForEachNodeType::Skip));
+ expectedSkippedNodeList.push_back(new ForEachTestNodeReverse(ForEachNodeType::Skip));
+
+ RefPtr<ForEachTestNodeReverse> root = expectedVisitedNodeList[0];
+ expectedVisitedNodeList[0]->AddChild(expectedVisitedNodeList[2]);
+ expectedVisitedNodeList[0]->AddChild(expectedVisitedNodeList[1]);
+ expectedVisitedNodeList[1]->AddChild(expectedSkippedNodeList[1]);
+ expectedVisitedNodeList[1]->AddChild(expectedSkippedNodeList[0]);
+ expectedVisitedNodeList[2]->AddChild(expectedVisitedNodeList[3]);
+ expectedVisitedNodeList[3]->AddChild(expectedSkippedNodeList[3]);
+ expectedVisitedNodeList[3]->AddChild(expectedSkippedNodeList[2]);
+
+ ForEachNode<layers::ReverseIterator>(root.get(),
+ [&visitCount](ForEachTestNodeReverse* aNode)
+ {
+ aNode->SetActualTraversalRank(visitCount);
+ visitCount++;
+ return aNode->GetType() == ForEachNodeType::Continue
+ ? TraversalFlag::Continue : TraversalFlag::Skip;
+ });
+
+ for (size_t i = 0; i < expectedVisitedNodeList.size(); i++)
+ {
+ ASSERT_EQ(expectedVisitedNodeList[i]->GetExpectedTraversalRank(),
+ expectedVisitedNodeList[i]->GetActualTraversalRank())
+ << "Node at index " << i << " was hit out of order.";
+ }
+
+ for (size_t i = 0; i < expectedSkippedNodeList.size(); i++)
+ {
+ ASSERT_EQ(expectedSkippedNodeList[i]->GetExpectedTraversalRank(),
+ expectedSkippedNodeList[i]->GetActualTraversalRank())
+ << "Node at index " << i << "was not expected to be hit.";
+ }
+}
+
+TEST(TreeTraversal, ForEachNodeIneligibleRoot)
+{
+ int visitCount = 0;
+
+ RefPtr<ForEachTestNodeReverse> root = new ForEachTestNodeReverse(ForEachNodeType::Skip, 0);
+ RefPtr<ForEachTestNodeReverse> childNode1 = new ForEachTestNodeReverse(ForEachNodeType::Continue);
+ RefPtr<ForEachTestNodeReverse> chlidNode2 = new ForEachTestNodeReverse(ForEachNodeType::Skip);
+
+ ForEachNode<layers::ReverseIterator>(root.get(),
+ [&visitCount](ForEachTestNodeReverse* aNode)
+ {
+ aNode->SetActualTraversalRank(visitCount);
+ visitCount++;
+ return aNode->GetType() == ForEachNodeType::Continue
+ ? TraversalFlag::Continue : TraversalFlag::Skip;
+ });
+
+ ASSERT_EQ(root->GetExpectedTraversalRank(), root->GetActualTraversalRank())
+ << "Root was hit out of order.";
+ ASSERT_EQ(childNode1->GetExpectedTraversalRank(), childNode1->GetActualTraversalRank())
+ << "Eligible child was still hit.";
+ ASSERT_EQ(chlidNode2->GetExpectedTraversalRank(), chlidNode2->GetActualTraversalRank())
+ << "Ineligible child was still hit.";
+}
+
+TEST(TreeTraversal, ForEachNodeLeavesIneligible)
+{
+
+ std::vector<RefPtr<ForEachTestNodeForward>> nodeList;
+ int visitCount = 0;
+ for (int i = 0; i < 10; i++)
+ {
+ if (i == 1 || i == 9) {
+ nodeList.push_back(new ForEachTestNodeForward(ForEachNodeType::Skip, i));
+ } else {
+ nodeList.push_back(new ForEachTestNodeForward(ForEachNodeType::Continue, i));
+ }
+ }
+
+ RefPtr<ForEachTestNodeForward> root = nodeList[0];
+ nodeList[0]->AddChild(nodeList[1]);
+ nodeList[0]->AddChild(nodeList[2]);
+ nodeList[2]->AddChild(nodeList[3]);
+ nodeList[2]->AddChild(nodeList[4]);
+ 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<layers::ForwardIterator>(root.get(),
+ [&visitCount](ForEachTestNodeForward* aNode)
+ {
+ aNode->SetActualTraversalRank(visitCount);
+ visitCount++;
+ return aNode->GetType() == ForEachNodeType::Continue
+ ? TraversalFlag::Continue : TraversalFlag::Skip;
+ });
+
+ 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.";
+ }
+}
+
+TEST(TreeTraversal, ForEachNodeLeavesIneligibleReverse)
+{
+
+ std::vector<RefPtr<ForEachTestNodeReverse>> nodeList;
+ int visitCount = 0;
+ for (int i = 0; i < 10; i++)
+ {
+ if (i == 1 || i == 9) {
+ nodeList.push_back(new ForEachTestNodeReverse(ForEachNodeType::Skip, i));
+ } else {
+ nodeList.push_back(new ForEachTestNodeReverse(ForEachNodeType::Continue, i));
+ }
+ }
+
+ RefPtr<ForEachTestNodeReverse> root = nodeList[0];
+ nodeList[0]->AddChild(nodeList[2]);
+ nodeList[0]->AddChild(nodeList[1]);
+ nodeList[2]->AddChild(nodeList[4]);
+ nodeList[2]->AddChild(nodeList[3]);
+ nodeList[4]->AddChild(nodeList[6]);
+ nodeList[4]->AddChild(nodeList[5]);
+ nodeList[6]->AddChild(nodeList[7]);
+ nodeList[7]->AddChild(nodeList[9]);
+ nodeList[7]->AddChild(nodeList[8]);
+
+ ForEachNode<layers::ReverseIterator>(root.get(),
+ [&visitCount](ForEachTestNodeReverse* aNode)
+ {
+ aNode->SetActualTraversalRank(visitCount);
+ visitCount++;
+ return aNode->GetType() == ForEachNodeType::Continue
+ ? TraversalFlag::Continue : TraversalFlag::Skip;
+ });
+
+ 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.";
+ }
+}
+
+TEST(TreeTraversal, ForEachNodeLambdaReturnsVoid)
+{
+ std::vector<RefPtr<ForEachTestNodeReverse>> nodeList;
+ int visitCount = 0;
+ for (int i = 0; i < 10; i++)
+ {
+ nodeList.push_back(new ForEachTestNodeReverse(ForEachNodeType::Continue,i));
+ }
+
+ RefPtr<ForEachTestNodeReverse> root = nodeList[0];
+ nodeList[0]->AddChild(nodeList[4]);
+ nodeList[0]->AddChild(nodeList[1]);
+ nodeList[1]->AddChild(nodeList[3]);
+ nodeList[1]->AddChild(nodeList[2]);
+ nodeList[4]->AddChild(nodeList[6]);
+ nodeList[4]->AddChild(nodeList[5]);
+ nodeList[6]->AddChild(nodeList[7]);
+ nodeList[7]->AddChild(nodeList[9]);
+ nodeList[7]->AddChild(nodeList[8]);
+
+
+ ForEachNode<layers::ReverseIterator>(root.get(),
+ [&visitCount](ForEachTestNodeReverse* 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.";
+ }
+}
+
+struct AssignSearchNodeTypesWithLastLeafAsNeedle {
+ RefPtr<SearchTestNodeForward>& node;
+ void operator()(SearchTestNodeForward* aNode) {
+ aNode->SetType(SearchNodeType::Hay);
+ if (aNode->IsLeaf()) {
+ node = aNode;
+ }
+ }
+};
+
+bool FindNeedle(SearchTestNode* aNode) {
+ return aNode->GetType() == SearchNodeType::Needle;
+}
+
+struct AssignSearchNodeTypesAllHay
+{
+ void operator()(SearchTestNode* aNode){
+ aNode->SetType(SearchNodeType::Hay);
+ }
+};
+
+struct AssignSearchNodeTypesWithFirstLeafAsNeedle
+{
+ RefPtr<SearchTestNodeReverse>& needleNode;
+ void operator()(SearchTestNodeReverse* aNode){
+ if (!needleNode && aNode->IsLeaf()) {
+ needleNode = aNode;
+ }
+ aNode->SetType(SearchNodeType::Hay);
+ }
+};
+
+struct AssignSearchNodeValuesAllFalseValuesReverse
+{
+ int falseValue;
+ RefPtr<SearchTestNodeReverse>& needleNode;
+ void operator()(SearchTestNodeReverse* aNode){
+ aNode->SetValue(falseValue);
+ if (!needleNode && aNode->IsLeaf()) {
+ needleNode = aNode;
+ }
+ }
+};
+
+struct AssignSearchNodeValuesAllFalseValuesForward
+{
+ int falseValue;
+ RefPtr<SearchTestNodeForward>& needleNode;
+ void operator()(SearchTestNodeForward* aNode){
+ aNode->SetValue(falseValue);
+ needleNode = aNode;
+ }
+};
+
+struct AllocateUnitRegionsToLeavesOnly
+{
+ int& xWrap;
+ int& squareCount;
+ void operator()(ForEachTestNode* aNode) {
+ if (aNode->IsLeaf()) {
+ int x = squareCount % xWrap;
+ int y = squareCount / xWrap;
+ aNode->SetRegion(nsRegion(nsRect(x, y, 1, 1)));
+ squareCount++;
+ }
+ }
+};
+
+void ForEachNodeDoNothing(ForEachTestNode* aNode) {}
+
+template <typename Node>
+static RefPtr<Node> DepthFirstSearchForwardRecursive(RefPtr<Node> aNode)
+{
+ if (aNode->GetType() == SearchNodeType::Needle) {
+ return aNode;
+ }
+ for (RefPtr<Node> node = aNode->GetFirstChild();
+ node != nullptr;
+ node = node->GetNextSibling()) {
+ if (RefPtr<Node> foundNode = DepthFirstSearchForwardRecursive(node)) {
+ return foundNode;
+ }
+ }
+ return nullptr;
+}
+
+static void Plain_ForwardDepthFirstSearchPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ RefPtr<SearchTestNodeForward> needleNode;
+ RefPtr<SearchTestNodeForward> root = CreateBenchmarkTree<SearchTestNodeForward>(depth, childrenCount,
+ AssignSearchNodeTypesWithLastLeafAsNeedle{needleNode});
+ needleNode->SetType(SearchNodeType::Needle);
+ RefPtr<SearchTestNodeForward> foundNode =
+ DepthFirstSearchForwardRecursive<SearchTestNodeForward>(root.get());
+ ASSERT_EQ(foundNode->GetType(), SearchNodeType::Needle);
+ ASSERT_EQ(needleNode, foundNode);
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, Plain_ForwardDepthFirstSearchPerformance, &Plain_ForwardDepthFirstSearchPerformance);
+
+static void TreeTraversal_ForwardDepthFirstSearchPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ RefPtr<SearchTestNodeForward> needleNode;
+ RefPtr<SearchTestNodeForward> root = CreateBenchmarkTree<SearchTestNodeForward>(depth, childrenCount,
+ AssignSearchNodeTypesWithLastLeafAsNeedle{needleNode});
+ needleNode->SetType(SearchNodeType::Needle);
+ RefPtr<SearchTestNodeForward> foundNode = DepthFirstSearch<layers::ForwardIterator>(root.get(), &FindNeedle);
+ ASSERT_EQ(foundNode->GetType(), SearchNodeType::Needle);
+ ASSERT_EQ(needleNode, foundNode);
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, TreeTraversal_ForwardDepthFirstSearchPerformance, &TreeTraversal_ForwardDepthFirstSearchPerformance);
+
+template <typename Node>
+static RefPtr<Node> DepthFirstSearchCaptureVariablesForwardRecursive(RefPtr<Node> aNode,
+ int a, int b, int c, int d, int e, int f,
+ int g, int h, int i, int j, int k, int l,
+ int m, int& n, int& o, int& p, int& q, int& r,
+ int& s, int& t, int& u, int& v, int& w, int& x,
+ int& y, int& z)
+{
+ if (aNode->GetValue() == a + b + c + d + e + f + g + h + i + j + k + l + m +
+ n + o + p + q + r + s + t + u + v + w + x + y + z) {
+ return aNode;
+ }
+ for (RefPtr<Node> node = aNode->GetFirstChild();
+ node != nullptr;
+ node = node->GetNextSibling()) {
+ if (RefPtr<Node> foundNode = DepthFirstSearchCaptureVariablesForwardRecursive(node,
+ a, b, c, d, e, f, g, h, i, j, k, l, m,
+ n, o, p, q, r, s, t, u, v, w, x, y, z)) {
+ return foundNode;
+ }
+ }
+ return nullptr;
+}
+
+static void Plain_ForwardDepthFirstSearchCaptureVariablesPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int a = 1; int b = 1; int c = 1; int d = 1; int e = 1; int f = 1;
+ int g = 1; int h = 1; int i = 1; int j = 1; int k = 1; int l = 1;
+ int m = 1; int n = 1; int o = 1; int p = 1; int q = 1; int r = 1;
+ int s = 1; int t = 1; int u = 1; int v = 1; int w = 1; int x = 1;
+ int y = 1; int z = 1;
+ int needleTotal = a + b + c + d + e + f + g + h + i + j + k + l + m +
+ n + o + p + q + r + s + t + u + v + w + x + y + z;
+ int hayTotal = 0;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ RefPtr<SearchTestNodeForward> needleNode;
+ RefPtr<SearchTestNodeForward> root = CreateBenchmarkTree<SearchTestNodeForward>(depth, childrenCount,
+ AssignSearchNodeValuesAllFalseValuesForward{hayTotal, needleNode});
+ needleNode->SetValue(needleTotal);
+ RefPtr<SearchTestNodeForward> foundNode =
+ DepthFirstSearchCaptureVariablesForwardRecursive<SearchTestNodeForward>(root.get(),
+ a, b, c, d, e, f, g, h, i, j, k, l, m,
+ n, o, p, q, r, s, t, u, v, w, x, y, z);
+ ASSERT_EQ(foundNode->GetValue(), needleTotal);
+ ASSERT_EQ(needleNode, foundNode);
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, Plain_ForwardDepthFirstSearchCaptureVariablesPerformance, &Plain_ForwardDepthFirstSearchCaptureVariablesPerformance);
+
+static void TreeTraversal_ForwardDepthFirstSearchCaptureVariablesPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ int a = 1; int b = 1; int c = 1; int d = 1; int e = 1; int f = 1;
+ int g = 1; int h = 1; int i = 1; int j = 1; int k = 1; int l = 1;
+ int m = 1; int n = 1; int o = 1; int p = 1; int q = 1; int r = 1;
+ int s = 1; int t = 1; int u = 1; int v = 1; int w = 1; int x = 1;
+ int y = 1; int z = 1;
+ int needleTotal = a + b + c + d + e + f + g + h + i + j + k + l + m +
+ n + o + p + q + r + s + t + u + v + w + x + y + z;
+ int hayTotal = 0;
+ RefPtr<SearchTestNodeForward> needleNode;
+ RefPtr<SearchTestNodeForward> root = CreateBenchmarkTree<SearchTestNodeForward>(depth, childrenCount,
+ AssignSearchNodeValuesAllFalseValuesForward{hayTotal, needleNode});
+ needleNode->SetValue(needleTotal);
+ RefPtr<SearchTestNodeForward> foundNode = DepthFirstSearch<layers::ForwardIterator>(root.get(),
+ [a, b, c, d, e, f, g, h, i, j, k, l, m,
+ &n, &o, &p, &q, &r, &s, &t, &u, &v, &w, &x, &y, &z]
+ (SearchTestNodeForward* aNode) {
+ return aNode->GetValue() == a + b + c + d + e + f + g + h + i + j + k + l + m +
+ n + o + p + q + r + s + t + u + v + w + x + y + z;
+ });
+ ASSERT_EQ(foundNode->GetValue(), needleTotal);
+ ASSERT_EQ(needleNode, foundNode);
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, TreeTraversal_ForwardDepthFirstSearchCaptureVariablesPerformance, &TreeTraversal_ForwardDepthFirstSearchCaptureVariablesPerformance);
+
+template <typename Node>
+static RefPtr<Node> DepthFirstSearchPostOrderForwardRecursive(RefPtr<Node> aNode)
+{
+ for (RefPtr<Node> node = aNode->GetFirstChild();
+ node != nullptr;
+ node = node->GetNextSibling()) {
+ if (RefPtr<Node> foundNode = DepthFirstSearchPostOrderForwardRecursive(node)) {
+ return foundNode;
+ }
+ }
+ if (aNode->GetType() == SearchNodeType::Needle) {
+ return aNode;
+ }
+ return nullptr;
+}
+
+static void Plain_ForwardDepthFirstSearchPostOrderPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ RefPtr<SearchTestNodeForward> root = CreateBenchmarkTree<SearchTestNodeForward>(depth, childrenCount,
+ AssignSearchNodeTypesAllHay{});
+ root->SetType(SearchNodeType::Needle);
+ RefPtr<SearchTestNodeForward> foundNode =
+ DepthFirstSearchPostOrderForwardRecursive<SearchTestNodeForward>(root.get());
+ ASSERT_EQ(foundNode->GetType(), SearchNodeType::Needle);
+ ASSERT_EQ(root, foundNode);
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, Plain_ForwardDepthFirstSearchPostOrderPerformance, &Plain_ForwardDepthFirstSearchPostOrderPerformance);
+
+static void TreeTraversal_ForwardDepthFirstSearchPostOrderPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ RefPtr<SearchTestNodeForward> root = CreateBenchmarkTree<SearchTestNodeForward>(depth, childrenCount,
+ AssignSearchNodeTypesAllHay{});
+ root->SetType(SearchNodeType::Needle);
+ RefPtr<SearchTestNodeForward> foundNode = DepthFirstSearchPostOrder<layers::ForwardIterator>(root.get(), &FindNeedle);
+ ASSERT_EQ(foundNode->GetType(), SearchNodeType::Needle);
+ ASSERT_EQ(root, foundNode);
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, TreeTraversal_ForwardDepthFirstSearchPostOrderPerformance, &TreeTraversal_ForwardDepthFirstSearchPostOrderPerformance);
+
+template <typename Node>
+static RefPtr<Node> BreadthFirstSearchForwardQueue(RefPtr<Node> aNode)
+{
+ queue<RefPtr<Node>> nodes;
+ nodes.push(aNode);
+ while(!nodes.empty()) {
+ RefPtr<Node> node = nodes.front();
+ nodes.pop();
+ if (node->GetType() == SearchNodeType::Needle) {
+ return node;
+ }
+ for (RefPtr<Node> childNode = node->GetFirstChild();
+ childNode != nullptr;
+ childNode = childNode->GetNextSibling()) {
+ nodes.push(childNode);
+ }
+ }
+ return nullptr;
+}
+
+static void Plain_ForwardBreadthFirstSearchPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ RefPtr<SearchTestNodeForward> needleNode;
+ RefPtr<SearchTestNodeForward> root = CreateBenchmarkTree<SearchTestNodeForward>(depth, childrenCount,
+ AssignSearchNodeTypesWithLastLeafAsNeedle{needleNode});
+ needleNode->SetType(SearchNodeType::Needle);
+ RefPtr<SearchTestNodeForward> foundNode =
+ BreadthFirstSearchForwardQueue<SearchTestNodeForward>(root.get());
+ ASSERT_EQ(foundNode->GetType(), SearchNodeType::Needle);
+ ASSERT_EQ(needleNode, foundNode);
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, Plain_ForwardBreadthFirstSearchPerformance, &Plain_ForwardBreadthFirstSearchPerformance);
+
+static void TreeTraversal_ForwardBreadthFirstSearchPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ RefPtr<SearchTestNodeForward> needleNode;
+ RefPtr<SearchTestNodeForward> root = CreateBenchmarkTree<SearchTestNodeForward>(depth, childrenCount,
+ AssignSearchNodeTypesWithLastLeafAsNeedle{needleNode});
+ needleNode->SetType(SearchNodeType::Needle);
+ RefPtr<SearchTestNodeForward> foundNode = BreadthFirstSearch<layers::ForwardIterator>(root.get(), &FindNeedle);
+ ASSERT_EQ(foundNode->GetType(), SearchNodeType::Needle);
+ ASSERT_EQ(needleNode, foundNode);
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, TreeTraversal_ForwardBreadthFirstSearchPerformance, &TreeTraversal_ForwardBreadthFirstSearchPerformance);
+
+// This test ((Plain|TreeTraversal)_ForwardForEachNodePostOrderPerformance)
+// uses the following benchmark:
+//
+// Starting with a tree whose leaves only are augmented with region data
+// (arranged as a series of 1x1 blocks stacked in rows of 100000), calculate
+// each ancestor's region as the union of its child regions.
+template <typename Node>
+static void ForEachNodePostOrderForwardRecursive(RefPtr<Node> aNode)
+{
+ if (!aNode->IsLeaf()) {
+ nsRegion newRegion;
+ for (RefPtr<Node> node = aNode->GetFirstChild();
+ node != nullptr;
+ node = node->GetNextSibling()) {
+ ForEachNodePostOrderForwardRecursive(node);
+ nsRegion childRegion = node->GetRegion();
+ newRegion.OrWith(childRegion);
+ }
+ aNode->SetRegion(newRegion);
+ }
+}
+
+static void Plain_ForwardForEachNodePostOrderPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ int squareCount = 0;
+ int xWrap = PERFORMANCE_REGION_XWRAP;
+ RefPtr<ForEachTestNodeForward> root = CreateBenchmarkTree<ForEachTestNodeForward>(depth, childrenCount,
+ AllocateUnitRegionsToLeavesOnly{xWrap, squareCount});
+ ForEachNodePostOrderForwardRecursive(root);
+ ASSERT_EQ(root->GetRegion(), nsRegion(nsRect(0, 0, PERFORMANCE_REGION_XWRAP, PERFORMANCE_REGION_XWRAP)));
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, Plain_ForwardForEachNodePostOrderPerformance, &Plain_ForwardForEachNodePostOrderPerformance);
+
+static void TreeTraversal_ForwardForEachNodePostOrderPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ int squareCount = 0;
+ int xWrap = PERFORMANCE_REGION_XWRAP;
+ RefPtr<ForEachTestNodeForward> root = CreateBenchmarkTree<ForEachTestNodeForward>(depth, childrenCount,
+ AllocateUnitRegionsToLeavesOnly{xWrap, squareCount});
+ ForEachNodePostOrder<layers::ForwardIterator>(root.get(),
+ [](ForEachTestNodeForward* aNode) {
+ if (!aNode->IsLeaf()) {
+ nsRegion newRegion;
+ for (RefPtr<ForEachTestNodeForward> node = aNode->GetFirstChild();
+ node != nullptr;
+ node = node->GetNextSibling()) {
+ nsRegion childRegion = node->GetRegion();
+ newRegion.OrWith(childRegion);
+ }
+ aNode->SetRegion(newRegion);
+ }
+ });
+ ASSERT_EQ(root->GetRegion(), nsRegion(nsRect(0, 0, PERFORMANCE_REGION_XWRAP, PERFORMANCE_REGION_XWRAP)));
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, TreeTraversal_ForwardForEachNodePostOrderPerformance, &TreeTraversal_ForwardForEachNodePostOrderPerformance);
+
+// This test ((Plain|TreeTraversal)_ForwardForEachNodePerformance) uses the
+// following benchmark:
+//
+// Starting with a tree whose root has a rectangular region of size
+// PERFORMANCE_TREE_LEAF_COUNT x 1, for each node, split the region into
+// PERFORMANCE_TREE_CHILD_COUNT separate regions of equal width and assign to
+// each child left-to-right. In the end, every node's region should equal the
+// sum of its childrens' regions, and each level of depth's regions should sum
+// to the root's region.
+template <typename Node>
+static void ForEachNodeForwardRecursive(RefPtr<Node> aNode)
+{
+ if (!aNode->IsLeaf()) {
+ int nChildren = 0;
+ for (RefPtr<Node> node = aNode->GetFirstChild();
+ node != nullptr;
+ node = node->GetNextSibling()) {
+ nChildren++;
+ }
+ nsRect bounds = aNode->GetRegion().GetBounds();
+ int childWidth = bounds.width / nChildren;
+ int x = bounds.x;
+ for (RefPtr<Node> node = aNode->GetFirstChild();
+ node != nullptr;
+ node = node->GetNextSibling()) {
+ node->SetRegion(nsRegion(nsRect(x, 0, childWidth, 1)));
+ ForEachNodeForwardRecursive(node);
+ x += childWidth;
+ }
+ }
+}
+
+static void Plain_ForwardForEachNodePerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ int rectangleWidth = PERFORMANCE_TREE_LEAF_COUNT;
+ RefPtr<ForEachTestNodeForward> root = CreateBenchmarkTree<ForEachTestNodeForward>(depth, childrenCount,
+ &ForEachNodeDoNothing);
+ root->SetRegion(nsRegion(nsRect(0, 0, rectangleWidth, 1)));
+ ForEachNodeForwardRecursive(root);
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, Plain_ForwardForEachNodePerformance, &Plain_ForwardForEachNodePerformance);
+
+static void TreeTraversal_ForwardForEachNodePerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ int rectangleWidth = PERFORMANCE_TREE_LEAF_COUNT;
+ RefPtr<ForEachTestNodeForward> root = CreateBenchmarkTree<ForEachTestNodeForward>(depth, childrenCount,
+ &ForEachNodeDoNothing);
+ root->SetRegion(nsRegion(nsRect(0, 0, rectangleWidth, 1)));
+ ForEachNode<layers::ForwardIterator>(root.get(),
+ [](ForEachTestNodeForward* aNode) {
+ if (!aNode->IsLeaf()) {
+ int nChildren = 0;
+ for (RefPtr<ForEachTestNodeForward> node = aNode->GetFirstChild();
+ node != nullptr;
+ node = node->GetNextSibling()) {
+ nChildren++;
+ }
+ nsRect bounds = aNode->GetRegion().GetBounds();
+ int childWidth = bounds.width / nChildren;
+ int x = bounds.x;
+ for (RefPtr<ForEachTestNodeForward> node = aNode->GetFirstChild();
+ node != nullptr;
+ node = node->GetNextSibling()) {
+ node->SetRegion(nsRegion(nsRect(x, 0, childWidth, 1)));
+ x += childWidth;
+ }
+ }
+ });
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, TreeTraversal_ForwardForEachNodePerformance, &TreeTraversal_ForwardForEachNodePerformance);
+
+// This test ((Plain|TreeTraversal)_ForwardForEachNodeStackPerformance) uses
+// the following benchmark:
+//
+// Starting with an unattached region equal to PERFORMANCE_TREE_LEAF_COUNT x 1,
+// a starting width of PERFORMANCE_TREE_LEAF_COUNT, and an empty tree, create a
+// tree with the same conditions as
+// ((Plain|TreeTraversal)_ForwardForEachNodePerformance) by assigning regions
+// of the current width, starting from the min x and min y coordinates. For
+// each level of depth, decrease the current width by a factor of
+// PERFORMANCE_TREE_CHILD_COUNT, and maintain a stack of ancestor regions.
+// Use the stack to track the portion of each region still available to assign
+// to children, which determines the aforementioned min x and min y coordinates.
+// Compare this to using the program stack.
+template <typename Node>
+static void ForEachNodeForwardStackRecursive(RefPtr<Node> aNode, int& aRectangleWidth, nsRegion aRegion, int aChildrenCount)
+{
+ nsRect parentRect = aRegion.GetBounds();
+ nsRect newRectangle(parentRect.x, parentRect.y, aRectangleWidth, 1);
+ nsRegion newRegion(newRectangle);
+ aNode->SetRegion(nsRegion(newRegion));
+
+ aRectangleWidth /= aChildrenCount;
+
+ for (RefPtr<Node> node = aNode->GetFirstChild();
+ node != nullptr;
+ node = node->GetNextSibling()) {
+ ForEachNodeForwardStackRecursive(node, aRectangleWidth, newRegion, aChildrenCount);
+ newRegion.SubOut(node->GetRegion());
+ }
+
+ // Handle case where rectangle width is truncated if power falls below 0,
+ // so we dont lose the regions in future iterations
+ if (aRectangleWidth == 0) {
+ aRectangleWidth = 1;
+ }
+ else {
+ aRectangleWidth *= aChildrenCount;
+ }
+}
+
+static void Plain_ForwardForEachNodeStackPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ int rectangleWidth = PERFORMANCE_TREE_LEAF_COUNT;
+ RefPtr<ForEachTestNodeForward> root = CreateBenchmarkTree<ForEachTestNodeForward>(depth, childrenCount,
+ &ForEachNodeDoNothing);
+ nsRegion startRegion(nsRect(0, 0, rectangleWidth, 1));
+ ForEachNodeForwardStackRecursive(root, rectangleWidth, startRegion, childrenCount);
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, Plain_ForwardForEachNodeStackPerformance, &Plain_ForwardForEachNodeStackPerformance);
+
+static void TreeTraversal_ForwardForEachNodeStackPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ int rectangleWidth = PERFORMANCE_TREE_LEAF_COUNT;
+ stack<nsRegion> regionStack;
+ RefPtr<ForEachTestNodeForward> root = CreateBenchmarkTree<ForEachTestNodeForward>(depth, childrenCount,
+ &ForEachNodeDoNothing);
+ regionStack.push(nsRegion(nsRect(0, 0, rectangleWidth, 1)));
+ ForEachNode<layers::ForwardIterator>(root.get(),
+ [&regionStack, &rectangleWidth, childrenCount](ForEachTestNodeForward* aNode) {
+ nsRegion parentRegion = regionStack.top();
+ nsRect parentRect = parentRegion.GetBounds();
+ nsRect newRect(parentRect.x, parentRect.y, rectangleWidth, 1);
+ nsRegion newRegion(newRect);
+ aNode->SetRegion(newRegion);
+ regionStack.top().SubOut(newRegion);
+ regionStack.push(newRegion);
+ rectangleWidth /= childrenCount;
+ },
+ [&regionStack, &rectangleWidth, childrenCount](ForEachTestNodeForward* aNode) {
+ regionStack.pop();
+ // Handle case where rectangle width is truncated if power falls below 0,
+ // so we dont lose the regions in future iterations
+ if (rectangleWidth == 0) {
+ rectangleWidth = 1;
+ }
+ else {
+ rectangleWidth *= childrenCount;
+ }
+ });
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, TreeTraversal_ForwardForEachNodeStackPerformance, &TreeTraversal_ForwardForEachNodeStackPerformance);
+
+template <typename Node>
+static RefPtr<Node> DepthFirstSearchReverseRecursive(RefPtr<Node> aNode)
+{
+ if (aNode->GetType() == SearchNodeType::Needle) {
+ return aNode;
+ }
+ for (RefPtr<Node> node = aNode->GetLastChild();
+ node != nullptr;
+ node = node->GetPrevSibling()) {
+ if (RefPtr<Node> foundNode = DepthFirstSearchReverseRecursive(node)) {
+ return foundNode;
+ }
+ }
+ return nullptr;
+}
+
+static void Plain_ReverseDepthFirstSearchPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ RefPtr<SearchTestNodeReverse> needleNode;
+ RefPtr<SearchTestNodeReverse> root = CreateBenchmarkTree<SearchTestNodeReverse>(depth, childrenCount,
+ AssignSearchNodeTypesWithFirstLeafAsNeedle{needleNode});
+ needleNode->SetType(SearchNodeType::Needle);
+ RefPtr<SearchTestNodeReverse> foundNode =
+ DepthFirstSearchReverseRecursive<SearchTestNodeReverse>(root.get());
+ ASSERT_EQ(foundNode->GetType(), SearchNodeType::Needle);
+ ASSERT_EQ(needleNode, foundNode);
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, Plain_ReverseDepthFirstSearchPerformance, &Plain_ReverseDepthFirstSearchPerformance);
+
+static void TreeTraversal_ReverseDepthFirstSearchPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ RefPtr<SearchTestNodeReverse> needleNode;
+ RefPtr<SearchTestNodeReverse> root = CreateBenchmarkTree<SearchTestNodeReverse>(depth, childrenCount,
+ AssignSearchNodeTypesWithFirstLeafAsNeedle{needleNode});
+ needleNode->SetType(SearchNodeType::Needle);
+ RefPtr<SearchTestNodeReverse> foundNode = DepthFirstSearch<layers::ReverseIterator>(root.get(),
+ &FindNeedle);
+ ASSERT_EQ(foundNode->GetType(), SearchNodeType::Needle);
+ ASSERT_EQ(needleNode, foundNode);
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, TreeTraversal_ReverseDepthFirstSearchPerformance, &TreeTraversal_ReverseDepthFirstSearchPerformance);
+
+template <typename Node>
+static RefPtr<Node> DepthFirstSearchCaptureVariablesReverseRecursive(RefPtr<Node> aNode,
+ int a, int b, int c, int d, int e, int f,
+ int g, int h, int i, int j, int k, int l,
+ int m, int& n, int& o, int& p, int& q, int& r,
+ int& s, int& t, int& u, int& v, int& w, int& x,
+ int& y, int& z)
+{
+ if (aNode->GetValue() == a + b + c + d + e + f + g + h + i + j + k + l +
+ m + n + o + p + q + r + s + t + u + v + w + x + y + z) {
+ return aNode;
+ }
+ for (RefPtr<Node> node = aNode->GetLastChild();
+ node != nullptr;
+ node = node->GetPrevSibling()) {
+ if (RefPtr<Node> foundNode = DepthFirstSearchCaptureVariablesReverseRecursive(node,
+ a, b, c, d, e, f, g, h, i, j, k, l, m,
+ n, o, p, q, r, s, t, u, v, w, x, y, z)) {
+ return foundNode;
+ }
+ }
+ return nullptr;
+}
+
+static void Plain_ReverseDepthFirstSearchCaptureVariablesPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int a = 1; int b = 1; int c = 1; int d = 1; int e = 1; int f = 1;
+ int g = 1; int h = 1; int i = 1; int j = 1; int k = 1; int l = 1;
+ int m = 1; int n = 1; int o = 1; int p = 1; int q = 1; int r = 1;
+ int s = 1; int t = 1; int u = 1; int v = 1; int w = 1; int x = 1;
+ int y = 1; int z = 1;
+ int needleTotal = a + b + c + d + e + f + g + h + i + j + k + l + m +
+ n + o + p + q + r + s + t + u + v + w + x + y + z;
+ int hayTotal = 0;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ RefPtr<SearchTestNodeReverse> needleNode;
+ RefPtr<SearchTestNodeReverse> root = CreateBenchmarkTree<SearchTestNodeReverse>(depth, childrenCount,
+ AssignSearchNodeValuesAllFalseValuesReverse{hayTotal, needleNode});
+ needleNode->SetValue(needleTotal);
+ RefPtr<SearchTestNodeReverse> foundNode =
+ DepthFirstSearchCaptureVariablesReverseRecursive<SearchTestNodeReverse>(root.get(),
+ a, b, c, d, e, f, g, h, i, j, k, l, m,
+ n, o, p, q, r, s, t, u, v, w, x, y, z);
+ ASSERT_EQ(foundNode->GetValue(), needleTotal);
+ ASSERT_EQ(needleNode, foundNode);
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, Plain_ReverseDepthFirstSearchCaptureVariablesPerformance, &Plain_ReverseDepthFirstSearchCaptureVariablesPerformance);
+
+static void TreeTraversal_ReverseDepthFirstSearchCaptureVariablesPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ int a = 1; int b = 1; int c = 1; int d = 1; int e = 1; int f = 1;
+ int g = 1; int h = 1; int i = 1; int j = 1; int k = 1; int l = 1;
+ int m = 1; int n = 1; int o = 1; int p = 1; int q = 1; int r = 1;
+ int s = 1; int t = 1; int u = 1; int v = 1; int w = 1; int x = 1;
+ int y = 1; int z = 1;
+ int needleTotal = a + b + c + d + e + f + g + h + i + j + k + l + m +
+ n + o + p + q + r + s + t + u + v + w + x + y + z;
+ int hayTotal = 0;
+ RefPtr<SearchTestNodeReverse> needleNode;
+ RefPtr<SearchTestNodeReverse> root = CreateBenchmarkTree<SearchTestNodeReverse>(depth, childrenCount,
+ AssignSearchNodeValuesAllFalseValuesReverse{hayTotal, needleNode});
+ needleNode->SetValue(needleTotal);
+ RefPtr<SearchTestNodeReverse> foundNode = DepthFirstSearch<layers::ReverseIterator>(root.get(),
+ [a, b, c, d, e, f, g, h, i, j, k, l, m,
+ &n, &o, &p, &q, &r, &s, &t, &u, &v, &w, &x, &y, &z] (SearchTestNodeReverse* aNode) {
+ return aNode->GetValue() == a + b + c + d + e + f + g + h + i + j + k + l +
+ m + n + o + p + q + r + s + t + u + v + w + x + y + z;
+ });
+ ASSERT_EQ(foundNode->GetValue(), needleTotal);
+ ASSERT_EQ(needleNode, foundNode);
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, TreeTraversal_ReverseDepthFirstSearchCaptureVariablesPerformance, &TreeTraversal_ReverseDepthFirstSearchCaptureVariablesPerformance);
+
+template <typename Node>
+static RefPtr<Node> DepthFirstSearchPostOrderReverseRecursive(RefPtr<Node> aNode)
+{
+ for (RefPtr<Node> node = aNode->GetLastChild();
+ node != nullptr;
+ node = node->GetPrevSibling()) {
+ if (RefPtr<Node> foundNode = DepthFirstSearchPostOrderReverseRecursive(node)) {
+ return foundNode;
+ }
+ }
+ if (aNode->GetType() == SearchNodeType::Needle) {
+ return aNode;
+ }
+ return nullptr;
+}
+
+static void Plain_ReverseDepthFirstSearchPostOrderPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ RefPtr<SearchTestNodeReverse> root = CreateBenchmarkTree<SearchTestNodeReverse>(depth, childrenCount,
+ AssignSearchNodeTypesAllHay{});
+ root->SetType(SearchNodeType::Needle);
+ RefPtr<SearchTestNodeReverse> foundNode =
+ DepthFirstSearchPostOrderReverseRecursive<SearchTestNodeReverse>(root.get());
+ ASSERT_EQ(foundNode->GetType(), SearchNodeType::Needle);
+ ASSERT_EQ(root, foundNode);
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, Plain_ReverseDepthFirstSearchPostOrderPerformance, &Plain_ReverseDepthFirstSearchPostOrderPerformance);
+
+static void TreeTraversal_ReverseDepthFirstSearchPostOrderPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ RefPtr<SearchTestNodeReverse> root = CreateBenchmarkTree<SearchTestNodeReverse>(depth, childrenCount,
+ AssignSearchNodeTypesAllHay{});
+ root->SetType(SearchNodeType::Needle);
+ RefPtr<SearchTestNodeReverse> foundNode = DepthFirstSearchPostOrder<layers::ReverseIterator>(root.get(), &FindNeedle);
+ ASSERT_EQ(foundNode->GetType(), SearchNodeType::Needle);
+ ASSERT_EQ(root, foundNode);
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, TreeTraversal_ReverseDepthFirstSearchPostOrderPerformance, &TreeTraversal_ReverseDepthFirstSearchPostOrderPerformance);
+
+template <typename Node>
+static RefPtr<Node> BreadthFirstSearchReverseQueue(RefPtr<Node> aNode)
+{
+ queue<RefPtr<Node>> nodes;
+ nodes.push(aNode);
+ while(!nodes.empty()) {
+ RefPtr<Node> node = nodes.front();
+ nodes.pop();
+ if (node->GetType() == SearchNodeType::Needle) {
+ return node;
+ }
+ for (RefPtr<Node> childNode = node->GetLastChild();
+ childNode != nullptr;
+ childNode = childNode->GetPrevSibling()) {
+ nodes.push(childNode);
+ }
+ }
+ return nullptr;
+}
+
+static void Plain_ReverseBreadthFirstSearchPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ RefPtr<SearchTestNodeReverse> needleNode;
+ RefPtr<SearchTestNodeReverse> root = CreateBenchmarkTree<SearchTestNodeReverse>(depth, childrenCount,
+ AssignSearchNodeTypesWithFirstLeafAsNeedle{needleNode});
+ needleNode->SetType(SearchNodeType::Needle);
+ RefPtr<SearchTestNodeReverse> foundNode =
+ BreadthFirstSearchReverseQueue<SearchTestNodeReverse>(root.get());
+ ASSERT_EQ(foundNode->GetType(), SearchNodeType::Needle);
+ ASSERT_EQ(needleNode, foundNode);
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, Plain_ReverseBreadthFirstSearchPerformance, &Plain_ReverseBreadthFirstSearchPerformance);
+
+static void TreeTraversal_ReverseBreadthFirstSearchPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ RefPtr<SearchTestNodeReverse> needleNode;
+ RefPtr<SearchTestNodeReverse> root = CreateBenchmarkTree<SearchTestNodeReverse>(depth, childrenCount,
+ AssignSearchNodeTypesWithFirstLeafAsNeedle{needleNode});
+ needleNode->SetType(SearchNodeType::Needle);
+ RefPtr<SearchTestNodeReverse> foundNode = BreadthFirstSearch<layers::ReverseIterator>(root.get(), &FindNeedle);
+ ASSERT_EQ(foundNode->GetType(), SearchNodeType::Needle);
+ ASSERT_EQ(needleNode, foundNode);
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, TreeTraversal_ReverseBreadthFirstSearchPerformance, &TreeTraversal_ReverseBreadthFirstSearchPerformance);
+
+// This test ((Plain|TreeTraversal)_ReverseForEachNodePostOrderPerformance)
+// uses the following benchmark:
+//
+// Starting with a tree whose leaves only are augmented with region data
+// (arranged as a series of 1x1 blocks stacked in rows of 100000), calculate
+// each ancestor's region as the union of its child regions.
+template <typename Node>
+static void ForEachNodePostOrderReverseRecursive(RefPtr<Node> aNode)
+{
+ if (!aNode->IsLeaf()) {
+ nsRegion newRegion;
+ for (RefPtr<Node> node = aNode->GetLastChild();
+ node != nullptr;
+ node = node->GetPrevSibling()) {
+ ForEachNodePostOrderReverseRecursive(node);
+ nsRegion childRegion = node->GetRegion();
+ newRegion.OrWith(childRegion);
+ }
+ aNode->SetRegion(newRegion);
+ }
+}
+
+static void Plain_ReverseForEachNodePostOrderPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ int squareCount = 0;
+ int xWrap = PERFORMANCE_REGION_XWRAP;
+ RefPtr<ForEachTestNodeReverse> root = CreateBenchmarkTree<ForEachTestNodeReverse>(depth, childrenCount,
+ AllocateUnitRegionsToLeavesOnly{xWrap, squareCount});
+ ForEachNodePostOrderReverseRecursive(root);
+ ASSERT_EQ(root->GetRegion(), nsRegion(nsRect(0, 0, PERFORMANCE_REGION_XWRAP, PERFORMANCE_REGION_XWRAP)));
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, Plain_ReverseForEachNodePostOrderPerformance, &Plain_ReverseForEachNodePostOrderPerformance);
+
+static void TreeTraversal_ReverseForEachNodePostOrderPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ int squareCount = 0;
+ int xWrap = PERFORMANCE_REGION_XWRAP;
+ RefPtr<ForEachTestNodeReverse> root = CreateBenchmarkTree<ForEachTestNodeReverse>(depth, childrenCount,
+ AllocateUnitRegionsToLeavesOnly{xWrap, squareCount});
+ ForEachNodePostOrder<layers::ReverseIterator>(root.get(),
+ [](ForEachTestNodeReverse* aNode) {
+ if (!aNode->IsLeaf()) {
+ nsRegion newRegion;
+ for (RefPtr<ForEachTestNodeReverse> node = aNode->GetLastChild();
+ node != nullptr;
+ node = node->GetPrevSibling()) {
+ nsRegion childRegion = node->GetRegion();
+ newRegion.OrWith(childRegion);
+ }
+ aNode->SetRegion(newRegion);
+ }
+ });
+ ASSERT_EQ(root->GetRegion(), nsRegion(nsRect(0, 0, PERFORMANCE_REGION_XWRAP, PERFORMANCE_REGION_XWRAP)));
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, TreeTraversal_ReverseForEachNodePostOrderPerformance, &TreeTraversal_ReverseForEachNodePostOrderPerformance);
+
+// This test ((Plain|TreeTraversal)_ReverseForEachNodePerformance) uses the
+// following benchmark:
+//
+// Starting with a tree whose root has a rectangular region of size
+// PERFORMANCE_TREE_LEAF_COUNT x 1, for each node, split the region into
+// PERFORMANCE_TREE_CHILD_COUNT separate regions of equal width and assign to
+// each child left-to-right. In the end, every node's region should equal the
+// sum of its childrens' regions, and each level of depth's regions should sum
+// to the root's region.
+template <typename Node>
+static void ForEachNodeReverseRecursive(RefPtr<Node> aNode)
+{
+ if (!aNode->IsLeaf()) {
+ int nChildren = 0;
+ for (RefPtr<Node> node = aNode->GetLastChild();
+ node != nullptr;
+ node = node->GetPrevSibling()) {
+ nChildren++;
+ }
+ nsRect bounds = aNode->GetRegion().GetBounds();
+ int childWidth = bounds.width / nChildren;
+ int x = bounds.x;
+ for (RefPtr<Node> node = aNode->GetLastChild();
+ node != nullptr;
+ node = node->GetPrevSibling()) {
+ node->SetRegion(nsRegion(nsRect(x, 0, childWidth, 1)));
+ ForEachNodeReverseRecursive(node);
+ x += childWidth;
+ }
+ }
+}
+
+static void Plain_ReverseForEachNodePerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ int rectangleWidth = PERFORMANCE_TREE_LEAF_COUNT;
+ RefPtr<ForEachTestNodeReverse> root = CreateBenchmarkTree<ForEachTestNodeReverse>(depth, childrenCount,
+ &ForEachNodeDoNothing);
+ root->SetRegion(nsRegion(nsRect(0, 0, rectangleWidth, 1)));
+ ForEachNodeReverseRecursive(root);
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, Plain_ReverseForEachNodePerformance, &Plain_ReverseForEachNodePerformance);
+
+static void TreeTraversal_ReverseForEachNodePerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ int rectangleWidth = PERFORMANCE_TREE_LEAF_COUNT;
+ RefPtr<ForEachTestNodeReverse> root = CreateBenchmarkTree<ForEachTestNodeReverse>(depth, childrenCount,
+ &ForEachNodeDoNothing);
+ root->SetRegion(nsRegion(nsRect(0, 0, rectangleWidth, 1)));
+ ForEachNode<layers::ReverseIterator>(root.get(),
+ [](ForEachTestNodeReverse* aNode) {
+ if (!aNode->IsLeaf()) {
+ int nChildren = 0;
+ for (RefPtr<ForEachTestNodeReverse> node = aNode->GetLastChild();
+ node != nullptr;
+ node = node->GetPrevSibling()) {
+ nChildren++;
+ }
+ nsRect bounds = aNode->GetRegion().GetBounds();
+ int childWidth = bounds.width / nChildren;
+ int x = bounds.x;
+ for (RefPtr<ForEachTestNodeReverse> node = aNode->GetLastChild();
+ node != nullptr;
+ node = node->GetPrevSibling()) {
+ node->SetRegion(nsRegion(nsRect(x, 0, childWidth, 1)));
+ x += childWidth;
+ }
+ }
+ });
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, TreeTraversal_ReverseForEachNodePerformance, &TreeTraversal_ReverseForEachNodePerformance);
+
+// This test ((Plain|TreeTraversal)_ReverseForEachNodeStackPerformance) uses
+// the following benchmark:
+//
+// Starting with an unattached region equal to PERFORMANCE_TREE_LEAF_COUNT x 1,
+// a starting width of PERFORMANCE_TREE_LEAF_COUNT, and an empty tree, create a
+// tree with the same conditions as
+// ((Plain|TreeTraversal)_ReverseForEachNodePerformance) by assigning regions
+// of the current width, starting from the min x and min y coordinates. For
+// each level of depth, decrease the current width by a factor of
+// PERFORMANCE_TREE_CHILD_COUNT, and maintain a stack of ancestor regions.
+// Use the stack to track the portion of each region still available to assign
+// to children, which determines the aforementioned min x and min y coordinates.
+// Compare this to using the program stack.
+template <typename Node>
+static void ForEachNodeReverseStackRecursive(RefPtr<Node> aNode, int& aRectangleWidth, nsRegion aRegion, int aChildrenCount)
+{
+ nsRect parentRect = aRegion.GetBounds();
+ nsRect newRectangle(parentRect.x, parentRect.y, aRectangleWidth, 1);
+ nsRegion newRegion(newRectangle);
+ aNode->SetRegion(nsRegion(newRegion));
+
+ aRectangleWidth /= aChildrenCount;
+
+ for (RefPtr<Node> node = aNode->GetLastChild();
+ node != nullptr;
+ node = node->GetPrevSibling()) {
+ ForEachNodeReverseStackRecursive(node, aRectangleWidth, newRegion, aChildrenCount);
+ newRegion.SubOut(node->GetRegion());
+ }
+ // Handle case where rectangle width is truncated if power falls below 0,
+ // so we dont lose the regions in future iterations
+ if (aRectangleWidth == 0) {
+ aRectangleWidth = 1;
+ }
+ else {
+ aRectangleWidth *= aChildrenCount;
+ }
+}
+
+static void Plain_ReverseForEachNodeStackPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ int rectangleWidth = PERFORMANCE_TREE_LEAF_COUNT;
+ RefPtr<ForEachTestNodeReverse> root = CreateBenchmarkTree<ForEachTestNodeReverse>(depth, childrenCount,
+ &ForEachNodeDoNothing);
+ nsRegion startRegion(nsRect(0, 0, rectangleWidth, 1));
+ ForEachNodeReverseStackRecursive(root, rectangleWidth, startRegion, childrenCount);
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, Plain_ReverseForEachNodeStackPerformance, &Plain_ReverseForEachNodeStackPerformance);
+
+static void TreeTraversal_ReverseForEachNodeStackPerformance()
+{
+ int depth = PERFORMANCE_TREE_DEPTH;
+ int childrenCount = PERFORMANCE_TREE_CHILD_COUNT;
+ int rectangleWidth = PERFORMANCE_TREE_LEAF_COUNT;
+ stack<nsRegion> regionStack;
+ RefPtr<ForEachTestNodeReverse> root = CreateBenchmarkTree<ForEachTestNodeReverse>(depth, childrenCount,
+ &ForEachNodeDoNothing);
+ regionStack.push(nsRegion(nsRect(0, 0, rectangleWidth, 1)));
+ ForEachNode<layers::ReverseIterator>(root.get(),
+ [&regionStack, &rectangleWidth, childrenCount](ForEachTestNodeReverse* aNode) {
+ nsRegion parentRegion = regionStack.top();
+ nsRect parentRect = parentRegion.GetBounds();
+ nsRect newRect(parentRect.x, parentRect.y, rectangleWidth, 1);
+ nsRegion newRegion(newRect);
+ aNode->SetRegion(newRegion);
+ regionStack.top().SubOut(newRegion);
+ regionStack.push(newRegion);
+ rectangleWidth /= childrenCount;
+ },
+ [&regionStack, &rectangleWidth, childrenCount](ForEachTestNodeReverse* aNode) {
+ regionStack.pop();
+ // Handle case where rectangle width is truncated if power falls below 0,
+ // so we dont lose the regions in future iterations
+ if (rectangleWidth == 0) {
+ rectangleWidth = 1;
+ }
+ else {
+ rectangleWidth *= childrenCount;
+ }
+ });
+}
+
+MOZ_GTEST_BENCH(TreeTraversal, TreeTraversal_ReverseForEachNodeStackPerformance, &TreeTraversal_ReverseForEachNodeStackPerformance);