summaryrefslogtreecommitdiff
path: root/src/value.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/value.h')
-rw-r--r--src/value.h580
1 files changed, 580 insertions, 0 deletions
diff --git a/src/value.h b/src/value.h
new file mode 100644
index 00000000..2b0adf2b
--- /dev/null
+++ b/src/value.h
@@ -0,0 +1,580 @@
+#ifndef _VALUE_H
+#define _VALUE_H
+
+#include "amount.h"
+#include "balance.h"
+
+namespace ledger {
+
+namespace xml {
+ class node_t;
+}
+
+// The following type is a polymorphous value type used solely for
+// performance reasons. The alternative is to compute value
+// expressions (valexpr.cc) in terms of the largest data type,
+// balance_t. This was found to be prohibitively expensive, especially
+// when large logic chains were involved, since many temporary
+// allocations would occur for every operator. With value_t, and the
+// fact that logic chains only need boolean values to continue, no
+// memory allocations need to take place at all.
+
+class value_t
+{
+ public:
+ typedef std::vector<value_t> sequence_t;
+
+ char data[sizeof(balance_pair_t)];
+
+ enum type_t {
+ BOOLEAN,
+ INTEGER,
+ DATETIME,
+ AMOUNT,
+ BALANCE,
+ BALANCE_PAIR,
+ STRING,
+ XML_NODE,
+ POINTER,
+ SEQUENCE
+ } type;
+
+ value_t() {
+ TRACE_CTOR(value_t, "");
+ *((long *) data) = 0;
+ type = INTEGER;
+ }
+
+ value_t(const value_t& val) : type(INTEGER) {
+ TRACE_CTOR(value_t, "copy");
+ *this = val;
+ }
+ value_t(const bool val) {
+ TRACE_CTOR(value_t, "const bool");
+ *((bool *) data) = val;
+ type = BOOLEAN;
+ }
+ value_t(const long val) {
+ TRACE_CTOR(value_t, "const long");
+ *((long *) data) = val;
+ type = INTEGER;
+ }
+ value_t(const moment_t val) {
+ TRACE_CTOR(value_t, "const moment_t");
+ *((moment_t *) data) = val;
+ type = DATETIME;
+ }
+ value_t(const unsigned long val) {
+ TRACE_CTOR(value_t, "const unsigned long");
+ new((amount_t *) data) amount_t(val);
+ type = AMOUNT;
+ }
+ value_t(const double val) {
+ TRACE_CTOR(value_t, "const double");
+ new((amount_t *) data) amount_t(val);
+ type = AMOUNT;
+ }
+ value_t(const string& val, bool literal = false) {
+ TRACE_CTOR(value_t, "const string&, bool");
+ if (literal) {
+ type = INTEGER;
+ set_string(val);
+ } else {
+ new((amount_t *) data) amount_t(val);
+ type = AMOUNT;
+ }
+ }
+ value_t(const char * val) {
+ TRACE_CTOR(value_t, "const char *");
+ new((amount_t *) data) amount_t(val);
+ type = AMOUNT;
+ }
+ value_t(const amount_t& val) {
+ TRACE_CTOR(value_t, "const amount_t&");
+ new((amount_t *)data) amount_t(val);
+ type = AMOUNT;
+ }
+ value_t(const balance_t& val) : type(INTEGER) {
+ TRACE_CTOR(value_t, "const balance_t&");
+ *this = val;
+ }
+ value_t(const balance_pair_t& val) : type(INTEGER) {
+ TRACE_CTOR(value_t, "const balance_pair_t&");
+ *this = val;
+ }
+ value_t(xml::node_t * xml_node) : type(INTEGER) { // gets set in =
+ TRACE_CTOR(value_t, "xml::node_t *");
+ *this = xml_node;
+ }
+ value_t(void * item) : type(INTEGER) { // gets set in =
+ TRACE_CTOR(value_t, "void *");
+ *this = item;
+ }
+ value_t(sequence_t * seq) : type(INTEGER) { // gets set in =
+ TRACE_CTOR(value_t, "sequence_t *");
+ *this = seq;
+ }
+
+ ~value_t() {
+ TRACE_DTOR(value_t);
+ destroy();
+ }
+
+ void destroy();
+ void simplify();
+
+ value_t& operator=(const value_t& val);
+ value_t& operator=(const bool val) {
+ if ((bool *) data != &val) {
+ destroy();
+ *((bool *) data) = val;
+ type = BOOLEAN;
+ }
+ return *this;
+ }
+ value_t& operator=(const long val) {
+ if ((long *) data != &val) {
+ destroy();
+ *((long *) data) = val;
+ type = INTEGER;
+ }
+ return *this;
+ }
+ value_t& operator=(const moment_t val) {
+ if ((moment_t *) data != &val) {
+ destroy();
+ *((moment_t *) data) = val;
+ type = DATETIME;
+ }
+ return *this;
+ }
+ value_t& operator=(const unsigned long val) {
+ return *this = amount_t(val);
+ }
+ value_t& operator=(const double val) {
+ return *this = amount_t(val);
+ }
+ value_t& operator=(const string& val) {
+ return *this = amount_t(val);
+ }
+ value_t& operator=(const char * val) {
+ return *this = amount_t(val);
+ }
+ value_t& operator=(const amount_t& val) {
+ if (type == AMOUNT &&
+ (amount_t *) data == &val)
+ return *this;
+
+ if (val.realzero()) {
+ return *this = 0L;
+ } else {
+ destroy();
+ new((amount_t *)data) amount_t(val);
+ type = AMOUNT;
+ }
+ return *this;
+ }
+ value_t& operator=(const balance_t& val) {
+ if (type == BALANCE &&
+ (balance_t *) data == &val)
+ return *this;
+
+ if (val.realzero()) {
+ return *this = 0L;
+ }
+ else if (val.amounts.size() == 1) {
+ return *this = (*val.amounts.begin()).second;
+ }
+ else {
+ destroy();
+ new((balance_t *)data) balance_t(val);
+ type = BALANCE;
+ return *this;
+ }
+ }
+ value_t& operator=(const balance_pair_t& val) {
+ if (type == BALANCE_PAIR &&
+ (balance_pair_t *) data == &val)
+ return *this;
+
+ if (val.realzero()) {
+ return *this = 0L;
+ }
+ else if (! val.cost) {
+ return *this = val.quantity;
+ }
+ else {
+ destroy();
+ new((balance_pair_t *)data) balance_pair_t(val);
+ type = BALANCE_PAIR;
+ return *this;
+ }
+ }
+ value_t& operator=(xml::node_t * xml_node) {
+ assert(xml_node);
+ if (type == XML_NODE && *(xml::node_t **) data == xml_node)
+ return *this;
+
+ if (! xml_node) {
+ type = XML_NODE;
+ return *this = 0L;
+ }
+ else {
+ destroy();
+ *(xml::node_t **)data = xml_node;
+ type = XML_NODE;
+ return *this;
+ }
+ }
+ value_t& operator=(void * item) {
+ assert(item);
+ if (type == POINTER && *(void **) data == item)
+ return *this;
+
+ if (! item) {
+ type = POINTER;
+ return *this = 0L;
+ }
+ else {
+ destroy();
+ *(void **)data = item;
+ type = POINTER;
+ return *this;
+ }
+ }
+ value_t& operator=(sequence_t * seq) {
+ assert(seq);
+ if (type == SEQUENCE && *(sequence_t **) data == seq)
+ return *this;
+
+ if (! seq) {
+ type = SEQUENCE;
+ return *this = 0L;
+ }
+ else {
+ destroy();
+ *(sequence_t **)data = seq;
+ type = SEQUENCE;
+ return *this;
+ }
+ }
+
+ value_t& set_string(const string& str = "") {
+ if (type != STRING) {
+ destroy();
+ *(string **) data = new string(str);
+ type = STRING;
+ } else {
+ **(string **) data = str;
+ }
+ return *this;
+ }
+
+ bool to_boolean() const;
+ long to_integer() const;
+ moment_t to_datetime() const;
+ amount_t to_amount() const;
+ balance_t to_balance() const;
+ balance_pair_t to_balance_pair() const;
+ string to_string() const;
+ xml::node_t * to_xml_node() const;
+ void * to_pointer() const;
+ sequence_t * to_sequence() const;
+
+ value_t& operator[](const int index) {
+ sequence_t * seq = to_sequence();
+ assert(seq);
+ return (*seq)[index];
+ }
+
+ void push_back(const value_t& val) {
+ sequence_t * seq = to_sequence();
+ assert(seq);
+ return seq->push_back(val);
+ }
+
+ std::size_t size() const {
+ sequence_t * seq = to_sequence();
+ assert(seq);
+ return seq->size();
+ }
+
+ value_t& operator+=(const value_t& val);
+ value_t& operator-=(const value_t& val);
+ value_t& operator*=(const value_t& val);
+ value_t& operator/=(const value_t& val);
+
+ template <typename T>
+ value_t& operator+=(const T& val) {
+ return *this += value_t(val);
+ }
+ template <typename T>
+ value_t& operator-=(const T& val) {
+ return *this -= value_t(val);
+ }
+ template <typename T>
+ value_t& operator*=(const T& val) {
+ return *this *= value_t(val);
+ }
+ template <typename T>
+ value_t& operator/=(const T& val) {
+ return *this /= value_t(val);
+ }
+
+ value_t operator+(const value_t& val) {
+ value_t temp(*this);
+ temp += val;
+ return temp;
+ }
+ value_t operator-(const value_t& val) {
+ value_t temp(*this);
+ temp -= val;
+ return temp;
+ }
+ value_t operator*(const value_t& val) {
+ value_t temp(*this);
+ temp *= val;
+ return temp;
+ }
+ value_t operator/(const value_t& val) {
+ value_t temp(*this);
+ temp /= val;
+ return temp;
+ }
+
+ template <typename T>
+ value_t operator+(const T& val) {
+ return *this + value_t(val);
+ }
+ template <typename T>
+ value_t operator-(const T& val) {
+ return *this - value_t(val);
+ }
+ template <typename T>
+ value_t operator*(const T& val) {
+ return *this * value_t(val);
+ }
+ template <typename T>
+ value_t operator/(const T& val) {
+ return *this / value_t(val);
+ }
+
+ bool operator<(const value_t& val);
+ bool operator<=(const value_t& val);
+ bool operator>(const value_t& val);
+ bool operator>=(const value_t& val);
+ bool operator==(const value_t& val);
+ bool operator!=(const value_t& val) {
+ return ! (*this == val);
+ }
+
+ template <typename T>
+ bool operator<(const T& val) {
+ return *this < value_t(val);
+ }
+ template <typename T>
+ bool operator<=(const T& val) {
+ return *this <= value_t(val);
+ }
+ template <typename T>
+ bool operator>(const T& val) {
+ return *this > value_t(val);
+ }
+ template <typename T>
+ bool operator>=(const T& val) {
+ return *this >= value_t(val);
+ }
+ template <typename T>
+ bool operator==(const T& val) {
+ return *this == value_t(val);
+ }
+ template <typename T>
+ bool operator!=(const T& val) {
+ return ! (*this == val);
+ }
+
+ template <typename T>
+ operator T() const;
+
+ void in_place_negate();
+ value_t negate() const {
+ value_t temp = *this;
+ temp.in_place_negate();
+ return temp;
+ }
+ value_t operator-() const {
+ return negate();
+ }
+
+ bool realzero() const {
+ switch (type) {
+ case BOOLEAN:
+ return ! *((bool *) data);
+ case INTEGER:
+ return *((long *) data) == 0;
+ case DATETIME:
+ return ! is_valid_moment(*((moment_t *) data));
+ case AMOUNT:
+ return ((amount_t *) data)->realzero();
+ case BALANCE:
+ return ((balance_t *) data)->realzero();
+ case BALANCE_PAIR:
+ return ((balance_pair_t *) data)->realzero();
+ case STRING:
+ return ((string *) data)->empty();
+ case XML_NODE:
+ case POINTER:
+ case SEQUENCE:
+ return *(void **) data == NULL;
+
+ default:
+ assert(0);
+ break;
+ }
+ assert(0);
+ return 0;
+ }
+
+ void in_place_abs();
+ value_t abs() const;
+ void in_place_cast(type_t cast_type);
+ value_t cost() const;
+ value_t price() const;
+ value_t date() const;
+
+ value_t cast(type_t cast_type) const {
+ value_t temp(*this);
+ temp.in_place_cast(cast_type);
+ return temp;
+ }
+
+ value_t strip_annotations(const bool keep_price = amount_t::keep_price,
+ const bool keep_date = amount_t::keep_date,
+ const bool keep_tag = amount_t::keep_tag) const;
+
+ value_t& add(const amount_t& amount, const amount_t * cost = NULL);
+ value_t value(const moment_t& moment) const;
+ void in_place_reduce();
+
+ value_t reduce() const {
+ value_t temp(*this);
+ temp.in_place_reduce();
+ return temp;
+ }
+
+ value_t round() const;
+ value_t unround() const;
+
+ void write(std::ostream& out, const int first_width,
+ const int latter_width = -1) const;
+};
+
+#define DEFINE_VALUE_OPERATORS(T, OP) \
+inline value_t operator OP(const T& val, const value_t& obj) { \
+ return value_t(val) OP obj; \
+}
+
+DEFINE_VALUE_OPERATORS(bool, ==)
+DEFINE_VALUE_OPERATORS(bool, !=)
+
+DEFINE_VALUE_OPERATORS(long, +)
+DEFINE_VALUE_OPERATORS(long, -)
+DEFINE_VALUE_OPERATORS(long, *)
+DEFINE_VALUE_OPERATORS(long, /)
+DEFINE_VALUE_OPERATORS(long, <)
+DEFINE_VALUE_OPERATORS(long, <=)
+DEFINE_VALUE_OPERATORS(long, >)
+DEFINE_VALUE_OPERATORS(long, >=)
+DEFINE_VALUE_OPERATORS(long, ==)
+DEFINE_VALUE_OPERATORS(long, !=)
+
+DEFINE_VALUE_OPERATORS(amount_t, +)
+DEFINE_VALUE_OPERATORS(amount_t, -)
+DEFINE_VALUE_OPERATORS(amount_t, *)
+DEFINE_VALUE_OPERATORS(amount_t, /)
+DEFINE_VALUE_OPERATORS(amount_t, <)
+DEFINE_VALUE_OPERATORS(amount_t, <=)
+DEFINE_VALUE_OPERATORS(amount_t, >)
+DEFINE_VALUE_OPERATORS(amount_t, >=)
+DEFINE_VALUE_OPERATORS(amount_t, ==)
+DEFINE_VALUE_OPERATORS(amount_t, !=)
+
+DEFINE_VALUE_OPERATORS(balance_t, +)
+DEFINE_VALUE_OPERATORS(balance_t, -)
+DEFINE_VALUE_OPERATORS(balance_t, *)
+DEFINE_VALUE_OPERATORS(balance_t, /)
+DEFINE_VALUE_OPERATORS(balance_t, <)
+DEFINE_VALUE_OPERATORS(balance_t, <=)
+DEFINE_VALUE_OPERATORS(balance_t, >)
+DEFINE_VALUE_OPERATORS(balance_t, >=)
+DEFINE_VALUE_OPERATORS(balance_t, ==)
+DEFINE_VALUE_OPERATORS(balance_t, !=)
+
+DEFINE_VALUE_OPERATORS(balance_pair_t, +)
+DEFINE_VALUE_OPERATORS(balance_pair_t, -)
+DEFINE_VALUE_OPERATORS(balance_pair_t, *)
+DEFINE_VALUE_OPERATORS(balance_pair_t, /)
+DEFINE_VALUE_OPERATORS(balance_pair_t, <)
+DEFINE_VALUE_OPERATORS(balance_pair_t, <=)
+DEFINE_VALUE_OPERATORS(balance_pair_t, >)
+DEFINE_VALUE_OPERATORS(balance_pair_t, >=)
+DEFINE_VALUE_OPERATORS(balance_pair_t, ==)
+DEFINE_VALUE_OPERATORS(balance_pair_t, !=)
+
+template <typename T>
+value_t::operator T() const
+{
+ switch (type) {
+ case BOOLEAN:
+ return *(bool *) data;
+ case INTEGER:
+ return *(long *) data;
+ case DATETIME:
+ return *(moment_t *) data;
+ case AMOUNT:
+ return *(amount_t *) data;
+ case BALANCE:
+ return *(balance_t *) data;
+ case STRING:
+ return **(string **) data;
+ case XML_NODE:
+ return *(xml::node_t **) data;
+ case POINTER:
+ return *(void **) data;
+ case SEQUENCE:
+ return *(sequence_t **) data;
+
+ default:
+ assert(0);
+ break;
+ }
+ assert(0);
+ return 0;
+}
+
+template <> value_t::operator bool() const;
+template <> value_t::operator long() const;
+template <> value_t::operator moment_t() const;
+template <> value_t::operator double() const;
+template <> value_t::operator string() const;
+
+std::ostream& operator<<(std::ostream& out, const value_t& val);
+
+#if 0
+class value_context : public error_context
+{
+ value_t * bal;
+ public:
+ value_context(const value_t& _bal,
+ const string& desc = "") throw();
+ virtual ~value_context() throw();
+
+ virtual void describe(std::ostream& out) const throw();
+};
+#endif
+
+DECLARE_EXCEPTION(value_exception);
+
+} // namespace ledger
+
+#endif // _VALUE_H