1 /******************************************************************************
3 * Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org) *
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. *
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. *
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 ******************************************************************************/
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>
28 using namespace icinga;
30 Value::operator double(void) const
32 const double *value = boost::get<double>(&m_Value);
37 const bool *fvalue = boost::get<bool>(&m_Value);
46 return boost::lexical_cast<double>(m_Value);
47 } catch (const std::exception&) {
48 std::ostringstream msgbuf;
49 msgbuf << "Can't convert '" << *this << "' to a floating point number.";
50 BOOST_THROW_EXCEPTION(std::invalid_argument(msgbuf.str()));
54 Value::operator String(void) const
57 double integral, fractional;
63 fractional = std::modf(boost::get<double>(m_Value), &integral);
66 return boost::lexical_cast<std::string>(m_Value);
68 return boost::lexical_cast<std::string>((long)integral);
70 if (boost::get<bool>(m_Value))
75 return boost::get<String>(m_Value);
77 object = boost::get<Object::Ptr>(m_Value).get();
78 return object->ToString();
80 BOOST_THROW_EXCEPTION(std::runtime_error("Unknown value type."));
84 std::ostream& icinga::operator<<(std::ostream& stream, const Value& value)
86 if (value.IsBoolean())
87 stream << static_cast<int>(value);
89 stream << static_cast<String>(value);
94 std::istream& icinga::operator>>(std::istream& stream, Value& value)
102 bool Value::operator==(bool rhs) const
104 return *this == Value(rhs);
107 bool Value::operator!=(bool rhs) const
109 return !(*this == rhs);
112 bool Value::operator==(int rhs) const
114 return *this == Value(rhs);
117 bool Value::operator!=(int rhs) const
119 return !(*this == rhs);
122 bool Value::operator==(double rhs) const
124 return *this == Value(rhs);
127 bool Value::operator!=(double rhs) const
129 return !(*this == rhs);
132 bool Value::operator==(const char *rhs) const
134 return static_cast<String>(*this) == rhs;
137 bool Value::operator!=(const char *rhs) const
139 return !(*this == rhs);
142 bool Value::operator==(const String& rhs) const
144 return static_cast<String>(*this) == rhs;
147 bool Value::operator!=(const String& rhs) const
149 return !(*this == rhs);
152 bool Value::operator==(const Value& rhs) const
154 if (IsNumber() && rhs.IsNumber())
155 return Get<double>() == rhs.Get<double>();
156 else if ((IsBoolean() || IsNumber() || IsEmpty()) && (rhs.IsBoolean() || rhs.IsNumber() || rhs.IsEmpty()) && !(IsEmpty() && rhs.IsEmpty()))
157 return static_cast<double>(*this) == static_cast<double>(rhs);
159 if (IsString() && rhs.IsString())
160 return Get<String>() == rhs.Get<String>();
161 else if ((IsString() || IsEmpty()) && (rhs.IsString() || rhs.IsEmpty()) && !(IsEmpty() && rhs.IsEmpty()))
162 return static_cast<String>(*this) == static_cast<String>(rhs);
164 if (IsEmpty() != rhs.IsEmpty())
170 if (IsObject() != rhs.IsObject())
174 if (IsObjectType<Array>() && rhs.IsObjectType<Array>()) {
175 Array::Ptr arr1 = *this;
176 Array::Ptr arr2 = rhs;
181 if (arr1->GetLength() != arr2->GetLength())
184 for (Array::SizeType i = 0; i < arr1->GetLength(); i++) {
185 if (arr1->Get(i) != arr2->Get(i))
192 return Get<Object::Ptr>() == rhs.Get<Object::Ptr>();
198 bool Value::operator!=(const Value& rhs) const
200 return !(*this == rhs);
203 Value icinga::operator+(const Value& lhs, const char *rhs)
205 return lhs + Value(rhs);
208 Value icinga::operator+(const char *lhs, const Value& rhs)
210 return Value(lhs) + rhs;
213 Value icinga::operator+(const Value& lhs, const String& rhs)
215 return lhs + Value(rhs);
218 Value icinga::operator+(const String& lhs, const Value& rhs)
220 return Value(lhs) + rhs;
223 Value icinga::operator+(const Value& lhs, const Value& rhs)
225 if ((lhs.IsEmpty() || lhs.IsNumber()) && (rhs.IsEmpty() || rhs.IsNumber()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
226 return static_cast<double>(lhs) + static_cast<double>(rhs);
227 if ((lhs.IsString() || lhs.IsEmpty() || lhs.IsNumber()) && (rhs.IsString() || rhs.IsEmpty() || rhs.IsNumber()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
228 return static_cast<String>(lhs) + static_cast<String>(rhs);
229 else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
230 return static_cast<double>(lhs) + static_cast<double>(rhs);
231 else if ((lhs.IsObjectType<Array>() || lhs.IsEmpty()) && (rhs.IsObjectType<Array>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) {
232 Array::Ptr result = new Array();
234 static_cast<Array::Ptr>(lhs)->CopyTo(result);
236 static_cast<Array::Ptr>(rhs)->CopyTo(result);
238 } else if ((lhs.IsObjectType<Dictionary>() || lhs.IsEmpty()) && (rhs.IsObjectType<Dictionary>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) {
239 Dictionary::Ptr result = new Dictionary();
241 static_cast<Dictionary::Ptr>(lhs)->CopyTo(result);
243 static_cast<Dictionary::Ptr>(rhs)->CopyTo(result);
246 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator + cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
250 Value icinga::operator+(const Value& lhs, double rhs)
252 return lhs + Value(rhs);
255 Value icinga::operator+(double lhs, const Value& rhs)
257 return Value(lhs) + rhs;
260 Value icinga::operator+(const Value& lhs, int rhs)
262 return lhs + Value(rhs);
265 Value icinga::operator+(int lhs, const Value& rhs)
267 return Value(lhs) + rhs;
270 Value icinga::operator-(const Value& lhs, const Value& rhs)
272 if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
273 return static_cast<double>(lhs) - static_cast<double>(rhs);
274 else if ((lhs.IsObjectType<Array>() || lhs.IsEmpty()) && (rhs.IsObjectType<Array>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) {
278 Array::Ptr result = new Array();
279 Array::Ptr left = lhs;
280 Array::Ptr right = rhs;
282 ObjectLock olock(left);
283 BOOST_FOREACH(const Value& lv, left) {
285 ObjectLock xlock(right);
286 BOOST_FOREACH(const Value& rv, right) {
301 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator - cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
304 Value icinga::operator-(const Value& lhs, double rhs)
306 return lhs - Value(rhs);
309 Value icinga::operator-(double lhs, const Value& rhs)
311 return Value(lhs) - rhs;
314 Value icinga::operator-(const Value& lhs, int rhs)
316 return lhs - Value(rhs);
319 Value icinga::operator-(int lhs, const Value& rhs)
321 return Value(lhs) - rhs;
324 Value icinga::operator*(const Value& lhs, const Value& rhs)
326 if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
327 return static_cast<double>(lhs) * static_cast<double>(rhs);
329 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator * cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
332 Value icinga::operator*(const Value& lhs, double rhs)
334 return lhs * Value(rhs);
337 Value icinga::operator*(double lhs, const Value& rhs)
339 return Value(lhs) * rhs;
342 Value icinga::operator*(const Value& lhs, int rhs)
344 return lhs * Value(rhs);
347 Value icinga::operator*(int lhs, const Value& rhs)
349 return Value(lhs) * rhs;
352 Value icinga::operator/(const Value& lhs, const Value& rhs)
355 BOOST_THROW_EXCEPTION(std::invalid_argument("Right-hand side argument for operator / is Empty."));
356 else if ((lhs.IsEmpty() || lhs.IsNumber()) && rhs.IsNumber()) {
357 if (static_cast<double>(rhs) == 0)
358 BOOST_THROW_EXCEPTION(std::invalid_argument("Right-hand side argument for operator / is 0."));
360 return static_cast<double>(lhs) / static_cast<double>(rhs);
362 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator / cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
365 Value icinga::operator/(const Value& lhs, double rhs)
367 return lhs / Value(rhs);
370 Value icinga::operator/(double lhs, const Value& rhs)
372 return Value(lhs) / rhs;
375 Value icinga::operator/(const Value& lhs, int rhs)
377 return lhs / Value(rhs);
380 Value icinga::operator/(int lhs, const Value& rhs)
382 return Value(lhs) / rhs;
385 Value icinga::operator%(const Value& lhs, const Value& rhs)
388 BOOST_THROW_EXCEPTION(std::invalid_argument("Right-hand side argument for operator % is Empty."));
389 else if ((rhs.IsNumber() || lhs.IsNumber()) && rhs.IsNumber()) {
390 if (static_cast<double>(rhs) == 0)
391 BOOST_THROW_EXCEPTION(std::invalid_argument("Right-hand side argument for operator % is 0."));
393 return static_cast<int>(lhs) % static_cast<int>(rhs);
395 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator % cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
398 Value icinga::operator%(const Value& lhs, double rhs)
400 return lhs % Value(rhs);
403 Value icinga::operator%(double lhs, const Value& rhs)
405 return Value(lhs) % rhs;
408 Value icinga::operator%(const Value& lhs, int rhs)
410 return lhs % Value(rhs);
413 Value icinga::operator%(int lhs, const Value& rhs)
415 return Value(lhs) % rhs;
418 Value icinga::operator^(const Value& lhs, const Value& rhs)
420 if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
421 return static_cast<int>(lhs) ^ static_cast<int>(rhs);
423 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator & cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
426 Value icinga::operator^(const Value& lhs, double rhs)
428 return lhs & Value(rhs);
431 Value icinga::operator^(double lhs, const Value& rhs)
433 return Value(lhs) & rhs;
436 Value icinga::operator^(const Value& lhs, int rhs)
438 return lhs & Value(rhs);
441 Value icinga::operator^(int lhs, const Value& rhs)
443 return Value(lhs) & rhs;
446 Value icinga::operator&(const Value& lhs, const Value& rhs)
448 if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
449 return static_cast<int>(lhs) & static_cast<int>(rhs);
451 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator & cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
454 Value icinga::operator&(const Value& lhs, double rhs)
456 return lhs & Value(rhs);
459 Value icinga::operator&(double lhs, const Value& rhs)
461 return Value(lhs) & rhs;
464 Value icinga::operator&(const Value& lhs, int rhs)
466 return lhs & Value(rhs);
469 Value icinga::operator&(int lhs, const Value& rhs)
471 return Value(lhs) & rhs;
474 Value icinga::operator|(const Value& lhs, const Value& rhs)
476 if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
477 return static_cast<int>(lhs) | static_cast<int>(rhs);
479 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator | cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
482 Value icinga::operator|(const Value& lhs, double rhs)
484 return lhs | Value(rhs);
487 Value icinga::operator|(double lhs, const Value& rhs)
489 return Value(lhs) | rhs;
492 Value icinga::operator|(const Value& lhs, int rhs)
494 return lhs | Value(rhs);
497 Value icinga::operator|(int lhs, const Value& rhs)
499 return Value(lhs) | rhs;
502 Value icinga::operator<<(const Value& lhs, const Value& rhs)
504 if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
505 return static_cast<int>(lhs) << static_cast<int>(rhs);
507 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator << cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
510 Value icinga::operator<<(const Value& lhs, double rhs)
512 return lhs << Value(rhs);
515 Value icinga::operator<<(double lhs, const Value& rhs)
517 return Value(lhs) << rhs;
520 Value icinga::operator<<(const Value& lhs, int rhs)
522 return lhs << Value(rhs);
525 Value icinga::operator<<(int lhs, const Value& rhs)
527 return Value(lhs) << rhs;
530 Value icinga::operator>>(const Value& lhs, const Value& rhs)
532 if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
533 return static_cast<int>(lhs) >> static_cast<int>(rhs);
535 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator >> cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
538 Value icinga::operator>>(const Value& lhs, double rhs)
540 return lhs >> Value(rhs);
543 Value icinga::operator>>(double lhs, const Value& rhs)
545 return Value(lhs) >> rhs;
548 Value icinga::operator>>(const Value& lhs, int rhs)
550 return lhs >> Value(rhs);
553 Value icinga::operator>>(int lhs, const Value& rhs)
555 return Value(lhs) >> rhs;
558 bool icinga::operator<(const Value& lhs, const Value& rhs)
560 if (lhs.IsString() && rhs.IsString())
561 return static_cast<String>(lhs) < static_cast<String>(rhs);
562 else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
563 return static_cast<double>(lhs) < static_cast<double>(rhs);
565 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator < cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
568 bool icinga::operator<(const Value& lhs, double rhs)
570 return lhs < Value(rhs);
573 bool icinga::operator<(double lhs, const Value& rhs)
575 return Value(lhs) < rhs;
578 bool icinga::operator<(const Value& lhs, int rhs)
580 return lhs < Value(rhs);
583 bool icinga::operator<(int lhs, const Value& rhs)
585 return Value(lhs) < rhs;
588 bool icinga::operator>(const Value& lhs, const Value& rhs)
590 if (lhs.IsString() && rhs.IsString())
591 return static_cast<String>(lhs) > static_cast<String>(rhs);
592 else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
593 return static_cast<double>(lhs) > static_cast<double>(rhs);
595 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator > cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
598 bool icinga::operator>(const Value& lhs, double rhs)
600 return lhs > Value(rhs);
603 bool icinga::operator>(double lhs, const Value& rhs)
605 return Value(lhs) > rhs;
608 bool icinga::operator>(const Value& lhs, int rhs)
610 return lhs > Value(rhs);
613 bool icinga::operator>(int lhs, const Value& rhs)
615 return Value(lhs) > rhs;
618 bool icinga::operator<=(const Value& lhs, const Value& rhs)
620 if (lhs.IsString() && rhs.IsString())
621 return static_cast<String>(lhs) <= static_cast<String>(rhs);
622 else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
623 return static_cast<double>(lhs) <= static_cast<double>(rhs);
625 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator <= cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
628 bool icinga::operator<=(const Value& lhs, double rhs)
630 return lhs <= Value(rhs);
633 bool icinga::operator<=(double lhs, const Value& rhs)
635 return Value(lhs) <= rhs;
638 bool icinga::operator<=(const Value& lhs, int rhs)
640 return lhs <= Value(rhs);
643 bool icinga::operator<=(int lhs, const Value& rhs)
645 return Value(lhs) <= rhs;
648 bool icinga::operator>=(const Value& lhs, const Value& rhs)
650 if (lhs.IsString() && rhs.IsString())
651 return static_cast<String>(lhs) >= static_cast<String>(rhs);
652 else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
653 return static_cast<double>(lhs) >= static_cast<double>(rhs);
655 BOOST_THROW_EXCEPTION(std::invalid_argument("Operator >= cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
658 bool icinga::operator>=(const Value& lhs, double rhs)
660 return lhs >= Value(rhs);
663 bool icinga::operator>=(double lhs, const Value& rhs)
665 return Value(lhs) >= rhs;
668 bool icinga::operator>=(const Value& lhs, int rhs)
670 return lhs >= Value(rhs);
673 bool icinga::operator>=(int lhs, const Value& rhs)
675 return Value(lhs) >= rhs;