]> git.tdb.fi Git - poefilter.git/blob - source/condition.cpp
a8a5a90d9c8b6ce1c87f542dad8422a0063d121d
[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 Condition *CompoundCondition::merge_two(Condition *cond1, Condition *cond2, bool del) const
95 {
96         vector<Condition *> parts;
97         parts.reserve(2);
98         parts.push_back(cond1);
99         parts.push_back(cond2);
100         Condition *result = cond1->merge(parts, *this);
101         if(del)
102         {
103                 delete cond1;
104                 delete cond2;
105         }
106         return result;
107 }
108
109 Condition *CompoundCondition::add_merged_to(Condition *cond, CompoundCondition *target, bool del) const
110 {
111         for(vector<Condition *>::iterator i=target->conditions.begin(); i!=target->conditions.end(); ++i)
112                 if((*i)->can_merge(*cond, *target))
113                 {
114                         Condition *m = merge_two(cond, *i, false);
115                         delete *i;
116                         if(del)
117                                 delete cond;
118                         *i = m;
119                         return target;
120                 }
121
122         target->add(del ? cond : cond->clone());
123         return target;
124 }
125
126 Condition *CompoundCondition::merge_contents_to(CompoundCondition *cond, CompoundCondition *target) const
127 {
128         for(vector<Condition *>::iterator i=cond->conditions.begin(); i!=cond->conditions.end(); ++i)
129                 add_merged_to(*i, target, false);
130
131         delete cond;
132         return target;
133 }
134
135
136 AndCondition *AndCondition::clone() const
137 {
138         AndCondition *result = new AndCondition;
139         clone_to(*result);
140         return result;
141 }
142
143 Condition *AndCondition::flatten(Condition *cond1, Condition *cond2) const
144 {
145         if(cond1->can_merge(*cond2, *this))
146                 return merge_two(cond1, cond2, true);
147
148         AndCondition *result = new AndCondition;
149         result->add(cond1);
150         result->add(cond2);
151         return result;
152 }
153
154 Condition *AndCondition::flatten(AndCondition *cond1, Condition *cond2) const
155 {
156         return add_merged_to(cond2, cond1, true);
157 }
158
159 Condition *AndCondition::flatten(AndCondition *cond1, AndCondition *cond2) const
160 {
161         return merge_contents_to(cond2, cond1);
162 }
163
164 Condition *AndCondition::flatten(OrCondition *cond1, Condition *cond2) const
165 {
166         OrCondition *result = new OrCondition;
167         unsigned count = cond1->count();
168         for(unsigned i=0; i<count; ++i)
169                 result->add(dispatch_flatten(cond1->get(i)->clone(), (i+1<count ? cond2->clone() : cond2)));
170         delete cond1;
171         return result;
172 }
173
174 Condition *AndCondition::flatten(OrCondition *cond1, AndCondition *cond2) const
175 {
176         return flatten(cond1, static_cast<Condition *>(cond2));
177 }
178
179 Condition *AndCondition::flatten(OrCondition *cond1, OrCondition *cond2) const
180 {
181         unsigned count1 = cond1->count();
182         unsigned count2 = cond2->count();
183         OrCondition *result = new OrCondition;
184         for(unsigned i=0; i<count1; ++i)
185                 for(unsigned j=0; j<count2; ++j)
186                         result->add(dispatch_flatten(cond1->get(i)->clone(), cond2->get(j)->clone()));
187         delete cond1;
188         delete cond2;
189         return result;
190 }
191
192 void AndCondition::add_lines(list<FilterStatement> &st) const
193 {
194         for(vector<Condition *>::const_iterator i=conditions.begin(); i!=conditions.end(); ++i)
195                 (*i)->add_lines(st);
196 }
197
198
199 OrCondition *OrCondition::clone() const
200 {
201         OrCondition *result = new OrCondition;
202         clone_to(*result);
203         return result;
204 }
205
206 Condition *OrCondition::flatten(Condition *cond1, Condition *cond2) const
207 {
208         if(cond1->can_merge(*cond2, *this))
209                 return merge_two(cond1, cond2, true);
210
211         OrCondition *result = new OrCondition;
212         result->add(cond1);
213         result->add(cond2);
214         return result;
215 }
216
217 Condition *OrCondition::flatten(AndCondition *cond1, Condition *cond2) const
218 {
219         return flatten(static_cast<Condition *>(cond1), cond2);
220 }
221
222 Condition *OrCondition::flatten(AndCondition *cond1, AndCondition *cond2) const
223 {
224         return flatten(static_cast<Condition *>(cond1), static_cast<Condition *>(cond2));
225 }
226
227 Condition *OrCondition::flatten(OrCondition *cond1, Condition *cond2) const
228 {
229         return add_merged_to(cond2, cond1, true);
230 }
231
232 Condition *OrCondition::flatten(OrCondition *cond1, AndCondition *cond2) const
233 {
234         return flatten(cond1, static_cast<Condition *>(cond2));
235 }
236
237 Condition *OrCondition::flatten(OrCondition *cond1, OrCondition *cond2) const
238 {
239         return merge_contents_to(cond2, cond1);
240 }
241
242 void OrCondition::add_lines(list<FilterStatement> &st) const
243 {
244         list<FilterStatement> result;
245         for(vector<Condition *>::const_iterator i=conditions.begin(); i!=conditions.end(); ++i)
246         {
247                 list<FilterStatement> sub_result = st;
248                 (*i)->add_lines(sub_result);
249                 result.splice(result.end(), sub_result);
250         }
251         swap(result, st);
252 }
253
254
255 LinkedColorsCondition::LinkedColorsCondition(const Colors &c):
256         colors(c)
257 { }
258
259 LinkedColorsCondition *LinkedColorsCondition::clone() const
260 {
261         return new LinkedColorsCondition(colors);
262 }
263
264 void LinkedColorsCondition::add_lines(list<FilterStatement> &st) const
265 {
266         FilterStatement::add_line(st, format("SocketGroup %s", colors.colors));
267 }
268
269
270 void operator>>(const LexicalConverter &conv, LinkedColorsCondition::Colors &colors)
271 {
272         const string &str = conv.get();
273         bool rgb = true;
274         for(string::const_iterator i=str.begin(); (rgb && i!=str.end()); ++i)
275                 rgb = (*i=='R' || *i=='G' || *i=='B');
276         if(str.size()>6 || !rgb)
277                 throw lexical_error(format("conversion of '%s' to LinkedColorsCondition::Colors", str));
278
279         fill(colors.colors, colors.colors+7, '\0');
280         copy(str.begin(), str.end(), colors.colors);
281 }