]> git.tdb.fi Git - poefilter.git/blobdiff - source/condition.cpp
Tighten some parameters and return values
[poefilter.git] / source / condition.cpp
index 9ff02aa322db9f93bbf8ce6f623a1471666d51cd..1ff316c361f76f51d6f0c13db000cd21a4b621f1 100644 (file)
@@ -18,17 +18,229 @@ void CompoundCondition::clone_to(CompoundCondition &other) const
 
 void CompoundCondition::add(Condition *cond)
 {
+       if(!cond)
+               throw invalid_argument("CompoundCondition::add");
        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)
+       {
+               vector<const Condition *> merge_conds(conditions.begin(), conditions.end());
+               return conditions.front()->merge(merge_conds, *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 if(sub)
+                               result = dispatch_flatten(result, sub);
+               }
+
+               if(result && result->is_viable())
+                       return result;
+
+               delete result;
+               return 0;
+       }
+}
+
+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");
+}
+
+Condition *CompoundCondition::merge_two(Condition *cond1, Condition *cond2, bool del) const
+{
+       vector<const Condition *> parts(2);
+       parts[0] = cond1;
+       parts[1] = cond2;
+       Condition *result = cond1->merge(parts, *this);
 
-Condition *AndCondition::clone() const
+       if(del)
+       {
+               delete cond1;
+               delete cond2;
+
+               if(!result->is_viable())
+               {
+                       delete result;
+                       return 0;
+               }
+       }
+
+       return result;
+}
+
+Condition *CompoundCondition::add_merged_to(Condition *cond, CompoundCondition *target, bool del) const
+{
+       bool merged = false;
+       for(vector<Condition *>::iterator i=target->conditions.begin(); i!=target->conditions.end(); ++i)
+               if((*i)->can_merge(*cond, *target))
+               {
+                       Condition *m = merge_two(cond, *i, false);
+                       delete *i;
+                       if(del)
+                               delete cond;
+                       *i = m;
+                       merged = true;
+                       break;
+               }
+
+       if(!merged)
+               target->add(del ? cond : cond->clone());
+
+       if(del && !target->is_viable())
+       {
+               delete target;
+               return 0;
+       }
+
+       return target;
+}
+
+Condition *CompoundCondition::merge_contents_to(CompoundCondition *cond, CompoundCondition *target) const
+{
+       for(vector<Condition *>::iterator i=cond->conditions.begin(); i!=cond->conditions.end(); ++i)
+               add_merged_to(*i, target, false);
+
+       delete cond;
+
+       if(target->is_viable())
+               return target;
+
+       delete target;
+       return 0;
+}
+
+
+AndCondition *AndCondition::clone() const
 {
        AndCondition *result = new AndCondition;
        clone_to(*result);
        return result;
 }
 
+Condition *AndCondition::flatten(Condition *cond1, Condition *cond2) const
+{
+       if(cond1->can_merge(*cond2, *this))
+               return merge_two(cond1, cond2, true);
+
+       AndCondition *result = new AndCondition;
+       result->add(cond1);
+       result->add(cond2);
+       return result;
+}
+
+Condition *AndCondition::flatten(AndCondition *cond1, Condition *cond2) const
+{
+       return add_merged_to(cond2, cond1, true);
+}
+
+Condition *AndCondition::flatten(AndCondition *cond1, AndCondition *cond2) const
+{
+       return merge_contents_to(cond2, cond1);
+}
+
+Condition *AndCondition::flatten(OrCondition *cond1, Condition *cond2) const
+{
+       OrCondition *result = new OrCondition;
+       unsigned count = cond1->count();
+       for(unsigned i=0; i<count; ++i)
+               if(Condition *sub = dispatch_flatten(cond1->get(i).clone(), (i+1<count ? cond2->clone() : cond2)))
+                       result->add(sub);
+       delete cond1;
+
+       if(result->is_viable())
+               return result;
+
+       delete result;
+       return 0;
+}
+
+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)
+                       if(Condition *sub = dispatch_flatten(cond1->get(i).clone(), cond2->get(j).clone()))
+                               result->add(sub);
+
+       delete cond1;
+       delete cond2;
+
+       if(result->is_viable())
+               return result;
+
+       delete result;
+       return 0;
+}
+
+bool AndCondition::is_viable() const
+{
+       for(vector<Condition *>::const_iterator i=conditions.begin(); i!=conditions.end(); ++i)
+               if(!(*i)->is_viable())
+                       return false;
+       return !conditions.empty();
+}
+
 void AndCondition::add_lines(list<FilterStatement> &st) const
 {
        for(vector<Condition *>::const_iterator i=conditions.begin(); i!=conditions.end(); ++i)
@@ -36,32 +248,67 @@ void AndCondition::add_lines(list<FilterStatement> &st) const
 }
 
 
-Condition *OrCondition::clone() const
+OrCondition *OrCondition::clone() const
 {
        OrCondition *result = new OrCondition;
        clone_to(*result);
        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);
+       if(cond1->can_merge(*cond2, *this))
+               return merge_two(cond1, cond2, true);
 
-       if(merge)
-               conditions.front()->add_merged_lines(conditions, *this, st);
-       else
+       OrCondition *result = new OrCondition;
+       result->add(cond1);
+       result->add(cond2);
+       return result;
+}
+
+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
+{
+       return add_merged_to(cond2, cond1, true);
+}
+
+Condition *OrCondition::flatten(OrCondition *cond1, AndCondition *cond2) const
+{
+       return flatten(cond1, static_cast<Condition *>(cond2));
+}
+
+Condition *OrCondition::flatten(OrCondition *cond1, OrCondition *cond2) const
+{
+       return merge_contents_to(cond2, cond1);
+}
+
+bool OrCondition::is_viable() const
+{
+       for(vector<Condition *>::const_iterator i=conditions.begin(); i!=conditions.end(); ++i)
+               if((*i)->is_viable())
+                       return true;
+       return false;
+}
+
+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);
 }
 
 
@@ -69,7 +316,7 @@ LinkedColorsCondition::LinkedColorsCondition(const Colors &c):
        colors(c)
 { }
 
-Condition *LinkedColorsCondition::clone() const
+LinkedColorsCondition *LinkedColorsCondition::clone() const
 {
        return new LinkedColorsCondition(colors);
 }