diff options
author | Yuri Gorshenin <y@maps.me> | 2016-05-26 17:38:33 +0300 |
---|---|---|
committer | Yuri Gorshenin <y@maps.me> | 2016-05-26 17:38:33 +0300 |
commit | 60e74b995a0d8bd6a00c08c8d5483ea090c2d20e (patch) | |
tree | a604541873fff5a0b73f920bb09cf77792a6ff47 /base | |
parent | 6f84875fb9912ef2d199418605362c1e427db578 (diff) |
[base] Implemented EqualsBy.
Diffstat (limited to 'base')
-rw-r--r-- | base/base_tests/stl_helpers_test.cpp | 57 | ||||
-rw-r--r-- | base/stl_helpers.hpp | 76 |
2 files changed, 97 insertions, 36 deletions
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<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, ()); - - vector<pair<int, int> const *> pv; - for (auto const & p : v) - pv.push_back(&p); - - 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, ()); + using TValue = pair<int, int>; + + { + 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, ()); + + 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); - - 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), ()); + 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()); + + vector<int> 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 <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)) : p_(p) {} inline bool operator()(C const & lhs, C const & rhs) const { return lhs.*p_ < rhs.*p_; } @@ -27,10 +28,10 @@ struct Comparer<true, T, C> T(C::*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) : p_(p) {} inline bool operator()(C const & lhs, C const & rhs) const { return (lhs.*p_)() < (rhs.*p_)(); } @@ -39,7 +40,40 @@ struct Comparer<false, T, C> return (lhs->*p_)() < (rhs->*p_)(); } - T(C::*p_)() const; + T (C::*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)) : 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 <typename T, typename C> +struct Equals<false, T, C> +{ + 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<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::Less<true, T, C>(p); +} + +template <typename T, typename C> +impl::Less<false, T, C> LessBy(T (C::*p)() const) +{ + return impl::Less<false, T, C>(p); +} + +template <typename T, typename C> +impl::Equals<true, T, C> EqualsBy(T(C::*p)) { - return impl::Comparer<true, T, C>(p); + return impl::Equals<true, T, C>(p); } template <typename T, typename C> -impl::Comparer<false, T, C> CompareBy(T (C::*p)() const) +impl::Equals<false, T, C> EqualsBy(T (C::*p)() const) { - return impl::Comparer<false, T, C>(p); + return impl::Equals<false, T, C>(p); } } // namespace my |