diff --git a/base/base_tests/stl_helpers_test.cpp b/base/base_tests/stl_helpers_test.cpp index 7d23bdd3d2..f898d69e5b 100644 --- a/base/base_tests/stl_helpers_test.cpp +++ b/base/base_tests/stl_helpers_test.cpp @@ -19,30 +19,45 @@ private: int m_v; }; -UNIT_TEST(CompareBy_Field) +UNIT_TEST(LessBy) { - vector> v = {{2, 2}, {0, 4}, {3, 1}, {4, 0}, {1, 3}}; - sort(v.begin(), v.end(), my::CompareBy(&pair::first)); - for (size_t i = 0; i < v.size(); ++i) - TEST_EQUAL(i, v[i].first, ()); + using TValue = pair; - vector const *> pv; - for (auto const & p : v) - pv.push_back(&p); + { + vector v = {{2, 2}, {0, 4}, {3, 1}, {4, 0}, {1, 3}}; + sort(v.begin(), v.end(), my::LessBy(&TValue::first)); + for (size_t i = 0; i < v.size(); ++i) + TEST_EQUAL(i, v[i].first, ()); - sort(pv.begin(), pv.end(), my::CompareBy(&pair::second)); - for (size_t i = 0; i < pv.size(); ++i) - TEST_EQUAL(i, pv[i]->second, ()); + vector pv; + for (auto const & p : v) + pv.push_back(&p); + + sort(pv.begin(), pv.end(), my::LessBy(&TValue::second)); + for (size_t i = 0; i < pv.size(); ++i) + TEST_EQUAL(i, pv[i]->second, ()); + } + + { + vector v; + for (int i = 9; i >= 0; --i) + v.emplace_back(i); + + sort(v.begin(), v.end(), my::LessBy(&Int::Get)); + for (size_t i = 0; i < v.size(); ++i) + TEST_EQUAL(v[i].Get(), static_cast(i), ()); + } } -UNIT_TEST(CompareBy_Method) +UNIT_TEST(EqualsBy) { - vector v; - for (int i = 9; i >= 0; --i) - v.emplace_back(i); + using TValue = pair; + vector actual = {{1, 2}, {1, 3}, {2, 100}, {3, 7}, {3, 8}, {2, 500}}; + actual.erase(unique(actual.begin(), actual.end(), my::EqualsBy(&TValue::first)), actual.end()); - sort(v.begin(), v.end(), my::CompareBy(&Int::Get)); - for (size_t i = 0; i < v.size(); ++i) - TEST_EQUAL(v[i].Get(), static_cast(i), ()); + vector expected = {{1, 2, 3, 2}}; + TEST_EQUAL(expected.size(), actual.size(), ()); + for (size_t i = 0; i < actual.size(); ++i) + TEST_EQUAL(expected[i], actual[i].first, ()); } } // namespace diff --git a/base/stl_helpers.hpp b/base/stl_helpers.hpp index 3375867f75..c01fbc5b99 100644 --- a/base/stl_helpers.hpp +++ b/base/stl_helpers.hpp @@ -7,15 +7,16 @@ namespace my { namespace impl { -// When isField is true, Comparer operates on a pointers-to-field. -// Otherwise, Comparer operates on a pointers-to-const-method. +// When isField is true, following functors operate on a +// pointers-to-field. Otherwise, they operate on a +// pointers-to-const-method. template -struct Comparer; +struct Less; -template -struct Comparer +template +struct Less { - Comparer(T(C::*p)) : p_(p) {} + Less(T(C::*p)) : p_(p) {} inline bool operator()(C const & lhs, C const & rhs) const { return lhs.*p_ < rhs.*p_; } @@ -27,10 +28,10 @@ struct Comparer T(C::*p_); }; -template -struct Comparer +template +struct Less { - Comparer(T (C::*p)() const) : p_(p) {} + Less(T (C::*p)() const) : p_(p) {} inline bool operator()(C const & lhs, C const & rhs) const { return (lhs.*p_)() < (rhs.*p_)(); } @@ -39,7 +40,40 @@ struct Comparer return (lhs->*p_)() < (rhs->*p_)(); } - T(C::*p_)() const; + T (C::*p_)() const; +}; + +template +struct Equals; + +template +struct Equals +{ + Equals(T(C::*p)) : p_(p) {} + + inline bool operator()(C const & lhs, C const & rhs) const { return lhs.*p_ == rhs.*p_; } + + inline bool operator()(C const * const lhs, C const * const rhs) const + { + return lhs->*p_ == rhs->*p_; + } + + T(C::*p_); +}; + +template +struct Equals +{ + Equals(T (C::*p)() const) : p_(p) {} + + inline bool operator()(C const & lhs, C const & rhs) const { return (lhs.*p_)() == (rhs.*p_)(); } + + inline bool operator()(C const * const lhs, C const * const rhs) const + { + return (lhs->*p_)() == (rhs->*p_)(); + } + + T (C::*p_)() const; }; } // namespace impl @@ -60,17 +94,29 @@ void EraseIf(vector & v, TFn && fn) // Creates a comparer being able to compare two instances of class C // (given by reference or pointer) by a field or const method of C. // For example, to create comparer that is able to compare pairs of -// ints by second component, it's enough to call CompareBy(&pair::second). template -impl::Comparer CompareBy(T(C::*p)) +impl::Less LessBy(T(C::*p)) { - return impl::Comparer(p); + return impl::Less(p); } template -impl::Comparer CompareBy(T (C::*p)() const) +impl::Less LessBy(T (C::*p)() const) { - return impl::Comparer(p); + return impl::Less(p); +} + +template +impl::Equals EqualsBy(T(C::*p)) +{ + return impl::Equals(p); +} + +template +impl::Equals EqualsBy(T (C::*p)() const) +{ + return impl::Equals(p); } } // namespace my diff --git a/search/processor.cpp b/search/processor.cpp index 087f97af2e..aa8cada014 100644 --- a/search/processor.cpp +++ b/search/processor.cpp @@ -510,7 +510,7 @@ void Processor::FlushViewportResults(v2::Geocoder::Params const & params, Result if (indV.empty()) return; - sort(indV.begin(), indV.end(), my::CompareBy(&IndexedValue::GetDistanceToPivot)); + sort(indV.begin(), indV.end(), my::LessBy(&IndexedValue::GetDistanceToPivot)); for (size_t i = 0; i < indV.size(); ++i) { @@ -720,7 +720,7 @@ void Processor::FlushResults(v2::Geocoder::Params const & params, Results & res, if (indV.empty()) return; - sort(indV.rbegin(), indV.rend(), my::CompareBy(&IndexedValue::GetRank)); + sort(indV.rbegin(), indV.rend(), my::LessBy(&IndexedValue::GetRank)); // Do not process suggestions in additional search. if (!allMWMs || res.GetCount() == 0) diff --git a/search/reverse_geocoder.cpp b/search/reverse_geocoder.cpp index 4cccc1ed03..d91089c491 100644 --- a/search/reverse_geocoder.cpp +++ b/search/reverse_geocoder.cpp @@ -51,7 +51,7 @@ void ReverseGeocoder::GetNearbyStreets(MwmSet::MwmId const & id, m2::PointD cons if (mwmHandle.IsAlive()) { search::v2::MwmContext(move(mwmHandle)).ForEachFeature(rect, addStreet); - sort(streets.begin(), streets.end(), my::CompareBy(&Street::m_distanceMeters)); + sort(streets.begin(), streets.end(), my::LessBy(&Street::m_distanceMeters)); } } @@ -174,7 +174,7 @@ void ReverseGeocoder::GetNearbyBuildings(m2::PointD const & center, vector