From d9b2ac0f330f0ba8e37fdead7cb945f0432846ad Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Tue, 5 Apr 2011 23:47:09 -0400 Subject: [PATCH] Variant - Salvaged Variant code from older project, for use in expression evaluation. --- src/CMakeLists.txt | 3 +- src/Duration.cpp | 4 +- src/Duration.h | 4 +- src/Variant.cpp | 806 ++++++++++++++++++++++++++++++++++++++++++++ src/Variant.h | 106 ++++++ test/.gitignore | 1 + test/CMakeLists.txt | 3 +- test/variant.t.cpp | 55 +++ 8 files changed, 976 insertions(+), 6 deletions(-) create mode 100644 src/Variant.cpp create mode 100644 src/Variant.h create mode 100644 test/variant.t.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6171216ab..0ab856c5a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,7 +16,8 @@ set (task_SRCS API.cpp API.h Att.cpp Att.h Cmd.cpp Cmd.h Color.cpp Color.h command.cpp custom.cpp dependency.cpp diag.cpp edit.cpp export.cpp history.cpp i18n.h import.cpp interactive.cpp recur.cpp report.cpp rules.cpp rx.cpp rx.h text.cpp text.h - utf8.cpp utf8.h util.cpp util.h Uri.cpp Uri.h) + utf8.cpp utf8.h util.cpp util.h Uri.cpp Uri.h Variant.cpp + Variant.h) add_library (task STATIC ${task_SRCS}) add_executable (task_executable main.cpp) diff --git a/src/Duration.cpp b/src/Duration.cpp index 7e5998df8..977f64129 100644 --- a/src/Duration.cpp +++ b/src/Duration.cpp @@ -126,13 +126,13 @@ Duration::Duration (const std::string& input) } //////////////////////////////////////////////////////////////////////////////// -Duration::operator time_t () +Duration::operator time_t () const { return mSecs; } //////////////////////////////////////////////////////////////////////////////// -Duration::operator std::string () +Duration::operator std::string () const { std::stringstream s; s << (mNegative ? - (long) mSecs : (long) mSecs); diff --git a/src/Duration.h b/src/Duration.h index 05184c9b6..f84be45f7 100644 --- a/src/Duration.h +++ b/src/Duration.h @@ -42,8 +42,8 @@ public: Duration& operator= (const Duration&); ~Duration (); // Destructor - operator time_t (); - operator std::string (); + operator time_t () const; + operator std::string () const; std::string format () const; std::string formatCompact () const; diff --git a/src/Variant.cpp b/src/Variant.cpp new file mode 100644 index 000000000..f1981825f --- /dev/null +++ b/src/Variant.cpp @@ -0,0 +1,806 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +#include +#include +#include + +//////////////////////////////////////////////////////////////////////////////// +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; + } +} + +//////////////////////////////////////////////////////////////////////////////// +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; + } + + 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; + } + + 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; + } + + 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; + } + + 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; + } + + 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: + // TODO operator-= only takes integers. + //mDate -= other.mDate; + break; + + case v_duration: + // TODO Missing operator -= + //mDuration -= other.mDuration; + 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; + } + + 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; + } + + 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; + } + + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// +Variant& Variant::operator< (const Variant& other) +{ + switch (mType) + { + case v_boolean: + throw std::string ("Cannot perform relationally 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; + } + + mType = v_boolean; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// +Variant& Variant::operator> (const Variant& other) +{ + switch (mType) + { + case v_boolean: + throw std::string ("Cannot perform relationally 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; + } + + 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 ()); + + // From v_date + + + // From v_duration + + + mType = type; +} + +//////////////////////////////////////////////////////////////////////////////// +Variant::variant_type Variant::type () +{ + return mType; +} + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/Variant.h b/src/Variant.h new file mode 100644 index 000000000..33f992ea8 --- /dev/null +++ b/src/Variant.h @@ -0,0 +1,106 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +// +//////////////////////////////////////////////////////////////////////////////// +#ifndef INCLUDED_VARIANT +#define INCLUDED_VARIANT + +#include +#include +#include +#include + +class Variant +{ +public: + enum variant_type + { + v_unknown, + v_boolean, + v_integer, + v_double, + v_string, + v_date, + v_duration, + v_other + }; + + Variant (); + Variant (const Variant&); + Variant (const bool); + Variant (const int); + Variant (const double&); + Variant (const std::string&); + Variant (const Date&); + Variant (const Duration&); + + Variant& operator&& (const Variant& other); + Variant& operator|| (const Variant& other); + Variant& operator<= (const Variant& other); + Variant& operator>= (const Variant& other); + Variant& operator== (const Variant& other); + Variant& operator!= (const Variant& other); + Variant& operator^ (const Variant& other); + Variant& operator! (); + Variant& operator- (const Variant& other); + Variant& operator+ (const Variant& other); + Variant& operator* (const Variant& other); + Variant& operator/ (const Variant& other); + Variant& operator< (const Variant& other); + Variant& operator> (const Variant& other); + + void sqrt (); + void sin (); + void cos (); + void tan (); + void asin (); + void acos (); + void atan (); + void log (); + void exp (); + void exp10 (); + void ln (); + void sign (); + void abs (); + + void input (const std::string&); + std::string format (); + void cast (const variant_type); + variant_type type (); + +private: + variant_type mType; + + bool mBool; + int mInteger; + double mDouble; + std::string mString; + Date mDate; + Duration mDuration; +}; + +#endif + +//////////////////////////////////////////////////////////////////////////////// diff --git a/test/.gitignore b/test/.gitignore index 6bf916fc0..894dc81af 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -33,3 +33,4 @@ tree.t tree2.t uri.t util.t +variant.t diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8a7d5d634..67cbe8923 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -6,7 +6,8 @@ include_directories (${CMAKE_SOURCE_DIR}/src set (test_SRCS date.t t.t tdb.t duration.t t.benchmark.t text.t autocomplete.t seq.t record.t att.t subst.t nibbler.t filt.t cmd.t config.t util.t color.t list.t path.t file.t grid.t directory.t rx.t - taskmod.t lisp.t rectangle.t tree.t tree2.t uri.t json.t) + taskmod.t lisp.t rectangle.t tree.t tree2.t uri.t json.t + variant.t) add_custom_target (test ./run_all DEPENDS ${test_SRCS} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/test) diff --git a/test/variant.t.cpp b/test/variant.t.cpp new file mode 100644 index 000000000..3e29b222f --- /dev/null +++ b/test/variant.t.cpp @@ -0,0 +1,55 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +#include +#include +#include + +Context context; + +//////////////////////////////////////////////////////////////////////////////// +int main (int argc, char** argv) +{ + UnitTest t (2); + + try + { + Variant v = Variant (1) + Variant (2); + t.ok (v.type () == Variant::v_integer, "1 + 2 --> integer"); + t.ok (v.format () == "3", "1 + 2 --> 3"); + } + + catch (std::string& e) + { + t.fail ("Exception thrown."); + t.diag (e); + } + + return 0; +} + +////////////////////////////////////////////////////////////////////////////////