From a59b30b3da5c46c352922328b28fdc253dd17d01 Mon Sep 17 00:00:00 2001 From: Yuri Gorshenin Date: Thu, 13 Oct 2016 13:21:25 +0300 Subject: [PATCH] [search] Identity checks for hotels filter. --- map/framework.cpp | 3 + search/hotels_filter.cpp | 17 +++ search/hotels_filter.hpp | 130 ++++++++++++++++++--- search/search_tests/hotels_filter_test.cpp | 35 ++++++ search/search_tests/search_tests.pro | 1 + 5 files changed, 169 insertions(+), 17 deletions(-) create mode 100644 search/search_tests/hotels_filter_test.cpp diff --git a/map/framework.cpp b/map/framework.cpp index 947796101f..a39cc69d6a 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -1361,6 +1361,9 @@ bool Framework::QueryMayBeSkipped(SearchIntent const & intent, search::SearchPar if (lastParams.IsValidPosition() != params.IsValidPosition()) return false; + if (!search::hotels_filter::Rule::IsIdentical(lastParams.m_hotelsFilter, params.m_hotelsFilter)) + return false; + return true; } diff --git a/search/hotels_filter.cpp b/search/hotels_filter.cpp index 10f335a39f..9a64085449 100644 --- a/search/hotels_filter.cpp +++ b/search/hotels_filter.cpp @@ -42,6 +42,23 @@ void Description::FromFeature(FeatureType & ft) } } +// Rule -------------------------------------------------------------------------------------------- +// static +bool Rule::IsIdentical(shared_ptr const & lhs, shared_ptr const & rhs) +{ + if (lhs && !rhs) + return false; + if (!lhs && rhs) + return false; + + if (lhs && rhs && !lhs->IdenticalTo(*rhs)) + return false; + + return true; +} + +string DebugPrint(Rule const & rule) { return rule.ToString(); } + // HotelsFilter::ScopedFilter ---------------------------------------------------------------------- HotelsFilter::ScopedFilter::ScopedFilter(MwmSet::MwmId const & mwmId, Descriptions const & descriptions, shared_ptr rule) diff --git a/search/hotels_filter.hpp b/search/hotels_filter.hpp index 6c2758a1d1..86f63e01ad 100644 --- a/search/hotels_filter.hpp +++ b/search/hotels_filter.hpp @@ -68,12 +68,18 @@ struct Description struct Rule { virtual ~Rule() = default; + + static bool IsIdentical(shared_ptr const & lhs, shared_ptr const & rhs); + virtual bool Matches(Description const & d) const = 0; + virtual bool IdenticalTo(Rule const & rhs) const = 0; virtual string ToString() const = 0; }; +string DebugPrint(Rule const & rule); + template -struct EqRule : public Rule +struct EqRule final : public Rule { using Value = typename Field::Value; @@ -85,6 +91,12 @@ struct EqRule : public Rule return Field::Eq(Field::Select(d), m_value); } + bool IdenticalTo(Rule const & rhs) const override + { + auto const * r = dynamic_cast(&rhs); + return r && Field::Eq(r->m_value, m_value); + } + string ToString() const override { ostringstream os; @@ -96,7 +108,7 @@ struct EqRule : public Rule }; template -struct LtRule : public Rule +struct LtRule final : public Rule { using Value = typename Field::Value; @@ -108,6 +120,12 @@ struct LtRule : public Rule return Field::Lt(Field::Select(d), m_value); } + bool IdenticalTo(Rule const & rhs) const override + { + auto const * r = dynamic_cast(&rhs); + return r && Field::Eq(r->m_value, m_value); + } + string ToString() const override { ostringstream os; @@ -119,7 +137,37 @@ struct LtRule : public Rule }; template -struct GtRule : public Rule +struct LeRule final : public Rule +{ + using Value = typename Field::Value; + + LeRule(Value value) : m_value(value) {} + + // Rule overrides: + bool Matches(Description const & d) const override + { + auto const value = Field::Select(d); + return Field::Lt(value, m_value) || Field::Eq(value, m_value); + } + + bool IdenticalTo(Rule const & rhs) const override + { + auto const * r = dynamic_cast(&rhs); + return r && Field::Eq(r->m_value, m_value); + } + + string ToString() const override + { + ostringstream os; + os << "[ " << Field::Name() << " <= " << m_value << " ]"; + return os.str(); + } + + Value const m_value; +}; + +template +struct GtRule final : public Rule { using Value = typename Field::Value; @@ -131,6 +179,12 @@ struct GtRule : public Rule return Field::Gt(Field::Select(d), m_value); } + bool IdenticalTo(Rule const & rhs) const override + { + auto const * r = dynamic_cast(&rhs); + return r && Field::Eq(r->m_value, m_value); + } + string ToString() const override { ostringstream os; @@ -141,7 +195,37 @@ struct GtRule : public Rule Value const m_value; }; -struct AndRule : public Rule +template +struct GeRule final : public Rule +{ + using Value = typename Field::Value; + + GeRule(Value value) : m_value(value) {} + + // Rule overrides: + bool Matches(Description const & d) const override + { + auto const value = Field::Select(d); + return Field::Gt(value, m_value) || Field::Eq(value, m_value); + } + + bool IdenticalTo(Rule const & rhs) const override + { + auto const * r = dynamic_cast(&rhs); + return r && Field::Eq(r->m_value, m_value); + } + + string ToString() const override + { + ostringstream os; + os << "[ " << Field::Name() << " >= " << m_value << " ]"; + return os.str(); + } + + Value const m_value; +}; + +struct AndRule final : public Rule { AndRule(shared_ptr lhs, shared_ptr rhs) : m_lhs(move(lhs)), m_rhs(move(rhs)) {} @@ -156,6 +240,12 @@ struct AndRule : public Rule return matches; } + bool IdenticalTo(Rule const & rhs) const override + { + auto const * r = dynamic_cast(&rhs); + return r && IsIdentical(m_lhs, r->m_lhs) && IsIdentical(m_rhs, r->m_rhs); + } + string ToString() const override { ostringstream os; @@ -171,7 +261,7 @@ struct AndRule : public Rule shared_ptr m_rhs; }; -struct OrRule : public Rule +struct OrRule final : public Rule { OrRule(shared_ptr lhs, shared_ptr rhs) : m_lhs(move(lhs)), m_rhs(move(rhs)) {} @@ -186,6 +276,12 @@ struct OrRule : public Rule return matches; } + bool IdenticalTo(Rule const & rhs) const override + { + auto const * r = dynamic_cast(&rhs); + return r && IsIdentical(m_lhs, r->m_lhs) && IsIdentical(m_rhs, r->m_rhs); + } + string ToString() const override { ostringstream os; @@ -213,12 +309,24 @@ shared_ptr Lt(typename Field::Value value) return make_shared>(value); } +template +shared_ptr Le(typename Field::Value value) +{ + return make_shared>(value); +} + template inline shared_ptr Gt(typename Field::Value value) { return make_shared>(value); } +template +shared_ptr Ge(typename Field::Value value) +{ + return make_shared>(value); +} + inline shared_ptr And(shared_ptr lhs, shared_ptr rhs) { return make_shared(lhs, rhs); @@ -229,18 +337,6 @@ inline shared_ptr Or(shared_ptr lhs, shared_ptr rhs) return make_shared(lhs, rhs); } -template -shared_ptr Le(typename Field::Value value) -{ - return Or(Lt(value), Eq(value)); -} - -template -shared_ptr Ge(typename Field::Value value) -{ - return Or(Gt(value), Eq(value)); -} - class HotelsFilter { public: diff --git a/search/search_tests/hotels_filter_test.cpp b/search/search_tests/hotels_filter_test.cpp new file mode 100644 index 0000000000..58dd6427fd --- /dev/null +++ b/search/search_tests/hotels_filter_test.cpp @@ -0,0 +1,35 @@ +#include "testing/testing.hpp" + +#include "search/hotels_filter.hpp" + +using namespace search::hotels_filter; + +namespace +{ +UNIT_TEST(HotelsFilter_Identity) +{ + { + auto const first = And(Or(Eq(5.0), Lt(2)), Ge(4.0)); + auto const second = And(Or(Eq(5.0), Lt(2)), Ge(4.0)); + TEST(first.get(), ()); + TEST(second.get(), ()); + TEST(first->IdenticalTo(*second), (*first, *second)); + } + + { + auto const first = And(Gt(5.0), Lt(5)); + auto const second = And(Lt(5), Gt(5.0)); + TEST(first.get(), ()); + TEST(second.get(), ()); + TEST(!first->IdenticalTo(*second), (*first, *second)); + } + + { + auto const first = Ge(1); + auto const second = Or(Gt(1), Eq(1)); + TEST(first.get(), ()); + TEST(second.get(), ()); + TEST(!first->IdenticalTo(*second), (*first, *second)); + } +} +} // namespace diff --git a/search/search_tests/search_tests.pro b/search/search_tests/search_tests.pro index 2bd4c2eddd..9307f0dbd3 100644 --- a/search/search_tests/search_tests.pro +++ b/search/search_tests/search_tests.pro @@ -19,6 +19,7 @@ macx-*: LIBS *= "-framework IOKit" SOURCES += \ ../../testing/testingmain.cpp \ algos_tests.cpp \ + hotels_filter_test.cpp \ house_detector_tests.cpp \ house_numbers_matcher_test.cpp \ interval_set_test.cpp \