Merge pull request #3353 from ygorshenin/implemented-equals-by

[base] Implemented EqualsBy.
This commit is contained in:
Vladimir Byko-Ianko 2016-05-27 14:14:40 +03:00
commit 566024bb40
6 changed files with 119 additions and 44 deletions

View file

@ -19,30 +19,59 @@ private:
int m_v;
};
UNIT_TEST(CompareBy_Field)
UNIT_TEST(LessBy)
{
vector<pair<int, int>> v = {{2, 2}, {0, 4}, {3, 1}, {4, 0}, {1, 3}};
sort(v.begin(), v.end(), my::CompareBy(&pair<int, int>::first));
for (size_t i = 0; i < v.size(); ++i)
TEST_EQUAL(i, v[i].first, ());
{
using TValue = pair<int, int>;
vector<pair<int, int> const *> pv;
for (auto const & p : v)
pv.push_back(&p);
vector<TValue> 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<int, int>::second));
for (size_t i = 0; i < pv.size(); ++i)
TEST_EQUAL(i, pv[i]->second, ());
vector<TValue const *> 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<Int> 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<int>(i), ());
}
}
UNIT_TEST(CompareBy_Method)
UNIT_TEST(EqualsBy)
{
vector<Int> v;
for (int i = 9; i >= 0; --i)
v.emplace_back(i);
{
using TValue = pair<int, int>;
vector<TValue> 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<int>(i), ());
vector<int> const 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, ());
}
{
vector<Int> actual;
for (auto const v : {0, 0, 1, 2, 2, 0})
actual.emplace_back(v);
actual.erase(unique(actual.begin(), actual.end(), my::EqualsBy(&Int::Get)), actual.end());
vector<int> const expected = {{0, 1, 2, 0}};
TEST_EQUAL(expected.size(), actual.size(), ());
for (size_t i = 0; i < actual.size(); ++i)
TEST_EQUAL(expected[i], actual[i].Get(), ());
}
}
} // namespace

View file

@ -7,39 +7,73 @@ 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 <bool isField, typename T, typename C>
struct Comparer;
struct Less;
template<typename T, typename C>
struct Comparer<true, T, C>
template <typename T, typename C>
struct Less<true, T, C>
{
Comparer(T(C::*p)) : p_(p) {}
Less(T(C::*p)) : m_p(p) {}
inline bool operator()(C const & lhs, C const & rhs) const { return lhs.*p_ < rhs.*p_; }
inline bool operator()(C const & lhs, C const & rhs) const { return lhs.*m_p < rhs.*m_p; }
inline bool operator()(C const * const lhs, C const * const rhs) const
{
return lhs->*p_ < rhs->*p_;
return lhs->*m_p < rhs->*m_p;
}
T(C::*p_);
T(C::*m_p);
};
template<typename T, typename C>
struct Comparer<false, T, C>
template <typename T, typename C>
struct Less<false, T, C>
{
Comparer(T (C::*p)() const) : p_(p) {}
Less(T (C::*p)() const) : m_p(p) {}
inline bool operator()(C const & lhs, C const & rhs) const { return (lhs.*p_)() < (rhs.*p_)(); }
inline bool operator()(C const & lhs, C const & rhs) const { return (lhs.*m_p)() < (rhs.*m_p)(); }
inline bool operator()(C const * const lhs, C const * const rhs) const
{
return (lhs->*p_)() < (rhs->*p_)();
return (lhs->*m_p)() < (rhs->*m_p)();
}
T(C::*p_)() const;
T (C::*m_p)() const;
};
template <bool isField, typename T, typename C>
struct Equals;
template <typename T, typename C>
struct Equals<true, T, C>
{
Equals(T(C::*p)) : m_p(p) {}
inline bool operator()(C const & lhs, C const & rhs) const { return lhs.*m_p == rhs.*m_p; }
inline bool operator()(C const * const lhs, C const * const rhs) const
{
return lhs->*m_p == rhs->*m_p;
}
T(C::*m_p);
};
template <typename T, typename C>
struct Equals<false, T, C>
{
Equals(T (C::*p)() const) : m_p(p) {}
inline bool operator()(C const & lhs, C const & rhs) const { return (lhs.*m_p)() == (rhs.*m_p)(); }
inline bool operator()(C const * const lhs, C const * const rhs) const
{
return (lhs->*m_p)() == (rhs->*m_p)();
}
T (C::*m_p)() const;
};
} // namespace impl
@ -60,17 +94,29 @@ void EraseIf(vector<T> & 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<int,
// ints by second component, it's enough to call LessBy(&pair<int,
// int>::second).
template <typename T, typename C>
impl::Comparer<true, T, C> CompareBy(T(C::*p))
impl::Less<true, T, C> LessBy(T(C::*p))
{
return impl::Comparer<true, T, C>(p);
return impl::Less<true, T, C>(p);
}
template <typename T, typename C>
impl::Comparer<false, T, C> CompareBy(T (C::*p)() const)
impl::Less<false, T, C> LessBy(T (C::*p)() const)
{
return impl::Comparer<false, T, C>(p);
return impl::Less<false, T, C>(p);
}
template <typename T, typename C>
impl::Equals<true, T, C> EqualsBy(T(C::*p))
{
return impl::Equals<true, T, C>(p);
}
template <typename T, typename C>
impl::Equals<false, T, C> EqualsBy(T (C::*p)() const)
{
return impl::Equals<false, T, C>(p);
}
} // namespace my

View file

@ -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)

View file

@ -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<Build
};
m_index.ForEachInRect(addBuilding, rect, kQueryScale);
sort(buildings.begin(), buildings.end(), my::CompareBy(&Building::m_distanceMeters));
sort(buildings.begin(), buildings.end(), my::LessBy(&Building::m_distanceMeters));
}
// static

View file

@ -98,7 +98,7 @@ public:
void GetTopLocalities(size_t limit)
{
m_scorer.GetTopLocalities(limit, m_localities);
sort(m_localities.begin(), m_localities.end(), my::CompareBy(&Geocoder::Locality::m_featureId));
sort(m_localities.begin(), m_localities.end(), my::LessBy(&Geocoder::Locality::m_featureId));
}
// LocalityScorer::Delegate overrides:

View file

@ -1361,7 +1361,7 @@ void Geocoder::FindPaths()
sortedLayers.reserve(m_layers.size());
for (auto & layer : m_layers)
sortedLayers.push_back(&layer);
sort(sortedLayers.begin(), sortedLayers.end(), my::CompareBy(&FeaturesLayer::m_type));
sort(sortedLayers.begin(), sortedLayers.end(), my::LessBy(&FeaturesLayer::m_type));
auto const & innermostLayer = *sortedLayers.front();