1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
3 #include "base/value.hpp"
4 #include "base/array.hpp"
5 #include "base/dictionary.hpp"
6 #include "base/datetime.hpp"
7 #include "base/convert.hpp"
8 #include "base/utility.hpp"
9 #include "base/objectlock.hpp"
10 #include <boost/lexical_cast.hpp>
12 using namespace icinga;
14 Value::operator double() const
16 const double *value = boost::get<double>(&m_Value);
21 const bool *fvalue = boost::get<bool>(&m_Value);
30 return boost::lexical_cast<double>(m_Value);
31 } catch (const std::exception&) {
32 std::ostringstream msgbuf;
33 msgbuf << "Can't convert '" << *this << "' to a floating point number.";
34 BOOST_THROW_EXCEPTION(std::invalid_argument(msgbuf.str()));
38 Value::operator String() const
46 return Convert::ToString(boost::get<double>(m_Value));
48 if (boost::get<bool>(m_Value))
53 return boost::get<String>(m_Value);
55 object = boost::get<Object::Ptr>(m_Value).get();
56 return object->ToString();
58 BOOST_THROW_EXCEPTION(std::runtime_error("Unknown value type."));
62 std::ostream& icinga::operator<<(std::ostream& stream, const Value& value)
64 if (value.IsBoolean())
65 stream << static_cast<int>(value);
67 stream << static_cast<String>(value);
72 std::istream& icinga::operator>>(std::istream& stream, Value& value)
80 bool Value::operator==(bool rhs) const
82 return *this == Value(rhs);
85 bool Value::operator!=(bool rhs) const
87 return !(*this == rhs);
90 bool Value::operator==(int rhs) const
92 return *this == Value(rhs);
95 bool Value::operator!=(int rhs) const
97 return !(*this == rhs);
100 bool Value::operator==(double rhs) const
102 return *this == Value(rhs);
105 bool Value::operator!=(double rhs) const
107 return !(*this == rhs);
110 bool Value::operator==(const char *rhs) const
112 return static_cast<String>(*this) == rhs;
115 bool Value::operator!=(const char *rhs) const
117 return !(*this == rhs);
120 bool Value::operator==(const String& rhs) const
122 return static_cast<String>(*this) == rhs;
125 bool Value::operator!=(const String& rhs) const
127 return !(*this == rhs);
130 bool Value::operator==(const Value& rhs) const
132 if (IsNumber() && rhs.IsNumber())
133 return Get<double>() == rhs.Get<double>();
134 else if ((IsBoolean() || IsNumber()) && (rhs.IsBoolean() || rhs.IsNumber()) && !(IsEmpty() && rhs.IsEmpty()))
135 return static_cast<double>(*this) == static_cast<double>(rhs);
137 if (IsString() && rhs.IsString())
138 return Get<String>() == rhs.Get<String>();
139 else if ((IsString() || IsEmpty()) && (rhs.IsString() || rhs.IsEmpty()) && !(IsEmpty() && rhs.IsEmpty()))
140 return static_cast<String>(*this) == static_cast<String>(rhs);
142 if (IsEmpty() != rhs.IsEmpty())
148 if (IsObject() != rhs.IsObject())
152 if (IsObjectType<DateTime>() && rhs.IsObjectType<DateTime>()) {
153 DateTime::Ptr dt1 = *this;
154 DateTime::Ptr dt2 = rhs;
156 return dt1->GetValue() == dt2->GetValue();
159 if (IsObjectType<Array>() && rhs.IsObjectType<Array>()) {
160 Array::Ptr arr1 = *this;
161 Array::Ptr arr2 = rhs;
166 if (arr1->GetLength() != arr2->GetLength())
169 for (Array::SizeType i = 0; i < arr1->GetLength(); i++) {
170 if (arr1->Get(i) != arr2->Get(i))
177 return Get<Object::Ptr>() == rhs.Get<Object::Ptr>();
183 bool Value::operator!=(const Value& rhs) const
185 return !(*this == rhs);
188 Value icinga::operator+(const Value& lhs, const char *rhs)
190 return lhs + Value(rhs);
193 Value icinga::operator+(const char *lhs, const Value& rhs)
195 return Value(lhs) + rhs;
198 Value icinga::operator+(const Value& lhs, const String& rhs)
200 return lhs + Value(rhs);
203 Value icinga::operator+(const String& lhs, const Value& rhs)
205 return Value(lhs) + rhs;
208 Value icinga::operator+(const Value& lhs, const Value& rhs)
210 if ((lhs.IsEmpty() || lhs.IsNumber()) && !lhs.IsString() && (rhs.IsEmpty() || rhs.IsNumber()) && !rhs.IsString() && !(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()) || lhs.IsString() || rhs.IsString()))
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()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
215 return static_cast<double>(lhs) + static_cast<double>(rhs);
216 else if (lhs.IsObjectType<DateTime>() && rhs.IsNumber())
217 return new DateTime(Convert::ToDateTimeValue(lhs) + rhs);
218 else if ((lhs.IsObjectType<Array>() || lhs.IsEmpty()) && (rhs.IsObjectType<Array>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) {
219 Array::Ptr result = new Array();
221 static_cast<Array::Ptr>(lhs)->CopyTo(result);
223 static_cast<Array::Ptr>(rhs)->CopyTo(result);
225 } else if ((lhs.IsObjectType<Dictionary>() || lhs.IsEmpty()) && (rhs.IsObjectType<Dictionary>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) {
226 Dictionary::Ptr result = new Dictionary();
228 static_cast<Dictionary::Ptr>(lhs)->CopyTo(result);
230 static_cast<Dictionary::Ptr>(rhs)->CopyTo(result);
233 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator + cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
237 Value icinga::operator+(const Value& lhs, double rhs)
239 return lhs + Value(rhs);
242 Value icinga::operator+(double lhs, const Value& rhs)
244 return Value(lhs) + rhs;
247 Value icinga::operator+(const Value& lhs, int rhs)
249 return lhs + Value(rhs);
252 Value icinga::operator+(int lhs, const Value& rhs)
254 return Value(lhs) + rhs;
257 Value icinga::operator-(const Value& lhs, const Value& rhs)
259 if ((lhs.IsNumber() || lhs.IsEmpty()) && !lhs.IsString() && (rhs.IsNumber() || rhs.IsEmpty()) && !rhs.IsString() && !(lhs.IsEmpty() && rhs.IsEmpty()))
260 return static_cast<double>(lhs) - static_cast<double>(rhs);
261 else if (lhs.IsObjectType<DateTime>() && rhs.IsNumber())
262 return new DateTime(Convert::ToDateTimeValue(lhs) - rhs);
263 else if (lhs.IsObjectType<DateTime>() && rhs.IsObjectType<DateTime>())
264 return Convert::ToDateTimeValue(lhs) - Convert::ToDateTimeValue(rhs);
265 else if ((lhs.IsObjectType<DateTime>() || lhs.IsEmpty()) && (rhs.IsObjectType<DateTime>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
266 return new DateTime(Convert::ToDateTimeValue(lhs) - Convert::ToDateTimeValue(rhs));
267 else if ((lhs.IsObjectType<Array>() || lhs.IsEmpty()) && (rhs.IsObjectType<Array>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) {
272 Array::Ptr left = lhs;
273 Array::Ptr right = rhs;
275 ObjectLock olock(left);
276 for (const Value& lv : left) {
278 ObjectLock xlock(right);
279 for (const Value& rv : right) {
289 result.push_back(lv);
292 return new Array(std::move(result));
294 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator - cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
297 Value icinga::operator-(const Value& lhs, double rhs)
299 return lhs - Value(rhs);
302 Value icinga::operator-(double lhs, const Value& rhs)
304 return Value(lhs) - rhs;
307 Value icinga::operator-(const Value& lhs, int rhs)
309 return lhs - Value(rhs);
312 Value icinga::operator-(int lhs, const Value& rhs)
314 return Value(lhs) - rhs;
317 Value icinga::operator*(const Value& lhs, const Value& rhs)
319 if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
320 return static_cast<double>(lhs) * static_cast<double>(rhs);
322 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator * cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
325 Value icinga::operator*(const Value& lhs, double rhs)
327 return lhs * Value(rhs);
330 Value icinga::operator*(double lhs, const Value& rhs)
332 return Value(lhs) * rhs;
335 Value icinga::operator*(const Value& lhs, int rhs)
337 return lhs * Value(rhs);
340 Value icinga::operator*(int lhs, const Value& rhs)
342 return Value(lhs) * rhs;
345 Value icinga::operator/(const Value& lhs, const Value& rhs)
348 BOOST_THROW_EXCEPTION(std::invalid_argument("Right-hand side argument for operator / is Empty."));
349 else if ((lhs.IsEmpty() || lhs.IsNumber()) && rhs.IsNumber()) {
350 if (static_cast<double>(rhs) == 0)
351 BOOST_THROW_EXCEPTION(std::invalid_argument("Right-hand side argument for operator / is 0."));
353 return static_cast<double>(lhs) / static_cast<double>(rhs);
355 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator / cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
358 Value icinga::operator/(const Value& lhs, double rhs)
360 return lhs / Value(rhs);
363 Value icinga::operator/(double lhs, const Value& rhs)
365 return Value(lhs) / rhs;
368 Value icinga::operator/(const Value& lhs, int rhs)
370 return lhs / Value(rhs);
373 Value icinga::operator/(int lhs, const Value& rhs)
375 return Value(lhs) / rhs;
378 Value icinga::operator%(const Value& lhs, const Value& rhs)
381 BOOST_THROW_EXCEPTION(std::invalid_argument("Right-hand side argument for operator % is Empty."));
382 else if ((rhs.IsNumber() || lhs.IsNumber()) && rhs.IsNumber()) {
383 if (static_cast<double>(rhs) == 0)
384 BOOST_THROW_EXCEPTION(std::invalid_argument("Right-hand side argument for operator % is 0."));
386 return static_cast<int>(lhs) % static_cast<int>(rhs);
388 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator % cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
391 Value icinga::operator%(const Value& lhs, double rhs)
393 return lhs % Value(rhs);
396 Value icinga::operator%(double lhs, const Value& rhs)
398 return Value(lhs) % rhs;
401 Value icinga::operator%(const Value& lhs, int rhs)
403 return lhs % Value(rhs);
406 Value icinga::operator%(int lhs, const Value& rhs)
408 return Value(lhs) % rhs;
411 Value icinga::operator^(const Value& lhs, const Value& rhs)
413 if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
414 return static_cast<int>(lhs) ^ static_cast<int>(rhs);
416 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator & cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
419 Value icinga::operator^(const Value& lhs, double rhs)
421 return lhs ^ Value(rhs);
424 Value icinga::operator^(double lhs, const Value& rhs)
426 return Value(lhs) ^ rhs;
429 Value icinga::operator^(const Value& lhs, int rhs)
431 return lhs ^ Value(rhs);
434 Value icinga::operator^(int lhs, const Value& rhs)
436 return Value(lhs) ^ rhs;
439 Value icinga::operator&(const Value& lhs, const Value& rhs)
441 if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
442 return static_cast<int>(lhs) & static_cast<int>(rhs);
444 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator & cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
447 Value icinga::operator&(const Value& lhs, double rhs)
449 return lhs & Value(rhs);
452 Value icinga::operator&(double lhs, const Value& rhs)
454 return Value(lhs) & rhs;
457 Value icinga::operator&(const Value& lhs, int rhs)
459 return lhs & Value(rhs);
462 Value icinga::operator&(int lhs, const Value& rhs)
464 return Value(lhs) & rhs;
467 Value icinga::operator|(const Value& lhs, const Value& rhs)
469 if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
470 return static_cast<int>(lhs) | static_cast<int>(rhs);
472 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator | cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
475 Value icinga::operator|(const Value& lhs, double rhs)
477 return lhs | Value(rhs);
480 Value icinga::operator|(double lhs, const Value& rhs)
482 return Value(lhs) | rhs;
485 Value icinga::operator|(const Value& lhs, int rhs)
487 return lhs | Value(rhs);
490 Value icinga::operator|(int lhs, const Value& rhs)
492 return Value(lhs) | rhs;
495 Value icinga::operator<<(const Value& lhs, const Value& rhs)
497 if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
498 return static_cast<int>(lhs) << static_cast<int>(rhs);
500 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator << cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
503 Value icinga::operator<<(const Value& lhs, double rhs)
505 return lhs << Value(rhs);
508 Value icinga::operator<<(double lhs, const Value& rhs)
510 return Value(lhs) << rhs;
513 Value icinga::operator<<(const Value& lhs, int rhs)
515 return lhs << Value(rhs);
518 Value icinga::operator<<(int lhs, const Value& rhs)
520 return Value(lhs) << rhs;
523 Value icinga::operator>>(const Value& lhs, const Value& rhs)
525 if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
526 return static_cast<int>(lhs) >> static_cast<int>(rhs);
528 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator >> cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
531 Value icinga::operator>>(const Value& lhs, double rhs)
533 return lhs >> Value(rhs);
536 Value icinga::operator>>(double lhs, const Value& rhs)
538 return Value(lhs) >> rhs;
541 Value icinga::operator>>(const Value& lhs, int rhs)
543 return lhs >> Value(rhs);
546 Value icinga::operator>>(int lhs, const Value& rhs)
548 return Value(lhs) >> rhs;
551 bool icinga::operator<(const Value& lhs, const Value& rhs)
553 if (lhs.IsString() && rhs.IsString())
554 return static_cast<String>(lhs) < static_cast<String>(rhs);
555 else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
556 return static_cast<double>(lhs) < static_cast<double>(rhs);
557 else if ((lhs.IsObjectType<DateTime>() || lhs.IsEmpty()) && (rhs.IsObjectType<DateTime>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
558 return Convert::ToDateTimeValue(lhs) < Convert::ToDateTimeValue(rhs);
559 else if (lhs.IsObjectType<Array>() && rhs.IsObjectType<Array>()) {
560 Array::Ptr larr = lhs;
561 Array::Ptr rarr = rhs;
563 ObjectLock llock(larr);
564 ObjectLock rlock(rarr);
566 Array::SizeType llen = larr->GetLength();
567 Array::SizeType rlen = rarr->GetLength();
569 for (Array::SizeType i = 0; i < std::max(llen, rlen); i++) {
570 Value lval = (i >= llen) ? Empty : larr->Get(i);
571 Value rval = (i >= rlen) ? Empty : rarr->Get(i);
575 else if (lval > rval)
581 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator < cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
584 bool icinga::operator<(const Value& lhs, double rhs)
586 return lhs < Value(rhs);
589 bool icinga::operator<(double lhs, const Value& rhs)
591 return Value(lhs) < rhs;
594 bool icinga::operator<(const Value& lhs, int rhs)
596 return lhs < Value(rhs);
599 bool icinga::operator<(int lhs, const Value& rhs)
601 return Value(lhs) < rhs;
604 bool icinga::operator>(const Value& lhs, const Value& rhs)
606 if (lhs.IsString() && rhs.IsString())
607 return static_cast<String>(lhs) > static_cast<String>(rhs);
608 else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
609 return static_cast<double>(lhs) > static_cast<double>(rhs);
610 else if ((lhs.IsObjectType<DateTime>() || lhs.IsEmpty()) && (rhs.IsObjectType<DateTime>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
611 return Convert::ToDateTimeValue(lhs) > Convert::ToDateTimeValue(rhs);
612 else if (lhs.IsObjectType<Array>() && rhs.IsObjectType<Array>()) {
613 Array::Ptr larr = lhs;
614 Array::Ptr rarr = rhs;
616 ObjectLock llock(larr);
617 ObjectLock rlock(rarr);
619 Array::SizeType llen = larr->GetLength();
620 Array::SizeType rlen = rarr->GetLength();
622 for (Array::SizeType i = 0; i < std::max(llen, rlen); i++) {
623 Value lval = (i >= llen) ? Empty : larr->Get(i);
624 Value rval = (i >= rlen) ? Empty : rarr->Get(i);
628 else if (lval < rval)
634 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator > cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
637 bool icinga::operator>(const Value& lhs, double rhs)
639 return lhs > Value(rhs);
642 bool icinga::operator>(double lhs, const Value& rhs)
644 return Value(lhs) > rhs;
647 bool icinga::operator>(const Value& lhs, int rhs)
649 return lhs > Value(rhs);
652 bool icinga::operator>(int lhs, const Value& rhs)
654 return Value(lhs) > rhs;
657 bool icinga::operator<=(const Value& lhs, const Value& rhs)
659 if (lhs.IsString() && rhs.IsString())
660 return static_cast<String>(lhs) <= static_cast<String>(rhs);
661 else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
662 return static_cast<double>(lhs) <= static_cast<double>(rhs);
663 else if ((lhs.IsObjectType<DateTime>() || lhs.IsEmpty()) && (rhs.IsObjectType<DateTime>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
664 return Convert::ToDateTimeValue(lhs) <= Convert::ToDateTimeValue(rhs);
666 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator <= cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
669 bool icinga::operator<=(const Value& lhs, double rhs)
671 return lhs <= Value(rhs);
674 bool icinga::operator<=(double lhs, const Value& rhs)
676 return Value(lhs) <= rhs;
679 bool icinga::operator<=(const Value& lhs, int rhs)
681 return lhs <= Value(rhs);
684 bool icinga::operator<=(int lhs, const Value& rhs)
686 return Value(lhs) <= rhs;
689 bool icinga::operator>=(const Value& lhs, const Value& rhs)
691 if (lhs.IsString() && rhs.IsString())
692 return static_cast<String>(lhs) >= static_cast<String>(rhs);
693 else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
694 return static_cast<double>(lhs) >= static_cast<double>(rhs);
695 else if ((lhs.IsObjectType<DateTime>() || lhs.IsEmpty()) && (rhs.IsObjectType<DateTime>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
696 return Convert::ToDateTimeValue(lhs) >= Convert::ToDateTimeValue(rhs);
698 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator >= cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
701 bool icinga::operator>=(const Value& lhs, double rhs)
703 return lhs >= Value(rhs);
706 bool icinga::operator>=(double lhs, const Value& rhs)
708 return Value(lhs) >= rhs;
711 bool icinga::operator>=(const Value& lhs, int rhs)
713 return lhs >= Value(rhs);
716 bool icinga::operator>=(int lhs, const Value& rhs)
718 return Value(lhs) >= rhs;