From 9e3c08db40b8916968b9f30096c7be3f00ce9647 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 21 Apr 2024 13:44:51 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- gfx/tests/gtest/TestTreeTraversal.cpp | 1408 +++++++++++++++++++++++++++++++++ 1 file changed, 1408 insertions(+) create mode 100644 gfx/tests/gtest/TestTreeTraversal.cpp (limited to 'gfx/tests/gtest/TestTreeTraversal.cpp') diff --git a/gfx/tests/gtest/TestTreeTraversal.cpp b/gfx/tests/gtest/TestTreeTraversal.cpp new file mode 100644 index 0000000000..7e538ca514 --- /dev/null +++ b/gfx/tests/gtest/TestTreeTraversal.cpp @@ -0,0 +1,1408 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include +#include "mozilla/RefPtr.h" +#include "gtest/gtest.h" +#include "nsRegion.h" +#include "nsRect.h" +#include "TreeTraversal.h" +#include +#include + +using namespace mozilla::layers; +using namespace mozilla; + +enum class SearchNodeType { Needle, Hay }; +enum class ForEachNodeType { Continue, Skip }; + +template +class TestNodeBase { + public: + NS_INLINE_DECL_REFCOUNTING(TestNodeBase); + 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() = default; +}; + +template +class TestNodeReverse : public TestNodeBase { + public: + explicit TestNodeReverse(T aType, int aExpectedTraversalRank = -1); + explicit TestNodeReverse(); + void AddChild(RefPtr> aNode); + TestNodeReverse* GetLastChild(); + TestNodeReverse* GetPrevSibling(); + bool IsLeaf(); + + private: + void SetPrevSibling(RefPtr> aNode); + void SetLastChild(RefPtr> aNode); + RefPtr> mSiblingNode; + RefPtr> mLastChildNode; + ~TestNodeReverse() = default; +}; + +template +class TestNodeForward : public TestNodeBase { + public: + explicit TestNodeForward(T aType, int aExpectedTraversalRank = -1); + explicit TestNodeForward(); + void AddChild(RefPtr> aNode); + TestNodeForward* GetFirstChild(); + TestNodeForward* GetNextSibling(); + bool IsLeaf(); + + private: + void SetNextSibling(RefPtr> aNode); + void SetLastChild(RefPtr> aNode); + void SetFirstChild(RefPtr> aNode); + RefPtr> mSiblingNode = nullptr; + RefPtr> mFirstChildNode = nullptr; + // Track last child to facilitate appending children + RefPtr> mLastChildNode = nullptr; + ~TestNodeForward() = default; +}; + +template +TestNodeReverse::TestNodeReverse(T aType, int aExpectedTraversalRank) + : TestNodeBase(aType, aExpectedTraversalRank) {} + +template +TestNodeReverse::TestNodeReverse() : TestNodeBase() {} + +template +void TestNodeReverse::SetLastChild(RefPtr> aNode) { + mLastChildNode = aNode; +} + +template +void TestNodeReverse::AddChild(RefPtr> aNode) { + aNode->SetPrevSibling(mLastChildNode); + SetLastChild(aNode); +} + +template +void TestNodeReverse::SetPrevSibling(RefPtr> aNode) { + mSiblingNode = aNode; +} + +template +TestNodeReverse* TestNodeReverse::GetLastChild() { + return mLastChildNode; +} + +template +TestNodeReverse* TestNodeReverse::GetPrevSibling() { + return mSiblingNode; +} + +template +bool TestNodeReverse::IsLeaf() { + return !mLastChildNode; +} + +template +TestNodeForward::TestNodeForward(T aType, int aExpectedTraversalRank) + : TestNodeBase(aType, aExpectedTraversalRank) {} + +template +TestNodeForward::TestNodeForward() : TestNodeBase() {} + +template +void TestNodeForward::AddChild(RefPtr> aNode) { + if (mFirstChildNode == nullptr) { + SetFirstChild(aNode); + SetLastChild(aNode); + } else { + mLastChildNode->SetNextSibling(aNode); + SetLastChild(aNode); + } +} + +template +void TestNodeForward::SetLastChild(RefPtr> aNode) { + mLastChildNode = aNode; +} + +template +void TestNodeForward::SetFirstChild(RefPtr> aNode) { + mFirstChildNode = aNode; +} + +template +void TestNodeForward::SetNextSibling(RefPtr> aNode) { + mSiblingNode = aNode; +} + +template +bool TestNodeForward::IsLeaf() { + return !mFirstChildNode; +} + +template +TestNodeForward* TestNodeForward::GetFirstChild() { + return mFirstChildNode; +} + +template +TestNodeForward* TestNodeForward::GetNextSibling() { + return mSiblingNode; +} + +template +TestNodeBase::TestNodeBase(T aType, int aExpectedTraversalRank) + : mExpectedTraversalRank(aExpectedTraversalRank), + mActualTraversalRank(-1), + mType(aType) {} + +template +TestNodeBase::TestNodeBase() = default; + +template +int TestNodeBase::GetActualTraversalRank() { + return mActualTraversalRank; +} + +template +void TestNodeBase::SetActualTraversalRank(int aRank) { + mActualTraversalRank = aRank; +} + +template +int TestNodeBase::GetExpectedTraversalRank() { + return mExpectedTraversalRank; +} + +template +T TestNodeBase::GetType() { + return mType; +} + +template +void TestNodeBase::SetType(T aType) { + mType = aType; +} + +template +nsRegion TestNodeBase::GetRegion() { + return mRegion; +} + +template +void TestNodeBase::SetRegion(nsRegion aRegion) { + mRegion = aRegion; +} + +template +int TestNodeBase::GetValue() { + return mValue; +} + +template +void TestNodeBase::SetValue(int aValue) { + mValue = aValue; +} + +typedef TestNodeBase SearchTestNode; +typedef TestNodeBase ForEachTestNode; +typedef TestNodeReverse SearchTestNodeReverse; +typedef TestNodeReverse ForEachTestNodeReverse; +typedef TestNodeForward SearchTestNodeForward; +typedef TestNodeForward ForEachTestNodeForward; + +TEST(TreeTraversal, DepthFirstSearchNull) +{ + RefPtr nullNode; + RefPtr result = + DepthFirstSearch( + 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 needleNode; + std::vector> nodeList; + nodeList.reserve(10); + 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 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 foundNode = + DepthFirstSearch( + 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 needleNode; + std::vector> nodeList; + nodeList.reserve(10); + 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 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 foundNode = + DepthFirstSearch( + 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 root = + new SearchTestNodeReverse(SearchNodeType::Needle, 0); + RefPtr childNode1 = + new SearchTestNodeReverse(SearchNodeType::Hay); + RefPtr childNode2 = + new SearchTestNodeReverse(SearchNodeType::Hay); + int visitCount = 0; + RefPtr result = + DepthFirstSearch( + 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> nodeList; + nodeList.reserve(10); + for (int i = 0; i < 10; i++) { + nodeList.push_back(new SearchTestNodeForward(SearchNodeType::Hay, i)); + } + + RefPtr 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 foundNode = + DepthFirstSearch( + 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> nodeList; + nodeList.reserve(10); + for (int i = 0; i < 10; i++) { + nodeList.push_back(new SearchTestNodeReverse(SearchNodeType::Hay, i)); + } + + RefPtr 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 foundNode = + DepthFirstSearch( + 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 nullNode; + RefPtr result = + DepthFirstSearchPostOrder( + 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 needleNode; + std::vector> 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 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 foundNode = + DepthFirstSearchPostOrder( + 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 needleNode; + std::vector> 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 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 foundNode = + DepthFirstSearchPostOrder( + 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 root = + new SearchTestNodeReverse(SearchNodeType::Needle, 0); + RefPtr childNode1 = + new SearchTestNodeReverse(SearchNodeType::Hay); + RefPtr childNode2 = + new SearchTestNodeReverse(SearchNodeType::Hay); + int visitCount = 0; + RefPtr result = + DepthFirstSearchPostOrder( + 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> nodeList; + nodeList.reserve(10); + for (int i = 0; i < 10; i++) { + nodeList.push_back(new SearchTestNodeForward(SearchNodeType::Hay, i)); + } + + RefPtr 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 foundNode = + DepthFirstSearchPostOrder( + 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> nodeList; + nodeList.reserve(10); + for (int i = 0; i < 10; i++) { + nodeList.push_back(new SearchTestNodeReverse(SearchNodeType::Hay, i)); + } + + RefPtr 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 foundNode = + DepthFirstSearchPostOrder( + 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 nullNode; + RefPtr result = + BreadthFirstSearch( + 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 root = + new SearchTestNodeReverse(SearchNodeType::Needle, 0); + RefPtr childNode1 = + new SearchTestNodeReverse(SearchNodeType::Hay); + RefPtr childNode2 = + new SearchTestNodeReverse(SearchNodeType::Hay); + int visitCount = 0; + RefPtr result = + BreadthFirstSearch( + 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 needleNode; + std::vector> nodeList; + nodeList.reserve(10); + 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 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 foundNode = + BreadthFirstSearch( + 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 needleNode; + std::vector> nodeList; + nodeList.reserve(10); + 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 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 foundNode = + BreadthFirstSearch( + 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> nodeList; + nodeList.reserve(10); + for (int i = 0; i < 10; i++) { + nodeList.push_back(new SearchTestNodeForward(SearchNodeType::Hay, i)); + } + + RefPtr 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 foundNode = + BreadthFirstSearch( + 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> nodeList; + nodeList.reserve(10); + for (int i = 0; i < 10; i++) { + nodeList.push_back(new SearchTestNodeReverse(SearchNodeType::Hay, i)); + } + + RefPtr 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 foundNode = + BreadthFirstSearch( + 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 nullNode; + ForEachNode( + nullNode.get(), + [](ForEachTestNodeReverse* aNode) { return TraversalFlag::Continue; }); +} + +TEST(TreeTraversal, ForEachNodeAllEligible) +{ + std::vector> nodeList; + int visitCount = 0; + nodeList.reserve(10); + for (int i = 0; i < 10; i++) { + nodeList.push_back( + new ForEachTestNodeForward(ForEachNodeType::Continue, i)); + } + + RefPtr 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](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> nodeList; + int visitCount = 0; + nodeList.reserve(10); + for (int i = 0; i < 10; i++) { + nodeList.push_back( + new ForEachTestNodeReverse(ForEachNodeType::Continue, i)); + } + + RefPtr 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( + 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> expectedVisitedNodeList; + std::vector> 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 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( + 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> expectedVisitedNodeList; + std::vector> 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 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( + 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 root = + new ForEachTestNodeReverse(ForEachNodeType::Skip, 0); + RefPtr childNode1 = + new ForEachTestNodeReverse(ForEachNodeType::Continue); + RefPtr chlidNode2 = + new ForEachTestNodeReverse(ForEachNodeType::Skip); + + ForEachNode( + 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> nodeList; + nodeList.reserve(10); + 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 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( + 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> nodeList; + nodeList.reserve(10); + 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 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( + 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> nodeList; + nodeList.reserve(10); + int visitCount = 0; + for (int i = 0; i < 10; i++) { + nodeList.push_back( + new ForEachTestNodeReverse(ForEachNodeType::Continue, i)); + } + + RefPtr 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( + 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& node; + void operator()(SearchTestNodeForward* aNode) { + aNode->SetType(SearchNodeType::Hay); + if (aNode->IsLeaf()) { + node = aNode; + } + } +}; + +struct AssignSearchNodeTypesAllHay { + void operator()(SearchTestNode* aNode) { + aNode->SetType(SearchNodeType::Hay); + } +}; + +struct AssignSearchNodeTypesWithFirstLeafAsNeedle { + RefPtr& needleNode; + void operator()(SearchTestNodeReverse* aNode) { + if (!needleNode && aNode->IsLeaf()) { + needleNode = aNode; + } + aNode->SetType(SearchNodeType::Hay); + } +}; + +struct AssignSearchNodeValuesAllFalseValuesReverse { + int falseValue; + RefPtr& needleNode; + void operator()(SearchTestNodeReverse* aNode) { + aNode->SetValue(falseValue); + if (!needleNode && aNode->IsLeaf()) { + needleNode = aNode; + } + } +}; + +struct AssignSearchNodeValuesAllFalseValuesForward { + int falseValue; + RefPtr& 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++; + } + } +}; + +template +static RefPtr DepthFirstSearchForwardRecursive(RefPtr aNode) { + if (aNode->GetType() == SearchNodeType::Needle) { + return aNode; + } + for (RefPtr node = aNode->GetFirstChild(); node != nullptr; + node = node->GetNextSibling()) { + if (RefPtr foundNode = DepthFirstSearchForwardRecursive(node)) { + return foundNode; + } + } + return nullptr; +} + +template +static RefPtr DepthFirstSearchCaptureVariablesForwardRecursive( + RefPtr 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 = aNode->GetFirstChild(); node != nullptr; + node = node->GetNextSibling()) { + if (RefPtr 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; +} + +template +static RefPtr DepthFirstSearchPostOrderForwardRecursive( + RefPtr aNode) { + for (RefPtr node = aNode->GetFirstChild(); node != nullptr; + node = node->GetNextSibling()) { + if (RefPtr foundNode = + DepthFirstSearchPostOrderForwardRecursive(node)) { + return foundNode; + } + } + if (aNode->GetType() == SearchNodeType::Needle) { + return aNode; + } + return nullptr; +} + +template +static RefPtr BreadthFirstSearchForwardQueue(RefPtr aNode) { + std::queue> nodes; + nodes.push(aNode); + while (!nodes.empty()) { + RefPtr node = nodes.front(); + nodes.pop(); + if (node->GetType() == SearchNodeType::Needle) { + return node; + } + for (RefPtr childNode = node->GetFirstChild(); childNode != nullptr; + childNode = childNode->GetNextSibling()) { + nodes.push(childNode); + } + } + return nullptr; +} + +template +static RefPtr DepthFirstSearchReverseRecursive(RefPtr aNode) { + if (aNode->GetType() == SearchNodeType::Needle) { + return aNode; + } + for (RefPtr node = aNode->GetLastChild(); node != nullptr; + node = node->GetPrevSibling()) { + if (RefPtr foundNode = DepthFirstSearchReverseRecursive(node)) { + return foundNode; + } + } + return nullptr; +} + +template +static RefPtr DepthFirstSearchCaptureVariablesReverseRecursive( + RefPtr 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 = aNode->GetLastChild(); node != nullptr; + node = node->GetPrevSibling()) { + if (RefPtr 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; +} + +template +static RefPtr DepthFirstSearchPostOrderReverseRecursive( + RefPtr aNode) { + for (RefPtr node = aNode->GetLastChild(); node != nullptr; + node = node->GetPrevSibling()) { + if (RefPtr foundNode = + DepthFirstSearchPostOrderReverseRecursive(node)) { + return foundNode; + } + } + if (aNode->GetType() == SearchNodeType::Needle) { + return aNode; + } + return nullptr; +} + +template +static RefPtr BreadthFirstSearchReverseQueue(RefPtr aNode) { + std::queue> nodes; + nodes.push(aNode); + while (!nodes.empty()) { + RefPtr node = nodes.front(); + nodes.pop(); + if (node->GetType() == SearchNodeType::Needle) { + return node; + } + for (RefPtr childNode = node->GetLastChild(); childNode != nullptr; + childNode = childNode->GetPrevSibling()) { + nodes.push(childNode); + } + } + return nullptr; +} -- cgit v1.2.3