other.add((*i)->clone());
}
+bool CompoundCondition::sub_equals(const CompoundCondition &other) const
+{
+ if(other.count()!=conditions.size())
+ return false;
+
+ for(unsigned i=0; i<conditions.size(); ++i)
+ if(!conditions[i]->equals(other.get(i)))
+ return false;
+
+ return true;
+}
+
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, const CompoundCondition &parent, bool del)
+{
+ vector<const Condition *> parts(2);
+ parts[0] = cond1;
+ parts[1] = cond2;
+ Condition *result = cond1->merge(parts, parent);
+
+ 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)
+{
+ 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, *target, 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)
+{
+ 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
{
return result;
}
+bool AndCondition::equals(const Condition &other) const
+{
+ const AndCondition *other_and = dynamic_cast<const AndCondition *>(&other);
+ return (other_and ? sub_equals(*other_and) : false);
+}
+
+Condition *AndCondition::flatten(Condition *cond1, Condition *cond2) const
+{
+ if(cond1->can_merge(*cond2, *this))
+ return merge_two(cond1, cond2, *this, 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)))
+ add_merged_to(sub, result, true);
+ 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()))
+ add_merged_to(sub, result, true);
+
+ delete cond1;
+ delete cond2;
+
+ if(result->is_viable())
+ return result;
+
+ delete result;
+ return 0;
+}
+
+bool AndCondition::can_merge(const Condition &other, const CompoundCondition &parent) const
+{
+ const AndCondition *other_and = dynamic_cast<const AndCondition *>(&other);
+ if(!other_and || !dynamic_cast<const OrCondition *>(&parent))
+ return false;
+
+ return merge(*this, *other_and, parent, 0);
+}
+
+AndCondition *AndCondition::merge(const vector<const Condition *> &conds, const CompoundCondition &parent) const
+{
+ if(conds.size()!=2)
+ return 0;
+
+ const AndCondition *and1 = dynamic_cast<const AndCondition *>(conds[0]);
+ const AndCondition *and2 = dynamic_cast<const AndCondition *>(conds[1]);
+ if(!and1 || !and2 || !dynamic_cast<const OrCondition *>(&parent))
+ return 0;
+
+ AndCondition *result = 0;
+ merge(*and1, *and2, parent, &result);
+ return result;
+}
+
+bool AndCondition::merge(const AndCondition &cond1, const AndCondition &cond2, const CompoundCondition &parent, AndCondition **result)
+{
+ if(cond1.count()!=cond2.count())
+ return false;
+
+ int merge1 = -1;
+ vector<bool> used(cond1.count(), false);
+ for(unsigned i=0; i<cond1.count(); ++i)
+ {
+ int match = -1;
+ for(unsigned j=0; (match<0 && j<cond2.count()); ++j)
+ if(!used[j] && cond1.get(i).equals(cond2.get(j)))
+ match = j;
+
+ if(match>=0)
+ used[match] = true;
+ else if(merge1<0)
+ merge1 = i;
+ else
+ return false;
+ }
+
+ if(merge1>=0)
+ {
+ vector<const Condition *> merge_conds(2, 0);
+ merge_conds[0] = &cond1.get(merge1);
+ for(unsigned i=0; (!merge_conds[1] && i<cond2.count()); ++i)
+ if(!used[i])
+ merge_conds[1] = &cond2.get(i);
+
+ if(!merge_conds[1] || !merge_conds[0]->can_merge(*merge_conds[1], parent))
+ return false;
+
+ if(result)
+ {
+ *result = new AndCondition;
+ (*result)->add(merge_conds[0]->merge(merge_conds, parent));
+ }
+ }
+ else if(result)
+ *result = new AndCondition;
+
+ if(result)
+ {
+ for(unsigned i=0; i<cond2.count(); ++i)
+ if(used[i])
+ (*result)->add(cond2.get(i).clone());
+ }
+
+ return true;
+}
+
+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)
return result;
}
-void OrCondition::add_lines(list<FilterStatement> &st) const
+bool OrCondition::equals(const Condition &other) 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);
+ const OrCondition *other_or = dynamic_cast<const OrCondition *>(&other);
+ return (other_or ? sub_equals(*other_or) : false);
+}
- if(merge)
- conditions.front()->add_merged_lines(conditions, *this, st);
- else
+Condition *OrCondition::flatten(Condition *cond1, Condition *cond2) const
+{
+ if(cond1->can_merge(*cond2, *this))
+ return merge_two(cond1, cond2, *this, true);
+
+ 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);
}
return new LinkedColorsCondition(colors);
}
+bool LinkedColorsCondition::equals(const Condition &other) const
+{
+ const LinkedColorsCondition *other_linked = dynamic_cast<const LinkedColorsCondition *>(&other);
+ if(!other_linked)
+ return false;
+
+ for(unsigned i=0; i<7; ++i)
+ {
+ if(colors.colors[i]!=other_linked->colors.colors[i])
+ return false;
+ if(!colors.colors[i])
+ break;
+ }
+
+ return true;
+}
+
void LinkedColorsCondition::add_lines(list<FilterStatement> &st) const
{
FilterStatement::add_line(st, format("SocketGroup %s", colors.colors));