taskwarrior/src/Variant.cpp
Paul Beckingham f971fcd110 Code Cleanup
- Obsoleted Filter.{h,cpp}.
- Obsoleted Sequence.{h,cpp}.
- Eliminated Context::autoFilter.
- Stubbed Expression::eval.
2011-06-15 23:45:50 -04:00

855 lines
19 KiB
C++

////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <text.h>
#include <Variant.h>
////////////////////////////////////////////////////////////////////////////////
Variant::Variant () :
mType (v_unknown)
{
}
////////////////////////////////////////////////////////////////////////////////
Variant::Variant (const Variant& other)
{
mType = other.mType;
// Explicitly copy only the relevant type. This saves memory.
switch (mType)
{
case v_boolean: mBool = other.mBool; break;
case v_integer: mInteger = other.mInteger; break;
case v_double: mDouble = other.mDouble; break;
case v_string: mString = other.mString; break;
case v_date: mDate = other.mDate; break;
case v_duration: mDuration = other.mDuration; break;
case v_unknown: break;
}
}
////////////////////////////////////////////////////////////////////////////////
Variant::Variant (const bool input)
{
mType = v_boolean;
mBool = input;
}
////////////////////////////////////////////////////////////////////////////////
Variant::Variant (const int input)
{
mType = v_integer;
mInteger = input;
}
////////////////////////////////////////////////////////////////////////////////
Variant::Variant (const double& input)
{
mType = v_double;
mDouble = input;
}
////////////////////////////////////////////////////////////////////////////////
Variant::Variant (const std::string& input)
{
mType = v_string;
mString = input;
}
////////////////////////////////////////////////////////////////////////////////
Variant::Variant (const Date& input)
{
mType = v_date;
mDate = input;
}
////////////////////////////////////////////////////////////////////////////////
Variant::Variant (const Duration& input)
{
mType = v_duration;
mDuration = input;
}
////////////////////////////////////////////////////////////////////////////////
Variant& Variant::operator&& (const Variant& other)
{
cast (v_boolean);
Variant copy (other);
copy.cast (v_boolean);
mBool = (mBool && copy.mBool) ? true : false;
return *this;
}
////////////////////////////////////////////////////////////////////////////////
Variant& Variant::operator|| (const Variant& other)
{
cast (v_boolean);
Variant copy (other);
copy.cast (v_boolean);
mBool = (mBool || copy.mBool) ? true : false;
return *this;
}
////////////////////////////////////////////////////////////////////////////////
Variant& Variant::operator<= (const Variant& other)
{
switch (mType)
{
case v_boolean:
mBool = false; // TODO Makes no sense.
break;
case v_integer:
mBool = mInteger <= other.mInteger ? true : false;
break;
case v_double:
mBool = mDouble <= other.mDouble ? true : false;
break;
case v_string:
{
int collating = strcmp (mString.c_str (), other.mString.c_str ());
mBool = collating <= 0 ? true : false;
}
break;
case v_date:
mBool = mDate <= other.mDate ? true : false;
break;
case v_duration:
mBool = (time_t)mDuration <= (time_t)other.mDuration ? true : false;
break;
case v_unknown:
break;
}
mType = v_boolean;
return *this;
}
////////////////////////////////////////////////////////////////////////////////
Variant& Variant::operator>= (const Variant& other)
{
switch (mType)
{
case v_boolean:
mBool = false; // TODO Makes no sense.
break;
case v_integer:
mBool = mInteger >= other.mInteger ? true : false;
break;
case v_double:
mBool = mDouble >= other.mDouble ? true : false;
break;
case v_string:
{
int collating = strcmp (mString.c_str (), other.mString.c_str ());
mBool = collating >= 0 ? true : false;
}
break;
case v_date:
mBool = mDate >= other.mDate ? true : false;
break;
case v_duration:
mBool = (time_t)mDuration >= (time_t)other.mDuration ? true : false;
break;
case v_unknown:
break;
}
mType = v_boolean;
return *this;
}
////////////////////////////////////////////////////////////////////////////////
Variant& Variant::operator== (const Variant& other)
{
switch (mType)
{
case v_boolean:
mBool = mBool == other.mBool ? true : false;
break;
case v_integer:
mBool = mInteger == other.mInteger ? true : false;
break;
case v_double:
mBool = mDouble == other.mDouble ? true : false;
break;
case v_string:
{
int collating = strcmp (mString.c_str (), other.mString.c_str ());
mBool = collating == 0 ? true : false;
}
break;
case v_date:
mBool = mDate == other.mDate ? true : false;
break;
case v_duration:
mBool = mDuration == other.mDuration ? true : false;
break;
case v_unknown:
break;
}
mType = v_boolean;
return *this;
}
////////////////////////////////////////////////////////////////////////////////
Variant& Variant::operator!= (const Variant& other)
{
switch (mType)
{
case v_boolean:
mBool = mBool != other.mBool ? true : false;
break;
case v_integer:
mBool = mInteger != other.mInteger ? true : false;
break;
case v_double:
mBool = mDouble != other.mDouble ? true : false;
break;
case v_string:
{
int collating = strcmp (mString.c_str (), other.mString.c_str ());
mBool = collating != 0 ? true : false;
}
break;
case v_date:
mBool = mDate != other.mDate ? true : false;
break;
case v_duration:
mBool = mDuration != other.mDuration ? true : false;
break;
case v_unknown:
break;
}
mType = v_boolean;
return *this;
}
////////////////////////////////////////////////////////////////////////////////
Variant& Variant::operator^ (const Variant& other)
{
switch (mType)
{
case v_boolean:
throw std::string ("Cannot perform exponentiation on Boolean types");
break;
case v_integer:
mInteger = (int) pow ((double) mInteger, (double) other.mInteger);
break;
case v_double:
mDouble = pow (mDouble, other.mDouble);
break;
case v_string:
throw std::string ("Cannot perform exponentiation on string types");
break;
case v_date:
throw std::string ("Cannot perform exponentiation on date types");
break;
case v_duration:
throw std::string ("Cannot perform exponentiation on duration types");
break;
case v_unknown:
break;
}
return *this;
}
////////////////////////////////////////////////////////////////////////////////
Variant& Variant::operator! ()
{
cast (v_boolean);
mBool = ! mBool;
return *this;
}
////////////////////////////////////////////////////////////////////////////////
Variant& Variant::operator- (const Variant& other)
{
switch (mType)
{
case v_boolean:
throw std::string ("Cannot perform subtraction on Boolean types");
break;
case v_integer:
mInteger -= other.mInteger;
break;
case v_double:
mDouble -= other.mDouble;
break;
case v_string:
throw std::string ("Cannot perform subtraction on string types");
break;
case v_date:
mDuration = Duration (mDate - other.mDate);
mType = v_duration;
break;
case v_duration:
mDuration = mDuration - other.mDuration;
break;
case v_unknown:
break;
}
return *this;
}
////////////////////////////////////////////////////////////////////////////////
Variant& Variant::operator+ (const Variant& other)
{
switch (mType)
{
case v_boolean:
throw std::string ("Cannot perform addition on Boolean types");
break;
case v_integer:
mInteger += other.mInteger;
break;
case v_double:
mDouble += other.mDouble;
break;
case v_string:
mString += other.mString;
break;
case v_date:
// TODO operator+ only works for int
//mDate += other.mDate;
break;
case v_duration:
// TODO operator+ missing
//mDuration += other.mDuration;
break;
case v_unknown:
break;
}
return *this;
}
////////////////////////////////////////////////////////////////////////////////
Variant& Variant::operator* (const Variant& other)
{
switch (mType)
{
case v_boolean:
throw std::string ("Cannot perform multiplication on Boolean types");
break;
case v_integer:
mInteger *= other.mInteger;
break;
case v_double:
mDouble *= other.mDouble;
break;
case v_string:
throw std::string ("Cannot perform multiplication on string types");
break;
case v_date:
throw std::string ("Cannot perform multiplication on date types");
break;
case v_duration:
throw std::string ("Cannot perform multiplication on duration types");
break;
case v_unknown:
break;
}
return *this;
}
////////////////////////////////////////////////////////////////////////////////
Variant& Variant::operator/ (const Variant& other)
{
switch (mType)
{
case v_boolean:
throw std::string ("Cannot perform division on Boolean types");
break;
case v_integer:
mInteger /= other.mInteger;
break;
case v_double:
mDouble /= other.mDouble;
break;
case v_string:
throw std::string ("Cannot perform division on string types");
break;
case v_date:
throw std::string ("Cannot perform division on date types");
break;
case v_duration:
throw std::string ("Cannot perform division on duration types");
break;
case v_unknown:
break;
}
return *this;
}
////////////////////////////////////////////////////////////////////////////////
Variant& Variant::operator< (const Variant& other)
{
switch (mType)
{
case v_boolean:
throw std::string ("Cannot perform relational compare Boolean types");
break;
case v_integer:
mBool = mInteger < other.mInteger ? true : false;
break;
case v_double:
mBool = mDouble < other.mDouble ? true : false;
break;
case v_string:
{
int collating = strcmp (mString.c_str (), other.mString.c_str ());
mBool = collating < 0 ? true : false;
}
break;
case v_date:
mBool = mDate < other.mDate ? true : false;
break;
case v_duration:
mBool = mDuration < other.mDuration ? true : false;
break;
case v_unknown:
break;
}
mType = v_boolean;
return *this;
}
////////////////////////////////////////////////////////////////////////////////
Variant& Variant::operator> (const Variant& other)
{
switch (mType)
{
case v_boolean:
throw std::string ("Cannot perform relational compare Boolean types");
break;
case v_integer:
mBool = mInteger > other.mInteger ? true : false;
break;
case v_double:
mBool = mDouble > other.mDouble ? true : false;
break;
case v_string:
{
int collating = strcmp (mString.c_str (), other.mString.c_str ());
mBool = collating > 0 ? true : false;
}
break;
case v_date:
mBool = mDate > other.mDate ? true : false;
break;
case v_duration:
mBool = mDuration > other.mDuration ? true : false;
break;
case v_unknown:
break;
}
mType = v_boolean;
return *this;
}
////////////////////////////////////////////////////////////////////////////////
void Variant::sqrt ()
{
cast (v_double);
if (mDouble < 0.0)
throw std::string ("Cannot take the square root of a negative number.");
mDouble = ::sqrt (mDouble);
}
////////////////////////////////////////////////////////////////////////////////
void Variant::sin ()
{
cast (v_double);
mDouble = ::sin (mDouble);
}
////////////////////////////////////////////////////////////////////////////////
void Variant::cos ()
{
cast (v_double);
mDouble = ::cos (mDouble);
}
////////////////////////////////////////////////////////////////////////////////
void Variant::tan ()
{
cast (v_double);
mDouble = ::tan (mDouble);
}
////////////////////////////////////////////////////////////////////////////////
void Variant::asin ()
{
cast (v_double);
mDouble = ::asin (mDouble);
}
////////////////////////////////////////////////////////////////////////////////
void Variant::acos ()
{
cast (v_double);
mDouble = ::acos (mDouble);
}
////////////////////////////////////////////////////////////////////////////////
void Variant::atan ()
{
cast (v_double);
mDouble = ::atan (mDouble);
}
////////////////////////////////////////////////////////////////////////////////
void Variant::log ()
{
cast (v_double);
mDouble = ::log10 (mDouble);
}
////////////////////////////////////////////////////////////////////////////////
void Variant::exp ()
{
cast (v_double);
mDouble = ::exp (mDouble);
}
////////////////////////////////////////////////////////////////////////////////
void Variant::exp10 ()
{
cast (v_double);
mDouble = ::pow (10.0, mDouble);
}
////////////////////////////////////////////////////////////////////////////////
void Variant::ln ()
{
cast (v_double);
mDouble = ::sqrt (mDouble);
}
////////////////////////////////////////////////////////////////////////////////
void Variant::sign ()
{
cast (v_double);
if (mDouble == 0.0)
throw std::string ("Divide by zero.");
mDouble /= fabs (mDouble);
}
////////////////////////////////////////////////////////////////////////////////
void Variant::abs ()
{
cast (v_double);
mDouble = ::fabs (mDouble);
}
////////////////////////////////////////////////////////////////////////////////
void Variant::input (const std::string& input)
{
if (! compare (input, "true", false) ||
! compare (input, "t", false) ||
! compare (input, "yes", false) ||
! compare (input, "on", false))
{
mType = v_boolean;
mBool = true;
return;
}
if (! compare (input, "false", false) ||
! compare (input, "f", false) ||
! compare (input, "no", false) ||
! compare (input, "off", false))
{
mType = v_boolean;
mBool = false;
return;
}
// TODO Attempt Date (input) parse.
// TODO Attempt Duration (input) parse.
bool numeric = true;
bool period = false;
for (unsigned int i = 0; i < input.length (); ++i)
{
if (input[i] == '.') period = true;
if (!isdigit (input[i]) && input[i] != '.') numeric = false;
}
if (numeric)
{
if (period)
{
mType = v_double;
mDouble = atof (input.c_str ());
}
else
{
mType = v_integer;
mInteger = atoi (input.c_str ());
}
return;
}
mType = v_string;
mString = input;
}
////////////////////////////////////////////////////////////////////////////////
std::string Variant::format ()
{
std::string output;
switch (mType)
{
case v_boolean:
output = mBool ? "true" : "false";
break;
case v_integer:
{
char temp [24];
sprintf (temp, "%d", mInteger);
output = temp;
}
break;
case v_double:
{
char temp [24];
sprintf (temp, "%g", mDouble);
output = temp;
}
break;
case v_string:
output = mString;
break;
case v_date:
// TODO Format mDate.
break;
case v_duration:
// TODO Format mDuration.
break;
case v_unknown:
default:
throw std::string ("Cannot render an unknown type.");
break;
}
return output;
}
////////////////////////////////////////////////////////////////////////////////
void Variant::cast (const variant_type type)
{
if (mType == v_unknown || type == v_unknown)
throw std::string ("Cannot coerce data either to or from an unknown type");
// Short circuit.
if (mType == type)
return;
// From v_boolean
if (mType == v_boolean && type == v_integer)
mInteger = mBool ? 1 : 0;
else if (mType == v_boolean && type == v_double)
mDouble = mBool ? 1.0 : 0.0;
else if (mType == v_boolean && type == v_string)
mString = mBool ? "true" : "false";
// From v_integer
else if (mType == v_integer && type == v_boolean)
mBool = mInteger == 0 ? false : true;
else if (mType == v_integer && type == v_double)
mDouble = (double)mInteger;
else if (mType == v_integer && type == v_string)
{
char temp [24];
sprintf (temp, "%d", mInteger);
mString = temp;
}
// From v_double
else if (mType == v_double && type == v_boolean)
mBool = mDouble == 0.0 ? false : true;
else if (mType == v_double && type == v_integer)
mInteger = (int)mDouble;
else if (mType == v_double && type == v_string)
{
char temp [24];
sprintf (temp, "%g", mDouble);
mString = temp;
}
// From v_string
else if (mType == v_string && type == v_boolean)
mBool = (mString.length () == 0 ||
mString == "0" ||
mString == "0.0") ? false : true;
else if (mType == v_string && type == v_integer)
mInteger = atol (mString.c_str ());
else if (mType == v_string && type == v_double)
mDouble = atol (mString.c_str ());
// TODO From v_date
// TODO From v_duration
mType = type;
}
////////////////////////////////////////////////////////////////////////////////
Variant::variant_type Variant::type ()
{
return mType;
}
////////////////////////////////////////////////////////////////////////////////
void Variant::promote (Variant& lhs, Variant& rhs)
{
// Short circuit.
if (lhs.type () == rhs.type ())
return;
variant_type newType;
switch (lhs.type () | rhs.type ())
{
case v_boolean | v_integer: newType = v_integer; break;
case v_boolean | v_double: newType = v_double; break;
case v_boolean | v_string: newType = v_string; break;
case v_boolean | v_date: newType = v_date; break;
case v_boolean | v_duration: newType = v_duration; break;
case v_integer | v_double: newType = v_integer; break;
case v_integer | v_string: newType = v_string; break;
case v_integer | v_date: newType = v_date; break;
case v_integer | v_duration: newType = v_duration; break;
case v_double | v_string: newType = v_string; break;
case v_double | v_date: newType = v_date; break;
case v_double | v_duration: newType = v_duration; break;
case v_string | v_date: newType = v_date; break;
case v_string | v_duration: newType = v_duration; break;
case v_date | v_duration: newType = v_date; break;
}
lhs.cast (newType);
rhs.cast (newType);
}
////////////////////////////////////////////////////////////////////////////////