taskwarrior/src/Variant.cpp
Paul Beckingham 3bc44681a5 Variant
- A variant now contains a source reference, which indicates where it came
  from.  This is used to determine whether 'H' is a priority or just a word.
2014-05-31 09:59:18 -04:00

1722 lines
60 KiB
C++

////////////////////////////////////////////////////////////////////////////////
//
// 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 <cmake.h>
#include <sstream>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <Variant.h>
#include <ISO8601.h>
#include <Date.h>
#include <Duration.h>
#include <RX.h>
#include <text.h>
std::string Variant::dateFormat = "";
////////////////////////////////////////////////////////////////////////////////
Variant::Variant ()
: _type (type_unknown)
, _bool (false)
, _integer (0)
, _real (0.0)
, _string ("")
, _date (0)
, _duration (0)
, _source ("")
{
}
////////////////////////////////////////////////////////////////////////////////
Variant::Variant (const Variant& other)
: _type (type_unknown)
, _bool (false)
, _integer (0)
, _real (0.0)
, _string ("")
, _date (0)
, _duration (0)
, _source ("")
{
*this = other;
}
////////////////////////////////////////////////////////////////////////////////
Variant::Variant (const bool value)
: _type (Variant::type_boolean)
, _bool (value)
, _integer (0)
, _real (0.0)
, _string ("")
, _date (0)
, _duration (0)
, _source ("")
{
}
////////////////////////////////////////////////////////////////////////////////
Variant::Variant (const int value)
: _type (Variant::type_integer)
, _bool (false)
, _integer (value)
, _real (0.0)
, _string ("")
, _date (0)
, _duration (0)
, _source ("")
{
}
////////////////////////////////////////////////////////////////////////////////
Variant::Variant (const double value)
: _type (Variant::type_real)
, _bool (false)
, _integer (0)
, _real (value)
, _string ("")
, _date (0)
, _duration (0)
, _source ("")
{
}
////////////////////////////////////////////////////////////////////////////////
Variant::Variant (const std::string& value)
: _type (Variant::type_string)
, _bool (false)
, _integer (0)
, _real (0.0)
, _string (value)
, _date (0)
, _duration (0)
, _source ("")
{
}
////////////////////////////////////////////////////////////////////////////////
Variant::Variant (const char* value)
: _type (Variant::type_string)
, _bool (false)
, _integer (0)
, _real (0.0)
, _string (std::string (value))
, _date (0)
, _duration (0)
, _source ("")
{
}
////////////////////////////////////////////////////////////////////////////////
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)
, _source ("")
{
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 ()
{
}
////////////////////////////////////////////////////////////////////////////////
void Variant::source (const std::string& input)
{
_source = input;
}
////////////////////////////////////////////////////////////////////////////////
std::string Variant::source () const
{
return _source;
}
////////////////////////////////////////////////////////////////////////////////
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;
_source = other._source;
}
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);
}
////////////////////////////////////////////////////////////////////////////////
// Partial match is mostly a clone of operator==, but with some overrides:
//
// date <partial> date --> same day check
// string <partial> string --> leftmost
//
bool Variant::operator_partial (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;
// TODO Implement same-day comparison.
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;
// TODO Implement same-day comparison.
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;
// TODO Implement same-day comparison.
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:
{
int left_length = left._string.length ();
if (left_length == 0)
return false;
int right_length = right._string.length ();
if (right_length == 0)
return false;
if (left_length < right_length)
return false;
return left._string.substr (0, right_length) == right._string;
}
// TODO Implement same-day comparison.
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");
// TODO Implement same-day comparison.
case type_boolean: right.cast (type_date); return left._date == right._date;
// TODO Implement same-day comparison.
case type_integer: right.cast (type_date); return left._date == right._date;
// TODO Implement same-day comparison.
case type_real: right.cast (type_date); return left._date == right._date;
// TODO Implement same-day comparison.
case type_string: right.cast (type_date); return left._date == right._date;
// TODO Implement same-day comparison.
case type_date: return left._date == right._date;
// TODO Implement same-day comparison.
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;
// TODO Implement same-day comparison.
case type_date: return left._duration == right._date;
// TODO Implement same-day comparison.
case type_duration: return left._duration == right._duration;
}
break;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Variant::operator_hastag (const Variant& other) const
{
Variant left (*this); // tags
Variant right (other); // tag
left.cast (type_string);
right.cast (type_string);
std::vector <std::string> individual;
split (individual, left._string, ',');
std::vector <std::string>::iterator i;
for (i = individual.begin (); i != individual.end (); ++i)
if (*i == right._string)
return true;
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Variant::operator_notag (const Variant& other) const
{
return ! operator_hastag (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<double>(_integer), static_cast<double>(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<double>(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<double>(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<double>(_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<double>(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<double>(_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<double>(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;
if (t)
{
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 ();
}
else
{
return "P0S";
}
}
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<double>(_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;
}
// Support legacy date formats.
else if (dateFormat != "")
{
Date d (_string, dateFormat);
_date = d.toEpoch ();
}
}
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<double>(_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<double>(_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;
}
////////////////////////////////////////////////////////////////////////////////