]> granicus.if.org Git - icinga2/blob - lib/base/value-operators.cpp
ad0039722a663cf35fa5bb6810702954c0b5e4a0
[icinga2] / lib / base / value-operators.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2016 Icinga Development Team (https://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/datetime.hpp"
24 #include "base/convert.hpp"
25 #include "base/utility.hpp"
26 #include "base/objectlock.hpp"
27 #include <boost/foreach.hpp>
28 #include <boost/lexical_cast.hpp>
29
30 using namespace icinga;
31
32 Value::operator double(void) const
33 {
34         const double *value = boost::get<double>(&m_Value);
35
36         if (value)
37                 return *value;
38
39         const bool *fvalue = boost::get<bool>(&m_Value);
40
41         if (fvalue)
42                 return *fvalue;
43
44         if (IsEmpty())
45                 return 0;
46
47         try {
48                 return boost::lexical_cast<double>(m_Value);
49         } catch (const std::exception&) {
50                 std::ostringstream msgbuf;
51                 msgbuf << "Can't convert '" << *this << "' to a floating point number.";
52                 BOOST_THROW_EXCEPTION(std::invalid_argument(msgbuf.str()));
53         }
54 }
55
56 Value::operator String(void) const
57 {
58         Object *object;
59
60         switch (GetType()) {
61                 case ValueEmpty:
62                         return String();
63                 case ValueNumber:
64                         return Convert::ToString(boost::get<double>(m_Value));
65                 case ValueBoolean:
66                         if (boost::get<bool>(m_Value))
67                                 return "true";
68                         else
69                                 return "false";
70                 case ValueString:
71                         return boost::get<String>(m_Value);
72                 case ValueObject:
73                         object = boost::get<Object::Ptr>(m_Value).get();
74                         return object->ToString();
75                 default:
76                         BOOST_THROW_EXCEPTION(std::runtime_error("Unknown value type."));
77         }
78 }
79
80 std::ostream& icinga::operator<<(std::ostream& stream, const Value& value)
81 {
82         if (value.IsBoolean())
83                 stream << static_cast<int>(value);
84         else
85                 stream << static_cast<String>(value);
86
87         return stream;
88 }
89
90 std::istream& icinga::operator>>(std::istream& stream, Value& value)
91 {
92         String tstr;
93         stream >> tstr;
94         value = tstr;
95         return stream;
96 }
97
98 Value& Value::operator=(const Value& other)
99 {
100         m_Value = other.m_Value;
101         return *this;
102 }
103
104 bool Value::operator==(bool rhs) const
105 {
106         return *this == Value(rhs);
107 }
108
109 bool Value::operator!=(bool rhs) const
110 {
111         return !(*this == rhs);
112 }
113
114 bool Value::operator==(int rhs) const
115 {
116         return *this == Value(rhs);
117 }
118
119 bool Value::operator!=(int rhs) const
120 {
121         return !(*this == rhs);
122 }
123
124 bool Value::operator==(double rhs) const
125 {
126         return *this == Value(rhs);
127 }
128
129 bool Value::operator!=(double rhs) const
130 {
131         return !(*this == rhs);
132 }
133
134 bool Value::operator==(const char *rhs) const
135 {
136         return static_cast<String>(*this) == rhs;
137 }
138
139 bool Value::operator!=(const char *rhs) const
140 {
141         return !(*this == rhs);
142 }
143
144 bool Value::operator==(const String& rhs) const
145 {
146         return static_cast<String>(*this) == rhs;
147 }
148
149 bool Value::operator!=(const String& rhs) const
150 {
151         return !(*this == rhs);
152 }
153
154 bool Value::operator==(const Value& rhs) const
155 {
156         if (IsNumber() && rhs.IsNumber())
157                 return Get<double>() == rhs.Get<double>();
158         else if ((IsBoolean() || IsNumber()) && (rhs.IsBoolean() || rhs.IsNumber()) && !(IsEmpty() && rhs.IsEmpty()))
159                 return static_cast<double>(*this) == static_cast<double>(rhs);
160
161         if (IsString() && rhs.IsString())
162                 return Get<String>() == rhs.Get<String>();
163         else if ((IsString() || IsEmpty()) && (rhs.IsString() || rhs.IsEmpty()) && !(IsEmpty() && rhs.IsEmpty()))
164                 return static_cast<String>(*this) == static_cast<String>(rhs);
165
166         if (IsEmpty() != rhs.IsEmpty())
167                 return false;
168
169         if (IsEmpty())
170                 return true;
171
172         if (IsObject() != rhs.IsObject())
173                 return false;
174
175         if (IsObject()) {
176                 if (IsObjectType<DateTime>() && rhs.IsObjectType<DateTime>()) {
177                         DateTime::Ptr dt1 = *this;
178                         DateTime::Ptr dt2 = rhs;
179
180                         return dt1->GetValue() == dt2->GetValue();
181                 }
182
183                 if (IsObjectType<Array>() && rhs.IsObjectType<Array>()) {
184                         Array::Ptr arr1 = *this;
185                         Array::Ptr arr2 = rhs;
186
187                         if (arr1 == arr2)
188                                 return true;
189
190                         if (arr1->GetLength() != arr2->GetLength())
191                                 return false;
192
193                         for (Array::SizeType i = 0; i < arr1->GetLength(); i++) {
194                                 if (arr1->Get(i) != arr2->Get(i))
195                                         return false;
196                         }
197
198                         return true;
199                 }
200
201                 return Get<Object::Ptr>() == rhs.Get<Object::Ptr>();
202         }
203
204         return false;
205 }
206
207 bool Value::operator!=(const Value& rhs) const
208 {
209         return !(*this == rhs);
210 }
211
212 Value icinga::operator+(const Value& lhs, const char *rhs)
213 {
214         return lhs + Value(rhs);
215 }
216
217 Value icinga::operator+(const char *lhs, const Value& rhs)
218 {
219         return Value(lhs) + rhs;
220 }
221
222 Value icinga::operator+(const Value& lhs, const String& rhs)
223 {
224         return lhs + Value(rhs);
225 }
226
227 Value icinga::operator+(const String& lhs, const Value& rhs)
228 {
229         return Value(lhs) + rhs;
230 }
231
232 Value icinga::operator+(const Value& lhs, const Value& rhs)
233 {
234         if ((lhs.IsEmpty() || lhs.IsNumber()) && !lhs.IsString() && (rhs.IsEmpty() || rhs.IsNumber()) && !rhs.IsString() && !(lhs.IsEmpty() && rhs.IsEmpty()))
235                 return static_cast<double>(lhs) + static_cast<double>(rhs);
236         if ((lhs.IsString() || lhs.IsEmpty() || lhs.IsNumber()) && (rhs.IsString() || rhs.IsEmpty() || rhs.IsNumber()) && (!(lhs.IsEmpty() && rhs.IsEmpty()) || lhs.IsString() || rhs.IsString()))
237                 return static_cast<String>(lhs) + static_cast<String>(rhs);
238         else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
239                 return static_cast<double>(lhs) + static_cast<double>(rhs);
240         else if (lhs.IsObjectType<DateTime>() && rhs.IsNumber())
241                 return new DateTime(Convert::ToDateTimeValue(lhs) + rhs);
242         else if ((lhs.IsObjectType<Array>() || lhs.IsEmpty()) && (rhs.IsObjectType<Array>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) {
243                 Array::Ptr result = new Array();
244                 if (!lhs.IsEmpty())
245                         static_cast<Array::Ptr>(lhs)->CopyTo(result);
246                 if (!rhs.IsEmpty())
247                         static_cast<Array::Ptr>(rhs)->CopyTo(result);
248                 return result;
249         } else if ((lhs.IsObjectType<Dictionary>() || lhs.IsEmpty()) && (rhs.IsObjectType<Dictionary>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) {
250                 Dictionary::Ptr result = new Dictionary();
251                 if (!lhs.IsEmpty())
252                         static_cast<Dictionary::Ptr>(lhs)->CopyTo(result);
253                 if (!rhs.IsEmpty())
254                         static_cast<Dictionary::Ptr>(rhs)->CopyTo(result);
255                 return result;
256         } else {
257                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator + cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
258         }
259 }
260
261 Value icinga::operator+(const Value& lhs, double rhs)
262 {
263         return lhs + Value(rhs);
264 }
265
266 Value icinga::operator+(double lhs, const Value& rhs)
267 {
268         return Value(lhs) + rhs;
269 }
270
271 Value icinga::operator+(const Value& lhs, int rhs)
272 {
273         return lhs + Value(rhs);
274 }
275
276 Value icinga::operator+(int lhs, const Value& rhs)
277 {
278         return Value(lhs) + rhs;
279 }
280
281 Value icinga::operator-(const Value& lhs, const Value& rhs)
282 {
283         if ((lhs.IsNumber() || lhs.IsEmpty()) && !lhs.IsString() && (rhs.IsNumber() || rhs.IsEmpty()) && !rhs.IsString() && !(lhs.IsEmpty() && rhs.IsEmpty()))
284                 return static_cast<double>(lhs) - static_cast<double>(rhs);
285         else if (lhs.IsObjectType<DateTime>() && rhs.IsNumber())
286                 return new DateTime(Convert::ToDateTimeValue(lhs) - rhs);
287         else if (lhs.IsObjectType<DateTime>() && rhs.IsObjectType<DateTime>())
288                 return Convert::ToDateTimeValue(lhs) - Convert::ToDateTimeValue(rhs);
289         else if ((lhs.IsObjectType<DateTime>() || lhs.IsEmpty()) && (rhs.IsObjectType<DateTime>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
290                 return new DateTime(Convert::ToDateTimeValue(lhs) - Convert::ToDateTimeValue(rhs));
291         else if ((lhs.IsObjectType<Array>() || lhs.IsEmpty()) && (rhs.IsObjectType<Array>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) {
292                 if (lhs.IsEmpty())
293                         return new Array();
294
295                 Array::Ptr result = new Array();
296                 Array::Ptr left = lhs;
297                 Array::Ptr right = rhs;
298
299                 ObjectLock olock(left);
300                 BOOST_FOREACH(const Value& lv, left) {
301                         bool found = false;
302                         ObjectLock xlock(right);
303                         BOOST_FOREACH(const Value& rv, right) {
304                                 if (lv == rv) {
305                                         found = true;
306                                         break;
307                                 }
308                         }
309
310                         if (found)
311                                 continue;
312
313                         result->Add(lv);
314                 }
315
316                 return result;
317         } else
318                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator - cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
319 }
320
321 Value icinga::operator-(const Value& lhs, double rhs)
322 {
323         return lhs - Value(rhs);
324 }
325
326 Value icinga::operator-(double lhs, const Value& rhs)
327 {
328         return Value(lhs) - rhs;
329 }
330
331 Value icinga::operator-(const Value& lhs, int rhs)
332 {
333         return lhs - Value(rhs);
334 }
335
336 Value icinga::operator-(int lhs, const Value& rhs)
337 {
338         return Value(lhs) - rhs;
339 }
340
341 Value icinga::operator*(const Value& lhs, const Value& rhs)
342 {
343         if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
344                 return static_cast<double>(lhs) * static_cast<double>(rhs);
345         else
346                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator * cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
347 }
348
349 Value icinga::operator*(const Value& lhs, double rhs)
350 {
351         return lhs * Value(rhs);
352 }
353
354 Value icinga::operator*(double lhs, const Value& rhs)
355 {
356         return Value(lhs) * rhs;
357 }
358
359 Value icinga::operator*(const Value& lhs, int rhs)
360 {
361         return lhs * Value(rhs);
362 }
363
364 Value icinga::operator*(int lhs, const Value& rhs)
365 {
366         return Value(lhs) * rhs;
367 }
368
369 Value icinga::operator/(const Value& lhs, const Value& rhs)
370 {
371         if (rhs.IsEmpty())
372                 BOOST_THROW_EXCEPTION(std::invalid_argument("Right-hand side argument for operator / is Empty."));
373         else if ((lhs.IsEmpty() || lhs.IsNumber()) && rhs.IsNumber()) {
374                 if (static_cast<double>(rhs) == 0)
375                         BOOST_THROW_EXCEPTION(std::invalid_argument("Right-hand side argument for operator / is 0."));
376
377                 return static_cast<double>(lhs) / static_cast<double>(rhs);
378         } else
379                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator / cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
380 }
381
382 Value icinga::operator/(const Value& lhs, double rhs)
383 {
384         return lhs / Value(rhs);
385 }
386
387 Value icinga::operator/(double lhs, const Value& rhs)
388 {
389         return Value(lhs) / rhs;
390 }
391
392 Value icinga::operator/(const Value& lhs, int rhs)
393 {
394         return lhs / Value(rhs);
395 }
396
397 Value icinga::operator/(int lhs, const Value& rhs)
398 {
399         return Value(lhs) / rhs;
400 }
401
402 Value icinga::operator%(const Value& lhs, const Value& rhs)
403 {
404         if (rhs.IsEmpty())
405                 BOOST_THROW_EXCEPTION(std::invalid_argument("Right-hand side argument for operator % is Empty."));
406         else if ((rhs.IsNumber() || lhs.IsNumber()) && rhs.IsNumber()) {
407                 if (static_cast<double>(rhs) == 0)
408                         BOOST_THROW_EXCEPTION(std::invalid_argument("Right-hand side argument for operator % is 0."));
409
410                 return static_cast<int>(lhs) % static_cast<int>(rhs);
411         } else
412                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator % cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
413 }
414
415 Value icinga::operator%(const Value& lhs, double rhs)
416 {
417         return lhs % Value(rhs);
418 }
419
420 Value icinga::operator%(double lhs, const Value& rhs)
421 {
422         return Value(lhs) % rhs;
423 }
424
425 Value icinga::operator%(const Value& lhs, int rhs)
426 {
427         return lhs % Value(rhs);
428 }
429
430 Value icinga::operator%(int lhs, const Value& rhs)
431 {
432         return Value(lhs) % rhs;
433 }
434
435 Value icinga::operator^(const Value& lhs, const Value& rhs)
436 {
437         if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
438                 return static_cast<int>(lhs) ^ static_cast<int>(rhs);
439         else
440                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator & cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
441 }
442
443 Value icinga::operator^(const Value& lhs, double rhs)
444 {
445         return lhs ^ Value(rhs);
446 }
447
448 Value icinga::operator^(double lhs, const Value& rhs)
449 {
450         return Value(lhs) ^ rhs;
451 }
452
453 Value icinga::operator^(const Value& lhs, int rhs)
454 {
455         return lhs ^ Value(rhs);
456 }
457
458 Value icinga::operator^(int lhs, const Value& rhs)
459 {
460         return Value(lhs) ^ rhs;
461 }
462
463 Value icinga::operator&(const Value& lhs, const Value& rhs)
464 {
465         if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
466                 return static_cast<int>(lhs) & static_cast<int>(rhs);
467         else
468                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator & cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
469 }
470
471 Value icinga::operator&(const Value& lhs, double rhs)
472 {
473         return lhs & Value(rhs);
474 }
475
476 Value icinga::operator&(double lhs, const Value& rhs)
477 {
478         return Value(lhs) & rhs;
479 }
480
481 Value icinga::operator&(const Value& lhs, int rhs)
482 {
483         return lhs & Value(rhs);
484 }
485
486 Value icinga::operator&(int lhs, const Value& rhs)
487 {
488         return Value(lhs) & rhs;
489 }
490
491 Value icinga::operator|(const Value& lhs, const Value& rhs)
492 {
493         if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
494                 return static_cast<int>(lhs) | static_cast<int>(rhs);
495         else
496                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator | cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
497 }
498
499 Value icinga::operator|(const Value& lhs, double rhs)
500 {
501         return lhs | Value(rhs);
502 }
503
504 Value icinga::operator|(double lhs, const Value& rhs)
505 {
506         return Value(lhs) | rhs;
507 }
508
509 Value icinga::operator|(const Value& lhs, int rhs)
510 {
511         return lhs | Value(rhs);
512 }
513
514 Value icinga::operator|(int lhs, const Value& rhs)
515 {
516         return Value(lhs) | rhs;
517 }
518
519 Value icinga::operator<<(const Value& lhs, const Value& rhs)
520 {
521         if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
522                 return static_cast<int>(lhs) << static_cast<int>(rhs);
523         else
524                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator << cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
525 }
526
527 Value icinga::operator<<(const Value& lhs, double rhs)
528 {
529         return lhs << Value(rhs);
530 }
531
532 Value icinga::operator<<(double lhs, const Value& rhs)
533 {
534         return Value(lhs) << rhs;
535 }
536
537 Value icinga::operator<<(const Value& lhs, int rhs)
538 {
539         return lhs << Value(rhs);
540 }
541
542 Value icinga::operator<<(int lhs, const Value& rhs)
543 {
544         return Value(lhs) << rhs;
545 }
546
547 Value icinga::operator>>(const Value& lhs, const Value& rhs)
548 {
549         if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
550                 return static_cast<int>(lhs) >> static_cast<int>(rhs);
551         else
552                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator >> cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
553 }
554
555 Value icinga::operator>>(const Value& lhs, double rhs)
556 {
557         return lhs >> Value(rhs);
558 }
559
560 Value icinga::operator>>(double lhs, const Value& rhs)
561 {
562         return Value(lhs) >> rhs;
563 }
564
565 Value icinga::operator>>(const Value& lhs, int rhs)
566 {
567         return lhs >> Value(rhs);
568 }
569
570 Value icinga::operator>>(int lhs, const Value& rhs)
571 {
572         return Value(lhs) >> rhs;
573 }
574
575 bool icinga::operator<(const Value& lhs, const Value& rhs)
576 {
577         if (lhs.IsString() && rhs.IsString())
578                 return static_cast<String>(lhs) < static_cast<String>(rhs);
579         else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
580                 return static_cast<double>(lhs) < static_cast<double>(rhs);
581         else if ((lhs.IsObjectType<DateTime>() || lhs.IsEmpty()) && (rhs.IsObjectType<DateTime>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
582                 return Convert::ToDateTimeValue(lhs) < Convert::ToDateTimeValue(rhs);
583         else if (lhs.IsObjectType<Array>() && rhs.IsObjectType<Array>()) {
584                 Array::Ptr larr = lhs;
585                 Array::Ptr rarr = rhs;
586
587                 ObjectLock llock(larr);
588                 ObjectLock rlock(rarr);
589
590                 Array::SizeType llen = larr->GetLength();
591                 Array::SizeType rlen = rarr->GetLength();
592
593                 for (Array::SizeType i = 0; i < std::max(llen, rlen); i++) {
594                         Value lval = (i >= llen) ? Empty : larr->Get(i);
595                         Value rval = (i >= rlen) ? Empty : rarr->Get(i);
596
597                         if (lval < rval)
598                                 return true;
599                         else if (lval > rval)
600                                 return false;
601                 }
602
603                 return false;
604         } else
605                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator < cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
606 }
607
608 bool icinga::operator<(const Value& lhs, double rhs)
609 {
610         return lhs < Value(rhs);
611 }
612
613 bool icinga::operator<(double lhs, const Value& rhs)
614 {
615         return Value(lhs) < rhs;
616 }
617
618 bool icinga::operator<(const Value& lhs, int rhs)
619 {
620         return lhs < Value(rhs);
621 }
622
623 bool icinga::operator<(int lhs, const Value& rhs)
624 {
625         return Value(lhs) < rhs;
626 }
627
628 bool icinga::operator>(const Value& lhs, const Value& rhs)
629 {
630         if (lhs.IsString() && rhs.IsString())
631                 return static_cast<String>(lhs) > static_cast<String>(rhs);
632         else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
633                 return static_cast<double>(lhs) > static_cast<double>(rhs);
634         else if ((lhs.IsObjectType<DateTime>() || lhs.IsEmpty()) && (rhs.IsObjectType<DateTime>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
635                 return Convert::ToDateTimeValue(lhs) > Convert::ToDateTimeValue(rhs);
636         else if (lhs.IsObjectType<Array>() && rhs.IsObjectType<Array>()) {
637                 Array::Ptr larr = lhs;
638                 Array::Ptr rarr = rhs;
639
640                 ObjectLock llock(larr);
641                 ObjectLock rlock(rarr);
642
643                 Array::SizeType llen = larr->GetLength();
644                 Array::SizeType rlen = rarr->GetLength();
645
646                 for (Array::SizeType i = 0; i < std::max(llen, rlen); i++) {
647                         Value lval = (i >= llen) ? Empty : larr->Get(i);
648                         Value rval = (i >= rlen) ? Empty : rarr->Get(i);
649
650                         if (lval > rval)
651                                 return true;
652                         else if (lval < rval)
653                                 return false;
654                 }
655
656                 return false;
657         } else
658                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator > cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
659 }
660
661 bool icinga::operator>(const Value& lhs, double rhs)
662 {
663         return lhs > Value(rhs);
664 }
665
666 bool icinga::operator>(double lhs, const Value& rhs)
667 {
668         return Value(lhs) > rhs;
669 }
670
671 bool icinga::operator>(const Value& lhs, int rhs)
672 {
673         return lhs > Value(rhs);
674 }
675
676 bool icinga::operator>(int lhs, const Value& rhs)
677 {
678         return Value(lhs) > rhs;
679 }
680
681 bool icinga::operator<=(const Value& lhs, const Value& rhs)
682 {
683         if (lhs.IsString() && rhs.IsString())
684                 return static_cast<String>(lhs) <= static_cast<String>(rhs);
685         else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
686                 return static_cast<double>(lhs) <= static_cast<double>(rhs);
687         else if ((lhs.IsObjectType<DateTime>() || lhs.IsEmpty()) && (rhs.IsObjectType<DateTime>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
688                 return Convert::ToDateTimeValue(lhs) <= Convert::ToDateTimeValue(rhs);
689         else
690                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator <= cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
691 }
692
693 bool icinga::operator<=(const Value& lhs, double rhs)
694 {
695         return lhs <= Value(rhs);
696 }
697
698 bool icinga::operator<=(double lhs, const Value& rhs)
699 {
700         return Value(lhs) <= rhs;
701 }
702
703 bool icinga::operator<=(const Value& lhs, int rhs)
704 {
705         return lhs <= Value(rhs);
706 }
707
708 bool icinga::operator<=(int lhs, const Value& rhs)
709 {
710         return Value(lhs) <= rhs;
711 }
712
713 bool icinga::operator>=(const Value& lhs, const Value& rhs)
714 {
715         if (lhs.IsString() && rhs.IsString())
716                 return static_cast<String>(lhs) >= static_cast<String>(rhs);
717         else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
718                 return static_cast<double>(lhs) >= static_cast<double>(rhs);
719         else if ((lhs.IsObjectType<DateTime>() || lhs.IsEmpty()) && (rhs.IsObjectType<DateTime>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
720                 return Convert::ToDateTimeValue(lhs) >= Convert::ToDateTimeValue(rhs);
721         else
722                 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator >= cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
723 }
724
725 bool icinga::operator>=(const Value& lhs, double rhs)
726 {
727         return lhs >= Value(rhs);
728 }
729
730 bool icinga::operator>=(double lhs, const Value& rhs)
731 {
732         return Value(lhs) >= rhs;
733 }
734
735 bool icinga::operator>=(const Value& lhs, int rhs)
736 {
737         return lhs >= Value(rhs);
738 }
739
740 bool icinga::operator>=(int lhs, const Value& rhs)
741 {
742         return Value(lhs) >= rhs;
743 }