]> git.tdb.fi Git - poefilter.git/commitdiff
Rework condition merging
authorMikko Rasa <tdb@tdb.fi>
Wed, 15 Aug 2018 21:03:36 +0000 (00:03 +0300)
committerMikko Rasa <tdb@tdb.fi>
Wed, 15 Aug 2018 21:55:44 +0000 (00:55 +0300)
The condition tree is now actually flattened and adjacent similar
conditions merged rather than just producing special output.

source/category.cpp
source/choicecondition.h
source/condition.cpp
source/condition.h

index fb12fec0ddfd25fa0dc14996b80e780af62507ae..5e454bb9dc7af7dcef5843efa9b4a3b96761404c 100644 (file)
@@ -47,7 +47,11 @@ void Category::create_statements(list<FilterStatement> &st) const
                st.push_back(FilterStatement());
 
        if(condition)
-               condition->add_lines(st);
+       {
+               Condition *flat = condition->flatten();
+               flat->add_lines(st);
+               delete flat;
+       }
 }
 
 
index 170af0e0634a27c4615eb6d5b35e1db8c6168601..424dca6a8fce12be193e6a9fb02f8048db309a7a 100644 (file)
@@ -12,15 +12,16 @@ public:
        typedef typename Traits::Type Type;
 
 private:
-       Type value;
+       std::vector<Type> values;
 
 public:
        ChoiceCondition(Type);
+       ChoiceCondition(const std::vector<Type> &);
 
        virtual ChoiceCondition<T> *clone() const;
        virtual bool can_merge(const Condition &, const CompoundCondition &) const;
+       virtual ChoiceCondition<T> *merge(const std::vector<Condition *> &, const CompoundCondition &) const;
        virtual void add_lines(std::list<FilterStatement> &) const;
-       virtual void add_merged_lines(const std::vector<Condition *> &, const CompoundCondition &, std::list<FilterStatement> &) const;
 };
 
 
@@ -43,14 +44,20 @@ typedef ChoiceCondition<BaseTypeTraits> BaseTypeCondition;
 
 
 template<typename T>
-ChoiceCondition<T>::ChoiceCondition(Type v):
-       value(v)
+ChoiceCondition<T>::ChoiceCondition(Type v)
+{
+       values.push_back(v);
+}
+
+template<typename T>
+ChoiceCondition<T>::ChoiceCondition(const std::vector<Type> &v):
+       values(v)
 { }
 
 template<typename T>
 ChoiceCondition<T> *ChoiceCondition<T>::clone() const
 {
-       return new ChoiceCondition<T>(value);
+       return new ChoiceCondition<T>(values);
 }
 
 template<typename T>
@@ -60,22 +67,32 @@ bool ChoiceCondition<T>::can_merge(const Condition &other, const CompoundConditi
 }
 
 template<typename T>
-void ChoiceCondition<T>::add_lines(std::list<FilterStatement> &st) const
+ChoiceCondition<T> *ChoiceCondition<T>::merge(const std::vector<Condition *> &conditions, const CompoundCondition &parent) const
 {
-       const char *keyword = Traits::get_keyword();
-       FilterStatement::add_line(st, Msp::format("%s \"%s\"", keyword, value));
+       if(dynamic_cast<const OrCondition *>(&parent) && !conditions.empty())
+       {
+               ChoiceCondition<T> *result = 0;
+               for(std::vector<Condition *>::const_iterator i=conditions.begin(); ++i!=conditions.end(); )
+               {
+                       const std::vector<Type> &v = static_cast<ChoiceCondition<T> *>(*i)->values;
+                       if(!result)
+                               result = new ChoiceCondition<T>(v);
+                       else
+                               result->values.insert(result->values.end(), v.begin(), v.end());
+               }
+               return result;
+       }
+       else
+               return 0;
 }
 
 template<typename T>
