From 9b13fadba148bc0e20afbd2d68e94ccb60fbed0d Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Thu, 2 Jan 2014 01:15:15 -0500 Subject: [PATCH] Variant - Merged libexpr changes. --- src/CMakeLists.txt | 1 + src/Variant.cpp | 1533 ++++++++++++++++++++++++++++++++++++++++++++ src/Variant.h | 107 ++++ 3 files changed, 1641 insertions(+) create mode 100644 src/Variant.cpp create mode 100644 src/Variant.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 760e96b52..9dd0f336b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -40,6 +40,7 @@ set (task_SRCS A3.cpp A3.h TransportShell.cpp TransportShell.h Tree.cpp Tree.h Uri.cpp Uri.h + Variant.cpp Variant.h ViewTask.cpp ViewTask.h ViewText.cpp ViewText.h dependency.cpp diff --git a/src/Variant.cpp b/src/Variant.cpp new file mode 100644 index 000000000..af9716069 --- /dev/null +++ b/src/Variant.cpp @@ -0,0 +1,1533 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright 2013 - 2014, Paul Beckingham, Federico Hernandez. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// http://www.opensource.org/licenses/mit-license.php +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//////////////////////////////////////////////////////////////////////////////// +Variant::Variant () +: _type (type_unknown) +, _bool (false) +, _integer (0) +, _real (0.0) +, _string ("") +, _date (0) +, _duration (0) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Variant::Variant (const Variant& other) +: _type (type_unknown) +, _bool (false) +, _integer (0) +, _real (0.0) +, _string ("") +, _date (0) +, _duration (0) +{ + *this = other; +} + +//////////////////////////////////////////////////////////////////////////////// +Variant::Variant (const bool value) +: _type (Variant::type_boolean) +, _bool (value) +, _integer (0) +, _real (0.0) +, _string ("") +, _date (0) +, _duration (0) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Variant::Variant (const int value) +: _type (Variant::type_integer) +, _bool (false) +, _integer (value) +, _real (0.0) +, _string ("") +, _date (0) +, _duration (0) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Variant::Variant (const double value) +: _type (Variant::type_real) +, _bool (false) +, _integer (0) +, _real (value) +, _string ("") +, _date (0) +, _duration (0) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Variant::Variant (const std::string& value) +: _type (Variant::type_string) +, _bool (false) +, _integer (0) +, _real (0.0) +, _string (value) +, _date (0) +, _duration (0) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Variant::Variant (const char* value) +: _type (Variant::type_string) +, _bool (false) +, _integer (0) +, _real (0.0) +, _string (std::string (value)) +, _date (0) +, _duration (0) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Variant::Variant (const time_t value, const enum type new_type /*=type_date*/) +: _type (new_type) +, _bool (false) +, _integer (0) +, _real (0.0) +, _string ("") +, _date (0) +, _duration (0) +{ + switch (new_type) + { + case type_date: _date = value; break; + case type_duration: _duration = value; break; + default: + throw std::string ("Cannot instantiate this type with a time_t value."); + } +} + +//////////////////////////////////////////////////////////////////////////////// +Variant::~Variant () +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Variant& Variant::operator= (const Variant& other) +{ + if (this != &other) + { + _type = other._type; + _bool = other._bool; + _integer = other._integer; + _real = other._real; + _string = other._string; + _date = other._date; + _duration = other._duration; + } + + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Variant::operator&& (const Variant& other) const +{ + Variant left (*this); + Variant right (other); + + left.cast (type_boolean); + right.cast (type_boolean); + + return left._bool && right._bool; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Variant::operator|| (const Variant& other) const +{ + Variant left (*this); + Variant right (other); + + left.cast (type_boolean); + right.cast (type_boolean); + + return left._bool || right._bool; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Variant::operator_xor (const Variant& other) const +{ + Variant left (*this); + Variant right (other); + + left.cast (type_boolean); + right.cast (type_boolean); + + return (left._bool && !right._bool) || + (!left._bool && right._bool); +} + +//////////////////////////////////////////////////////////////////////////////// +bool Variant::operator< (const Variant& other) const +{ + Variant left (*this); + Variant right (other); + + switch (left._type) + { + case type_unknown: + throw std::string ("Cannot compare unknown type"); + break; + + case type_boolean: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: return !left._bool && right._bool; + case type_integer: left.cast (type_integer); return left._integer < right._integer; + case type_real: left.cast (type_real); return left._real < right._real; + case type_string: left.cast (type_string); return left._string < right._string; + case type_date: left.cast (type_date); return left._date < right._date; + case type_duration: left.cast (type_duration); return left._duration < right._duration; + } + break; + + case type_integer: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: right.cast (type_integer); return left._integer < right._integer; + case type_integer: return left._integer < right._integer; + case type_real: left.cast (type_real); return left._real < right._real; + case type_string: left.cast (type_string); return left._string < right._string; + case type_date: left.cast (type_date); return left._date < right._date; + case type_duration: left.cast (type_duration); return left._duration < right._duration; + } + break; + + case type_real: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: right.cast (type_real); return left._real < right._real; + case type_integer: right.cast (type_real); return left._real < right._real; + case type_real: return left._real < right._real; + case type_string: left.cast (type_string); return left._string < right._string; + case type_date: left.cast (type_date); return left._date < right._date; + case type_duration: left.cast (type_duration); return left._duration < right._duration; + } + break; + + case type_string: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: right.cast (type_string); return left._string < right._string; + case type_integer: right.cast (type_string); return left._string < right._string; + case type_real: right.cast (type_string); return left._string < right._string; + case type_string: return left._string < right._string; + case type_date: left.cast (type_date); return left._date < right._date; + case type_duration: left.cast (type_duration); return left._duration < right._duration; + } + break; + + case type_date: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: right.cast (type_date); return left._date < right._date; + case type_integer: right.cast (type_date); return left._date < right._date; + case type_real: right.cast (type_date); return left._date < right._date; + case type_string: right.cast (type_date); return left._date < right._date; + case type_date: return left._date < right._date; + case type_duration: return left._date < right._duration; + } + break; + + case type_duration: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: right.cast (type_duration); return left._duration < right._duration; + case type_integer: right.cast (type_duration); return left._duration < right._duration; + case type_real: right.cast (type_duration); return left._duration < right._duration; + case type_string: right.cast (type_duration); return left._duration < right._duration; + case type_date: return left._duration < right._date; + case type_duration: return left._duration < right._duration; + } + break; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Variant::operator<= (const Variant& other) const +{ + Variant left (*this); + Variant right (other); + + switch (left._type) + { + case type_unknown: + throw std::string ("Cannot compare unknown type"); + break; + + case type_boolean: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: return !left._bool || right._bool; + case type_integer: left.cast (type_integer); return left._integer <= right._integer; + case type_real: left.cast (type_real); return left._real <= right._real; + case type_string: left.cast (type_string); return left._string <= right._string; + case type_date: left.cast (type_date); return left._date <= right._date; + case type_duration: left.cast (type_duration); return left._duration <= right._duration; + } + break; + + case type_integer: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: right.cast (type_integer); return left._integer <= right._integer; + case type_integer: return left._integer <= right._integer; + case type_real: left.cast (type_real); return left._real <= right._real; + case type_string: left.cast (type_string); return left._string <= right._string; + case type_date: left.cast (type_date); return left._date <= right._date; + case type_duration: left.cast (type_duration); return left._duration <= right._duration; + } + break; + + case type_real: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: right.cast (type_real); return left._real <= right._real; + case type_integer: right.cast (type_real); return left._real <= right._real; + case type_real: return left._real <= right._real; + case type_string: left.cast (type_string); return left._string <= right._string; + case type_date: left.cast (type_date); return left._date <= right._date; + case type_duration: left.cast (type_duration); return left._duration <= right._duration; + } + break; + + case type_string: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: right.cast (type_string); return left._string <= right._string; + case type_integer: right.cast (type_string); return left._string <= right._string; + case type_real: right.cast (type_string); return left._string <= right._string; + case type_string: return left._string <= right._string; + case type_date: left.cast (type_date); return left._date <= right._date; + case type_duration: left.cast (type_duration); return left._duration <= right._duration; + } + break; + + case type_date: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: right.cast (type_date); return left._date <= right._date; + case type_integer: right.cast (type_date); return left._date <= right._date; + case type_real: right.cast (type_date); return left._date <= right._date; + case type_string: right.cast (type_date); return left._date <= right._date; + case type_date: return left._date <= right._date; + case type_duration: return left._date <= right._duration; + } + break; + + case type_duration: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: right.cast (type_duration); return left._duration <= right._duration; + case type_integer: right.cast (type_duration); return left._duration <= right._duration; + case type_real: right.cast (type_duration); return left._duration <= right._duration; + case type_string: right.cast (type_duration); return left._duration <= right._duration; + case type_date: return left._duration <= right._date; + case type_duration: return left._duration <= right._duration; + } + break; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Variant::operator> (const Variant& other) const +{ + Variant left (*this); + Variant right (other); + + switch (left._type) + { + case type_unknown: + throw std::string ("Cannot compare unknown type"); + break; + + case type_boolean: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: return !left._bool && right._bool; + case type_integer: left.cast (type_integer); return left._integer > right._integer; + case type_real: left.cast (type_real); return left._real > right._real; + case type_string: left.cast (type_string); return left._string > right._string; + case type_date: left.cast (type_date); return left._date > right._date; + case type_duration: left.cast (type_duration); return left._duration > right._duration; + } + break; + + case type_integer: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: right.cast (type_integer); return left._integer > right._integer; + case type_integer: return left._integer > right._integer; + case type_real: left.cast (type_real); return left._real > right._real; + case type_string: left.cast (type_string); return left._string > right._string; + case type_date: left.cast (type_date); return left._date > right._date; + case type_duration: left.cast (type_duration); return left._duration > right._duration; + } + break; + + case type_real: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: right.cast (type_real); return left._real > right._real; + case type_integer: right.cast (type_real); return left._real > right._real; + case type_real: return left._real > right._real; + case type_string: left.cast (type_string); return left._string > right._string; + case type_date: left.cast (type_date); return left._date > right._date; + case type_duration: left.cast (type_duration); return left._duration > right._duration; + } + break; + + case type_string: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: right.cast (type_string); return left._string > right._string; + case type_integer: right.cast (type_string); return left._string > right._string; + case type_real: right.cast (type_string); return left._string > right._string; + case type_string: return left._string > right._string; + case type_date: left.cast (type_date); return left._date > right._date; + case type_duration: left.cast (type_duration); return left._duration > right._duration; + } + break; + + case type_date: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: right.cast (type_date); return left._date > right._date; + case type_integer: right.cast (type_date); return left._date > right._date; + case type_real: right.cast (type_date); return left._date > right._date; + case type_string: right.cast (type_date); return left._date > right._date; + case type_date: return left._date > right._date; + case type_duration: return left._date > right._duration; + } + break; + + case type_duration: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: right.cast (type_duration); return left._duration > right._duration; + case type_integer: right.cast (type_duration); return left._duration > right._duration; + case type_real: right.cast (type_duration); return left._duration > right._duration; + case type_string: right.cast (type_duration); return left._duration > right._duration; + case type_date: return left._duration > right._date; + case type_duration: return left._duration > right._duration; + } + break; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Variant::operator>= (const Variant& other) const +{ + Variant left (*this); + Variant right (other); + + switch (left._type) + { + case type_unknown: + throw std::string ("Cannot compare unknown type"); + break; + + case type_boolean: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: return left._bool || !right._bool; + case type_integer: left.cast (type_integer); return left._integer >= right._integer; + case type_real: left.cast (type_real); return left._real >= right._real; + case type_string: left.cast (type_string); return left._string >= right._string; + case type_date: left.cast (type_date); return left._date >= right._date; + case type_duration: left.cast (type_duration); return left._duration >= right._duration; + } + break; + + case type_integer: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: right.cast (type_integer); return left._integer >= right._integer; + case type_integer: return left._integer >= right._integer; + case type_real: left.cast (type_real); return left._real >= right._real; + case type_string: left.cast (type_string); return left._string >= right._string; + case type_date: left.cast (type_date); return left._date >= right._date; + case type_duration: left.cast (type_duration); return left._duration >= right._duration; + } + break; + + case type_real: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: right.cast (type_real); return left._real >= right._real; + case type_integer: right.cast (type_real); return left._real >= right._real; + case type_real: return left._real >= right._real; + case type_string: left.cast (type_string); return left._string >= right._string; + case type_date: left.cast (type_date); return left._date >= right._date; + case type_duration: left.cast (type_duration); return left._duration >= right._duration; + } + break; + + case type_string: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: right.cast (type_string); return left._string >= right._string; + case type_integer: right.cast (type_string); return left._string >= right._string; + case type_real: right.cast (type_string); return left._string >= right._string; + case type_string: return left._string >= right._string; + case type_date: left.cast (type_date); return left._date >= right._date; + case type_duration: left.cast (type_duration); return left._duration >= right._duration; + } + break; + + case type_date: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: right.cast (type_date); return left._date >= right._date; + case type_integer: right.cast (type_date); return left._date >= right._date; + case type_real: right.cast (type_date); return left._date >= right._date; + case type_string: right.cast (type_date); return left._date >= right._date; + case type_date: return left._date >= right._date; + case type_duration: return left._date >= right._duration; + } + break; + + case type_duration: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot compare unknown type"); + case type_boolean: right.cast (type_duration); return left._duration >= right._duration; + case type_integer: right.cast (type_duration); return left._duration >= right._duration; + case type_real: right.cast (type_duration); return left._duration >= right._duration; + case type_string: right.cast (type_duration); return left._duration >= right._duration; + case type_date: return left._duration >= right._date; + case type_duration: return left._duration >= right._duration; + } + break; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Variant::operator== (const Variant& other) const +{ + Variant left (*this); + Variant right (other); + + switch (left._type) + { + case type_unknown: + throw std::string ("Cannot equate unknown type"); + break; + + case type_boolean: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot equate unknown type"); + case type_boolean: return left._bool == right._bool; + case type_integer: left.cast (type_integer); return left._integer == right._integer; + case type_real: left.cast (type_real); return left._real == right._real; + case type_string: left.cast (type_string); return left._string == right._string; + case type_date: left.cast (type_date); return left._date == right._date; + case type_duration: left.cast (type_duration); return left._duration == right._duration; + } + break; + + case type_integer: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot equate unknown type"); + case type_boolean: right.cast (type_integer); return left._integer == right._integer; + case type_integer: return left._integer == right._integer; + case type_real: left.cast (type_real); return left._real == right._real; + case type_string: left.cast (type_string); return left._string == right._string; + case type_date: left.cast (type_date); return left._date == right._date; + case type_duration: left.cast (type_duration); return left._duration == right._duration; + } + break; + + case type_real: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot equate unknown type"); + case type_boolean: right.cast (type_real); return left._real == right._real; + case type_integer: right.cast (type_real); return left._real == right._real; + case type_real: return left._real == right._real; + case type_string: left.cast (type_string); return left._string == right._string; + case type_date: left.cast (type_date); return left._date == right._date; + case type_duration: left.cast (type_duration); return left._duration == right._duration; + } + break; + + case type_string: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot equate unknown type"); + case type_boolean: right.cast (type_string); return left._string == right._string; + case type_integer: right.cast (type_string); return left._string == right._string; + case type_real: right.cast (type_string); return left._string == right._string; + case type_string: return left._string == right._string; + case type_date: left.cast (type_date); return left._date == right._date; + case type_duration: left.cast (type_duration); return left._duration == right._duration; + } + break; + + case type_date: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot equate unknown type"); + case type_boolean: right.cast (type_date); return left._date == right._date; + case type_integer: right.cast (type_date); return left._date == right._date; + case type_real: right.cast (type_date); return left._date == right._date; + case type_string: right.cast (type_date); return left._date == right._date; + case type_date: return left._date == right._date; + case type_duration: return left._date == right._duration; + } + break; + + case type_duration: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot equate unknown type"); + case type_boolean: right.cast (type_duration); return left._duration == right._duration; + case type_integer: right.cast (type_duration); return left._duration == right._duration; + case type_real: right.cast (type_duration); return left._duration == right._duration; + case type_string: right.cast (type_duration); return left._duration == right._duration; + case type_date: return left._duration == right._date; + case type_duration: return left._duration == right._duration; + } + break; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Variant::operator!= (const Variant& other) const +{ + return !(*this == other); +} + +//////////////////////////////////////////////////////////////////////////////// +bool Variant::operator_match (const Variant& other) const +{ + Variant left (*this); + Variant right (other); + + left.cast (type_string); + right.cast (type_string); + + RX r (right._string, true); + return r.match (left._string); +} + +//////////////////////////////////////////////////////////////////////////////// +bool Variant::operator_nomatch (const Variant& other) const +{ + return ! operator_match (other); +} + +//////////////////////////////////////////////////////////////////////////////// +bool Variant::operator! () const +{ + Variant left (*this); + left.cast (type_boolean); + return ! left._bool; +} + +//////////////////////////////////////////////////////////////////////////////// +Variant& Variant::operator^= (const Variant& other) +{ + switch (_type) + { + case type_unknown: + throw std::string ("Cannot exponentiate unknown type"); + break; + + case type_boolean: + throw std::string ("Cannot exponentiate Boolean values"); + break; + + case type_integer: + switch (other._type) + { + case type_unknown: throw std::string ("Cannot exponentiate unknown type"); + case type_boolean: throw std::string ("Cannot exponentiate Booleans"); + case type_integer: _integer = (int) pow (static_cast(_integer), static_cast(other._integer)); break; + case type_real: throw std::string ("Cannot exponentiate to a non-integer power"); + case type_string: throw std::string ("Cannot exponentiate strings"); + case type_date: throw std::string ("Cannot exponentiate dates"); + case type_duration: throw std::string ("Cannot exponentiate durations"); + } + break; + + case type_real: + switch (other._type) + { + case type_unknown: throw std::string ("Cannot exponentiate unknown type"); + case type_boolean: throw std::string ("Cannot exponentiate Booleans"); + case type_integer: _real = pow (_real, static_cast(other._integer)); break; + case type_real: throw std::string ("Cannot exponentiate to a non-integer power"); + case type_string: throw std::string ("Cannot exponentiate strings"); + case type_date: throw std::string ("Cannot exponentiate dates"); + case type_duration: throw std::string ("Cannot exponentiate durations"); + } + break; + + case type_string: + throw std::string ("Cannot perform exponentiation on string values"); + break; + + case type_date: + throw std::string ("Cannot perform exponentiation on date values"); + break; + + case type_duration: + throw std::string ("Cannot perform exponentiation on duration values"); + break; + } + + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// +Variant Variant::operator^ (const Variant& other) const +{ + Variant left (*this); + left ^= other; + return left; +} + +//////////////////////////////////////////////////////////////////////////////// +Variant& Variant::operator-= (const Variant& other) +{ + Variant right (other); + + switch (_type) + { + case type_unknown: + throw std::string ("Cannot subtract unknown type"); + break; + + case type_boolean: + throw std::string ("Cannot subtract from a Boolean value"); + break; + + case type_integer: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot subtract unknown type"); + case type_boolean: right.cast (type_integer); _integer -= right._integer; break; + case type_integer: _integer -= right._integer; break; + case type_real: cast (type_real); _real -= right._real; break; + case type_string: throw std::string ("Cannot subtract strings"); + case type_date: cast (type_date); _date -= right._date; break; + case type_duration: cast (type_duration); _duration -= right._duration; break; + } + break; + + case type_real: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot subtract unknown type"); + case type_boolean: right.cast (type_real); _real -= right._real; break; + case type_integer: right.cast (type_real); _real -= right._real; break; + case type_real: _real -= right._real; break; + case type_string: throw std::string ("Cannot subtract strings"); + case type_date: right.cast (type_real); _real -= right._real; break; + case type_duration: right.cast (type_real); _real -= right._real; break; + } + break; + + case type_string: + throw std::string ("Cannot subtract strings"); + break; + + case type_date: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot subtract unknown type"); + case type_boolean: right.cast (type_integer); _date -= right._integer; break; + case type_integer: _date -= right._integer; break; + case type_real: _date -= (int) right._real; break; + case type_string: throw std::string ("Cannot subtract strings"); + case type_date: cast (type_duration); _duration -= right._date; break; + case type_duration: _date -= right._duration; break; + } + break; + + case type_duration: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot subtract unknown type"); + case type_boolean: right.cast (type_integer); _duration -= right._integer; break; + case type_integer: _duration -= right._integer; break; + case type_real: _duration -= (int) right._real; break; + case type_string: throw std::string ("Cannot subtract strings"); + case type_date: throw std::string ("Cannot subtract a date"); + case type_duration: _duration -= right._duration; break; + } + break; + } + + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// +Variant Variant::operator- (const Variant& other) const +{ + Variant left (*this); + left -= other; + return left; +} + +//////////////////////////////////////////////////////////////////////////////// +Variant& Variant::operator+= (const Variant& other) +{ + Variant right (other); + + switch (_type) + { + case type_unknown: + throw std::string ("Cannot add unknown type"); + break; + + case type_boolean: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot add unknown type"); + case type_boolean: throw std::string ("Cannot add two Boolean values"); + case type_integer: cast (type_integer); _integer += right._integer; break; + case type_real: cast (type_real); _real += right._real; break; + case type_string: cast (type_string); _string += right._string; break; + case type_date: cast (type_date); _date += right._date; break; + case type_duration: cast (type_duration); _duration += right._duration; break; + } + break; + + case type_integer: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot add unknown type"); + case type_boolean: right.cast (type_integer); _integer += right._integer; break; + case type_integer: _integer += right._integer; break; + case type_real: cast (type_real); _real += right._real; break; + case type_string: cast (type_string); _string += right._string; break; + case type_date: cast (type_date); _date += right._date; break; + case type_duration: cast (type_duration); _duration += right._duration; break; + } + break; + + case type_real: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot add unknown type"); + case type_boolean: right.cast (type_real); _real += right._real; break; + case type_integer: right.cast (type_real); _real += right._real; break; + case type_real: _real += right._real; break; + case type_string: cast (type_string); _string += right._string; break; + case type_date: + _type = type_date; + _date = (unsigned) (int) _real + right._date; + break; + case type_duration: + _type = type_duration; + _duration = (unsigned) (int) _real + right._duration; + break; + } + break; + + case type_string: + _string += (std::string) right; + break; + + case type_date: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot add unknown type"); + case type_boolean: right.cast (type_date); _date += right._date; break; + case type_integer: _date += right._integer; break; + case type_real: _date += (int) right._real; break; + case type_string: cast (type_string); _string += right._string; break; + case type_date: throw std::string ("Cannot add two date values"); + case type_duration: _date += right._duration; break; + } + break; + + case type_duration: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot add unknown type"); + case type_boolean: right.cast (type_duration); _duration += right._duration; break; + case type_integer: _duration += right._integer; break; + case type_real: _duration += (int) right._real; break; + case type_string: cast (type_string); _string += right._string; break; + case type_date: cast (type_date); _date += right._date; break; + case type_duration: _duration += right._duration; break; + } + break; + } + + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// +Variant Variant::operator+ (const Variant& other) const +{ + Variant left (*this); + left += other; + return left; +} + +//////////////////////////////////////////////////////////////////////////////// +Variant& Variant::operator*= (const Variant& other) +{ + Variant right (other); + + switch (_type) + { + case type_unknown: + throw std::string ("Cannot multiply unknown type"); + break; + + case type_boolean: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot multiply unknown type"); + case type_boolean: throw std::string ("Cannot multiply Boolean values"); + case type_integer: cast (type_integer); _integer *= right._integer; break; + case type_real: cast (type_real); _real *= right._real; break; + case type_string: _string = (_bool ? right._string : ""); _type = type_string; break; + case type_date: throw std::string ("Cannot multiply date values"); + case type_duration: cast (type_duration); _duration *= right._duration; break; + } + break; + + case type_integer: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot multiply unknown type"); + case type_boolean: right.cast (type_integer); _integer *= right._integer; break; + case type_integer: _integer *= right._integer; break; + case type_real: cast (type_real); _real *= right._real; break; + case type_string: + { + int limit = _integer; + // assert (limit < 128); + _type = type_string; + _string = ""; + while (limit--) + _string += right._string; + } + break; + case type_date: throw std::string ("Cannot multiply date values"); + case type_duration: cast (type_duration); _duration *= right._duration; break; + } + break; + + case type_real: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot multiply unknown type"); + case type_boolean: right.cast (type_real); _real *= right._real; break; + case type_integer: right.cast (type_real); _real *= right._real; break; + case type_real: _real *= right._real; break; + case type_string: throw std::string ("Cannot multiply real numbers by strings"); + case type_date: throw std::string ("Cannot multiply real numbers by dates"); + case type_duration: + _type = type_duration; + _duration = (time_t) (unsigned) (int) (_real * static_cast(right._duration)); + } + break; + + case type_string: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot multiply unknown type"); + case type_boolean: if (! right._bool) _string = ""; break; + case type_integer: + { + int limit = right._integer - 1; + // assert (limit < 128); + std::string fragment = _string; + while (limit--) + _string += fragment; + } + break; + case type_real: throw std::string ("Cannot multiply strings by real nubmers"); + case type_string: throw std::string ("Cannot multiply strings by strings"); + case type_date: throw std::string ("Cannot multiply strings by dates"); + case type_duration: throw std::string ("Cannot multiply strings by durations"); + } + break; + + case type_date: + throw std::string ("Cannot multiply date values"); + + case type_duration: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot multiply unknown type"); + case type_boolean: right.cast (type_duration); _duration *= right._duration; break; + case type_integer: _duration *= right._integer; break; + case type_real: + _duration = (time_t) (unsigned) (int) (static_cast(_duration) * right._real); + break; + case type_string: throw std::string ("Cannot multiply durations by strings"); + case type_date: throw std::string ("Cannot multuply durations by dates"); + case type_duration: throw std::string ("Cannot multiply durations by durations"); + } + break; + } + + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// +Variant Variant::operator* (const Variant& other) const +{ + Variant left (*this); + left *= other; + return left; +} + +//////////////////////////////////////////////////////////////////////////////// +Variant& Variant::operator/= (const Variant& other) +{ + Variant right (other); + + switch (_type) + { + case type_unknown: + throw std::string ("Cannot divide unknown type"); + break; + + case type_boolean: + throw std::string ("Cannot divide Boolean"); + break; + + case type_integer: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot divide unknown type"); + case type_boolean: throw std::string ("Cannot divide integer by Boolean"); + case type_integer: + if (right._integer == 0) + throw std::string ("Divide by zero"); + _integer /= right._integer; + break; + case type_real: + if (right._real == 0.0) + throw std::string ("Divide by zero"); + cast (type_real); + _real /= right._real; + break; + case type_string: throw std::string ("Cannot divide integer by string"); + case type_date: throw std::string ("Cannot divide integer by date values"); + case type_duration: + if (right._duration == 0) + throw std::string ("Divide by zero"); + _type = type_duration; + _duration = (time_t) (unsigned) (int) (_integer / right._duration); + break; + } + break; + + case type_real: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot divide unknown type"); + case type_boolean: throw std::string ("Cannot divide real by Boolean"); + case type_integer: + if (right._integer == 0) + throw std::string ("Divide by zero"); + _real /= static_cast(right._integer); + break; + case type_real: + if (right._real == 0) + throw std::string ("Divide by zero"); + _real /= right._real; + break; + case type_string: throw std::string ("Cannot divide real numbers by strings"); + case type_date: throw std::string ("Cannot divide real numbers by dates"); + case type_duration: + if (right._duration == 0) + throw std::string ("Divide by zero"); + _type = type_duration; + _duration = (time_t) (unsigned) (int) (_real / right._duration); + break; + } + break; + + case type_string: + throw std::string ("Cannot divide string values"); + break; + + case type_date: + throw std::string ("Cannot divide date values"); + + case type_duration: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot divide unknown type"); + case type_boolean: throw std::string ("Cannot divide duration by Boolean"); + case type_integer: + if (right._integer == 0) + throw std::string ("Divide by zero"); + _duration /= right._integer; + break; + case type_real: + if (right._real == 0) + throw std::string ("Divide by zero"); + _duration = (time_t) (unsigned) (int) (static_cast(_duration) / right._real); + break; + case type_string: throw std::string ("Cannot divide durations by strings"); + case type_date: throw std::string ("Cannot divide durations by dates"); + case type_duration: throw std::string ("Cannot divide durations by durations"); + } + break; + } + + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// +Variant Variant::operator/ (const Variant& other) const +{ + Variant left (*this); + left /= other; + return left; +} + +//////////////////////////////////////////////////////////////////////////////// +Variant& Variant::operator%= (const Variant& other) +{ + Variant right (other); + + switch (_type) + { + case type_unknown: + throw std::string ("Cannot modulo unknown type"); + break; + + case type_boolean: + throw std::string ("Cannot modulo Boolean"); + break; + + case type_integer: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot modulo unknown type"); + case type_boolean: throw std::string ("Cannot modulo integer by Boolean"); + case type_integer: + if (right._integer == 0) + throw std::string ("Modulo zero"); + _integer %= right._integer; + break; + case type_real: + if (right._real == 0.0) + throw std::string ("Modulo zero"); + cast (type_real); + _real = fmod (_real, right._real); + break; + case type_string: throw std::string ("Cannot modulo integer by string"); + case type_date: throw std::string ("Cannot modulo integer by date values"); + case type_duration: throw std::string ("Cannot modulo integer by duration values"); + } + break; + + case type_real: + switch (right._type) + { + case type_unknown: throw std::string ("Cannot modulo unknown type"); + case type_boolean: throw std::string ("Cannot modulo real by Boolean"); + case type_integer: + if (right._integer == 0) + throw std::string ("Modulo zero"); + _real = fmod (_real, static_cast(right._integer)); + break; + case type_real: + if (right._real == 0) + throw std::string ("Modulo zero"); + _real = fmod (_real, right._real); + break; + case type_string: throw std::string ("Cannot modulo real numbers by strings"); + case type_date: throw std::string ("Cannot modulo real numbers by dates"); + case type_duration: throw std::string ("Cannot modulo real by duration values"); + } + break; + + case type_string: + throw std::string ("Cannot modulo string values"); + + case type_date: + throw std::string ("Cannot modulo date values"); + + case type_duration: + throw std::string ("Cannot modulo duration values"); + } + + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// +Variant Variant::operator% (const Variant& other) const +{ + Variant left (*this); + left %= other; + return left; +} + +//////////////////////////////////////////////////////////////////////////////// +Variant::operator std::string () const +{ + switch (_type) + { + case type_boolean: + return std::string (_bool ? "true" : "false"); + + case type_integer: + { + std::stringstream s; + s << _integer; + return s.str (); + } + + case type_real: + { + std::stringstream s; + s << _real; + return s.str (); + } + + case type_string: + return _string; + + case type_date: + { + struct tm* t = localtime (&_date); + + std::stringstream s; + s.width (4); + s << t->tm_year + 1900; + s << '-'; + s.width (2); + s.fill ('0'); + s << t->tm_mon + 1; + s << '-'; + s.width (2); + s.fill ('0'); + s << t->tm_mday; + s << 'T'; + s.width (2); + s.fill ('0'); + s << t->tm_hour; + s << ':'; + s.width (2); + s.fill ('0'); + s << t->tm_min; + s << ':'; + s.width (2); + s.fill ('0'); + s << t->tm_sec; + return s.str (); + } + + case type_duration: + { + time_t t = _duration; + + int seconds = t % 60; t /= 60; + int minutes = t % 60; t /= 60; + int hours = t % 24; t /= 24; + int days = t % 30; t /= 30; + int months = t % 12; t /= 12; + int years = t; + + std::stringstream s; + s << 'P'; + if (years) s << years << 'Y'; + if (months) s << months << 'M'; + if (days) s << days << 'D'; + + if (hours || minutes || seconds) + { + s << 'T'; + if (hours) s << hours << 'H'; + if (minutes) s << minutes << 'M'; + if (seconds) s << seconds << 'S'; + } + + return s.str (); + } + + case type_unknown: + throw std::string ("Cannot render an unknown type."); + } +} + +//////////////////////////////////////////////////////////////////////////////// +void Variant::sqrt () +{ + cast (type_real); + if (_real < 0.0) + throw std::string ("Cannot take the square root of a negative number."); + _real = ::sqrt (_real); +} + +//////////////////////////////////////////////////////////////////////////////// +void Variant::cast (const enum type new_type) +{ + // Short circuit. + if (_type == new_type) + return; + + if (_type == type_unknown || new_type == type_unknown) + throw std::string ("Cannot coerce data either to or from an unknown type"); + + // From type_boolean + switch (_type) + { + case type_unknown: + break; + + case type_boolean: + switch (new_type) + { + case type_unknown: break; + case type_boolean: break; + case type_integer: _integer = _bool ? 1 : 0; break; + case type_real: _real = _bool ? 1.0 : 0.0; break; + case type_string: _string = _bool ? "true" : "false"; break; + case type_date: _date = _bool ? 1 : 0; break; + case type_duration: _duration = _bool ? 1 : 0; break; + } + break; + + case type_integer: + switch (new_type) + { + case type_unknown: break; + case type_boolean: _bool = _integer == 0 ? false : true; break; + case type_integer: break; + case type_real: _real = static_cast(_integer); break; + case type_string: + { + char temp[24]; + sprintf (temp, "%d", _integer); + _string = temp; + } + break; + case type_date: _date = (time_t) _integer; break; + case type_duration: _duration = (time_t) _integer; break; + } + break; + + case type_real: + switch (new_type) + { + case type_unknown: break; + case type_boolean: _bool = _real == 0.0 ? false : true; break; + case type_integer: _integer = (int) _real; break; + case type_real: break; + case type_string: + { + char temp[24]; + sprintf (temp, "%g", _real); + _string = temp; + } + break; + case type_date: _date = (time_t) (int) _real; break; + case type_duration: _duration = (time_t) (int) _real; break; + } + break; + + case type_string: + switch (new_type) + { + case type_unknown: break; + case type_boolean: + _bool = (_string.length () == 0 || + _string == "0" || + _string == "0.0") ? false : true; + break; + case type_integer: + _integer = (int) strtol (_string.c_str (), NULL, (_string.substr (0, 2) == "0x" ? 16 : 10)); + break; + case type_real: _real = strtod (_string.c_str (), NULL); break; + case type_string: break; + case type_date: + { + _date = 0; + ISO8601d iso; + std::string::size_type pos = 0; + if (iso.parse (_string, pos) && + pos == _string.length ()) + { + _date = (time_t) iso; + } + } + break; + case type_duration: + { + _duration = 0; + ISO8601p iso; + std::string::size_type pos = 0; + if (iso.parse (_string, pos) && + pos == _string.length ()) + { + _duration = (time_t) iso; + } + else + { + Duration dur; + pos = 0; + if (dur.parse (_string, pos) && + pos == _string.length ()) + { + _duration = (time_t) dur; + } + } + } + break; + } + break; + + case type_date: + switch (new_type) + { + case type_unknown: break; + case type_boolean: _bool = _date != 0 ? true : false; break; + case type_integer: _integer = (int) _date; break; + case type_real: _real = static_cast(_date); break; + case type_string: _string = (std::string) *this; break; + case type_date: break; + case type_duration: _duration = _date; break; + } + break; + + case type_duration: + switch (new_type) + { + case type_unknown: break; + case type_boolean: _bool = _duration != 0 ? true : false; break; + case type_integer: _integer = (int) _duration; break; + case type_real: _real = static_cast(_duration); break; + case type_string: _string = (std::string) *this; break; + case type_date: _date = _duration; break; + case type_duration: break; + } + break; + } + + _type = new_type; +} + +//////////////////////////////////////////////////////////////////////////////// +int Variant::type () +{ + return _type; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Variant::get_bool () const +{ + return _bool; +} + +//////////////////////////////////////////////////////////////////////////////// +int Variant::get_integer () const +{ + return _integer; +} + +//////////////////////////////////////////////////////////////////////////////// +double Variant::get_real () const +{ + return _real; +} + +//////////////////////////////////////////////////////////////////////////////// +std::string Variant::get_string () const +{ + return _string; +} + +//////////////////////////////////////////////////////////////////////////////// +time_t Variant::get_date () const +{ + return _date; +} + +//////////////////////////////////////////////////////////////////////////////// +time_t Variant::get_duration () const +{ + return _duration; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/Variant.h b/src/Variant.h new file mode 100644 index 000000000..8a34bd4d0 --- /dev/null +++ b/src/Variant.h @@ -0,0 +1,107 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright 2013 - 2014, Paul Beckingham, Federico Hernandez. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// http://www.opensource.org/licenses/mit-license.php +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDED_VARIANT +#define INCLUDED_VARIANT + +#include +#include + +class Variant +{ +public: + enum type {type_unknown, type_boolean, type_integer, type_real, type_string, + type_date, type_duration}; + + Variant (); + Variant (const Variant&); + Variant (const bool); + Variant (const int); + Variant (const double); + Variant (const std::string&); + Variant (const char*); + Variant (const time_t, const enum type new_type = type_date); + ~Variant (); + + Variant& operator= (const Variant&); + + bool operator&& (const Variant&) const; + bool operator|| (const Variant&) const; + bool operator_xor (const Variant&) const; + bool operator< (const Variant&) const; + bool operator<= (const Variant&) const; + bool operator> (const Variant&) const; + bool operator>= (const Variant&) const; + bool operator== (const Variant&) const; + bool operator!= (const Variant&) const; + bool operator_match (const Variant&) const; + bool operator_nomatch (const Variant&) const; + bool operator! () const; + + Variant& operator^= (const Variant&); + Variant operator^ (const Variant&) const; + + Variant& operator-= (const Variant&); + Variant operator- (const Variant&) const; + + Variant& operator+= (const Variant&); + Variant operator+ (const Variant&) const; + + Variant& operator*= (const Variant&); + Variant operator* (const Variant&) const; + + Variant& operator/= (const Variant&); + Variant operator/ (const Variant&) const; + + Variant& operator%= (const Variant&); + Variant operator% (const Variant&) const; + + operator std::string () const; + void sqrt (); + + void cast (const enum type); + int type (); + + bool get_bool () const; + int get_integer () const; + double get_real () const; + std::string get_string () const; + time_t get_date () const; + time_t get_duration () const; + +private: + enum type _type; + bool _bool; + int _integer; + double _real; + std::string _string; + time_t _date; + time_t _duration; +}; + +#endif + +////////////////////////////////////////////////////////////////////////////////