]> git.tdb.fi Git - poefilter.git/blob - source/condition.cpp
Rework condition merging
[poefilter.git] / source / condition.cpp
1 #include "condition.h"
2 #include "filter.h"
3
4 using namespace std;
5 using namespace Msp;
6
7 CompoundCondition::~CompoundCondition()
8 {
9         for(vector<Condition *>::const_iterator i=conditions.begin(); i!=conditions.end(); ++i)
10                 delete *i;
11 }
12
13 void CompoundCondition::clone_to(CompoundCondition &other) const
14 {
15         for(vector<Condition *>::const_iterator i=conditions.begin(); i!=conditions.end(); ++i)
16                 other.add((*i)->clone());
17 }
18
19 void CompoundCondition::add(Condition *cond)
20 {
21         conditions.push_back(cond);
22 }
23
24 const Condition *CompoundCondition::get(unsigned i) const
25 {
26         if(i>=conditions.size())
27                 throw out_of_range("CompoundCondition::get");
28         return conditions[i];
29 }
30
31 Condition *CompoundCondition::flatten() const
32 {
33         if(conditions.empty())
34                 return 0;
35         else if(conditions.size()==1)
36                 return conditions.front()->clone();
37
38         bool merge = true;
39         for(vector<Condition *>::const_iterator i=conditions.begin(); (merge && ++i!=conditions.end()); )
40                 merge = conditions.front()->can_merge(**i, *this);
41
42         if(merge)
43                 return conditions.front()->merge(conditions, *this);
44         else
45         {
46                 Condition *result = 0;
47                 for(vector<Condition *>::const_iterator i=conditions.begin(); i!=conditions.end(); ++i)
48                 {
49                         Condition *sub = (*i)->flatten();
50                         if(!result)
51                                 result = sub;
52                         else
53                                 result = dispatch_flatten(result, sub);
54                 }
55
56                 return result;
57         }
58 }
59
60 Condition *CompoundCondition::dispatch_flatten(Condition *cond1, Condition *cond2) const
61 {
62         OrCondition *or1 = dynamic_cast<OrCondition *>(cond1);
63         AndCondition *and1 = dynamic_cast<AndCondition *>(cond1);
64         OrCondition *or2 = dynamic_cast<OrCondition *>(cond2);
65         AndCondition *and2 = dynamic_cast<AndCondition *>(cond2);
66         if(or1 || or2)
67         {
68                 if(or1 && or2)
69                         return flatten(or1, or2);
70                 else if(or1 && and2)
71                         return flatten(or1, and2);
72                 else if(or2 && and1)
73                         return flatten(or2, and1);
74                 else if(or1)
75                         return flatten(or1, cond2);
76                 else if(or2)
77                         return flatten(or2, cond1);
78         }
79         else if(and1 || and2)
80         {
81                 if(and1 && and2)
82                         return flatten(and1, and2);
83                 else if(and1)
84                         return flatten(and1, cond2);
85                 else if(and2)
86                         return flatten(and2, cond1);
87         }
88         else
89                 return flatten(cond1, cond2);
90
91         throw logic_error("CompoundCondition::dispatch_flatten");
92 }
93
94
95 AndCondition *AndCondition::clone() const
96 {
97         AndCondition *result = new AndCondition;
98         clone_to(*result);
99         return result;
100 }
101
102 Condition *AndCondition::flatten(Condition *cond1, Condition *cond2) const
103 {
104         AndCondition *result = new AndCondition;
105         result->add(cond1);
106         result->add(cond2);
107         return result;
108 }
109
110 Condition *AndCondition::flatten(AndCondition *cond1, Condition *cond2) const
111 {
112         cond1->add(cond2);
113         return cond1;
114 }
115
116 Condition *AndCondition::flatten(AndCondition *cond1, AndCondition *cond2) const
117 {
118         unsigned count2 = cond2->count();
119         for(unsigned i=0; i<count2; ++i)
120                 cond1->add(cond2->get(i)->clone());
121         delete cond2;
122         return cond1;
123 }
124
125 Condition *AndCondition::flatten(OrCondition *cond1, Condition *cond2) const
126 {
127         OrCondition *result = new OrCondition;
128         unsigned count = cond1->count();
129         for(unsigned i=0; i<count; ++i)
130                 result->add(dispatch_flatten(cond1->get(i)->clone(), (i+1<count ? cond2->clone() : cond2)));
131         delete cond1;
132         return result;
133 }
134
135 Condition *AndCondition::flatten(OrCondition *cond1, AndCondition *cond2) const
136 {
137         return flatten(cond1, static_cast<Condition *>(cond2));
138 }
139
140 Condition *AndCondition::flatten(OrCondition *cond1, OrCondition *cond2) const
141 {
142         unsigned count1 = cond1->count();
143         unsigned count2 = cond2->count();
144         OrCondition *result = new OrCondition;
145         for(unsigned i=0; i<count1; ++i)
146                 for(unsigned j=0; j<count2; ++j)
147                         result->add(dispatch_flatten(cond1->get(i)->clone(), cond2->get(j)->clone()));
148         delete cond1;
149         delete cond2;
150         return result;
151 }
152
153 void AndCondition::add_lines(list<FilterStatement> &st) const
154 {
155         for(vector<Condition *>::const_iterator i=conditions.begin(); i!=conditions.end(); ++i)
156                 (*i)->add_lines(st);
157 }
158
159
160 OrCondition *OrCondition::clone() const
161 {
162         OrCondition *result = new OrCondition;
163         clone_to(*result);
164         return result;
165 }
166
167 Condition *OrCondition::flatten(Condition *cond1, Condition *cond2) const
168 {
169         OrCondition *result = new OrCondition;
170         result->add(cond1);
171         result->add(cond2);
172         return result;
173 }
174
175 Condition *OrCondition::flatten(AndCondition *cond1, Condition *cond2) const
176 {
177         return flatten(static_cast<Condition *>(cond1), cond2);
178 }
179
180 Condition *OrCondition::flatten(AndCondition *cond1, AndCondition *cond2) const
181 {
182         return flatten(static_cast<Condition *>(cond1), static_cast<Condition *>(cond2));
183 }
184
185 Condition *OrCondition::flatten(OrCondition *cond1, Condition *cond2) const
186 {
187         cond1->add(cond2);
188         return cond1;
189 }
190
191 Condition *OrCondition::flatten(OrCondition *cond1, AndCondition *cond2) const
192 {
193         return flatten(cond1, static_cast<Condition *>(cond2));
194 }
195
196 Condition *OrCondition::flatten(OrCondition *cond1, OrCondition *cond2) const
197 {
198         unsigned count2 = cond2->count();
199         for(unsigned i=0; i<count2; ++i)
200                 cond1->add(cond2->get(i)->clone());
201         delete cond2;
202         return cond1;
203 }
204
205 void OrCondition::add_lines(list<FilterStatement> &st) const
206 {
207         list<FilterStatement> result;
208         for(vector<Condition *>::const_iterator i=conditions.begin(); i!=conditions.end(); ++i)
209         {
210                 list<FilterStatement> sub_result = st;
211                 (*i)->add_lines(sub_result);
212                 result.splice(result.end(), sub_result);
213         }
214         swap(result, st);
215 }
216
217
218 LinkedColorsCondition::LinkedColorsCondition(const Colors &c):
219         colors(c)
220 { }
221
222 LinkedColorsCondition *LinkedColorsCondition::clone() const
223 {
224         return new LinkedColorsCondition(colors);
225 }
226
227 void LinkedColorsCondition::add_lines(list<FilterStatement> &st) const
228 {
229         FilterStatement::add_line(st, format("SocketGroup %s", colors.colors));
230 }
231
232
233 void operator>>(const LexicalConverter &conv, LinkedColorsCondition::Colors &colors)
234 {
235         const string &str = conv.get();
236         bool rgb = true;
237         for(string::const_iterator i=str.begin(); (rgb && i!=str.end()); ++i)
238                 rgb = (*i=='R' || *i=='G' || *i=='B');
239         if(str.size()>6 || !rgb)
240                 throw lexical_error(format("conversion of '%s' to LinkedColorsCondition::Colors", str));
241
242         fill(colors.colors, colors.colors+7, '\0');
243         copy(str.begin(), str.end(), colors.colors);
244 }