]> git.tdb.fi Git - poefilter.git/blob - source/condition.cpp
Check for and prune non-viable branches in the condition tree
[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 if(sub)
53                                 result = dispatch_flatten(result, sub);
54                 }
55
56                 if(result && result->is_viable())
57                         return result;
58
59                 delete result;
60                 return 0;
61         }
62 }
63
64 Condition *CompoundCondition::dispatch_flatten(Condition *cond1, Condition *cond2) const
65 {
66         OrCondition *or1 = dynamic_cast<OrCondition *>(cond1);
67         AndCondition *and1 = dynamic_cast<AndCondition *>(cond1);
68         OrCondition *or2 = dynamic_cast<OrCondition *>(cond2);
69         AndCondition *and2 = dynamic_cast<AndCondition *>(cond2);
70         if(or1 || or2)
71         {
72                 if(or1 && or2)
73                         return flatten(or1, or2);
74                 else if(or1 && and2)
75                         return flatten(or1, and2);
76                 else if(or2 && and1)
77                         return flatten(or2, and1);
78                 else if(or1)
79                         return flatten(or1, cond2);
80                 else if(or2)
81                         return flatten(or2, cond1);
82         }
83         else if(and1 || and2)
84         {
85                 if(and1 && and2)
86                         return flatten(and1, and2);
87                 else if(and1)
88                         return flatten(and1, cond2);
89                 else if(and2)
90                         return flatten(and2, cond1);
91         }
92         else
93                 return flatten(cond1, cond2);
94
95         throw logic_error("CompoundCondition::dispatch_flatten");
96 }
97
98 Condition *CompoundCondition::merge_two(Condition *cond1, Condition *cond2, bool del) const
99 {
100         vector<Condition *> parts;
101         parts.reserve(2);
102         parts.push_back(cond1);
103         parts.push_back(cond2);
104         Condition *result = cond1->merge(parts, *this);
105
106         if(del)
107         {
108                 delete cond1;
109                 delete cond2;
110
111                 if(!result->is_viable())
112                 {
113                         delete result;
114                         return 0;
115                 }
116         }
117
118         return result;
119 }
120
121 Condition *CompoundCondition::add_merged_to(Condition *cond, CompoundCondition *target, bool del) const
122 {
123         bool merged = false;
124         for(vector<Condition *>::iterator i=target->conditions.begin(); i!=target->conditions.end(); ++i)
125                 if((*i)->can_merge(*cond, *target))
126                 {
127                         Condition *m = merge_two(cond, *i, false);
128                         delete *i;
129                         if(del)
130                                 delete cond;
131                         *i = m;
132                         merged = true;
133                         break;
134                 }
135
136         if(!merged)
137                 target->add(del ? cond : cond->clone());
138
139         if(del && !target->is_viable())
140         {
141                 delete target;
142                 return 0;
143         }
144
145         return target;
146 }
147
148 Condition *CompoundCondition::merge_contents_to(CompoundCondition *cond, CompoundCondition *target) const
149 {
150         for(vector<Condition *>::iterator i=cond->conditions.begin(); i!=cond->conditions.end(); ++i)
151                 add_merged_to(*i, target, false);
152
153         delete cond;
154
155         if(target->is_viable())
156                 return target;
157
158         delete target;
159         return 0;
160 }
161
162
163 AndCondition *AndCondition::clone() const
164 {
165         AndCondition *result = new AndCondition;
166         clone_to(*result);
167         return result;
168 }
169
170 Condition *AndCondition::flatten(Condition *cond1, Condition *cond2) const
171 {
172         if(cond1->can_merge(*cond2, *this))
173                 return merge_two(cond1, cond2, true);
174
175         AndCondition *result = new AndCondition;
176         result->add(cond1);
177         result->add(cond2);
178         return result;
179 }
180
181 Condition *AndCondition::flatten(AndCondition *cond1, Condition *cond2) const
182 {
183         return add_merged_to(cond2, cond1, true);
184 }
185
186 Condition *AndCondition::flatten(AndCondition *cond1, AndCondition *cond2) const
187 {
188         return merge_contents_to(cond2, cond1);
189 }
190
191 Condition *AndCondition::flatten(OrCondition *cond1, Condition *cond2) const
192 {
193         OrCondition *result = new OrCondition;
194         unsigned count = cond1->count();
195         for(unsigned i=0; i<count; ++i)
196                 if(Condition *sub = dispatch_flatten(cond1->get(i)->clone(), (i+1<count ? cond2->clone() : cond2)))
197                         result->add(sub);
198         delete cond1;
199
200         if(result->is_viable())
201                 return result;
202
203         delete result;
204         return 0;
205 }
206
207 Condition *AndCondition::flatten(OrCondition *cond1, AndCondition *cond2) const
208 {
209         return flatten(cond1, static_cast<Condition *>(cond2));
210 }
211
212 Condition *AndCondition::flatten(OrCondition *cond1, OrCondition *cond2) const
213 {
214         unsigned count1 = cond1->count();
215         unsigned count2 = cond2->count();
216         OrCondition *result = new OrCondition;
217         for(unsigned i=0; i<count1; ++i)
218                 for(unsigned j=0; j<count2; ++j)
219                         if(Condition *sub = dispatch_flatten(cond1->get(i)->clone(), cond2->get(j)->clone()))
220                                 result->add(sub);
221
222         delete cond1;
223         delete cond2;
224
225         if(result->is_viable())
226                 return result;
227
228         delete result;
229         return 0;
230 }
231
232 bool AndCondition::is_viable() const
233 {
234         for(vector<Condition *>::const_iterator i=conditions.begin(); i!=conditions.end(); ++i)
235                 if(!(*i)->is_viable())
236                         return false;
237         return !conditions.empty();
238 }
239
240 void AndCondition::add_lines(list<FilterStatement> &st) const
241 {
242         for(vector<Condition *>::const_iterator i=conditions.begin(); i!=conditions.end(); ++i)
243                 (*i)->add_lines(st);
244 }
245
246
247 OrCondition *OrCondition::clone() const
248 {
249         OrCondition *result = new OrCondition;
250         clone_to(*result);
251         return result;
252 }
253
254 Condition *OrCondition::flatten(Condition *cond1, Condition *cond2) const
255 {
256         if(cond1->can_merge(*cond2, *this))
257                 return merge_two(cond1, cond2, true);
258
259         OrCondition *result = new OrCondition;
260         result->add(cond1);
261         result->add(cond2);
262         return result;
263 }
264
265 Condition *OrCondition::flatten(AndCondition *cond1, Condition *cond2) const
266 {
267         return flatten(static_cast<Condition *>(cond1), cond2);
268 }
269
270 Condition *OrCondition::flatten(AndCondition *cond1, AndCondition *cond2) const
271 {
272         return flatten(static_cast<Condition *>(cond1), static_cast<Condition *>(cond2));
273 }
274
275 Condition *OrCondition::flatten(OrCondition *cond1, Condition *cond2) const
276 {
277         return add_merged_to(cond2, cond1, true);
278 }
279
280 Condition *OrCondition::flatten(OrCondition *cond1, AndCondition *cond2) const
281 {
282         return flatten(cond1, static_cast<Condition *>(cond2));
283 }
284
285 Condition *OrCondition::flatten(OrCondition *cond1, OrCondition *cond2) const
286 {
287         return merge_contents_to(cond2, cond1);
288 }
289
290 bool OrCondition::is_viable() const
291 {
292         for(vector<Condition *>::const_iterator i=conditions.begin(); i!=conditions.end(); ++i)
293                 if((*i)->is_viable())
294                         return true;
295         return false;
296 }
297
298 void OrCondition::add_lines(list<FilterStatement> &st) const
299 {
300         list<FilterStatement> result;
301         for(vector<Condition *>::const_iterator i=conditions.begin(); i!=conditions.end(); ++i)
302         {
303                 list<FilterStatement> sub_result = st;
304                 (*i)->add_lines(sub_result);
305                 result.splice(result.end(), sub_result);
306         }
307         swap(result, st);
308 }
309
310
311 LinkedColorsCondition::LinkedColorsCondition(const Colors &c):
312         colors(c)
313 { }
314
315 LinkedColorsCondition *LinkedColorsCondition::clone() const
316 {
317         return new LinkedColorsCondition(colors);
318 }
319
320 void LinkedColorsCondition::add_lines(list<FilterStatement> &st) const
321 {
322         FilterStatement::add_line(st, format("SocketGroup %s", colors.colors));
323 }
324
325
326 void operator>>(const LexicalConverter &conv, LinkedColorsCondition::Colors &colors)
327 {
328         const string &str = conv.get();
329         bool rgb = true;
330         for(string::const_iterator i=str.begin(); (rgb && i!=str.end()); ++i)
331                 rgb = (*i=='R' || *i=='G' || *i=='B');
332         if(str.size()>6 || !rgb)
333                 throw lexical_error(format("conversion of '%s' to LinkedColorsCondition::Colors", str));
334
335         fill(colors.colors, colors.colors+7, '\0');
336         copy(str.begin(), str.end(), colors.colors);
337 }