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