From 56db1951c81653c24758081ad6cc2e5a4d050933 Mon Sep 17 00:00:00 2001 From: vng Date: Fri, 26 Dec 2014 11:37:37 +0300 Subject: [PATCH] Minor m4::Tree code refactoring: ReplaceAllInRect, ReplaceEqualInRect. --- geometry/geometry_tests/tree_test.cpp | 104 ++++++++++++++++----- geometry/tree4d.hpp | 126 ++++++++++++++------------ graphics/overlay.cpp | 2 +- 3 files changed, 147 insertions(+), 85 deletions(-) diff --git a/geometry/geometry_tests/tree_test.cpp b/geometry/geometry_tests/tree_test.cpp index 2bbffcd973..8f83df777f 100644 --- a/geometry/geometry_tests/tree_test.cpp +++ b/geometry/geometry_tests/tree_test.cpp @@ -1,17 +1,17 @@ -#include "../../base/SRC_FIRST.hpp" - #include "../../testing/testing.hpp" #include "../tree4d.hpp" + namespace { typedef m2::RectD R; - typedef m4::Tree tree_t; + struct traits_t { m2::RectD LimitRect(m2::RectD const & r) const { return r; }}; + typedef m4::Tree tree_t; - bool compare_true(R const &, R const &) { return true; } - bool compare_false(R const &, R const &) { return false; } + template bool RTrue(T const &, T const &) { return true; } + template bool RFalse(T const &, T const &) { return false; } } UNIT_TEST(Tree4D_Smoke) @@ -25,7 +25,7 @@ UNIT_TEST(Tree4D_Smoke) }; for (size_t i = 0; i < ARRAY_SIZE(arr); ++i) - theTree.ReplaceIf(arr[i], arr[i], &compare_true); + theTree.ReplaceAllInRect(arr[i], &RTrue); vector test; theTree.ForEach(MakeBackInsertFunctor(test)); @@ -38,7 +38,7 @@ UNIT_TEST(Tree4D_Smoke) TEST_EQUAL(test[0], arr[1], ()); R const replaceR(0.5, 0.5, 2.5, 2.5); - theTree.ReplaceIf(replaceR, replaceR, &compare_true); + theTree.ReplaceAllInRect(replaceR, &RTrue); test.clear(); theTree.ForEach(MakeBackInsertFunctor(test)); @@ -50,7 +50,7 @@ UNIT_TEST(Tree4D_Smoke) TEST_EQUAL(1, test.size(), ()); } -UNIT_TEST(Tree4D_ReplaceIf) +UNIT_TEST(Tree4D_ReplaceAllInRect) { tree_t theTree; @@ -72,10 +72,10 @@ UNIT_TEST(Tree4D_ReplaceIf) { size_t const count = theTree.GetSize(); - theTree.ReplaceIf(arr[i], arr[i], &compare_false); + theTree.ReplaceAllInRect(arr[i], &RFalse); TEST_EQUAL ( theTree.GetSize(), count + 1, () ); - theTree.ReplaceIf(arr1[i], arr1[i], &compare_false); + theTree.ReplaceAllInRect(arr1[i], &RFalse); TEST_EQUAL ( theTree.GetSize(), count + 1, () ); } @@ -105,21 +105,77 @@ namespace UNIT_TEST(Tree4D_ForEachInRect) { + R arr[] = { - R arr[] = { - R(0, 0, 1, 1), R(5, 5, 10, 10), R(-1, -1, 0, 0), R(-10, -10, -5, -5) - }; - CheckInRect(arr, ARRAY_SIZE(arr), R(1, 1, 5, 5), 0); - CheckInRect(arr, ARRAY_SIZE(arr), R(-5, -5, -1, -1), 0); - CheckInRect(arr, ARRAY_SIZE(arr), R(3, 3, 3, 3), 0); - CheckInRect(arr, ARRAY_SIZE(arr), R(-3, -3, -3, -3), 0); + R(0, 0, 1, 1), R(5, 5, 10, 10), R(-1, -1, 0, 0), R(-10, -10, -5, -5) + }; + CheckInRect(arr, ARRAY_SIZE(arr), R(1, 1, 5, 5), 0); + CheckInRect(arr, ARRAY_SIZE(arr), R(-5, -5, -1, -1), 0); + CheckInRect(arr, ARRAY_SIZE(arr), R(3, 3, 3, 3), 0); + CheckInRect(arr, ARRAY_SIZE(arr), R(-3, -3, -3, -3), 0); - CheckInRect(arr, ARRAY_SIZE(arr), R(0.5, 0.5, 0.5, 0.5), 1); - CheckInRect(arr, ARRAY_SIZE(arr), R(8, 8, 8, 8), 1); - CheckInRect(arr, ARRAY_SIZE(arr), R(-0.5, -0.5, -0.5, -0.5), 1); - CheckInRect(arr, ARRAY_SIZE(arr), R(-8, -8, -8, -8), 1); + CheckInRect(arr, ARRAY_SIZE(arr), R(0.5, 0.5, 0.5, 0.5), 1); + CheckInRect(arr, ARRAY_SIZE(arr), R(8, 8, 8, 8), 1); + CheckInRect(arr, ARRAY_SIZE(arr), R(-0.5, -0.5, -0.5, -0.5), 1); + CheckInRect(arr, ARRAY_SIZE(arr), R(-8, -8, -8, -8), 1); - CheckInRect(arr, ARRAY_SIZE(arr), R(0.5, 0.5, 5.5, 5.5), 2); - CheckInRect(arr, ARRAY_SIZE(arr), R(-5.5, -5.5, -0.5, -0.5), 2); - } + CheckInRect(arr, ARRAY_SIZE(arr), R(0.5, 0.5, 5.5, 5.5), 2); + CheckInRect(arr, ARRAY_SIZE(arr), R(-5.5, -5.5, -0.5, -0.5), 2); +} + +namespace +{ + +struct TestObj : public m2::RectD +{ + int m_id; + + TestObj(double minX, double minY, double maxX, double maxY, int id) + : m2::RectD(minX, minY, maxX, maxY), m_id(id) + { + } + + bool operator==(TestObj const & r) const { return m_id == r.m_id; } +}; + +} + +UNIT_TEST(Tree4D_ReplaceEqual) +{ + typedef TestObj T; + m4::Tree theTree; + + T arr[] = { + T(0, 0, 1, 1, 1), + T(1, 1, 2, 2, 2), + T(2, 2, 3, 3, 3) + }; + + // 1. + for (size_t i = 0; i < ARRAY_SIZE(arr); ++i) + theTree.ReplaceEqualInRect(arr[i], equal_to(), &RTrue); + + vector test; + theTree.ForEach(MakeBackInsertFunctor(test)); + TEST_EQUAL(3, test.size(), ()); + + // 2. + theTree.ReplaceEqualInRect(T(0, 0, 3, 3, 2), equal_to(), &RFalse); + + test.clear(); + theTree.ForEach(MakeBackInsertFunctor(test)); + TEST_EQUAL(3, test.size(), ()); + + auto i = find(test.begin(), test.end(), T(1, 1, 2, 2, 2)); + TEST_EQUAL(R(*i), R(1, 1, 2, 2), ()); + + // 3. + theTree.ReplaceEqualInRect(T(0, 0, 3, 3, 2), equal_to(), &RTrue); + + test.clear(); + theTree.ForEach(MakeBackInsertFunctor(test)); + TEST_EQUAL(3, test.size(), ()); + + i = find(test.begin(), test.end(), T(1, 1, 2, 2, 2)); + TEST_EQUAL(R(*i), R(0, 0, 3, 3), ()); } diff --git a/geometry/tree4d.hpp b/geometry/tree4d.hpp index 99629243f7..0b3ee1771d 100644 --- a/geometry/tree4d.hpp +++ b/geometry/tree4d.hpp @@ -9,6 +9,7 @@ #include "../std/sstream.hpp" #include "../std/kdtree.hpp" + namespace m4 { template @@ -72,14 +73,15 @@ namespace m4 typedef vector store_vec_t; - // Base do-class for rect-iteration in tree. - class for_each_base + // Do-class for rect-iteration in tree. + template class for_each_helper { - protected: m2::RectD const & m_rect; + ToDo m_toDo; public: - for_each_base(m2::RectD const & r) : m_rect(r) + for_each_helper(m2::RectD const & r, ToDo toDo) + : m_rect(r), m_toDo(toDo) { } @@ -102,44 +104,18 @@ namespace m4 default: return true; } } + + void operator() (value_t const & v) const + { + if (v.IsIntersect(m_rect)) + m_toDo(v); + } }; - // Do-class for getting elements in rect. - class insert_if_intersect : public for_each_base + template for_each_helper GetFunctor(m2::RectD const & rect, ToDo toDo) const { - typedef for_each_base base_t; - - store_vec_t & m_isect; - - public: - insert_if_intersect(store_vec_t & isect, m2::RectD const & r) - : for_each_base(r), m_isect(isect) - { - } - void operator() (value_t const & v) - { - if (v.IsIntersect(base_t::m_rect)) - m_isect.push_back(&v); - } - }; - - // Do-class for processing elements in rect. - template class for_each_in_rect : public for_each_base - { - typedef for_each_base base_t; - - ToDo & m_toDo; - public: - for_each_in_rect(ToDo & toDo, m2::RectD const & rect) - : for_each_base(rect), m_toDo(toDo) - { - } - void operator() (value_t const & v) - { - if (v.IsIntersect(base_t::m_rect)) - m_toDo(v.m_val); - } - }; + return for_each_helper(rect, toDo); + } protected: Traits m_traits; @@ -160,22 +136,60 @@ namespace m4 m_tree.insert(value_t(obj, rect)); } + private: template - void ReplaceIf(T const & obj, m2::RectD const & rect, TCompare comp) + void ReplaceImpl(T const & obj, m2::RectD const & rect, TCompare comp) { + bool skip = false; store_vec_t isect; - m_tree.for_each(insert_if_intersect(isect, rect)); - for (size_t i = 0; i < isect.size(); ++i) - if (!comp(obj, isect[i]->m_val)) + m_tree.for_each(GetFunctor(rect, [&] (value_t const & v) + { + if (skip) return; - for (size_t i = 0; i < isect.size(); ++i) - m_tree.erase(*isect[i]); + switch (comp(obj, v.m_val)) + { + case 1: + isect.push_back(&v); + break; + case -1: + skip = true; + break; + } + })); + + if (skip) + return; + + for (value_t const * v : isect) + m_tree.erase(*v); Add(obj, rect); } + public: + template + void ReplaceAllInRect(T const & obj, TCompare comp) + { + ReplaceImpl(obj, GetLimitRect(obj), [&comp] (T const & t1, T const & t2) + { + return comp(t1, t2) ? 1 : -1; + }); + } + + template + void ReplaceEqualInRect(T const & obj, TEqual eq, TCompare comp) + { + ReplaceImpl(obj, GetLimitRect(obj), [&] (T const & t1, T const & t2) + { + if (eq(t1, t2)) + return comp(t1, t2) ? 1 : -1; + else + return 0; + }); + } + void Erase(T const & obj, m2::RectD const & r) { value_t val(obj, r); @@ -188,30 +202,24 @@ namespace m4 m_tree.erase_exact(val); } - template - void ReplaceIf(T const & obj, TCompare comp) - { - ReplaceIf(obj, GetLimitRect(obj), comp); - } - template void ForEach(ToDo toDo) const { - for (typename tree_t::const_iterator i = m_tree.begin(); i != m_tree.end(); ++i) - toDo((*i).m_val); + for (value_t const & v : m_tree) + toDo(v.m_val); } template void ForEachWithRect(ToDo toDo) const { - for (typename tree_t::const_iterator i = m_tree.begin(); i != m_tree.end(); ++i) - toDo((*i).GetRect(), (*i).m_val); + for (value_t const & v : m_tree) + toDo(v.GetRect(), v.m_val); } template void ForEachInRect(m2::RectD const & rect, ToDo toDo) const { - m_tree.for_each(for_each_in_rect(toDo, rect)); + m_tree.for_each(GetFunctor(rect, [&toDo] (value_t const & v) { toDo(v.m_val); })); } bool IsEmpty() const { return m_tree.empty(); } @@ -223,10 +231,8 @@ namespace m4 string DebugPrint() const { ostringstream out; - for (typename tree_t::const_iterator it = m_tree.begin(); - it != m_tree.end(); - ++it) - out << it->DebugPrint() << ", "; + for (value_t const & v : m_tree.begin()) + out << v.DebugPrint() << ", "; return out.str(); } }; diff --git a/graphics/overlay.cpp b/graphics/overlay.cpp index 09dfa9a6c3..9bc65490df 100644 --- a/graphics/overlay.cpp +++ b/graphics/overlay.cpp @@ -168,7 +168,7 @@ void Overlay::replaceOverlayElement(shared_ptr const & oe) m_tree.ForEachInRect(fn.GetSearchRect(), bind(ref(fn), _1)); if (fn.IsIntersect()) - m_tree.ReplaceIf(oe, &betterOverlayElement); + m_tree.ReplaceAllInRect(oe, &betterOverlayElement); else m_tree.Add(oe); }