-void ChoiceCondition<T>::add_merged_lines(const std::vector<Condition *> &conditions, const CompoundCondition &parent, std::list<FilterStatement> &st) const
+void ChoiceCondition<T>::add_lines(std::list<FilterStatement> &st) const
 {
-       if(dynamic_cast<const OrCondition *>(&parent))
-       {
-               std::string line = Traits::get_keyword();
-               for(std::vector<Condition *>::const_iterator i=conditions.begin(); i!=conditions.end(); ++i)
-                       line += Msp::format(" \"%s\"", static_cast<const ChoiceCondition<Traits> *>(*i)->value);
-               FilterStatement::add_line(st, line);
-       }
+       std::string line = Traits::get_keyword();
+       for(typename std::vector<Type>::const_iterator i=values.begin(); i!=values.end(); ++i)
+               line += Msp::format(" \"%s\"", *i);
+       FilterStatement::add_line(st, line);
 }
 
 #endif
index be5a29f4d11df67cf5785a5938514574701d48b4..42e9ee8f3f1360829d2b518d9d22e99a569f0a69 100644 (file)
@@ -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<Condition *>::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<Condition *>::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<OrCondition *>(cond1);
+       AndCondition *and1 = dynamic_cast<AndCondition *>(cond1);
+       OrCondition *or2 = dynamic_cast<OrCondition *>(cond2);
+       AndCondition *and2 = dynamic_cast<AndCondition *>(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; i<count2; ++i)
+               cond1->add(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; i<count; ++i)
+               result->add(dispatch_flatten(cond1->get(i)->clone(), (i+1<count ? cond2->clone() : cond2)));
+       delete cond1;
+       return result;
+}
+
+Condition *AndCondition::flatten(OrCondition *cond1, AndCondition *cond2) const
+{
+       return flatten(cond1, static_cast<Condition *>(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; i<count1; ++i)
+               for(unsigned j=0; j<count2; ++j)
+                       result->add(dispatch_flatten(cond1->get(i)->clone(), cond2->get(j)->clone()));
+       delete cond1;
+       delete cond2;
+       return result;
+}
+
 void AndCondition::add_lines(list<FilterStatement> &st) const
 {
        for(vector<Condition *>::const_iterator i=conditions.begin(); i!=conditions.end(); ++i)
@@ -43,25 +164,54 @@ OrCondition *OrCondition::clone() const
        return result;
 }
 
-void OrCondition::add_lines(list<FilterStatement> &st) const
+Condition *OrCondition::flatten(Condition *cond1, Condition *cond2) const
 {
-       bool merge = conditions.size()>1;
-       for(vector<Condition *>::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<Condition *>(cond1), cond2);
+}
+
+Condition *OrCondition::flatten(AndCondition *cond1, AndCondition *cond2) const
+{
+       return flatten(static_cast<Condition *>(cond1), static_cast<Condition *>(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<Condition *>(cond2));
+}
+
+Condition *OrCondition::flatten(OrCondition *cond1, OrCondition *cond2) const
+{
+       unsigned count2 = cond2->count();
+       for(unsigned i=0; i<count2; ++i)
+               cond1->add(cond2->get(i)->clone());
+       delete cond2;
+       return cond1;
+}
+
+void OrCondition::add_lines(list<FilterStatement> &st) const
+{
+       list<FilterStatement> result;
+       for(vector<Condition *>::const_iterator i=conditions.begin(); i!=conditions.end(); ++i)
        {
-               list<FilterStatement> result;
-               for(vector<Condition *>::const_iterator i=conditions.begin(); i!=conditions.end(); ++i)
-               {
-                       list<FilterStatement> sub_result = st;
-                       (*i)->add_lines(sub_result);
-                       result.splice(result.end(), sub_result);
-               }
-               swap(result, st);
+               list<FilterStatement> sub_result = st;
+               (*i)->add_lines(sub_result);
+               result.splice(result.end(), sub_result);
        }
+       swap(result, st);
 }
 
 
index 53f2a8a8268be8e0248f76d41a1032b8a89516b7..141e57094cfd666a3b789b889329dbec50b2c1ed 100644 (file)
@@ -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<Condition *> &, const CompoundCondition &) const { return 0; }
        virtual void add_lines(std::list<FilterStatement> &) const = 0;
-       virtual void add_merged_lines(const std::vector<Condition *> &, const CompoundCondition &, std::list<FilterStatement> &) 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<FilterStatement> &) 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<FilterStatement> &) const;
 };