void CompoundCondition::add(Condition *cond)
{
+ if(!cond)
+ throw invalid_argument("CompoundCondition::add");
conditions.push_back(cond);
}
-const Condition *CompoundCondition::get(unsigned i) const
+const Condition &CompoundCondition::get(unsigned i) const
{
if(i>=conditions.size())
throw out_of_range("CompoundCondition::get");
- return conditions[i];
+ return *conditions[i];
}
Condition *CompoundCondition::flatten() const
merge = conditions.front()->can_merge(**i, *this);
if(merge)
- return conditions.front()->merge(conditions, *this);
+ {
+ vector<const Condition *> merge_conds(conditions.begin(), conditions.end());
+ return conditions.front()->merge(merge_conds, *this);
+ }
else
{
Condition *result = 0;
Condition *sub = (*i)->flatten();
if(!result)
result = sub;
- else
+ else if(sub)
result = dispatch_flatten(result, sub);
}
- return result;
+ if(result && result->is_viable())
+ return result;
+
+ delete result;
+ return 0;
}
}
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
{
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);
Condition *AndCondition::flatten(AndCondition *cond1, Condition *cond2) const
{
- cond1->add(cond2);
- return cond1;
+ return add_merged_to(cond2, cond1, true);
}
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;
+ 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)
- result->add(dispatch_flatten(cond1->get(i)->clone(), (i+1<count ? cond2->clone() : cond2)));
+ if(Condition *sub = dispatch_flatten(cond1->get(i).clone(), (i+1<count ? cond2->clone() : cond2)))
+ result->add(sub);
delete cond1;
- return result;
+
+ if(result->is_viable())
+ return result;
+
+ delete result;
+ return 0;
}
Condition *AndCondition::flatten(OrCondition *cond1, AndCondition *cond2) const
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()));
+ if(Condition *sub = dispatch_flatten(cond1->get(i).clone(), cond2->get(j).clone()))
+ result->add(sub);
+
delete cond1;
delete cond2;
- return result;
+
+ 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
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);
Condition *OrCondition::flatten(OrCondition *cond1, Condition *cond2) const
{
- cond1->add(cond2);
- return cond1;
+ return add_merged_to(cond2, cond1, true);
}
Condition *OrCondition::flatten(OrCondition *cond1, AndCondition *cond2) const
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;
+ 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