]> granicus.if.org Git - icinga2/blob - lib/base/value-operators.cpp
Implement a boolean sub-type for the Value class
[icinga2] / lib / base / value-operators.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org)    *
4  *                                                                            *
5  * This program is free software; you can redistribute it and/or              *
6  * modify it under the terms of the GNU General Public License                *
7  * as published by the Free Software Foundation; either version 2             *
8  * of the License, or (at your option) any later version.                     *
9  *                                                                            *
10  * This program is distributed in the hope that it will be useful,            *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
13  * GNU General Public License for more details.                               *
14  *                                                                            *
15  * You should have received a copy of the GNU General Public License          *
16  * along with this program; if not, write to the Free Software Foundation     *
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
18  ******************************************************************************/
19
20 #include "base/value.hpp"
21 #include "base/array.hpp"
22 #include "base/dictionary.hpp"
23 #include "base/utility.hpp"
24 #include "base/objectlock.hpp"
25 #include <boost/foreach.hpp>
26 #include <boost/lexical_cast.hpp>
27
28 using namespace icinga;
29
30 Value::operator double(void) const
31 {
32         const double *value = boost::get<double>(&m_Value);
33
34         if (value)
35                 return *value;
36
37         if (IsEmpty())
38                 return 0;
39
40         return boost::lexical_cast<double>(m_Value);
41 }
42
43 Value::operator String(void) const
44 {
45         Object *object;
46         double integral, fractional;
47
48         switch (GetType()) {
49                 case ValueEmpty:
50                         return String();
51                 case ValueNumber:
52                         fractional = std::modf(boost::get<double>(m_Value), &integral);
53
54                         if (fractional != 0)
55                                 return boost::lexical_cast<std::string>(m_Value);
56                         else
57                                 return boost::lexical_cast<std::string>((long)integral);
58                 case ValueBoolean:
59                         if (boost::get<bool>(m_Value))
60                                 return "true";
61                         else
62                                 return "false";
63                 case ValueString:
64                         return boost::get<String>(m_Value);
65                 case ValueObject:
66                         object = boost::get<Object::Ptr>(m_Value).get();
67                         return object->ToString();
68                 default:
69                         BOOST_THROW_EXCEPTION(std::runtime_error("Unknown value type."));
70         }
71 }
72
73 std::ostream& icinga::operator<<(std::ostream& stream, const Value& value)
74 {
75         stream << static_cast<String>(value);
76         return stream;
77 }
78
79 std::istream& icinga::operator>>(std::istream& stream, Value& value)
80 {
81         String tstr;
82         stream >> tstr;
83         value = tstr;
84         return stream;
85 }
86
87 bool Value::operator==(bool rhs) const
88 {
89         return *this == Value(rhs);
90 }
91
92 bool Value::operator!=(bool rhs) const
93 {
94         return !(*this == rhs);
95 }
96
97 bool Value::operator==(int rhs) const
98 {
99         return *this == Value(rhs);
100 }
101
102 bool Value::operator!=(int rhs) const
103 {
104         return !(*this == rhs);
105 }
106
107 bool Value::operator==(double rhs) const
108 {
109         return *this == Value(rhs);
110 }
111
112 bool Value::operator!=(double rhs) const
113 {
114         return !(*this == rhs);
115 }
116
117 bool Value::operator==(const char *rhs) const
118 {
119         return static_cast<String>(*this) == rhs;
120 }
121
122 bool Value::operator!=(const char *rhs) const
123 {
124         return !(*this == rhs);
125 }
126
127 bool Value::operator==(const String& rhs) const
128 {
129         return static_cast<String>(*this) == rhs;
130 }
131
132 bool Value::operator!=(const String& rhs) const
133 {
134         return !(*this == rhs);
135 }
136
137 bool Value::operator==(const Value& rhs) const
138 {
139         if (IsNumber() && rhs.IsNumber())
140                 return Get<double>() == rhs.Get<double>();
141         else if ((IsBoolean() || IsNumber() || IsEmpty()) && (rhs.IsBoolean() || rhs.IsNumber() || rhs.IsEmpty()) && !(IsEmpty() && rhs.IsEmpty()))
142                 return static_cast<double>(*this) == static_cast<double>(rhs);
143
144         if (IsString() && rhs.IsString())
145                 return Get<String>() == rhs.Get<String>();
146         else if ((IsString() || IsEmpty()) && (rhs.IsString() || rhs.IsEmpty()) && !(IsEmpty() && rhs.IsEmpty()))
147                 return static_cast<String>(*this) == static_cast<String>(rhs);
148
149         if (IsEmpty() != rhs.IsEmpty())
150                 return false;
151
152         if (IsEmpty())
153                 return true;
154
155         if (IsObject() != rhs.IsObject())
156                 return false;
157
158         if (IsObject()) {
159                 if (IsObjectType<Array>() && rhs.IsObjectType<Array>()) {
160                         Array::Ptr arr1 = *this;
161                         Array::Ptr arr2 = rhs;
162
163                         if (arr1 == arr2)
164                                 return true;
165
166                         if (arr1->GetLength() != arr2->GetLength())
167                                 return false;
168
169                         for (Array::SizeType i = 0; i < arr1->GetLength(); i++) {
170                                 if (arr1->Get(i) != arr2->Get(i))
171                                         return false;
172                         }
173
174                         return true;
175                 }
176
177                 return Get<Object::Ptr>() == rhs.Get<Object::Ptr>();
178         }
179
180         return false;
181 }
182
183 bool Value::operator!=(const Value& rhs) const
184 {
185         return !(*this == rhs);
186 }
187
188 Value icinga::operator+(const Value& lhs, const char *rhs)
189 {
190         return lhs + Value(rhs);
191 }
192
193 Value icinga::operator+(const char *lhs, const Value& rhs)
194 {
195         return Value(lhs) + rhs;
196 }
197
198 Value icinga::operator+(const Value& lhs, const String& rhs)
199 {
200         return lhs + Value(rhs);
201 }
202
203 Value icinga::operator+(const String& lhs, const Value& rhs)
204 {
205         return Value(lhs) + rhs;
206 }
207
208 Value icinga::operator+(const Value& lhs, const Value& rhs)
209 {
210         if ((lhs.IsEmpty() || lhs.IsNumber()) && (rhs.IsEmpty() || rhs.IsNumber()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
211                 return static_cast<double>(lhs) + static_cast<double>(rhs);
212         if ((lhs.IsString() || lhs.IsEmpty() || lhs.IsNumber()) && (rhs.IsString() || rhs.IsEmpty() || rhs.IsNumber()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
213                 return static_cast<String>(lhs) + static_cast<String>(rhs);
214         else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
215                 return static_cast<double>(lhs) + static_cast<double>(rhs);
216         else if ((lhs.IsObjectType<Array>() || lhs.IsEmpty()) && (rhs.IsObjectType<Array>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) {
217                 Array::Ptr result = new Array();
218                 if (!lhs.IsEmpty())
219                         static_cast<Array::Ptr>(lhs)->CopyTo(result);
220                 if (!rhs.IsEmpty())
221                         static_cast<Array::Ptr>(rhs)->CopyTo(result);
222                 return result;
223         } else if ((lhs.IsObjectType<Dictionary>() || lhs.IsEmpty()) && (rhs.IsObjectType<Dictionary>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) {
224                 Dictionary::Ptr result = new Dictionary();
225                 if (!lhs.IsEmpty())
226                         static_cast<Dictionary::Ptr>(lhs)->CopyTo(result);
227                 if (!rhs.IsEmpty())
228                         static_cast<Dictionary::Ptr>(rhs)->CopyTo(result);
229                 return result;
230         } else {
231                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator + cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
232         }
233 }
234
235 Value icinga::operator+(const Value& lhs, double rhs)
236 {
237         return lhs + Value(rhs);
238 }
239
240 Value icinga::operator+(double lhs, const Value& rhs)
241 {
242         return Value(lhs) + rhs;
243 }
244
245 Value icinga::operator+(const Value& lhs, int rhs)
246 {
247         return lhs + Value(rhs);
248 }
249
250 Value icinga::operator+(int lhs, const Value& rhs)
251 {
252         return Value(lhs) + rhs;
253 }
254
255 Value icinga::operator-(const Value& lhs, const Value& rhs)
256 {
257         if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
258                 return static_cast<double>(lhs) - static_cast<double>(rhs);
259         else if ((lhs.IsObjectType<Array>() || lhs.IsEmpty()) && (rhs.IsObjectType<Array>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) {
260                 if (lhs.IsEmpty())
261                         return new Array();
262
263                 Array::Ptr result = new Array();
264                 Array::Ptr left = lhs;
265                 Array::Ptr right = rhs;
266
267                 ObjectLock olock(left);
268                 BOOST_FOREACH(const Value& lv, left) {
269                         bool found = false;
270                         ObjectLock xlock(right);
271                         BOOST_FOREACH(const Value& rv, right) {
272                                 if (lv == rv) {
273                                         found = true;
274                                         break;
275                                 }
276                         }
277
278                         if (found)
279                                 continue;
280
281                         result->Add(lv);
282                 }
283
284                 return result;
285         } else
286                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator - cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
287 }
288
289 Value icinga::operator-(const Value& lhs, double rhs)
290 {
291         return lhs - Value(rhs);
292 }
293
294 Value icinga::operator-(double lhs, const Value& rhs)
295 {
296         return Value(lhs) - rhs;
297 }
298
299 Value icinga::operator-(const Value& lhs, int rhs)
300 {
301         return lhs - Value(rhs);
302 }
303
304 Value icinga::operator-(int lhs, const Value& rhs)
305 {
306         return Value(lhs) - rhs;
307 }
308
309 Value icinga::operator*(const Value& lhs, const Value& rhs)
310 {
311         if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
312                 return static_cast<double>(lhs) * static_cast<double>(rhs);
313         else
314                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator * cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
315 }
316
317 Value icinga::operator*(const Value& lhs, double rhs)
318 {
319         return lhs * Value(rhs);
320 }
321
322 Value icinga::operator*(double lhs, const Value& rhs)
323 {
324         return Value(lhs) * rhs;
325 }
326
327 Value icinga::operator*(const Value& lhs, int rhs)
328 {
329         return lhs * Value(rhs);
330 }
331
332 Value icinga::operator*(int lhs, const Value& rhs)
333 {
334         return Value(lhs) * rhs;
335 }
336
337 Value icinga::operator/(const Value& lhs, const Value& rhs)
338 {
339         if (lhs.IsEmpty())
340                 return 0;
341         else if (rhs.IsEmpty())
342                 BOOST_THROW_EXCEPTION(std::invalid_argument("Right-hand side argument for operator / is Empty."));
343         else if (lhs.IsNumber() && rhs.IsNumber()) {
344                 if (static_cast<double>(rhs) == 0)
345                         BOOST_THROW_EXCEPTION(std::invalid_argument("Right-hand side argument for operator / is 0."));
346
347                 return static_cast<double>(lhs) / static_cast<double>(rhs);
348         } else
349                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator / cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
350 }
351
352 Value icinga::operator/(const Value& lhs, double rhs)
353 {
354         return lhs / Value(rhs);
355 }
356
357 Value icinga::operator/(double lhs, const Value& rhs)
358 {
359         return Value(lhs) / rhs;
360 }
361
362 Value icinga::operator/(const Value& lhs, int rhs)
363 {
364         return lhs / Value(rhs);
365 }
366
367 Value icinga::operator/(int lhs, const Value& rhs)
368 {
369         return Value(lhs) / rhs;
370 }
371
372 Value icinga::operator&(const Value& lhs, const Value& rhs)
373 {
374         if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
375                 return static_cast<int>(lhs) & static_cast<int>(rhs);
376         else
377                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator & cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
378 }
379
380 Value icinga::operator&(const Value& lhs, double rhs)
381 {
382         return lhs & Value(rhs);
383 }
384
385 Value icinga::operator&(double lhs, const Value& rhs)
386 {
387         return Value(lhs) & rhs;
388 }
389
390 Value icinga::operator&(const Value& lhs, int rhs)
391 {
392         return lhs & Value(rhs);
393 }
394
395 Value icinga::operator&(int lhs, const Value& rhs)
396 {
397         return Value(lhs) & rhs;
398 }
399
400 Value icinga::operator|(const Value& lhs, const Value& rhs)
401 {
402         if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
403                 return static_cast<int>(lhs) | static_cast<int>(rhs);
404         else
405                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator | cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
406 }
407
408 Value icinga::operator|(const Value& lhs, double rhs)
409 {
410         return lhs | Value(rhs);
411 }
412
413 Value icinga::operator|(double lhs, const Value& rhs)
414 {
415         return Value(lhs) | rhs;
416 }
417
418 Value icinga::operator|(const Value& lhs, int rhs)
419 {
420         return lhs | Value(rhs);
421 }
422
423 Value icinga::operator|(int lhs, const Value& rhs)
424 {
425         return Value(lhs) | rhs;
426 }
427
428 Value icinga::operator<<(const Value& lhs, const Value& rhs)
429 {
430         if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
431                 return static_cast<int>(lhs) << static_cast<int>(rhs);
432         else
433                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator << cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
434 }
435
436 Value icinga::operator<<(const Value& lhs, double rhs)
437 {
438         return lhs << Value(rhs);
439 }
440
441 Value icinga::operator<<(double lhs, const Value& rhs)
442 {
443         return Value(lhs) << rhs;
444 }
445
446 Value icinga::operator<<(const Value& lhs, int rhs)
447 {
448         return lhs << Value(rhs);
449 }
450
451 Value icinga::operator<<(int lhs, const Value& rhs)
452 {
453         return Value(lhs) << rhs;
454 }
455
456 Value icinga::operator>>(const Value& lhs, const Value& rhs)
457 {
458         if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
459                 return static_cast<int>(lhs) >> static_cast<int>(rhs);
460         else
461                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator >> cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
462 }
463
464 Value icinga::operator>>(const Value& lhs, double rhs)
465 {
466         return lhs >> Value(rhs);
467 }
468
469 Value icinga::operator>>(double lhs, const Value& rhs)
470 {
471         return Value(lhs) >> rhs;
472 }
473
474 Value icinga::operator>>(const Value& lhs, int rhs)
475 {
476         return lhs >> Value(rhs);
477 }
478
479 Value icinga::operator>>(int lhs, const Value& rhs)
480 {
481         return Value(lhs) >> rhs;
482 }
483
484 bool icinga::operator<(const Value& lhs, const Value& rhs)
485 {
486         if (lhs.IsString() && rhs.IsString())
487                 return static_cast<String>(lhs) < static_cast<String>(rhs);
488         else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
489                 return static_cast<int>(lhs) < static_cast<int>(rhs);
490         else if (lhs.GetTypeName() != rhs.GetTypeName())
491                 return lhs.GetTypeName() < rhs.GetTypeName();
492         else
493                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator < cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
494 }
495
496 bool icinga::operator<(const Value& lhs, double rhs)
497 {
498         return lhs < Value(rhs);
499 }
500
501 bool icinga::operator<(double lhs, const Value& rhs)
502 {
503         return Value(lhs) < rhs;
504 }
505
506 bool icinga::operator<(const Value& lhs, int rhs)
507 {
508         return lhs < Value(rhs);
509 }
510
511 bool icinga::operator<(int lhs, const Value& rhs)
512 {
513         return Value(lhs) < rhs;
514 }
515
516 bool icinga::operator>(const Value& lhs, const Value& rhs)
517 {
518         if (lhs.IsString() && rhs.IsString())
519                 return static_cast<String>(lhs) > static_cast<String>(rhs);
520         else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
521                 return static_cast<int>(lhs) > static_cast<int>(rhs);
522         else if (lhs.GetTypeName() != rhs.GetTypeName())
523                 return lhs.GetTypeName() > rhs.GetTypeName();
524         else
525                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator > cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
526 }
527
528 bool icinga::operator>(const Value& lhs, double rhs)
529 {
530         return lhs > Value(rhs);
531 }
532
533 bool icinga::operator>(double lhs, const Value& rhs)
534 {
535         return Value(lhs) > rhs;
536 }
537
538 bool icinga::operator>(const Value& lhs, int rhs)
539 {
540         return lhs > Value(rhs);
541 }
542
543 bool icinga::operator>(int lhs, const Value& rhs)
544 {
545         return Value(lhs) > rhs;
546 }
547
548 bool icinga::operator<=(const Value& lhs, const Value& rhs)
549 {
550         if (lhs.IsString() && rhs.IsString())
551                 return static_cast<String>(lhs) <= static_cast<String>(rhs);
552         else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
553                 return static_cast<int>(lhs) <= static_cast<int>(rhs);
554         else if (lhs.GetTypeName() != rhs.GetTypeName())
555                 return lhs.GetTypeName() <= rhs.GetTypeName();
556         else
557                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator <= cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
558 }
559
560 bool icinga::operator<=(const Value& lhs, double rhs)
561 {
562         return lhs <= Value(rhs);
563 }
564
565 bool icinga::operator<=(double lhs, const Value& rhs)
566 {
567         return Value(lhs) <= rhs;
568 }
569
570 bool icinga::operator<=(const Value& lhs, int rhs)
571 {
572         return lhs <= Value(rhs);
573 }
574
575 bool icinga::operator<=(int lhs, const Value& rhs)
576 {
577         return Value(lhs) <= rhs;
578 }
579
580 bool icinga::operator>=(const Value& lhs, const Value& rhs)
581 {
582         if (lhs.IsString() && rhs.IsString())
583                 return static_cast<String>(lhs) >= static_cast<String>(rhs);
584         else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
585                 return static_cast<int>(lhs) >= static_cast<int>(rhs);
586         else if (lhs.GetTypeName() != rhs.GetTypeName())
587                 return lhs.GetTypeName() >= rhs.GetTypeName();
588         else
589                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator >= cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
590 }
591
592 bool icinga::operator>=(const Value& lhs, double rhs)
593 {
594         return lhs >= Value(rhs);
595 }
596
597 bool icinga::operator>=(double lhs, const Value& rhs)
598 {
599         return Value(lhs) >= rhs;
600 }
601
602 bool icinga::operator>=(const Value& lhs, int rhs)
603 {
604         return lhs >= Value(rhs);
605 }
606
607 bool icinga::operator>=(int lhs, const Value& rhs)
608 {
609         return Value(lhs) >= rhs;
610 }