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;
};
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>
}
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
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
{
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)
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);
}
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:
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;
};
{
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;
};
{
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;
};