X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fcondition.cpp;h=5978250243f6e51b6fb1ebadeadbbd401f5003bf;hb=HEAD;hp=12ee7301a33dd21a1ab9387089665a32024fb2e6;hpb=fc27eb63c05d915d606e17992ecd5b7f68478101;p=poefilter.git diff --git a/source/condition.cpp b/source/condition.cpp index 12ee730..5978250 100644 --- a/source/condition.cpp +++ b/source/condition.cpp @@ -6,62 +6,409 @@ using namespace Msp; CompoundCondition::~CompoundCondition() { - for(list::const_iterator i=conditions.begin(); i!=conditions.end(); ++i) + for(vector::const_iterator i=conditions.begin(); i!=conditions.end(); ++i) delete *i; } void CompoundCondition::clone_to(CompoundCondition &other) const { - for(list::const_iterator i=conditions.begin(); i!=conditions.end(); ++i) + for(vector::const_iterator i=conditions.begin(); i!=conditions.end(); ++i) other.add((*i)->clone()); } +bool CompoundCondition::sub_equals(const CompoundCondition &other) const +{ + if(other.count()!=conditions.size()) + return false; + + for(unsigned i=0; iequals(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 *AndCondition::clone() const +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) + { + vector merge_conds(conditions.begin(), conditions.end()); + return conditions.front()->merge(merge_conds, *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 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(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"); +} + +Condition *CompoundCondition::merge_two(Condition *cond1, Condition *cond2, const CompoundCondition &parent, bool del) +{ + vector 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::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::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; } +bool AndCondition::equals(const Condition &other) const +{ + const AndCondition *other_and = dynamic_cast(&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; iget(i).clone(), (i+1clone() : 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(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; iget(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(&other); + if(!other_and || !dynamic_cast(&parent)) + return false; + + return merge(*this, *other_and, parent, 0); +} + +AndCondition *AndCondition::merge(const vector &conds, const CompoundCondition &parent) const +{ + if(conds.size()!=2) + return 0; + + const AndCondition *and1 = dynamic_cast(conds[0]); + const AndCondition *and2 = dynamic_cast(conds[1]); + if(!and1 || !and2 || !dynamic_cast(&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 used(cond1.count(), false); + for(unsigned i=0; i=0) + used[match] = true; + else if(merge1<0) + merge1 = i; + else + return false; + } + + if(merge1>=0) + { + vector merge_conds(2, 0); + merge_conds[0] = &cond1.get(merge1); + for(unsigned i=0; (!merge_conds[1] && ican_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; iadd(cond2.get(i).clone()); + } + + return true; +} + +bool AndCondition::is_viable() const +{ + for(vector::const_iterator i=conditions.begin(); i!=conditions.end(); ++i) + if(!(*i)->is_viable()) + return false; + return !conditions.empty(); +} + void AndCondition::add_lines(list &st) const { - for(list::const_iterator i=conditions.begin(); i!=conditions.end(); ++i) + for(vector::const_iterator i=conditions.begin(); i!=conditions.end(); ++i) (*i)->add_lines(st); } -Condition *OrCondition::clone() const +OrCondition *OrCondition::clone() const { OrCondition *result = new OrCondition; clone_to(*result); return result; } -void OrCondition::add_lines(list &st) const +bool OrCondition::equals(const Condition &other) const { - bool merge = conditions.size()>1; - for(list::const_iterator i=conditions.begin(); (merge && ++i!=conditions.end()); ) - merge = conditions.front()->can_merge(**i, *this); + const OrCondition *other_or = dynamic_cast(&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(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 +{ + return add_merged_to(cond2, cond1, true); +} + +Condition *OrCondition::flatten(OrCondition *cond1, AndCondition *cond2) const +{ + return flatten(cond1, static_cast(cond2)); +} + +Condition *OrCondition::flatten(OrCondition *cond1, OrCondition *cond2) const +{ + return merge_contents_to(cond2, cond1); +} + +bool OrCondition::is_viable() const +{ + for(vector::const_iterator i=conditions.begin(); i!=conditions.end(); ++i) + if((*i)->is_viable()) + return true; + return false; +} + +void OrCondition::add_lines(list &st) const +{ + list result; + for(vector::const_iterator i=conditions.begin(); i!=conditions.end(); ++i) { - list result; - for(list::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); } @@ -69,11 +416,28 @@ LinkedColorsCondition::LinkedColorsCondition(const Colors &c): colors(c) { } -Condition *LinkedColorsCondition::clone() const +LinkedColorsCondition *LinkedColorsCondition::clone() const { return new LinkedColorsCondition(colors); } +bool LinkedColorsCondition::equals(const Condition &other) const +{ + const LinkedColorsCondition *other_linked = dynamic_cast(&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 &st) const { FilterStatement::add_line(st, format("SocketGroup %s", colors.colors));