From: Mikko Rasa Date: Wed, 15 Aug 2018 21:03:36 +0000 (+0300) Subject: Rework condition merging X-Git-Url: http://git.tdb.fi/?p=poefilter.git;a=commitdiff_plain;h=8b9d1f472e7bfbb1e097bb6d8bcad026e9636822 Rework condition merging The condition tree is now actually flattened and adjacent similar conditions merged rather than just producing special output. --- diff --git a/source/category.cpp b/source/category.cpp index fb12fec..5e454bb 100644 --- a/source/category.cpp +++ b/source/category.cpp @@ -47,7 +47,11 @@ void Category::create_statements(list &st) const st.push_back(FilterStatement()); if(condition) - condition->add_lines(st); + { + Condition *flat = condition->flatten(); + flat->add_lines(st); + delete flat; + } } diff --git a/source/choicecondition.h b/source/choicecondition.h index 170af0e..424dca6 100644 --- a/source/choicecondition.h +++ b/source/choicecondition.h @@ -12,15 +12,16 @@ public: typedef typename Traits::Type Type; private: - Type value; + std::vector values; public: ChoiceCondition(Type); + ChoiceCondition(const std::vector &); virtual ChoiceCondition *clone() const; virtual bool can_merge(const Condition &, const CompoundCondition &) const; + virtual ChoiceCondition *merge(const std::vector &, const CompoundCondition &) const; virtual void add_lines(std::list &) const; - virtual void add_merged_lines(const std::vector &, const CompoundCondition &, std::list &) const; }; @@ -43,14 +44,20 @@ typedef ChoiceCondition BaseTypeCondition; template -ChoiceCondition::ChoiceCondition(Type v): - value(v) +ChoiceCondition::ChoiceCondition(Type v) +{ + values.push_back(v); +} + +template +ChoiceCondition::ChoiceCondition(const std::vector &v): + values(v) { } template ChoiceCondition *ChoiceCondition::clone() const { - return new ChoiceCondition(value); + return new ChoiceCondition(values); } template @@ -60,22 +67,32 @@ bool ChoiceCondition::can_merge(const Condition &other, const CompoundConditi } template -void ChoiceCondition::add_lines(std::list &st) const +ChoiceCondition *ChoiceCondition::merge(const std::vector &conditions, const CompoundCondition &parent) const { - const char *keyword = Traits::get_keyword(); - FilterStatement::add_line(st, Msp::format("%s \"%s\"", keyword, value)); + if(dynamic_cast(&parent) && !conditions.empty()) + { + ChoiceCondition *result = 0; + for(std::vector::const_iterator i=conditions.begin(); ++i!=conditions.end(); ) + { + const std::vector &v = static_cast *>(*i)->values; + if(!result) + result = new ChoiceCondition(v); + else + result->values.insert(result->values.end(), v.begin(), v.end()); + } + return result; + } + else + return 0; } template -void ChoiceCondition::add_merged_lines(const std::vector &conditions, const CompoundCondition &parent, std::list &st) const +void ChoiceCondition::add_lines(std::list &st) const { - if(dynamic_cast(&parent)) - { - std::string line = Traits::get_keyword(); - for(std::vector::const_iterator i=conditions.begin(); i!=conditions.end(); ++i) - line += Msp::format(" \"%s\"", static_cast *>(*i)->value); - FilterStatement::add_line(st, line); - } + std::string line = Traits::get_keyword(); + for(typename std::vector::const_iterator i=values.begin(); i!=values.end(); ++i) + line += Msp::format(" \"%s\"", *i); + FilterStatement::add_line(st, line); } #endif diff --git a/source/condition.cpp b/source/condition.cpp index be5a29f..42e9ee8 100644 --- a/source/condition.cpp +++ b/source/condition.cpp @@ -21,6 +21,76 @@ void CompoundCondition::add(Condition *cond) conditions.push_back(cond); } +const Condition *CompoundCondition::get(unsigned i) const +{ + if(i>=conditions.size()) + throw out_of_range("CompoundCondition::get"); + return conditions[i]; +} + +Condition *CompoundCondition::flatten() const +{ + if(conditions.empty()) + return 0; + else if(conditions.size()==1) + return conditions.front()->clone(); + + bool merge = true; + for(vector::const_iterator i=conditions.begin(); (merge && ++i!=conditions.end()); ) + merge = conditions.front()->can_merge(**i, *this); + + if(merge) + return conditions.front()->merge(conditions, *this); + else + { + Condition *result = 0; + for(vector::const_iterator i=conditions.begin(); i!=conditions.end(); ++i) + { + Condition *sub = (*i)->flatten(); + if(!result) + result = sub; + else + result = dispatch_flatten(result, sub); + } + + return result; + } +} + +Condition *CompoundCondition::dispatch_flatten(Condition *cond1, Condition *cond2) const +{ + OrCondition *or1 = dynamic_cast(cond1); + AndCondition *and1 = dynamic_cast(cond1); + OrCondition *or2 = dynamic_cast(cond2); + AndCondition *and2 = dynamic_cast(cond2); + if(or1 || or2) + { + if(or1 && or2) + return flatten(or1, or2); + else if(or1 && and2) + return flatten(or1, and2); + else if(or2 && and1) + return flatten(or2, and1); + else if(or1) + return flatten(or1, cond2); + else if(or2) + return flatten(or2, cond1); + } + else if(and1 || and2) + { + if(and1 && and2) + return flatten(and1, and2); + else if(and1) + return flatten(and1, cond2); + else if(and2) + return flatten(and2, cond1); + } + else + return flatten(cond1, cond2); + + throw logic_error("CompoundCondition::dispatch_flatten"); +} + AndCondition *AndCondition::clone() const { @@ -29,6 +99,57 @@ AndCondition *AndCondition::clone() const return result; } +Condition *AndCondition::flatten(Condition *cond1, Condition *cond2) const +{ + AndCondition *result = new AndCondition; + result->add(cond1); + result->add(cond2); + return result; +} + +Condition *AndCondition::flatten(AndCondition *cond1, Condition *cond2) const +{ + cond1->add(cond2); + return cond1; +} + +Condition *AndCondition::flatten(AndCondition *cond1, AndCondition *cond2) const +{ + unsigned count2 = cond2->count(); + for(unsigned i=0; iadd(cond2->get(i)->clone()); + delete cond2; + return cond1; +} + +Condition *AndCondition::flatten(OrCondition *cond1, Condition *cond2) const +{ + OrCondition *result = new OrCondition; + unsigned count = cond1->count(); + for(unsigned i=0; iadd(dispatch_flatten(cond1->get(i)->clone(), (i+1clone() : cond2))); + delete cond1; + return result; +} + +Condition *AndCondition::flatten(OrCondition *cond1, AndCondition *cond2) const +{ + return flatten(cond1, static_cast(cond2)); +} + +Condition *AndCondition::flatten(OrCondition *cond1, OrCondition *cond2) const +{ + unsigned count1 = cond1->count(); + unsigned count2 = cond2->count(); + OrCondition *result = new OrCondition; + for(unsigned i=0; iadd(dispatch_flatten(cond1->get(i)->clone(), cond2->get(j)->clone())); + delete cond1; + delete cond2; + return result; +} + void AndCondition::add_lines(list &st) const { for(vector::const_iterator i=conditions.begin(); i!=conditions.end(); ++i) @@ -43,25 +164,54 @@ OrCondition *OrCondition::clone() const return result; } -void OrCondition::add_lines(list &st) const +Condition *OrCondition::flatten(Condition *cond1, Condition *cond2) const { - bool merge = conditions.size()>1; - for(vector::const_iterator i=conditions.begin(); (merge && ++i!=conditions.end()); ) - merge = conditions.front()->can_merge(**i, *this); + OrCondition *result = new OrCondition; + result->add(cond1); + result->add(cond2); + return result; +} - if(merge) - conditions.front()->add_merged_lines(conditions, *this, st); - else +Condition *OrCondition::flatten(AndCondition *cond1, Condition *cond2) const +{ + return flatten(static_cast(cond1), cond2); +} + +Condition *OrCondition::flatten(AndCondition *cond1, AndCondition *cond2) const +{ + return flatten(static_cast(cond1), static_cast(cond2)); +} + +Condition *OrCondition::flatten(OrCondition *cond1, Condition *cond2) const +{ + cond1->add(cond2); + return cond1; +} + +Condition *OrCondition::flatten(OrCondition *cond1, AndCondition *cond2) const +{ + return flatten(cond1, static_cast(cond2)); +} + +Condition *OrCondition::flatten(OrCondition *cond1, OrCondition *cond2) const +{ + unsigned count2 = cond2->count(); + for(unsigned i=0; iadd(cond2->get(i)->clone()); + delete cond2; + return cond1; +} + +void OrCondition::add_lines(list &st) const +{ + list result; + for(vector::const_iterator i=conditions.begin(); i!=conditions.end(); ++i) { - list result; - for(vector::const_iterator i=conditions.begin(); i!=conditions.end(); ++i) - { - list sub_result = st; - (*i)->add_lines(sub_result); - result.splice(result.end(), sub_result); - } - swap(result, st); + list sub_result = st; + (*i)->add_lines(sub_result); + result.splice(result.end(), sub_result); } + swap(result, st); } diff --git a/source/condition.h b/source/condition.h index 53f2a8a..141e570 100644 --- a/source/condition.h +++ b/source/condition.h @@ -18,12 +18,16 @@ public: virtual ~Condition() { } virtual Condition *clone() const = 0; + virtual Condition *flatten() const { return clone(); } virtual bool can_merge(const Condition &, const CompoundCondition &) const { return false; } + virtual Condition *merge(const std::vector &, const CompoundCondition &) const { return 0; } virtual void add_lines(std::list &) const = 0; - virtual void add_merged_lines(const std::vector &, const CompoundCondition &, std::list &) const { } }; +class AndCondition; +class OrCondition; + class CompoundCondition: public Condition { protected: @@ -37,6 +41,18 @@ protected: public: void add(Condition *); + unsigned count() const { return conditions.size(); } + const Condition *get(unsigned) const; + + virtual Condition *flatten() const; +protected: + Condition *dispatch_flatten(Condition *, Condition *) const; + virtual Condition *flatten(Condition *, Condition *) const = 0; + virtual Condition *flatten(AndCondition *, Condition *) const = 0; + virtual Condition *flatten(AndCondition *, AndCondition *) const = 0; + virtual Condition *flatten(OrCondition *, Condition *) const = 0; + virtual Condition *flatten(OrCondition *, AndCondition *) const = 0; + virtual Condition *flatten(OrCondition *, OrCondition *) const = 0; }; @@ -44,6 +60,14 @@ class AndCondition: public CompoundCondition { public: virtual AndCondition *clone() const; +protected: + virtual Condition *flatten(Condition *, Condition *) const; + virtual Condition *flatten(AndCondition *, Condition *) const; + virtual Condition *flatten(AndCondition *, AndCondition *) const; + virtual Condition *flatten(OrCondition *, Condition *) const; + virtual Condition *flatten(OrCondition *, AndCondition *) const; + virtual Condition *flatten(OrCondition *, OrCondition *) const; +public: virtual void add_lines(std::list &) const; }; @@ -52,6 +76,14 @@ class OrCondition: public CompoundCondition { public: virtual OrCondition *clone() const; +protected: + virtual Condition *flatten(Condition *, Condition *) const; + virtual Condition *flatten(AndCondition *, Condition *) const; + virtual Condition *flatten(AndCondition *, AndCondition *) const; + virtual Condition *flatten(OrCondition *, Condition *) const; + virtual Condition *flatten(OrCondition *, AndCondition *) const; + virtual Condition *flatten(OrCondition *, OrCondition *) const; +public: virtual void add_lines(std::list &) const; };