summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--Makefile.in58
-rw-r--r--src/amount.cc697
-rw-r--r--src/amount.h560
-rw-r--r--src/balance.cc2
-rw-r--r--src/balance.h475
-rw-r--r--src/commodity.cc418
-rw-r--r--src/commodity.h328
-rw-r--r--src/journal.cc7
-rw-r--r--src/journal.h2
-rw-r--r--src/py_amount.cc37
-rw-r--r--src/py_balance.cc2
-rw-r--r--src/system.hh1
-rw-r--r--src/textual.cc12
-rw-r--r--src/value.cc670
-rw-r--r--src/value.h188
-rw-r--r--src/xmlparse.cc7
17 files changed, 1468 insertions, 1998 deletions
diff --git a/Makefile.am b/Makefile.am
index e7a7f455..6b98298c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -36,6 +36,7 @@ libledger_la_SOURCES = \
src/journal.cc \
src/amount.cc \
src/balance.cc \
+ src/commodity.cc \
src/value.cc \
src/binary.cc \
src/qif.cc \
@@ -100,6 +101,7 @@ libpyledger_la_SOURCES = \
pkginclude_HEADERS = \
src/amount.h \
src/balance.h \
+ src/commodity.h \
src/binary.h \
src/context.h \
src/csv.h \
diff --git a/Makefile.in b/Makefile.in
index 6adae186..57abbd79 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -86,30 +86,31 @@ libLTLIBRARIES_INSTALL = $(INSTALL)
LTLIBRARIES = $(lib_LTLIBRARIES)
libledger_la_LIBADD =
am__libledger_la_SOURCES_DIST = src/session.cc src/journal.cc \
- src/amount.cc src/balance.cc src/value.cc src/binary.cc \
- src/qif.cc src/textual.cc src/quotes.cc src/csv.cc \
- src/derive.cc src/emacs.cc src/format.cc src/reconcile.cc \
- src/register.cc src/report.cc src/transform.cc src/mask.cc \
- src/times.cc src/utils.cc src/xml.cc src/xmlparse.cc \
- src/xpath.cc src/gnucash.cc src/ofx.cc src/pyinterp.cc
+ src/amount.cc src/balance.cc src/commodity.cc src/value.cc \
+ src/binary.cc src/qif.cc src/textual.cc src/quotes.cc \
+ src/csv.cc src/derive.cc src/emacs.cc src/format.cc \
+ src/reconcile.cc src/register.cc src/report.cc \
+ src/transform.cc src/mask.cc src/times.cc src/utils.cc \
+ src/xml.cc src/xmlparse.cc src/xpath.cc src/gnucash.cc \
+ src/ofx.cc src/pyinterp.cc
@HAVE_EXPAT_TRUE@am__objects_1 = libledger_la-gnucash.lo
@HAVE_XMLPARSE_TRUE@am__objects_2 = libledger_la-gnucash.lo
@HAVE_LIBOFX_TRUE@am__objects_3 = libledger_la-ofx.lo
@HAVE_BOOST_PYTHON_TRUE@am__objects_4 = libledger_la-pyinterp.lo
am_libledger_la_OBJECTS = libledger_la-session.lo \
libledger_la-journal.lo libledger_la-amount.lo \
- libledger_la-balance.lo libledger_la-value.lo \
- libledger_la-binary.lo libledger_la-qif.lo \
- libledger_la-textual.lo libledger_la-quotes.lo \
- libledger_la-csv.lo libledger_la-derive.lo \
- libledger_la-emacs.lo libledger_la-format.lo \
- libledger_la-reconcile.lo libledger_la-register.lo \
- libledger_la-report.lo libledger_la-transform.lo \
- libledger_la-mask.lo libledger_la-times.lo \
- libledger_la-utils.lo libledger_la-xml.lo \
- libledger_la-xmlparse.lo libledger_la-xpath.lo \
- $(am__objects_1) $(am__objects_2) $(am__objects_3) \
- $(am__objects_4)
+ libledger_la-balance.lo libledger_la-commodity.lo \
+ libledger_la-value.lo libledger_la-binary.lo \
+ libledger_la-qif.lo libledger_la-textual.lo \
+ libledger_la-quotes.lo libledger_la-csv.lo \
+ libledger_la-derive.lo libledger_la-emacs.lo \
+ libledger_la-format.lo libledger_la-reconcile.lo \
+ libledger_la-register.lo libledger_la-report.lo \
+ libledger_la-transform.lo libledger_la-mask.lo \
+ libledger_la-times.lo libledger_la-utils.lo \
+ libledger_la-xml.lo libledger_la-xmlparse.lo \
+ libledger_la-xpath.lo $(am__objects_1) $(am__objects_2) \
+ $(am__objects_3) $(am__objects_4)
nodist_libledger_la_OBJECTS =
libledger_la_OBJECTS = $(am_libledger_la_OBJECTS) \
$(nodist_libledger_la_OBJECTS)
@@ -360,12 +361,12 @@ libledger_la_CPPFLAGS = -I$(top_builddir)/gdtoa -I$(srcdir)/gdtoa \
$(am__append_6) $(am__append_8) $(am__append_9)
libledger_la_LDFLAGS = -release 3.0
libledger_la_SOURCES = src/session.cc src/journal.cc src/amount.cc \
- src/balance.cc src/value.cc src/binary.cc src/qif.cc \
- src/textual.cc src/quotes.cc src/csv.cc src/derive.cc \
- src/emacs.cc src/format.cc src/reconcile.cc src/register.cc \
- src/report.cc src/transform.cc src/mask.cc src/times.cc \
- src/utils.cc src/xml.cc src/xmlparse.cc src/xpath.cc \
- $(am__append_3) $(am__append_5) $(am__append_7) \
+ src/balance.cc src/commodity.cc src/value.cc src/binary.cc \
+ src/qif.cc src/textual.cc src/quotes.cc src/csv.cc \
+ src/derive.cc src/emacs.cc src/format.cc src/reconcile.cc \
+ src/register.cc src/report.cc src/transform.cc src/mask.cc \
+ src/times.cc src/utils.cc src/xml.cc src/xmlparse.cc \
+ src/xpath.cc $(am__append_3) $(am__append_5) $(am__append_7) \
$(am__append_10)
@USE_PCH_TRUE@libledger_la_CXXFLAGS = $(WARNFLAGS)
@USE_PCH_TRUE@nodist_libledger_la_SOURCES = system.hh.gch
@@ -377,6 +378,7 @@ libpyledger_la_SOURCES = \
pkginclude_HEADERS = \
src/amount.h \
src/balance.h \
+ src/commodity.h \
src/binary.h \
src/context.h \
src/csv.h \
@@ -597,6 +599,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libledger_la-amount.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libledger_la-balance.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libledger_la-binary.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libledger_la-commodity.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libledger_la-csv.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libledger_la-derive.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libledger_la-emacs.Plo@am__quote@
@@ -672,6 +675,13 @@ libledger_la-balance.lo: src/balance.cc
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libledger_la_CPPFLAGS) $(CPPFLAGS) $(libledger_la_CXXFLAGS) $(CXXFLAGS) -c -o libledger_la-balance.lo `test -f 'src/balance.cc' || echo '$(srcdir)/'`src/balance.cc
+libledger_la-commodity.lo: src/commodity.cc
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libledger_la_CPPFLAGS) $(CPPFLAGS) $(libledger_la_CXXFLAGS) $(CXXFLAGS) -MT libledger_la-commodity.lo -MD -MP -MF $(DEPDIR)/libledger_la-commodity.Tpo -c -o libledger_la-commodity.lo `test -f 'src/commodity.cc' || echo '$(srcdir)/'`src/commodity.cc
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libledger_la-commodity.Tpo $(DEPDIR)/libledger_la-commodity.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/commodity.cc' object='libledger_la-commodity.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libledger_la_CPPFLAGS) $(CPPFLAGS) $(libledger_la_CXXFLAGS) $(CXXFLAGS) -c -o libledger_la-commodity.lo `test -f 'src/commodity.cc' || echo '$(srcdir)/'`src/commodity.cc
+
libledger_la-value.lo: src/value.cc
@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libledger_la_CPPFLAGS) $(CPPFLAGS) $(libledger_la_CXXFLAGS) $(CXXFLAGS) -MT libledger_la-value.lo -MD -MP -MF $(DEPDIR)/libledger_la-value.Tpo -c -o libledger_la-value.lo `test -f 'src/value.cc' || echo '$(srcdir)/'`src/value.cc
@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libledger_la-value.Tpo $(DEPDIR)/libledger_la-value.Plo
diff --git a/src/amount.cc b/src/amount.cc
index 7a74ef34..111b91a7 100644
--- a/src/amount.cc
+++ b/src/amount.cc
@@ -103,18 +103,6 @@ inline amount_t::bigint_t::~bigint_t() {
mpz_clear(val);
}
-#ifndef THREADSAFE
-base_commodities_map commodity_base_t::commodities;
-
-commodity_base_t::updater_t * commodity_base_t::updater = NULL;
-
-commodities_map commodity_t::commodities;
-commodities_array * commodity_t::commodities_by_ident;
-bool commodity_t::commodities_sorted = false;
-commodity_t * commodity_t::null_commodity;
-commodity_t * commodity_t::default_commodity = NULL;
-#endif
-
void amount_t::initialize()
{
mpz_init(temp);
@@ -176,52 +164,90 @@ void amount_t::shutdown()
true_value = NULL;
}
-static void mpz_round(mpz_t out, mpz_t value, int value_prec, int round_prec)
+void amount_t::_release()
{
- // Round `value', with an encoding precision of `value_prec', to a
- // rounded value with precision `round_prec'. Result is stored in
- // `out'.
+ DEBUG("amounts.refs", quantity << " ref--, now " << (quantity->ref - 1));
- assert(value_prec > round_prec);
+ if (--quantity->ref == 0) {
+ if (! (quantity->flags & BIGINT_BULK_ALLOC))
+ checked_delete(quantity);
+ else
+ quantity->~bigint_t();
+ }
+}
- mpz_t quotient;
- mpz_t remainder;
+void amount_t::_init()
+{
+ if (! quantity) {
+ quantity = new bigint_t;
+ }
+ else if (quantity->ref > 1) {
+ _release();
+ quantity = new bigint_t;
+ }
+}
- mpz_init(quotient);
- mpz_init(remainder);
+void amount_t::_dup()
+{
+ if (quantity->ref > 1) {
+ bigint_t * q = new bigint_t(*quantity);
+ _release();
+ quantity = q;
+ }
+}
+
+void amount_t::_copy(const amount_t& amt)
+{
+ if (quantity != amt.quantity) {
+ if (quantity)
+ _release();
- mpz_ui_pow_ui(divisor, 10, value_prec - round_prec);
- mpz_tdiv_qr(quotient, remainder, value, divisor);
- mpz_divexact_ui(divisor, divisor, 10);
- mpz_mul_ui(divisor, divisor, 5);
-
- if (mpz_sgn(remainder) < 0) {
- mpz_neg(divisor, divisor);
- if (mpz_cmp(remainder, divisor) < 0) {
- mpz_ui_pow_ui(divisor, 10, value_prec - round_prec);
- mpz_add(remainder, divisor, remainder);
- mpz_ui_sub(remainder, 0, remainder);
- mpz_add(out, value, remainder);
+ // Never maintain a pointer into a bulk allocation pool; such
+ // pointers are not guaranteed to remain.
+ if (amt.quantity->flags & BIGINT_BULK_ALLOC) {
+ quantity = new bigint_t(*amt.quantity);
} else {
- mpz_sub(out, value, remainder);
+ quantity = amt.quantity;
+ DEBUG("amounts.refs",
+ quantity << " ref++, now " << (quantity->ref + 1));
+ quantity->ref++;
}
+ }
+ commodity_ = amt.commodity_;
+}
+
+void amount_t::_resize(unsigned int prec)
+{
+ assert(prec < 256);
+
+ if (! quantity || prec == quantity->prec)
+ return;
+
+ _dup();
+
+ if (prec < quantity->prec) {
+ mpz_ui_pow_ui(divisor, 10, quantity->prec - prec);
+ mpz_tdiv_q(MPZ(quantity), MPZ(quantity), divisor);
} else {
- if (mpz_cmp(remainder, divisor) >= 0) {
- mpz_ui_pow_ui(divisor, 10, value_prec - round_prec);
- mpz_sub(remainder, divisor, remainder);
- mpz_add(out, value, remainder);
- } else {
- mpz_sub(out, value, remainder);
- }
+ mpz_ui_pow_ui(divisor, 10, prec - quantity->prec);
+ mpz_mul(MPZ(quantity), MPZ(quantity), divisor);
}
- mpz_clear(quotient);
- mpz_clear(remainder);
- // chop off the rounded bits
- mpz_ui_pow_ui(divisor, 10, value_prec - round_prec);
- mpz_tdiv_q(out, out, divisor);
+ quantity->prec = prec;
}
+void amount_t::_clear()
+{
+ if (quantity) {
+ _release();
+ quantity = NULL;
+ commodity_ = NULL;
+ } else {
+ assert(! commodity_);
+ }
+}
+
+
amount_t::amount_t(const long val)
{
TRACE_CTOR(amount_t, "const long");
@@ -340,72 +366,37 @@ amount_t::amount_t(const double val)
commodity_ = NULL;
}
-void amount_t::_release()
-{
- DEBUG("amounts.refs", quantity << " ref--, now " << (quantity->ref - 1));
-
- if (--quantity->ref == 0) {
- if (! (quantity->flags & BIGINT_BULK_ALLOC))
- checked_delete(quantity);
- else
- quantity->~bigint_t();
- }
-}
-void amount_t::_init()
+int amount_t::compare(const amount_t& amt) const
{
if (! quantity) {
- quantity = new bigint_t;
- }
- else if (quantity->ref > 1) {
- _release();
- quantity = new bigint_t;
- }
-}
-
-void amount_t::_dup()
-{
- if (quantity->ref > 1) {
- bigint_t * q = new bigint_t(*quantity);
- _release();
- quantity = q;
+ if (! amt.quantity)
+ return 0;
+ return - amt.sign();
}
-}
+ if (! amt.quantity)
+ return sign();
-void amount_t::_copy(const amount_t& amt)
-{
- if (quantity != amt.quantity) {
- if (quantity)
- _release();
+ if (has_commodity() && amt.commodity() && commodity() != amt.commodity())
+ throw_(amount_error,
+ "Cannot compare amounts with different commodities: " <<
+ commodity().symbol() << " and " << amt.commodity().symbol());
- // Never maintain a pointer into a bulk allocation pool; such
- // pointers are not guaranteed to remain.
- if (amt.quantity->flags & BIGINT_BULK_ALLOC) {
- quantity = new bigint_t(*amt.quantity);
- } else {
- quantity = amt.quantity;
- DEBUG("amounts.refs",
- quantity << " ref++, now " << (quantity->ref + 1));
- quantity->ref++;
- }
+ if (quantity->prec == amt.quantity->prec) {
+ return mpz_cmp(MPZ(quantity), MPZ(amt.quantity));
+ }
+ else if (quantity->prec < amt.quantity->prec) {
+ amount_t t = *this;
+ t._resize(amt.quantity->prec);
+ return mpz_cmp(MPZ(t.quantity), MPZ(amt.quantity));
+ }
+ else {
+ amount_t t = amt;
+ t._resize(quantity->prec);
+ return mpz_cmp(MPZ(quantity), MPZ(t.quantity));
}
- commodity_ = amt.commodity_;
-}
-
-amount_t& amount_t::operator=(const string& val)
-{
- std::istringstream str(val);
- parse(str);
- return *this;
}
-amount_t& amount_t::operator=(const char * val)
-{
- string valstr(val);
- std::istringstream str(valstr);
- parse(str);
- return *this;
-}
// assignment operator
amount_t& amount_t::operator=(const amount_t& amt)
@@ -419,6 +410,7 @@ amount_t& amount_t::operator=(const amount_t& amt)
return *this;
}
+#if 0
amount_t& amount_t::operator=(const long val)
{
if (val == 0) {
@@ -453,38 +445,21 @@ amount_t& amount_t::operator=(const double val)
return *this;
}
-
-void amount_t::_resize(unsigned int prec)
+amount_t& amount_t::operator=(const string& val)
{
- assert(prec < 256);
-
- if (! quantity || prec == quantity->prec)
- return;
-
- _dup();
-
- if (prec < quantity->prec) {
- mpz_ui_pow_ui(divisor, 10, quantity->prec - prec);
- mpz_tdiv_q(MPZ(quantity), MPZ(quantity), divisor);
- } else {
- mpz_ui_pow_ui(divisor, 10, prec - quantity->prec);
- mpz_mul(MPZ(quantity), MPZ(quantity), divisor);
- }
-
- quantity->prec = prec;
+ std::istringstream str(val);
+ parse(str);
+ return *this;
}
-
-void amount_t::_clear()
+amount_t& amount_t::operator=(const char * val)
{
- if (quantity) {
- _release();
- quantity = NULL;
- commodity_ = NULL;
- } else {
- assert(! commodity_);
- }
+ string valstr(val);
+ std::istringstream str(valstr);
+ parse(str);
+ return *this;
}
+#endif
amount_t& amount_t::operator+=(const amount_t& amt)
@@ -559,6 +534,54 @@ amount_t& amount_t::operator-=(const amount_t& amt)
return *this;
}
+namespace {
+ void mpz_round(mpz_t out, mpz_t value, int value_prec, int round_prec)
+ {
+ // Round `value', with an encoding precision of `value_prec', to a
+ // rounded value with precision `round_prec'. Result is stored in
+ // `out'.
+
+ assert(value_prec > round_prec);
+
+ mpz_t quotient;
+ mpz_t remainder;
+
+ mpz_init(quotient);
+ mpz_init(remainder);
+
+ mpz_ui_pow_ui(divisor, 10, value_prec - round_prec);
+ mpz_tdiv_qr(quotient, remainder, value, divisor);
+ mpz_divexact_ui(divisor, divisor, 10);
+ mpz_mul_ui(divisor, divisor, 5);
+
+ if (mpz_sgn(remainder) < 0) {
+ mpz_neg(divisor, divisor);
+ if (mpz_cmp(remainder, divisor) < 0) {
+ mpz_ui_pow_ui(divisor, 10, value_prec - round_prec);
+ mpz_add(remainder, divisor, remainder);
+ mpz_ui_sub(remainder, 0, remainder);
+ mpz_add(out, value, remainder);
+ } else {
+ mpz_sub(out, value, remainder);
+ }
+ } else {
+ if (mpz_cmp(remainder, divisor) >= 0) {
+ mpz_ui_pow_ui(divisor, 10, value_prec - round_prec);
+ mpz_sub(remainder, divisor, remainder);
+ mpz_add(out, value, remainder);
+ } else {
+ mpz_sub(out, value, remainder);
+ }
+ }
+ mpz_clear(quotient);
+ mpz_clear(remainder);
+
+ // chop off the rounded bits
+ mpz_ui_pow_ui(divisor, 10, value_prec - round_prec);
+ mpz_tdiv_q(out, out, divisor);
+ }
+}
+
amount_t& amount_t::operator*=(const amount_t& amt)
{
if (has_commodity() && amt.has_commodity() &&
@@ -665,50 +688,6 @@ int amount_t::sign() const
return quantity ? mpz_sgn(MPZ(quantity)) : 0;
}
-int amount_t::compare(const amount_t& amt) const
-{
- if (! quantity) {
- if (! amt.quantity)
- return 0;
- return - amt.sign();
- }
- if (! amt.quantity)
- return sign();
-
- if (has_commodity() && amt.commodity() && commodity() != amt.commodity())
- throw_(amount_error,
- "Cannot compare amounts with different commodities: " <<
- commodity().symbol() << " and " << amt.commodity().symbol());
-
- if (quantity->prec == amt.quantity->prec) {
- return mpz_cmp(MPZ(quantity), MPZ(amt.quantity));
- }
- else if (quantity->prec < amt.quantity->prec) {
- amount_t t = *this;
- t._resize(amt.quantity->prec);
- return mpz_cmp(MPZ(t.quantity), MPZ(amt.quantity));
- }
- else {
- amount_t t = amt;
- t._resize(quantity->prec);
- return mpz_cmp(MPZ(quantity), MPZ(t.quantity));
- }
-}
-
-bool amount_t::operator==(const amount_t& amt) const
-{
- if (commodity() != amt.commodity())
- return false;
- return compare(amt) == 0;
-}
-
-bool amount_t::operator!=(const amount_t& amt) const
-{
- if (commodity() != amt.commodity())
- return true;
- return compare(amt) != 0;
-}
-
bool amount_t::zero() const
{
if (! quantity)
@@ -723,6 +702,7 @@ bool amount_t::zero() const
return realzero();
}
+#if 0
amount_t::operator long() const
{
if (! quantity)
@@ -759,6 +739,7 @@ amount_t::operator double() const
return std::atof(num.str().c_str());
}
+#endif
amount_t amount_t::value(const moment_t& moment) const
{
@@ -912,7 +893,7 @@ void amount_t::print(std::ostream& _out, bool omit_commodity,
while (last.commodity().larger()) {
last /= last.commodity().larger()->number();
last.commodity_ = last.commodity().larger()->commodity_;
- if (last.abs() < 1)
+ if (last.abs() < amount_t(1.0))
break;
base = last.round();
}
@@ -1671,370 +1652,4 @@ optional<string> amount_t::tag() const
return optional<string>();
}
-
-void commodity_base_t::add_price(const moment_t& date,
- const amount_t& price)
-{
- if (! history)
- history = new history_t;
-
- history_map::iterator i = history->prices.find(date);
- if (i != history->prices.end()) {
- (*i).second = price;
- } else {
- std::pair<history_map::iterator, bool> result
- = history->prices.insert(history_pair(date, price));
- assert(result.second);
- }
-}
-
-bool commodity_base_t::remove_price(const moment_t& date)
-{
- if (history) {
- history_map::size_type n = history->prices.erase(date);
- if (n > 0) {
- if (history->prices.empty())
- history = NULL;
- return true;
- }
- }
- return false;
-}
-
-commodity_base_t * commodity_base_t::create(const string& symbol)
-{
- commodity_base_t * commodity = new commodity_base_t(symbol);
-
- DEBUG("amounts.commodities", "Creating base commodity " << symbol);
-
- std::pair<base_commodities_map::iterator, bool> result
- = commodities.insert(base_commodities_pair(symbol, commodity));
- assert(result.second);
-
- return commodity;
-}
-
-bool commodity_t::needs_quotes(const string& symbol)
-{
- for (const char * p = symbol.c_str(); *p; p++)
- if (std::isspace(*p) || std::isdigit(*p) || *p == '-' || *p == '.')
- return true;
-
- return false;
-}
-
-bool commodity_t::valid() const
-{
- if (symbol().empty() && this != null_commodity) {
- DEBUG("ledger.validate",
- "commodity_t: symbol().empty() && this != null_commodity");
- return false;
- }
-
- if (annotated && ! base) {
- DEBUG("ledger.validate", "commodity_t: annotated && ! base");
- return false;
- }
-
- if (precision() > 16) {
- DEBUG("ledger.validate", "commodity_t: precision() > 16");
- return false;
- }
-
- return true;
-}
-
-commodity_t * commodity_t::create(const string& symbol)
-{
- std::auto_ptr<commodity_t> commodity(new commodity_t);
-
- commodity->base = commodity_base_t::create(symbol);
-
- if (needs_quotes(symbol)) {
- commodity->qualified_symbol = "\"";
- commodity->qualified_symbol += symbol;
- commodity->qualified_symbol += "\"";
- } else {
- commodity->qualified_symbol = symbol;
- }
-
- DEBUG("amounts.commodities",
- "Creating commodity " << commodity->qualified_symbol);
-
- std::pair<commodities_map::iterator, bool> result
- = commodities.insert(commodities_pair(symbol, commodity.get()));
- if (! result.second)
- return NULL;
-
- commodity->ident = commodities_by_ident->size();
- commodities_by_ident->push_back(commodity.get());
-
- // Start out the new commodity with the default commodity's flags
- // and precision, if one has been defined.
- if (default_commodity)
- commodity->drop_flags(COMMODITY_STYLE_THOUSANDS |
- COMMODITY_STYLE_NOMARKET);
-
- return commodity.release();
-}
-
-commodity_t * commodity_t::find_or_create(const string& symbol)
-{
- DEBUG("amounts.commodities", "Find-or-create commodity " << symbol);
-
- commodity_t * commodity = find(symbol);
- if (commodity)
- return commodity;
- return create(symbol);
-}
-
-commodity_t * commodity_t::find(const string& symbol)
-{
- DEBUG("amounts.commodities", "Find commodity " << symbol);
-
- commodities_map::const_iterator i = commodities.find(symbol);
- if (i != commodities.end())
- return (*i).second;
- return NULL;
-}
-
-amount_t commodity_base_t::value(const moment_t& moment)
-{
- moment_t age;
- amount_t price;
-
- if (history) {
- assert(history->prices.size() > 0);
-
- if (! is_valid_moment(moment)) {
- history_map::reverse_iterator r = history->prices.rbegin();
- age = (*r).first;
- price = (*r).second;
- } else {
- history_map::iterator i = history->prices.lower_bound(moment);
- if (i == history->prices.end()) {
- history_map::reverse_iterator r = history->prices.rbegin();
- age = (*r).first;
- price = (*r).second;
- } else {
- age = (*i).first;
- if (moment != age) {
- if (i != history->prices.begin()) {
- --i;
- age = (*i).first;
- price = (*i).second;
- } else {
- age = moment_t();
- }
- } else {
- price = (*i).second;
- }
- }
- }
- }
-
- if (updater && ! (flags & COMMODITY_STYLE_NOMARKET))
- (*updater)(*this, moment, age,
- (history && history->prices.size() > 0 ?
- (*history->prices.rbegin()).first : moment_t()), price);
-
- return price;
-}
-
-bool annotated_commodity_t::operator==(const commodity_t& comm) const
-{
- // If the base commodities don't match, the game's up.
- if (base != comm.base)
- return false;
-
- if (price &&
- (! comm.annotated ||
- price != static_cast<const annotated_commodity_t&>(comm).price))
- return false;
-
- if (date &&
- (! comm.annotated ||
- date != static_cast<const annotated_commodity_t&>(comm).date))
- return false;
-
- if (tag &&
- (! comm.annotated ||
- tag != static_cast<const annotated_commodity_t&>(comm).tag))
- return false;
-
- return true;
-}
-
-void
-annotated_commodity_t::write_annotations(std::ostream& out,
- const optional<amount_t>& price,
- const optional<moment_t>& date,
- const optional<string>& tag)
-{
- if (price)
- out << " {" << *price << '}';
-
- if (date)
- out << " [" << *date << ']';
-
- if (tag)
- out << " (" << *tag << ')';
-}
-
-commodity_t *
-annotated_commodity_t::create(const commodity_t& comm,
- const optional<amount_t>& price,
- const optional<moment_t>& date,
- const optional<string>& tag,
- const string& mapping_key)
-{
- std::auto_ptr<annotated_commodity_t> commodity(new annotated_commodity_t);
-
- // Set the annotated bits
- commodity->price = price;
- commodity->date = date;
- commodity->tag = tag;
-
- commodity->ptr = &comm;
- assert(commodity->ptr);
- commodity->base = comm.base;
- assert(commodity->base);
-
- commodity->qualified_symbol = comm.symbol();
-
- DEBUG("amounts.commodities", "Creating annotated commodity "
- << "symbol " << commodity->symbol()
- << " key " << mapping_key << std::endl
- << " price " << (price ? price->to_string() : "NONE") << " "
- << " date " << (date ? *date : moment_t()) << " "
- << " tag " << (tag ? *tag : "NONE"));
-
- // Add the fully annotated name to the map, so that this symbol may
- // quickly be found again.
- std::pair<commodities_map::iterator, bool> result
- = commodities.insert(commodities_pair(mapping_key, commodity.get()));
- if (! result.second)
- return NULL;
-
- commodity->ident = commodities_by_ident->size();
- commodities_by_ident->push_back(commodity.get());
-
- return commodity.release();
-}
-
-namespace {
- string make_qualified_name(const commodity_t& comm,
- const optional<amount_t>& price,
- const optional<moment_t>& date,
- const optional<string>& tag)
- {
- if (price && *price < 0)
- throw_(amount_error, "A commodity's price may not be negative");
-
- std::ostringstream name;
-
- comm.write(name);
- annotated_commodity_t::write_annotations(name, price, date, tag);
-
- DEBUG("amounts.commodities", "make_qualified_name for "
- << comm.qualified_symbol << std::endl
- << " price " << (price ? price->to_string() : "NONE") << " "
- << " date " << (date ? *date : moment_t()) << " "
- << " tag " << (tag ? *tag : "NONE"));
-
- DEBUG("amounts.commodities", "qualified_name is " << name.str());
-
- return name.str();
- }
-}
-
-commodity_t *
-annotated_commodity_t::find_or_create(const commodity_t& comm,
- const optional<amount_t>& price,
- const optional<moment_t>& date,
- const optional<string>& tag)
-{
- string name = make_qualified_name(comm, price, date, tag);
-
- commodity_t * ann_comm = commodity_t::find(name);
- if (ann_comm) {
- assert(ann_comm->annotated);
- return ann_comm;
- }
- return create(comm, price, date, tag, name);
-}
-
-bool compare_amount_commodities::operator()(const amount_t * left,
- const amount_t * right) const
-{
- commodity_t& leftcomm(left->commodity());
- commodity_t& rightcomm(right->commodity());
-
- int cmp = leftcomm.base_symbol().compare(rightcomm.base_symbol());
- if (cmp != 0)
- return cmp < 0;
-
- if (! leftcomm.annotated) {
- assert(rightcomm.annotated);
- return true;
- }
- else if (! rightcomm.annotated) {
- assert(leftcomm.annotated);
- return false;
- }
- else {
- annotated_commodity_t& aleftcomm(static_cast<annotated_commodity_t&>(leftcomm));
- annotated_commodity_t& arightcomm(static_cast<annotated_commodity_t&>(rightcomm));
-
- if (! aleftcomm.price && arightcomm.price)
- return true;
- if (aleftcomm.price && ! arightcomm.price)
- return false;
-
- if (aleftcomm.price && arightcomm.price) {
- amount_t leftprice(*aleftcomm.price);
- leftprice.in_place_reduce();
- amount_t rightprice(*arightcomm.price);
- rightprice.in_place_reduce();
-
- if (leftprice.commodity() == rightprice.commodity()) {
- amount_t val = leftprice - rightprice;
- if (val)
- return val < 0;
- } else {
- // Since we have two different amounts, there's really no way
- // to establish a true sorting order; we'll just do it based
- // on the numerical values.
- leftprice.clear_commodity();
- rightprice.clear_commodity();
-
- amount_t val = leftprice - rightprice;
- if (val)
- return val < 0;
- }
- }
-
- if (! aleftcomm.date && arightcomm.date)
- return true;
- if (aleftcomm.date && ! arightcomm.date)
- return false;
-
- if (aleftcomm.date && arightcomm.date) {
- duration_t diff = *aleftcomm.date - *arightcomm.date;
- return diff.is_negative();
- }
-
- if (! aleftcomm.tag && arightcomm.tag)
- return true;
- if (aleftcomm.tag && ! arightcomm.tag)
- return false;
-
- if (aleftcomm.tag && arightcomm.tag)
- return *aleftcomm.tag < *arightcomm.tag;
-
- assert(false);
- return true;
- }
-}
-
} // namespace ledger
diff --git a/src/amount.h b/src/amount.h
index e1f7d6ef..b4b5df54 100644
--- a/src/amount.h
+++ b/src/amount.h
@@ -55,6 +55,8 @@ extern bool do_cleanup;
class commodity_t;
+DECLARE_EXCEPTION(amount_error);
+
/**
* @class amount_t
*
@@ -67,8 +69,7 @@ class commodity_t;
* uncommoditized numbers, no display truncation is ever done.
* Internally, precision is always kept to an excessive degree.
*/
-
-class amount_t
+class amount_t : public ordered_field_operators<amount_t>
{
public:
class bigint_t;
@@ -105,6 +106,10 @@ class amount_t
else
commodity_ = NULL;
}
+ amount_t(const long val);
+ amount_t(const unsigned long val);
+ amount_t(const double val);
+
amount_t(const string& val) : quantity(NULL) {
TRACE_CTOR(amount_t, "const string&");
parse(val);
@@ -113,63 +118,29 @@ class amount_t
TRACE_CTOR(amount_t, "const char *");
parse(val);
}
- amount_t(const long val);
- amount_t(const unsigned long val);
- amount_t(const double val);
- // destructor
~amount_t() {
TRACE_DTOR(amount_t);
if (quantity)
_release();
}
- amount_t number() const {
- if (! has_commodity())
- return *this;
- amount_t temp(*this);
- temp.clear_commodity();
- return temp;
- }
-
- bool has_commodity() const;
- void set_commodity(commodity_t& comm) {
- commodity_ = &comm;
- }
- void clear_commodity() {
- commodity_ = NULL;
- }
-
- commodity_t& commodity() const;
-
- void annotate_commodity(const optional<amount_t>& tprice,
- const optional<moment_t>& tdate = optional<moment_t>(),
- const optional<string>& ttag = optional<string>());
-
- amount_t strip_annotations(const bool _keep_price = keep_price,
- const bool _keep_date = keep_date,
- const bool _keep_tag = keep_tag) const;
-
- optional<amount_t> price() const;
- optional<moment_t> date() const;
- optional<string> tag() const;
-
- bool null() const {
- return ! quantity && ! has_commodity();
- }
-
// assignment operator
amount_t& operator=(const amount_t& amt);
+#if 0
+ amount_t& operator=(const double val);
+ amount_t& operator=(const unsigned long val);
+ amount_t& operator=(const long val);
amount_t& operator=(const string& val);
amount_t& operator=(const char * val);
- amount_t& operator=(const long val);
- amount_t& operator=(const unsigned long val);
- amount_t& operator=(const double val);
+#endif
- // general methods
- amount_t round(unsigned int prec) const;
- amount_t round() const;
- amount_t unround() const;
+ // comparisons between amounts
+ int compare(const amount_t& amt) const;
+ bool operator==(const amount_t& amt) const;
+ bool operator<(const amount_t& amt) const {
+ return compare(amt) < 0;
+ }
// in-place arithmetic
amount_t& operator+=(const amount_t& amt);
@@ -177,70 +148,6 @@ class amount_t
amount_t& operator*=(const amount_t& amt);
amount_t& operator/=(const amount_t& amt);
- template <typename T>
- amount_t& operator+=(T val) {
- return *this += amount_t(val);
- }
- template <typename T>
- amount_t& operator-=(T val) {
- return *this -= amount_t(val);
- }
- template <typename T>
- amount_t& operator*=(T val) {
- return *this *= amount_t(val);
- }
- template <typename T>
- amount_t& operator/=(T val) {
- return *this /= amount_t(val);
- }
-
- // simple arithmetic
- amount_t operator+(const amount_t& amt) const {
- amount_t temp = *this;
- temp += amt;
- return temp;
- }
- amount_t operator-(const amount_t& amt) const {
- amount_t temp = *this;
- temp -= amt;
- return temp;
- }
- amount_t operator*(const amount_t& amt) const {
- amount_t temp = *this;
- temp *= amt;
- return temp;
- }
- amount_t operator/(const amount_t& amt) const {
- amount_t temp = *this;
- temp /= amt;
- return temp;
- }
-
- template <typename T>
- amount_t operator+(T val) const {
- amount_t temp = *this;
- temp += val;
- return temp;
- }
- template <typename T>
- amount_t operator-(T val) const {
- amount_t temp = *this;
- temp -= val;
- return temp;
- }
- template <typename T>
- amount_t operator*(T val) const {
- amount_t temp = *this;
- temp *= val;
- return temp;
- }
- template <typename T>
- amount_t operator/(T val) const {
- amount_t temp = *this;
- temp /= val;
- return temp;
- }
-
// unary negation
void in_place_negate();
amount_t negate() const {
@@ -261,76 +168,66 @@ class amount_t
operator bool() const {
return ! zero();
}
- operator string() const {
- return to_string();
- }
- operator long() const;
- operator double() const;
-
- string to_string() const;
- string to_fullstring() const;
- string quantity_string() const;
+ // Methods relating to this amount's commodity
- // comparisons between amounts
- int compare(const amount_t& amt) const;
-
- bool operator<(const amount_t& amt) const {
- return compare(amt) < 0;
- }
- bool operator<=(const amount_t& amt) const {
- return compare(amt) <= 0;
+ bool is_null() const {
+ return ! quantity && ! has_commodity();
}
- bool operator>(const amount_t& amt) const {
- return compare(amt) > 0;
+
+ amount_t number() const {
+ if (! has_commodity())
+ return *this;
+ amount_t temp(*this);
+ temp.clear_commodity();
+ return temp;
}
- bool operator>=(const amount_t& amt) const {
- return compare(amt) >= 0;
+
+ bool has_commodity() const;
+ void set_commodity(commodity_t& comm) {
+ commodity_ = &comm;
}
- bool operator==(const amount_t& amt) const;
- bool operator!=(const amount_t& amt) const;
-
- template <typename T>
- void parse_num(T num) {
- std::ostringstream temp;
- temp << num;
- std::istringstream in(temp.str());
- parse(in);
+ void clear_commodity() {
+ commodity_ = NULL;
}
- // POD comparisons
-#define AMOUNT_CMP_INT(OP) \
- template <typename T> \
- bool operator OP (T num) const { \
- if (num == 0) { \
- return sign() OP 0; \
- } else { \
- amount_t amt; \
- amt.parse_num(num); \
- return *this OP amt; \
- } \
- }
+ commodity_t& commodity() const;
+
+ void annotate_commodity(const optional<amount_t>& tprice,
+ const optional<moment_t>& tdate = optional<moment_t>(),
+ const optional<string>& ttag = optional<string>());
+
+ amount_t strip_annotations(const bool _keep_price = keep_price,
+ const bool _keep_date = keep_date,
+ const bool _keep_tag = keep_tag) const;
- AMOUNT_CMP_INT(<)
- AMOUNT_CMP_INT(<=)
- AMOUNT_CMP_INT(>)
- AMOUNT_CMP_INT(>=)
- AMOUNT_CMP_INT(==)
+ optional<amount_t> price() const;
+ optional<moment_t> date() const;
+ optional<string> tag() const;
- template <typename T>
- bool operator!=(T num) const {
- return ! (*this == num);
+#if 0
+ // string and numeric conversions
+ operator string() const {
+ return to_string();
}
+ operator long() const;
+ operator double() const;
+#endif
- amount_t value(const moment_t& moment) const;
+ string to_string() const;
+ string to_fullstring() const;
+ string quantity_string() const;
+ // general methods
+ amount_t round(unsigned int prec) const;
+ amount_t round() const;
+ amount_t unround() const;
+ amount_t value(const moment_t& moment) const;
amount_t abs() const {
- if (*this < 0)
+ if (sign() < 0)
return negate();
return *this;
}
-
- void in_place_reduce();
amount_t reduce() const {
amount_t temp(*this);
temp.in_place_reduce();
@@ -339,6 +236,8 @@ class amount_t
bool valid() const;
+ void in_place_reduce();
+
static amount_t exact(const string& value);
// This function is special, and exists only to support a custom
@@ -407,51 +306,6 @@ inline string amount_t::quantity_string() const {
return bufstream.str();
}
-#define DEFINE_AMOUNT_OPERATORS(T) \
-inline amount_t operator+(const T val, const amount_t& amt) { \
- amount_t temp(val); \
- temp += amt; \
- return temp; \
-} \
-inline amount_t operator-(const T val, const amount_t& amt) { \
- amount_t temp(val); \
- temp -= amt; \
- return temp; \
-} \
-inline amount_t operator*(const T val, const amount_t& amt) { \
- amount_t temp(val); \
- temp *= amt; \
- return temp; \
-} \
-inline amount_t operator/(const T val, const amount_t& amt) { \
- amount_t temp(val); \
- temp /= amt; \
- return temp; \
-} \
- \
-inline bool operator<(const T val, const amount_t& amt) { \
- return amount_t(val) < amt; \
-} \
-inline bool operator<=(const T val, const amount_t& amt) { \
- return amount_t(val) <= amt; \
-} \
-inline bool operator>(const T val, const amount_t& amt) { \
- return amount_t(val) > amt; \
-} \
-inline bool operator>=(const T val, const amount_t& amt) { \
- return amount_t(val) >= amt; \
-} \
-inline bool operator==(const T val, const amount_t& amt) { \
- return amount_t(val) == amt; \
-} \
-inline bool operator!=(const T val, const amount_t& amt) { \
- return amount_t(val) != amt; \
-}
-
-DEFINE_AMOUNT_OPERATORS(long)
-DEFINE_AMOUNT_OPERATORS(unsigned long)
-DEFINE_AMOUNT_OPERATORS(double)
-
inline std::ostream& operator<<(std::ostream& out, const amount_t& amt) {
amt.print(out, false, amount_t::full_strings);
return out;
@@ -461,282 +315,16 @@ inline std::istream& operator>>(std::istream& in, amount_t& amt) {
return in;
}
+} // namespace ledger
-#define COMMODITY_STYLE_DEFAULTS 0x0000
-#define COMMODITY_STYLE_SUFFIXED 0x0001
-#define COMMODITY_STYLE_SEPARATED 0x0002
-#define COMMODITY_STYLE_EUROPEAN 0x0004
-#define COMMODITY_STYLE_THOUSANDS 0x0008
-#define COMMODITY_STYLE_NOMARKET 0x0010
-#define COMMODITY_STYLE_BUILTIN 0x0020
-
-typedef std::map<const moment_t, amount_t> history_map;
-typedef std::pair<const moment_t, amount_t> history_pair;
-
-class commodity_base_t;
-
-typedef std::map<const string, commodity_base_t *> base_commodities_map;
-typedef std::pair<const string, commodity_base_t *> base_commodities_pair;
-
-class commodity_base_t
-{
- public:
- friend class commodity_t;
- friend class annotated_commodity_t;
-
- typedef unsigned long ident_t;
-
- ident_t ident;
- string name;
- string note;
- unsigned char precision;
- unsigned char flags;
- amount_t * smaller;
- amount_t * larger;
-
- commodity_base_t()
- : precision(0), flags(COMMODITY_STYLE_DEFAULTS),
- smaller(NULL), larger(NULL), history(NULL) {
- TRACE_CTOR(commodity_base_t, "");
- }
-
- commodity_base_t(const commodity_base_t&) {
- TRACE_CTOR(commodity_base_t, "copy");
- assert(0);
- }
-
- commodity_base_t(const string& _symbol,
- unsigned int _precision = 0,
- unsigned int _flags = COMMODITY_STYLE_DEFAULTS)
- : precision(_precision), flags(_flags),
- smaller(NULL), larger(NULL), symbol(_symbol), history(NULL) {
- TRACE_CTOR(commodity_base_t, "const string&, unsigned int, unsigned int");
- }
-
- ~commodity_base_t() {
- TRACE_DTOR(commodity_base_t);
- if (history) checked_delete(history);
- if (smaller) checked_delete(smaller);
- if (larger) checked_delete(larger);
- }
-
- static base_commodities_map commodities;
- static commodity_base_t * create(const string& symbol);
-
- string symbol;
-
- struct history_t {
- history_map prices;
- ptime last_lookup;
- history_t() : last_lookup() {}
- };
- history_t * history;
-
- void add_price(const moment_t& date, const amount_t& price);
- bool remove_price(const moment_t& date);
- amount_t value(const moment_t& moment = now);
-
- class updater_t {
- public:
- virtual ~updater_t() {}
- virtual void operator()(commodity_base_t& commodity,
- const moment_t& moment,
- const moment_t& date,
- const moment_t& last,
- amount_t& price) = 0;
- };
- friend class updater_t;
-
- static updater_t * updater;
-};
-
-typedef std::map<const string, commodity_t *> commodities_map;
-typedef std::pair<const string, commodity_t *> commodities_pair;
-
-typedef std::vector<commodity_t *> commodities_array;
-
-class commodity_t
-{
- friend class annotated_commodity_t;
-
- public:
- // This map remembers all commodities that have been defined.
-
- static commodities_map commodities;
- static commodities_array * commodities_by_ident;
- static bool commodities_sorted;
- static commodity_t * null_commodity;
- static commodity_t * default_commodity;
-
- static commodity_t * create(const string& symbol);
- static commodity_t * find(const string& name);
- static commodity_t * find_or_create(const string& symbol);
-
- static bool needs_quotes(const string& symbol);
-
- static void make_alias(const string& symbol,
- commodity_t * commodity);
-
- // These are specific to each commodity reference
-
- typedef unsigned long ident_t;
-
- ident_t ident;
- commodity_base_t * base;
- string qualified_symbol;
- bool annotated;
-
- public:
- explicit commodity_t() : base(NULL), annotated(false) {
- TRACE_CTOR(commodity_t, "");
- }
- commodity_t(const commodity_t& o)
- : ident(o.ident), base(o.base),
- qualified_symbol(o.qualified_symbol), annotated(o.annotated) {
- TRACE_CTOR(commodity_t, "copy");
- }
- virtual ~commodity_t() {
- TRACE_DTOR(commodity_t);
- }
-
- operator bool() const {
- return this != null_commodity;
- }
- virtual bool operator==(const commodity_t& comm) const {
- if (comm.annotated)
- return comm == *this;
- return base == comm.base;
- }
- bool operator!=(const commodity_t& comm) const {
- return ! (*this == comm);
- }
-
- string base_symbol() const {
- return base->symbol;
- }
- string symbol() const {
- return qualified_symbol;
- }
-
- void write(std::ostream& out) const {
- out << symbol();
- }
-
- string name() const {
- return base->name;
- }
- void set_name(const string& arg) {
- base->name = arg;
- }
-
- string note() const {
- return base->note;
- }
- void set_note(const string& arg) {
- base->note = arg;
- }
-
- unsigned char precision() const {
- return base->precision;
- }
- void set_precision(unsigned char arg) {
- base->precision = arg;
- }
-
- unsigned char flags() const {
- return base->flags;
- }
- void set_flags(unsigned char arg) {
- base->flags = arg;
- }
- void add_flags(unsigned char arg) {
- base->flags |= arg;
- }
- void drop_flags(unsigned char arg) {
- base->flags &= ~arg;
- }
-
- amount_t * smaller() const {
- return base->smaller;
- }
- void set_smaller(const amount_t& arg) {
- if (base->smaller)
- checked_delete(base->smaller);
- base->smaller = new amount_t(arg);
- }
-
- amount_t * larger() const {
- return base->larger;
- }
- void set_larger(const amount_t& arg) {
- if (base->larger)
- checked_delete(base->larger);
- base->larger = new amount_t(arg);
- }
-
- commodity_base_t::history_t * history() const {
- return base->history;
- }
-
- void add_price(const moment_t& date, const amount_t& price) {
- return base->add_price(date, price);
- }
- bool remove_price(const moment_t& date) {
- return base->remove_price(date);
- }
- amount_t value(const moment_t& moment = now) const {
- return base->value(moment);
- }
-
- bool valid() const;
-};
-
-class annotated_commodity_t : public commodity_t
-{
- public:
- const commodity_t * ptr;
-
- optional<amount_t> price;
- optional<moment_t> date;
- optional<string> tag;
-
- explicit annotated_commodity_t() {
- TRACE_CTOR(annotated_commodity_t, "");
- annotated = true;
- }
- virtual ~annotated_commodity_t() {
- TRACE_DTOR(annotated_commodity_t);
- }
-
- virtual bool operator==(const commodity_t& comm) const;
-
- void write_annotations(std::ostream& out) const {
- annotated_commodity_t::write_annotations(out, price, date, tag);
- }
-
- static void write_annotations(std::ostream& out,
- const optional<amount_t>& price,
- const optional<moment_t>& date,
- const optional<string>& tag);
-
- private:
- static commodity_t * create(const commodity_t& comm,
- const optional<amount_t>& price,
- const optional<moment_t>& date,
- const optional<string>& tag,
- const string& mapping_key);
-
- static commodity_t * find_or_create(const commodity_t& comm,
- const optional<amount_t>& price,
- const optional<moment_t>& date,
- const optional<string>& tag);
+#include "commodity.h"
- friend class amount_t;
-};
+namespace ledger {
-inline std::ostream& operator<<(std::ostream& out, const commodity_t& comm) {
- out << comm.symbol();
- return out;
+inline bool amount_t::operator==(const amount_t& amt) const {
+ if (commodity() != amt.commodity())
+ return false;
+ return compare(amt) == 0;
}
inline amount_t amount_t::round() const {
@@ -756,12 +344,6 @@ inline commodity_t& amount_t::commodity() const {
void parse_conversion(const string& larger_str,
const string& smaller_str);
-DECLARE_EXCEPTION(amount_error);
-
-struct compare_amount_commodities {
- bool operator()(const amount_t * left, const amount_t * right) const;
-};
-
} // namespace ledger
#endif // _AMOUNT_H
diff --git a/src/balance.cc b/src/balance.cc
index 462a7074..e2e7df43 100644
--- a/src/balance.cc
+++ b/src/balance.cc
@@ -298,6 +298,7 @@ balance_t& balance_t::operator/=(const amount_t& amt)
return *this;
}
+#if 0
balance_t::operator amount_t() const
{
if (amounts.size() == 1) {
@@ -317,5 +318,6 @@ balance_t::operator amount_t() const
"multiple commodities to an amount: " << temp);
}
}
+#endif
} // namespace ledger
diff --git a/src/balance.h b/src/balance.h
index 463191b7..2a81379b 100644
--- a/src/balance.h
+++ b/src/balance.h
@@ -5,23 +5,24 @@
namespace ledger {
-typedef std::map<const commodity_t *, amount_t> amounts_map;
-typedef std::pair<const commodity_t *, amount_t> amounts_pair;
-
class balance_t
+ : public totally_ordered<balance_t,
+ totally_ordered<balance_t, amount_t,
+ integer_arithmetic<balance_t,
+ integer_arithmetic<balance_t, amount_t
+ > > > >
{
- public:
+public:
+ typedef std::map<const commodity_t *, amount_t> amounts_map;
+ typedef std::pair<const commodity_t *, amount_t> amounts_pair;
+
+protected:
amounts_map amounts;
- bool valid() const {
- for (amounts_map::const_iterator i = amounts.begin();
- i != amounts.end();
- i++)
- if (! (*i).second.valid())
- return false;
- return true;
- }
+ friend class value_t;
+ friend class entry_base_t;
+public:
// constructors
balance_t() {
TRACE_CTOR(balance_t, "");
@@ -38,14 +39,6 @@ class balance_t
if (! amt.realzero())
amounts.insert(amounts_pair(&amt.commodity(), amt));
}
- template <typename T>
- balance_t(T val) {
- TRACE_CTOR(balance_t, "T");
- amount_t amt(val);
- if (! amt.realzero())
- amounts.insert(amounts_pair(&amt.commodity(), amt));
- }
-
~balance_t() {
TRACE_DTOR(balance_t);
}
@@ -66,12 +59,6 @@ class balance_t
*this += amt;
return *this;
}
- template <typename T>
- balance_t& operator=(T val) {
- amounts.clear();
- *this += val;
- return *this;
- }
// in-place arithmetic
balance_t& operator+=(const balance_t& bal) {
@@ -89,10 +76,7 @@ class balance_t
amounts.insert(amounts_pair(&amt.commodity(), amt));
return *this;
}
- template <typename T>
- balance_t& operator+=(T val) {
- return *this += amount_t(val);
- }
+
balance_t& operator-=(const balance_t& bal) {
for (amounts_map::const_iterator i = bal.amounts.begin();
i != bal.amounts.end();
@@ -112,93 +96,13 @@ class balance_t
}
return *this;
}
- template <typename T>
- balance_t& operator-=(T val) {
- return *this -= amount_t(val);
- }
-
- // simple arithmetic
- balance_t operator+(const balance_t& bal) const {
- balance_t temp = *this;
- temp += bal;
- return temp;
- }
- balance_t operator+(const amount_t& amt) const {
- balance_t temp = *this;
- temp += amt;
- return temp;
- }
- template <typename T>
- balance_t operator+(T val) const {
- balance_t temp = *this;
- temp += val;
- return temp;
- }
- balance_t operator-(const balance_t& bal) const {
- balance_t temp = *this;
- temp -= bal;
- return temp;
- }
- balance_t operator-(const amount_t& amt) const {
- balance_t temp = *this;
- temp -= amt;
- return temp;
- }
- template <typename T>
- balance_t operator-(T val) const {
- balance_t temp = *this;
- temp -= val;
- return temp;
- }
// multiplication and divide
balance_t& operator*=(const balance_t& bal);
balance_t& operator*=(const amount_t& amt);
- template <typename T>
- balance_t& operator*=(T val) {
- return *this *= amount_t(val);
- }
balance_t& operator/=(const balance_t& bal);
balance_t& operator/=(const amount_t& amt);
- template <typename T>
- balance_t& operator/=(T val) {
- return *this /= amount_t(val);
- }
-
- // multiplication and divide
- balance_t operator*(const balance_t& bal) const {
- balance_t temp = *this;
- temp *= bal;
- return temp;
- }
- balance_t operator*(const amount_t& amt) const {
- balance_t temp = *this;
- temp *= amt;
- return temp;
- }
- template <typename T>
- balance_t operator*(T val) const {
- balance_t temp = *this;
- temp *= val;
- return temp;
- }
- balance_t operator/(const balance_t& bal) const {
- balance_t temp = *this;
- temp /= bal;
- return temp;
- }
- balance_t operator/(const amount_t& amt) const {
- balance_t temp = *this;
- temp /= amt;
- return temp;
- }
- template <typename T>
- balance_t operator/(T val) const {
- balance_t temp = *this;
- temp /= val;
- return temp;
- }
// comparison
bool operator<(const balance_t& bal) const {
@@ -230,126 +134,8 @@ class balance_t
return true;
return false;
}
- template <typename T>
- bool operator<(T val) const {
- for (amounts_map::const_iterator i = amounts.begin();
- i != amounts.end();
- i++)
- if ((*i).second < val)
- return true;
- return false;
- }
-
- bool operator<=(const balance_t& bal) const {
- for (amounts_map::const_iterator i = bal.amounts.begin();
- i != bal.amounts.end();
- i++)
- if (! (amount(*(*i).first) <= (*i).second))
- return false;
-
- for (amounts_map::const_iterator i = amounts.begin();
- i != amounts.end();
- i++)
- if (! ((*i).second <= bal.amount(*(*i).first)))
- return false;
-
- return true;
- }
- bool operator<=(const amount_t& amt) const {
- if (amt.commodity())
- return amount(amt.commodity()) <= amt;
- for (amounts_map::const_iterator i = amounts.begin();
- i != amounts.end();
- i++)
- if ((*i).second <= amt)
- return true;
- return false;
- }
- template <typename T>
- bool operator<=(T val) const {
- for (amounts_map::const_iterator i = amounts.begin();
- i != amounts.end();
- i++)
- if ((*i).second <= val)
- return true;
- return false;
- }
-
- bool operator>(const balance_t& bal) const {
- for (amounts_map::const_iterator i = bal.amounts.begin();
- i != bal.amounts.end();
- i++)
- if (! (amount(*(*i).first) > (*i).second))
- return false;
-
- for (amounts_map::const_iterator i = amounts.begin();
- i != amounts.end();
- i++)
- if (! ((*i).second > bal.amount(*(*i).first)))
- return false;
-
- if (bal.amounts.size() == 0 && amounts.size() == 0)
- return false;
-
- return true;
- }
- bool operator>(const amount_t& amt) const {
- if (amt.commodity())
- return amount(amt.commodity()) > amt;
-
- for (amounts_map::const_iterator i = amounts.begin();
- i != amounts.end();
- i++)
- if ((*i).second > amt)
- return true;
- return false;
- }
- template <typename T>
- bool operator>(T val) const {
- for (amounts_map::const_iterator i = amounts.begin();
- i != amounts.end();
- i++)
- if ((*i).second > val)
- return true;
- return false;
- }
-
- bool operator>=(const balance_t& bal) const {
- for (amounts_map::const_iterator i = bal.amounts.begin();
- i != bal.amounts.end();
- i++)
- if (! (amount(*(*i).first) >= (*i).second))
- return false;
-
- for (amounts_map::const_iterator i = amounts.begin();
- i != amounts.end();
- i++)
- if (! ((*i).second >= bal.amount(*(*i).first)))
- return false;
-
- return true;
- }
- bool operator>=(const amount_t& amt) const {
- if (amt.commodity())
- return amount(amt.commodity()) >= amt;
-
- for (amounts_map::const_iterator i = amounts.begin();
- i != amounts.end();
- i++)
- if ((*i).second >= amt)
- return true;
- return false;
- }
- template <typename T>
- bool operator>=(T val) const {
- for (amounts_map::const_iterator i = amounts.begin();
- i != amounts.end();
- i++)
- if ((*i).second >= val)
- return true;
- return false;
- }
+ int compare(const balance_t& bal) const;
bool operator==(const balance_t& bal) const {
amounts_map::const_iterator i, j;
@@ -373,26 +159,6 @@ class balance_t
return true;
return false;
}
- template <typename T>
- bool operator==(T val) const {
- for (amounts_map::const_iterator i = amounts.begin();
- i != amounts.end();
- i++)
- if ((*i).second == val)
- return true;
- return false;
- }
-
- bool operator!=(const balance_t& bal) const {
- return ! (*this == bal);
- }
- bool operator!=(const amount_t& amt) const {
- return ! (*this == amt);
- }
- template <typename T>
- bool operator!=(T val) const {
- return ! (*this == val);
- }
// unary negation
void in_place_negate() {
@@ -411,7 +177,9 @@ class balance_t
}
// conversion operators
+#if 0
operator amount_t() const;
+#endif
operator bool() const {
for (amounts_map::const_iterator i = amounts.begin();
i != amounts.end();
@@ -490,6 +258,15 @@ class balance_t
temp += (*i).second.unround();
return temp;
}
+
+ bool valid() const {
+ for (amounts_map::const_iterator i = amounts.begin();
+ i != amounts.end();
+ i++)
+ if (! (*i).second.valid())
+ return false;
+ return true;
+ }
};
inline std::ostream& operator<<(std::ostream& out, const balance_t& bal) {
@@ -498,11 +275,21 @@ inline std::ostream& operator<<(std::ostream& out, const balance_t& bal) {
}
class balance_pair_t
+ : public totally_ordered<balance_pair_t,
+ totally_ordered<balance_pair_t, balance_t,
+ totally_ordered<balance_pair_t, amount_t,
+ integer_arithmetic<balance_pair_t,
+ integer_arithmetic<balance_pair_t, balance_t,
+ integer_arithmetic<balance_pair_t, amount_t
+ > > > > > >
{
- public:
- balance_t quantity;
+ balance_t quantity;
optional<balance_t> cost;
+ friend class value_t;
+ friend class entry_base_t;
+
+public:
// constructors
balance_pair_t() {
TRACE_CTOR(balance_pair_t, "");
@@ -519,12 +306,6 @@ class balance_pair_t
: quantity(_quantity) {
TRACE_CTOR(balance_pair_t, "const amount_t&");
}
- template <typename T>
- balance_pair_t(T val) : quantity(val) {
- TRACE_CTOR(balance_pair_t, "T");
- }
-
- // destructor
~balance_pair_t() {
TRACE_DTOR(balance_pair_t);
}
@@ -547,12 +328,6 @@ class balance_pair_t
cost = optional<balance_t>();
return *this;
}
- template <typename T>
- balance_pair_t& operator=(T val) {
- quantity = val;
- cost = optional<balance_t>();
- return *this;
- }
// in-place arithmetic
balance_pair_t& operator+=(const balance_pair_t& bal_pair) {
@@ -575,10 +350,6 @@ class balance_pair_t
*cost += amt;
return *this;
}
- template <typename T>
- balance_pair_t& operator+=(T val) {
- return *this += amount_t(val);
- }
balance_pair_t& operator-=(const balance_pair_t& bal_pair) {
if (bal_pair.cost && ! cost)
@@ -600,55 +371,6 @@ class balance_pair_t
*cost -= amt;
return *this;
}
- template <typename T>
- balance_pair_t& operator-=(T val) {
- return *this -= amount_t(val);
- }
-
- // simple arithmetic
- balance_pair_t operator+(const balance_pair_t& bal_pair) const {
- balance_pair_t temp = *this;
- temp += bal_pair;
- return temp;
- }
- balance_pair_t operator+(const balance_t& bal) const {
- balance_pair_t temp = *this;
- temp += bal;
- return temp;
- }
- balance_pair_t operator+(const amount_t& amt) const {
- balance_pair_t temp = *this;
- temp += amt;
- return temp;
- }
- template <typename T>
- balance_pair_t operator+(T val) const {
- balance_pair_t temp = *this;
- temp += val;
- return temp;
- }
-
- balance_pair_t operator-(const balance_pair_t& bal_pair) const {
- balance_pair_t temp = *this;
- temp -= bal_pair;
- return temp;
- }
- balance_pair_t operator-(const balance_t& bal) const {
- balance_pair_t temp = *this;
- temp -= bal;
- return temp;
- }
- balance_pair_t operator-(const amount_t& amt) const {
- balance_pair_t temp = *this;
- temp -= amt;
- return temp;
- }
- template <typename T>
- balance_pair_t operator-(T val) const {
- balance_pair_t temp = *this;
- temp -= val;
- return temp;
- }
// multiplication and division
balance_pair_t& operator*=(const balance_pair_t& bal_pair) {
@@ -671,10 +393,6 @@ class balance_pair_t
*cost *= amt;
return *this;
}
- template <typename T>
- balance_pair_t& operator*=(T val) {
- return *this *= amount_t(val);
- }
balance_pair_t& operator/=(const balance_pair_t& bal_pair) {
if (bal_pair.cost && ! cost)
@@ -696,54 +414,6 @@ class balance_pair_t
*cost /= amt;
return *this;
}
- template <typename T>
- balance_pair_t& operator/=(T val) {
- return *this /= amount_t(val);
- }
-
- balance_pair_t operator*(const balance_pair_t& bal_pair) const {
- balance_pair_t temp = *this;
- temp *= bal_pair;
- return temp;
- }
- balance_pair_t operator*(const balance_t& bal) const {
- balance_pair_t temp = *this;
- temp *= bal;
- return temp;
- }
- balance_pair_t operator*(const amount_t& amt) const {
- balance_pair_t temp = *this;
- temp *= amt;
- return temp;
- }
- template <typename T>
- balance_pair_t operator*(T val) const {
- balance_pair_t temp = *this;
- temp *= val;
- return temp;
- }
-
- balance_pair_t operator/(const balance_pair_t& bal_pair) const {
- balance_pair_t temp = *this;
- temp /= bal_pair;
- return temp;
- }
- balance_pair_t operator/(const balance_t& bal) const {
- balance_pair_t temp = *this;
- temp /= bal;
- return temp;
- }
- balance_pair_t operator/(const amount_t& amt) const {
- balance_pair_t temp = *this;
- temp /= amt;
- return temp;
- }
- template <typename T>
- balance_pair_t operator/(T val) const {
- balance_pair_t temp = *this;
- temp /= val;
- return temp;
- }
// comparison
bool operator<(const balance_pair_t& bal_pair) const {
@@ -755,52 +425,8 @@ class balance_pair_t
bool operator<(const amount_t& amt) const {
return quantity < amt;
}
- template <typename T>
- bool operator<(T val) const {
- return quantity < val;
- }
- bool operator<=(const balance_pair_t& bal_pair) const {
- return quantity <= bal_pair.quantity;
- }
- bool operator<=(const balance_t& bal) const {
- return quantity <= bal;
- }
- bool operator<=(const amount_t& amt) const {
- return quantity <= amt;
- }
- template <typename T>
- bool operator<=(T val) const {
- return quantity <= val;
- }
-
- bool operator>(const balance_pair_t& bal_pair) const {
- return quantity > bal_pair.quantity;
- }
- bool operator>(const balance_t& bal) const {
- return quantity > bal;
- }
- bool operator>(const amount_t& amt) const {
- return quantity > amt;
- }
- template <typename T>
- bool operator>(T val) const {
- return quantity > val;
- }
-
- bool operator>=(const balance_pair_t& bal_pair) const {
- return quantity >= bal_pair.quantity;
- }
- bool operator>=(const balance_t& bal) const {
- return quantity >= bal;
- }
- bool operator>=(const amount_t& amt) const {
- return quantity >= amt;
- }
- template <typename T>
- bool operator>=(T val) const {
- return quantity >= val;
- }
+ int compare(const balance_pair_t& bal) const;
bool operator==(const balance_pair_t& bal_pair) const {
return quantity == bal_pair.quantity;
@@ -811,24 +437,6 @@ class balance_pair_t
bool operator==(const amount_t& amt) const {
return quantity == amt;
}
- template <typename T>
- bool operator==(T val) const {
- return quantity == val;
- }
-
- bool operator!=(const balance_pair_t& bal_pair) const {
- return ! (*this == bal_pair);
- }
- bool operator!=(const balance_t& bal) const {
- return ! (*this == bal);
- }
- bool operator!=(const amount_t& amt) const {
- return ! (*this == amt);
- }
- template <typename T>
- bool operator!=(T val) const {
- return ! (*this == val);
- }
// unary negation
void in_place_negate() {
@@ -846,12 +454,14 @@ class balance_pair_t
}
// test for non-zero (use ! for zero)
+#if 0
operator balance_t() const {
return quantity;
}
operator amount_t() const {
return quantity;
}
+#endif
operator bool() const {
return quantity;
}
@@ -939,6 +549,9 @@ class balance_pair_t
temp.cost = cost->unround();
return temp;
}
+
+ friend std::ostream& operator<<(std::ostream& out,
+ const balance_pair_t& bal_pair);
};
inline std::ostream& operator<<(std::ostream& out,
diff --git a/src/commodity.cc b/src/commodity.cc
new file mode 100644
index 00000000..397e4667
--- /dev/null
+++ b/src/commodity.cc
@@ -0,0 +1,418 @@
+/**
+ * @file commodity.cc
+ * @author John Wiegley
+ * @date Thu Apr 26 15:19:46 2007
+ *
+ * @brief Types for dealing with commodities.
+ *
+ * This file defines member functions for flavors of commodity_t.
+ */
+
+/*
+ * Copyright (c) 2003-2007, John Wiegley. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of New Artisans LLC nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "amount.h"
+
+namespace ledger {
+
+#ifndef THREADSAFE
+base_commodities_map commodity_base_t::commodities;
+
+commodity_base_t::updater_t * commodity_base_t::updater = NULL;
+
+commodities_map commodity_t::commodities;
+commodities_array * commodity_t::commodities_by_ident;
+bool commodity_t::commodities_sorted = false;
+commodity_t * commodity_t::null_commodity;
+commodity_t * commodity_t::default_commodity = NULL;
+#endif
+
+void commodity_base_t::add_price(const moment_t& date,
+ const amount_t& price)
+{
+ if (! history)
+ history = new history_t;
+
+ history_map::iterator i = history->prices.find(date);
+ if (i != history->prices.end()) {
+ (*i).second = price;
+ } else {
+ std::pair<history_map::iterator, bool> result
+ = history->prices.insert(history_pair(date, price));
+ assert(result.second);
+ }
+}
+
+bool commodity_base_t::remove_price(const moment_t& date)
+{
+ if (history) {
+ history_map::size_type n = history->prices.erase(date);
+ if (n > 0) {
+ if (history->prices.empty())
+ history = NULL;
+ return true;
+ }
+ }
+ return false;
+}
+
+commodity_base_t * commodity_base_t::create(const string& symbol)
+{
+ commodity_base_t * commodity = new commodity_base_t(symbol);
+
+ DEBUG("amounts.commodities", "Creating base commodity " << symbol);
+
+ std::pair<base_commodities_map::iterator, bool> result
+ = commodities.insert(base_commodities_pair(symbol, commodity));
+ assert(result.second);
+
+ return commodity;
+}
+
+bool commodity_t::needs_quotes(const string& symbol)
+{
+ for (const char * p = symbol.c_str(); *p; p++)
+ if (std::isspace(*p) || std::isdigit(*p) || *p == '-' || *p == '.')
+ return true;
+
+ return false;
+}
+
+bool commodity_t::valid() const
+{
+ if (symbol().empty() && this != null_commodity) {
+ DEBUG("ledger.validate",
+ "commodity_t: symbol().empty() && this != null_commodity");
+ return false;
+ }
+
+ if (annotated && ! base) {
+ DEBUG("ledger.validate", "commodity_t: annotated && ! base");
+ return false;
+ }
+
+ if (precision() > 16) {
+ DEBUG("ledger.validate", "commodity_t: precision() > 16");
+ return false;
+ }
+
+ return true;
+}
+
+commodity_t * commodity_t::create(const string& symbol)
+{
+ std::auto_ptr<commodity_t> commodity(new commodity_t);
+
+ commodity->base = commodity_base_t::create(symbol);
+
+ if (needs_quotes(symbol)) {
+ commodity->qualified_symbol = "\"";
+ commodity->qualified_symbol += symbol;
+ commodity->qualified_symbol += "\"";
+ } else {
+ commodity->qualified_symbol = symbol;
+ }
+
+ DEBUG("amounts.commodities",
+ "Creating commodity " << commodity->qualified_symbol);
+
+ std::pair<commodities_map::iterator, bool> result
+ = commodities.insert(commodities_pair(symbol, commodity.get()));
+ if (! result.second)
+ return NULL;
+
+ commodity->ident = commodities_by_ident->size();
+ commodities_by_ident->push_back(commodity.get());
+
+ // Start out the new commodity with the default commodity's flags
+ // and precision, if one has been defined.
+ if (default_commodity)
+ commodity->drop_flags(COMMODITY_STYLE_THOUSANDS |
+ COMMODITY_STYLE_NOMARKET);
+
+ return commodity.release();
+}
+
+commodity_t * commodity_t::find_or_create(const string& symbol)
+{
+ DEBUG("amounts.commodities", "Find-or-create commodity " << symbol);
+
+ commodity_t * commodity = find(symbol);
+ if (commodity)
+ return commodity;
+ return create(symbol);
+}
+
+commodity_t * commodity_t::find(const string& symbol)
+{
+ DEBUG("amounts.commodities", "Find commodity " << symbol);
+
+ commodities_map::const_iterator i = commodities.find(symbol);
+ if (i != commodities.end())
+ return (*i).second;
+ return NULL;
+}
+
+amount_t commodity_base_t::value(const moment_t& moment)
+{
+ moment_t age;
+ amount_t price;
+
+ if (history) {
+ assert(history->prices.size() > 0);
+
+ if (! is_valid_moment(moment)) {
+ history_map::reverse_iterator r = history->prices.rbegin();
+ age = (*r).first;
+ price = (*r).second;
+ } else {
+ history_map::iterator i = history->prices.lower_bound(moment);
+ if (i == history->prices.end()) {
+ history_map::reverse_iterator r = history->prices.rbegin();
+ age = (*r).first;
+ price = (*r).second;
+ } else {
+ age = (*i).first;
+ if (moment != age) {
+ if (i != history->prices.begin()) {
+ --i;
+ age = (*i).first;
+ price = (*i).second;
+ } else {
+ age = moment_t();
+ }
+ } else {
+ price = (*i).second;
+ }
+ }
+ }
+ }
+
+ if (updater && ! (flags & COMMODITY_STYLE_NOMARKET))
+ (*updater)(*this, moment, age,
+ (history && history->prices.size() > 0 ?
+ (*history->prices.rbegin()).first : moment_t()), price);
+
+ return price;
+}
+
+bool annotated_commodity_t::operator==(const commodity_t& comm) const
+{
+ // If the base commodities don't match, the game's up.
+ if (base != comm.base)
+ return false;
+
+ if (price &&
+ (! comm.annotated ||
+ price != static_cast<const annotated_commodity_t&>(comm).price))
+ return false;
+
+ if (date &&
+ (! comm.annotated ||
+ date != static_cast<const annotated_commodity_t&>(comm).date))
+ return false;
+
+ if (tag &&
+ (! comm.annotated ||
+ tag != static_cast<const annotated_commodity_t&>(comm).tag))
+ return false;
+
+ return true;
+}
+
+void
+annotated_commodity_t::write_annotations(std::ostream& out,
+ const optional<amount_t>& price,
+ const optional<moment_t>& date,
+ const optional<string>& tag)
+{
+ if (price)
+ out << " {" << *price << '}';
+
+ if (date)
+ out << " [" << *date << ']';
+
+ if (tag)
+ out << " (" << *tag << ')';
+}
+
+commodity_t *
+annotated_commodity_t::create(const commodity_t& comm,
+ const optional<amount_t>& price,
+ const optional<moment_t>& date,
+ const optional<string>& tag,
+ const string& mapping_key)
+{
+ std::auto_ptr<annotated_commodity_t> commodity(new annotated_commodity_t);
+
+ // Set the annotated bits
+ commodity->price = price;
+ commodity->date = date;
+ commodity->tag = tag;
+
+ commodity->ptr = &comm;
+ assert(commodity->ptr);
+ commodity->base = comm.base;
+ assert(commodity->base);
+
+ commodity->qualified_symbol = comm.symbol();
+
+ DEBUG("amounts.commodities", "Creating annotated commodity "
+ << "symbol " << commodity->symbol()
+ << " key " << mapping_key << std::endl
+ << " price " << (price ? price->to_string() : "NONE") << " "
+ << " date " << (date ? *date : moment_t()) << " "
+ << " tag " << (tag ? *tag : "NONE"));
+
+ // Add the fully annotated name to the map, so that this symbol may
+ // quickly be found again.
+ std::pair<commodities_map::iterator, bool> result
+ = commodities.insert(commodities_pair(mapping_key, commodity.get()));
+ if (! result.second)
+ return NULL;
+
+ commodity->ident = commodities_by_ident->size();
+ commodities_by_ident->push_back(commodity.get());
+
+ return commodity.release();
+}
+
+namespace {
+ string make_qualified_name(const commodity_t& comm,
+ const optional<amount_t>& price,
+ const optional<moment_t>& date,
+ const optional<string>& tag)
+ {
+ if (price && price->sign() < 0)
+ throw_(amount_error, "A commodity's price may not be negative");
+
+ std::ostringstream name;
+
+ comm.write(name);
+ annotated_commodity_t::write_annotations(name, price, date, tag);
+
+ DEBUG("amounts.commodities", "make_qualified_name for "
+ << comm.qualified_symbol << std::endl
+ << " price " << (price ? price->to_string() : "NONE") << " "
+ << " date " << (date ? *date : moment_t()) << " "
+ << " tag " << (tag ? *tag : "NONE"));
+
+ DEBUG("amounts.commodities", "qualified_name is " << name.str());
+
+ return name.str();
+ }
+}
+
+commodity_t *
+annotated_commodity_t::find_or_create(const commodity_t& comm,
+ const optional<amount_t>& price,
+ const optional<moment_t>& date,
+ const optional<string>& tag)
+{
+ string name = make_qualified_name(comm, price, date, tag);
+
+ commodity_t * ann_comm = commodity_t::find(name);
+ if (ann_comm) {
+ assert(ann_comm->annotated);
+ return ann_comm;
+ }
+ return create(comm, price, date, tag, name);
+}
+
+bool compare_amount_commodities::operator()(const amount_t * left,
+ const amount_t * right) const
+{
+ commodity_t& leftcomm(left->commodity());
+ commodity_t& rightcomm(right->commodity());
+
+ int cmp = leftcomm.base_symbol().compare(rightcomm.base_symbol());
+ if (cmp != 0)
+ return cmp < 0;
+
+ if (! leftcomm.annotated) {
+ assert(rightcomm.annotated);
+ return true;
+ }
+ else if (! rightcomm.annotated) {
+ assert(leftcomm.annotated);
+ return false;
+ }
+ else {
+ annotated_commodity_t& aleftcomm(static_cast<annotated_commodity_t&>(leftcomm));
+ annotated_commodity_t& arightcomm(static_cast<annotated_commodity_t&>(rightcomm));
+
+ if (! aleftcomm.price && arightcomm.price)
+ return true;
+ if (aleftcomm.price && ! arightcomm.price)
+ return false;
+
+ if (aleftcomm.price && arightcomm.price) {
+ amount_t leftprice(*aleftcomm.price);
+ leftprice.in_place_reduce();
+ amount_t rightprice(*arightcomm.price);
+ rightprice.in_place_reduce();
+
+ if (leftprice.commodity() == rightprice.commodity()) {
+ return (leftprice - rightprice).sign() < 0;
+ } else {
+ // Since we have two different amounts, there's really no way
+ // to establish a true sorting order; we'll just do it based
+ // on the numerical values.
+ leftprice.clear_commodity();
+ rightprice.clear_commodity();
+ return (leftprice - rightprice).sign() < 0;
+ }
+ }
+
+ if (! aleftcomm.date && arightcomm.date)
+ return true;
+ if (aleftcomm.date && ! arightcomm.date)
+ return false;
+
+ if (aleftcomm.date && arightcomm.date) {
+ duration_t diff = *aleftcomm.date - *arightcomm.date;
+ return diff.is_negative();
+ }
+
+ if (! aleftcomm.tag && arightcomm.tag)
+ return true;
+ if (aleftcomm.tag && ! arightcomm.tag)
+ return false;
+
+ if (aleftcomm.tag && arightcomm.tag)
+ return *aleftcomm.tag < *arightcomm.tag;
+
+ assert(false);
+ return true;
+ }
+}
+
+} // namespace ledger
diff --git a/src/commodity.h b/src/commodity.h
new file mode 100644
index 00000000..44754f0d
--- /dev/null
+++ b/src/commodity.h
@@ -0,0 +1,328 @@
+/**
+ * @file commodity.h
+ * @author John Wiegley
+ * @date Wed Apr 18 22:05:53 2007
+ *
+ * @brief Types for handling commodities.
+ *
+ * This file contains one of the most basic types in Ledger:
+ * commodity_t, and its derived cousin, annotated_commodity_t.
+ */
+
+/*
+ * Copyright (c) 2003-2007, John Wiegley. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of New Artisans LLC nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _COMMODITY_H
+#define _COMMODITY_H
+
+namespace ledger {
+
+#define COMMODITY_STYLE_DEFAULTS 0x0000
+#define COMMODITY_STYLE_SUFFIXED 0x0001
+#define COMMODITY_STYLE_SEPARATED 0x0002
+#define COMMODITY_STYLE_EUROPEAN 0x0004
+#define COMMODITY_STYLE_THOUSANDS 0x0008
+#define COMMODITY_STYLE_NOMARKET 0x0010
+#define COMMODITY_STYLE_BUILTIN 0x0020
+
+typedef std::map<const moment_t, amount_t> history_map;
+typedef std::pair<const moment_t, amount_t> history_pair;
+
+class commodity_base_t;
+
+typedef std::map<const string, commodity_base_t *> base_commodities_map;
+typedef std::pair<const string, commodity_base_t *> base_commodities_pair;
+
+class commodity_base_t
+{
+ public:
+ friend class commodity_t;
+ friend class annotated_commodity_t;
+
+ typedef unsigned long ident_t;
+
+ ident_t ident;
+ string name;
+ string note;
+ unsigned char precision;
+ unsigned char flags;
+ amount_t * smaller;
+ amount_t * larger;
+
+ commodity_base_t()
+ : precision(0), flags(COMMODITY_STYLE_DEFAULTS),
+ smaller(NULL), larger(NULL), history(NULL) {
+ TRACE_CTOR(commodity_base_t, "");
+ }
+
+ commodity_base_t(const commodity_base_t&) {
+ TRACE_CTOR(commodity_base_t, "copy");
+ assert(0);
+ }
+
+ commodity_base_t(const string& _symbol,
+ unsigned int _precision = 0,
+ unsigned int _flags = COMMODITY_STYLE_DEFAULTS)
+ : precision(_precision), flags(_flags),
+ smaller(NULL), larger(NULL), symbol(_symbol), history(NULL) {
+ TRACE_CTOR(commodity_base_t, "const string&, unsigned int, unsigned int");
+ }
+
+ ~commodity_base_t() {
+ TRACE_DTOR(commodity_base_t);
+ if (history) checked_delete(history);
+ if (smaller) checked_delete(smaller);
+ if (larger) checked_delete(larger);
+ }
+
+ static base_commodities_map commodities;
+ static commodity_base_t * create(const string& symbol);
+
+ string symbol;
+
+ struct history_t {
+ history_map prices;
+ ptime last_lookup;
+ history_t() : last_lookup() {}
+ };
+ history_t * history;
+
+ void add_price(const moment_t& date, const amount_t& price);
+ bool remove_price(const moment_t& date);
+ amount_t value(const moment_t& moment = now);
+
+ class updater_t {
+ public:
+ virtual ~updater_t() {}
+ virtual void operator()(commodity_base_t& commodity,
+ const moment_t& moment,
+ const moment_t& date,
+ const moment_t& last,
+ amount_t& price) = 0;
+ };
+ friend class updater_t;
+
+ static updater_t * updater;
+};
+
+typedef std::map<const string, commodity_t *> commodities_map;
+typedef std::pair<const string, commodity_t *> commodities_pair;
+
+typedef std::vector<commodity_t *> commodities_array;
+
+class commodity_t
+{
+ friend class annotated_commodity_t;
+
+ public:
+ // This map remembers all commodities that have been defined.
+
+ static commodities_map commodities;
+ static commodities_array * commodities_by_ident;
+ static bool commodities_sorted;
+ static commodity_t * null_commodity;
+ static commodity_t * default_commodity;
+
+ static commodity_t * create(const string& symbol);
+ static commodity_t * find(const string& name);
+ static commodity_t * find_or_create(const string& symbol);
+
+ static bool needs_quotes(const string& symbol);
+
+ static void make_alias(const string& symbol,
+ commodity_t * commodity);
+
+ // These are specific to each commodity reference
+
+ typedef unsigned long ident_t;
+
+ ident_t ident;
+ commodity_base_t * base;
+ string qualified_symbol;
+ bool annotated;
+
+ public:
+ explicit commodity_t() : base(NULL), annotated(false) {
+ TRACE_CTOR(commodity_t, "");
+ }
+ commodity_t(const commodity_t& o)
+ : ident(o.ident), base(o.base),
+ qualified_symbol(o.qualified_symbol), annotated(o.annotated) {
+ TRACE_CTOR(commodity_t, "copy");
+ }
+ virtual ~commodity_t() {
+ TRACE_DTOR(commodity_t);
+ }
+
+ operator bool() const {
+ return this != null_commodity;
+ }
+ virtual bool operator==(const commodity_t& comm) const {
+ if (comm.annotated)
+ return comm == *this;
+ return base == comm.base;
+ }
+
+ string base_symbol() const {
+ return base->symbol;
+ }
+ string symbol() const {
+ return qualified_symbol;
+ }
+
+ void write(std::ostream& out) const {
+ out << symbol();
+ }
+
+ string name() const {
+ return base->name;
+ }
+ void set_name(const string& arg) {
+ base->name = arg;
+ }
+
+ string note() const {
+ return base->note;
+ }
+ void set_note(const string& arg) {
+ base->note = arg;
+ }
+
+ unsigned char precision() const {
+ return base->precision;
+ }
+ void set_precision(unsigned char arg) {
+ base->precision = arg;
+ }
+
+ unsigned char flags() const {
+ return base->flags;
+ }
+ void set_flags(unsigned char arg) {
+ base->flags = arg;
+ }
+ void add_flags(unsigned char arg) {
+ base->flags |= arg;
+ }
+ void drop_flags(unsigned char arg) {
+ base->flags &= ~arg;
+ }
+
+ amount_t * smaller() const {
+ return base->smaller;
+ }
+ void set_smaller(const amount_t& arg) {
+ if (base->smaller)
+ checked_delete(base->smaller);
+ base->smaller = new amount_t(arg);
+ }
+
+ amount_t * larger() const {
+ return base->larger;
+ }
+ void set_larger(const amount_t& arg) {
+ if (base->larger)
+ checked_delete(base->larger);
+ base->larger = new amount_t(arg);
+ }
+
+ commodity_base_t::history_t * history() const {
+ return base->history;
+ }
+
+ void add_price(const moment_t& date, const amount_t& price) {
+ return base->add_price(date, price);
+ }
+ bool remove_price(const moment_t& date) {
+ return base->remove_price(date);
+ }
+ amount_t value(const moment_t& moment = now) const {
+ return base->value(moment);
+ }
+
+ bool valid() const;
+};
+
+class annotated_commodity_t : public commodity_t
+{
+ public:
+ const commodity_t * ptr;
+
+ optional<amount_t> price;
+ optional<moment_t> date;
+ optional<string> tag;
+
+ explicit annotated_commodity_t() {
+ TRACE_CTOR(annotated_commodity_t, "");
+ annotated = true;
+ }
+ virtual ~annotated_commodity_t() {
+ TRACE_DTOR(annotated_commodity_t);
+ }
+
+ virtual bool operator==(const commodity_t& comm) const;
+
+ void write_annotations(std::ostream& out) const {
+ annotated_commodity_t::write_annotations(out, price, date, tag);
+ }
+
+ static void write_annotations(std::ostream& out,
+ const optional<amount_t>& price,
+ const optional<moment_t>& date,
+ const optional<string>& tag);
+
+ private:
+ static commodity_t * create(const commodity_t& comm,
+ const optional<amount_t>& price,
+ const optional<moment_t>& date,
+ const optional<string>& tag,
+ const string& mapping_key);
+
+ static commodity_t * find_or_create(const commodity_t& comm,
+ const optional<amount_t>& price,
+ const optional<moment_t>& date,
+ const optional<string>& tag);
+
+ friend class amount_t;
+};
+
+inline std::ostream& operator<<(std::ostream& out, const commodity_t& comm) {
+ out << comm.symbol();
+ return out;
+}
+
+struct compare_amount_commodities {
+ bool operator()(const amount_t * left, const amount_t * right) const;
+};
+
+} // namespace ledger
+
+#endif // _COMMODITY_H
diff --git a/src/journal.cc b/src/journal.cc
index 6d50f50e..948d9b6a 100644
--- a/src/journal.cc
+++ b/src/journal.cc
@@ -150,9 +150,9 @@ bool entry_base_t::finalize()
assert((*x)->amount);
commodity_t& this_comm = (*x)->amount->commodity();
- amounts_map::const_iterator this_bal =
+ balance_t::amounts_map::const_iterator this_bal =
((balance_t *) balance.data)->amounts.find(&this_comm);
- amounts_map::const_iterator other_bal =
+ balance_t::amounts_map::const_iterator other_bal =
((balance_t *) balance.data)->amounts.begin();
if (this_bal == other_bal)
other_bal++;
@@ -218,7 +218,8 @@ bool entry_base_t::finalize()
balance.cast(value_t::AMOUNT);
} else {
bool first = true;
- for (amounts_map::const_iterator i = bal->amounts.begin();
+ for (balance_t::amounts_map::const_iterator
+ i = bal->amounts.begin();
i != bal->amounts.end();
i++) {
amount_t amt = (*i).second.negate();
diff --git a/src/journal.h b/src/journal.h
index 711cac19..5ac7c48c 100644
--- a/src/journal.h
+++ b/src/journal.h
@@ -155,7 +155,7 @@ class entry_base_t
class entry_t : public entry_base_t
{
- public:
+public:
moment_t _date;
optional<moment_t> _date_eff;
optional<string> code;
diff --git a/src/py_amount.cc b/src/py_amount.cc
index 059322f1..e26ba35e 100644
--- a/src/py_amount.cc
+++ b/src/py_amount.cc
@@ -55,6 +55,21 @@ commodity_t * py_find_commodity(const string& symbol)
EXC_TRANSLATOR(amount_error)
+namespace {
+ template <typename T>
+ amount_t operator+(const amount_t& amt, const T val) {
+ amount_t temp(amt);
+ temp += amount_t(val);
+ return temp;
+ }
+ template <typename T>
+ amount_t operator+(const T val, const amount_t& amt) {
+ amount_t temp(val);
+ temp += amt;
+ return temp;
+ }
+}
+
void export_amount()
{
scope().attr("AMOUNT_PARSE_NO_MIGRATE") = AMOUNT_PARSE_NO_MIGRATE;
@@ -72,66 +87,86 @@ void export_amount()
.def(self += double())
.def(self + self)
+#if 0
.def(self + long())
.def(long() + self)
.def(self + double())
.def(double() + self)
+#endif
.def(self -= self)
.def(self -= long())
.def(self -= double())
.def(self - self)
+#if 0
.def(self - long())
.def(long() - self)
.def(self - double())
.def(double() - self)
+#endif
.def(self *= self)
.def(self *= long())
.def(self *= double())
.def(self * self)
+#if 0
.def(self * long())
.def(long() * self)
.def(self * double())
.def(double() * self)
+#endif
.def(self /= self)
.def(self /= long())
.def(self /= double())
.def(self / self)
+#if 0
.def(self / long())
.def(long() / self)
.def(self / double())
.def(double() / self)
+#endif
.def(- self)
.def(self < self)
+#if 0
.def(self < long())
.def(long() < self)
+#endif
.def(self <= self)
+#if 0
.def(self <= long())
.def(long() <= self)
+#endif
.def(self > self)
+#if 0
.def(self > long())
.def(long() > self)
+#endif
.def(self >= self)
+#if 0
.def(self >= long())
.def(long() >= self)
+#endif
.def(self == self)
+#if 0
.def(self == long())
.def(long() == self)
+#endif
.def(self != self)
+#if 0
.def(self != long())
.def(long() != self)
+#endif
.def(! self)
@@ -166,7 +201,7 @@ void export_amount()
.def("compare", &amount_t::compare)
.def("date", &amount_t::date)
.def("negate", &amount_t::negate)
- .def("null", &amount_t::null)
+ .def("is_null", &amount_t::is_null)
.def("parse", py_parse_1)
.def("parse", py_parse_2)
.def("price", &amount_t::price)
diff --git a/src/py_balance.cc b/src/py_balance.cc
index 372bf1e9..ec4fee85 100644
--- a/src/py_balance.cc
+++ b/src/py_balance.cc
@@ -16,7 +16,7 @@ amount_t balance_getitem(balance_t& bal, int i)
}
int x = i < 0 ? len + i : i;
- amounts_map::iterator elem = bal.amounts.begin();
+ balance_t::amounts_map::iterator elem = bal.amounts.begin();
while (--x >= 0)
elem++;
diff --git a/src/system.hh b/src/system.hh
index 55e64734..fe1e7b7f 100644
--- a/src/system.hh
+++ b/src/system.hh
@@ -106,6 +106,7 @@ extern "C" {
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
+#include <boost/operators.hpp>
#include <boost/optional.hpp>
#include <boost/ptr_container/ptr_list.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
diff --git a/src/textual.cc b/src/textual.cc
index 9c9c931f..e464f9c3 100644
--- a/src/textual.cc
+++ b/src/textual.cc
@@ -1,8 +1,6 @@
#include "textual.h"
#include "session.h"
-#define TIMELOG_SUPPORT 1
-
namespace ledger {
#define MAX_LINE 1024
@@ -14,14 +12,18 @@ static accounts_map account_aliases;
static std::list<std::pair<path, int> > include_stack;
+#define TIMELOG_SUPPORT 1
#ifdef TIMELOG_SUPPORT
+
struct time_entry_t {
- moment_t checkin;
+ moment_t checkin;
account_t * account;
string desc;
};
+
std::list<time_entry_t> time_entries;
-#endif
+
+#endif // TIMELOG_SUPPORT
inline char * next_element(char * buf, bool variable = false)
{
@@ -248,7 +250,7 @@ transaction_t * parse_transaction(char * line,
POP_CONTEXT(context("While parsing transaction cost"));
- if (*xact->cost < 0)
+ if (xact->cost->sign() < 0)
throw_(parse_error, "A transaction's cost may not be negative");
assert(xact->amount);
diff --git a/src/value.cc b/src/value.cc
index 7956af12..accc5739 100644
--- a/src/value.cc
+++ b/src/value.cc
@@ -866,7 +866,6 @@ value_t& value_t::operator/=(const value_t& val)
return *this;
}
-template <>
value_t::operator bool() const
{
switch (type) {
@@ -900,6 +899,7 @@ value_t::operator bool() const
return 0;
}
+#if 0
template <>
value_t::operator long() const
{
@@ -1030,351 +1030,315 @@ value_t::operator string() const
assert(0);
return 0;
}
+#endif
-#define DEF_VALUE_CMP_OP(OP) \
-bool value_t::operator OP(const value_t& val) \
-{ \
- switch (type) { \
- case BOOLEAN: \
- switch (val.type) { \
- case BOOLEAN: \
- return *((bool *) data) OP *((bool *) val.data); \
- \
- case INTEGER: \
- return *((bool *) data) OP bool(*((long *) val.data)); \
- \
- case DATETIME: \
- throw_(value_error, "Cannot compare a boolean to a date/time"); \
- \
- case AMOUNT: \
- return *((bool *) data) OP bool(*((amount_t *) val.data)); \
- \
- case BALANCE: \
- return *((bool *) data) OP bool(*((balance_t *) val.data)); \
- \
- case BALANCE_PAIR: \
- return *((bool *) data) OP bool(*((balance_pair_t *) val.data)); \
- \
- case STRING: \
- throw_(value_error, "Cannot compare a boolean to a string"); \
- \
- case XML_NODE: \
- return *this OP (*(xml::node_t **) data)->to_value(); \
- \
- case POINTER: \
- throw_(value_error, "Cannot compare a boolean to a pointer"); \
- case SEQUENCE: \
- throw_(value_error, "Cannot compare a boolean to a sequence"); \
- \
- default: \
- assert(0); \
- break; \
- } \
- break; \
- \
- case INTEGER: \
- switch (val.type) { \
- case BOOLEAN: \
- return (*((long *) data) OP \
- ((long) *((bool *) val.data))); \
- \
- case INTEGER: \
- return (*((long *) data) OP *((long *) val.data)); \
- \
- case DATETIME: \
- throw_(value_error, "Cannot compare an integer to a date/time"); \
- \
- case AMOUNT: \
- return (amount_t(*((long *) data)) OP \
- *((amount_t *) val.data)); \
- \
- case BALANCE: \
- return (balance_t(*((long *) data)) OP \
- *((balance_t *) val.data)); \
- \
- case BALANCE_PAIR: \
- return (balance_pair_t(*((long *) data)) OP \
- *((balance_pair_t *) val.data)); \
- \
- case STRING: \
- throw_(value_error, "Cannot compare an integer to a string"); \
- \
- case XML_NODE: \
- return *this OP (*(xml::node_t **) data)->to_value(); \
- \
- case POINTER: \
- throw_(value_error, "Cannot compare an integer to a pointer"); \
- case SEQUENCE: \
- throw_(value_error, "Cannot compare an integer to a sequence"); \
- \
- default: \
- assert(0); \
- break; \
- } \
- break; \
- \
- case DATETIME: \
- switch (val.type) { \
- case BOOLEAN: \
- throw_(value_error, "Cannot compare a date/time to a boolean"); \
- \
- case INTEGER: \
- throw_(value_error, "Cannot compare a date/time to an integer"); \
- \
- case DATETIME: \
- return *((moment_t *) data) OP *((moment_t *) val.data); \
- \
- case AMOUNT: \
- throw_(value_error, "Cannot compare a date/time to an amount"); \
- case BALANCE: \
- throw_(value_error, "Cannot compare a date/time to a balance"); \
- case BALANCE_PAIR: \
- throw_(value_error, "Cannot compare a date/time to a balance pair"); \
- case STRING: \
- throw_(value_error, "Cannot compare a date/time to a string"); \
- \
- case XML_NODE: \
- return *this OP (*(xml::node_t **) data)->to_value(); \
- \
- case POINTER: \
- throw_(value_error, "Cannot compare a date/time to a pointer"); \
- case SEQUENCE: \
- throw_(value_error, "Cannot compare a date/time to a sequence"); \
- \
- default: \
- assert(0); \
- break; \
- } \
- break; \
- \
- case AMOUNT: \
- switch (val.type) { \
- case BOOLEAN: \
- throw_(value_error, "Cannot compare an amount to a boolean"); \
- \
- case INTEGER: \
- return (*((amount_t *) data) OP \
- amount_t(*((long *) val.data))); \
- \
- case DATETIME: \
- throw_(value_error, "Cannot compare an amount to a date/time"); \
- \
- case AMOUNT: \
- return *((amount_t *) data) OP *((amount_t *) val.data); \
- \
- case BALANCE: \
- return (balance_t(*((amount_t *) data)) OP \
- *((balance_t *) val.data)); \
- \
- case BALANCE_PAIR: \
- return (balance_t(*((amount_t *) data)) OP \
- *((balance_pair_t *) val.data)); \
- \
- case STRING: \
- throw_(value_error, "Cannot compare an amount to a string"); \
- \
- case XML_NODE: \
- return *this OP (*(xml::node_t **) data)->to_value(); \
- \
- case POINTER: \
- throw_(value_error, "Cannot compare an amount to a pointer"); \
- case SEQUENCE: \
- throw_(value_error, "Cannot compare an amount to a sequence"); \
- \
- default: \
- assert(0); \
- break; \
- } \
- break; \
- \
- case BALANCE: \
- switch (val.type) { \
- case BOOLEAN: \
- throw_(value_error, "Cannot compare a balance to a boolean"); \
- \
- case INTEGER: \
- return *((balance_t *) data) OP *((long *) val.data); \
- \
- case DATETIME: \
- throw_(value_error, "Cannot compare a balance to a date/time"); \
- \
- case AMOUNT: \
- return *((balance_t *) data) OP *((amount_t *) val.data); \
- \
- case BALANCE: \
- return *((balance_t *) data) OP *((balance_t *) val.data); \
- \
- case BALANCE_PAIR: \
- return (*((balance_t *) data) OP \
- ((balance_pair_t *) val.data)->quantity); \
- \
- case STRING: \
- throw_(value_error, "Cannot compare a balance to a string"); \
- \
- case XML_NODE: \
- return *this OP (*(xml::node_t **) data)->to_value(); \
- \
- case POINTER: \
- throw_(value_error, "Cannot compare a balance to a pointer"); \
- case SEQUENCE: \
- throw_(value_error, "Cannot compare a balance to a sequence"); \
- \
- default: \
- assert(0); \
- break; \
- } \
- break; \
- \
- case BALANCE_PAIR: \
- switch (val.type) { \
- case BOOLEAN: \
- throw_(value_error, "Cannot compare a balance pair to a boolean"); \
- \
- case INTEGER: \
- return (((balance_pair_t *) data)->quantity OP \
- *((long *) val.data)); \
- \
- case DATETIME: \
- throw_(value_error, "Cannot compare a balance pair to a date/time"); \
- \
- case AMOUNT: \
- return (((balance_pair_t *) data)->quantity OP \
- *((amount_t *) val.data)); \
- \
- case BALANCE: \
- return (((balance_pair_t *) data)->quantity OP \
- *((balance_t *) val.data)); \
- \
- case BALANCE_PAIR: \
- return (*((balance_pair_t *) data) OP \
- *((balance_pair_t *) val.data)); \
- \
- case STRING: \
- throw_(value_error, "Cannot compare a balance pair to a string"); \
- \
- case XML_NODE: \
- return *this OP (*(xml::node_t **) data)->to_value(); \
- \
- case POINTER: \
- throw_(value_error, "Cannot compare a balance pair to a pointer"); \
- case SEQUENCE: \
- throw_(value_error, "Cannot compare a balance pair to a sequence"); \
- \
- default: \
- assert(0); \
- break; \
- } \
- break; \
- \
- case STRING: \
- switch (val.type) { \
- case BOOLEAN: \
- throw_(value_error, "Cannot compare a string to a boolean"); \
- case INTEGER: \
- throw_(value_error, "Cannot compare a string to an integer"); \
- case DATETIME: \
- throw_(value_error, "Cannot compare a string to a date/time"); \
- case AMOUNT: \
- throw_(value_error, "Cannot compare a string to an amount"); \
- case BALANCE: \
- throw_(value_error, "Cannot compare a string to a balance"); \
- case BALANCE_PAIR: \
- throw_(value_error, "Cannot compare a string to a balance pair"); \
- \
- case STRING: \
- return (**((string **) data) OP \
- **((string **) val.data)); \
- \
- case XML_NODE: \
- return *this OP (*(xml::node_t **) data)->to_value(); \
- \
- case POINTER: \
- throw_(value_error, "Cannot compare a string to a pointer"); \
- case SEQUENCE: \
- throw_(value_error, "Cannot compare a string to a sequence"); \
- \
- default: \
- assert(0); \
- break; \
- } \
- break; \
- \
- case XML_NODE: \
- switch (val.type) { \
- case BOOLEAN: \
- return (*(xml::node_t **) data)->to_value() OP *this; \
- case INTEGER: \
- return (*(xml::node_t **) data)->to_value() OP *this; \
- case DATETIME: \
- return (*(xml::node_t **) data)->to_value() OP *this; \
- case AMOUNT: \
- return (*(xml::node_t **) data)->to_value() OP *this; \
- case BALANCE: \
- return (*(xml::node_t **) data)->to_value() OP *this; \
- case BALANCE_PAIR: \
- return (*(xml::node_t **) data)->to_value() OP *this; \
- case STRING: \
- return (*(xml::node_t **) data)->to_value() OP *this; \
- \
- case XML_NODE: \
- return ((*(xml::node_t **) data)->to_value() OP \
- (*(xml::node_t **) val.data)->to_value()); \
- \
- case POINTER: \
- throw_(value_error, "Cannot compare an XML node to a pointer"); \
- case SEQUENCE: \
- throw_(value_error, "Cannot compare an XML node to a sequence"); \
- \
- default: \
- assert(0); \
- break; \
- } \
- break; \
- \
- case POINTER: \
- switch (val.type) { \
- case BOOLEAN: \
- throw_(value_error, "Cannot compare a pointer to a boolean"); \
- case INTEGER: \
- throw_(value_error, "Cannot compare a pointer to an integer"); \
- case DATETIME: \
- throw_(value_error, "Cannot compare a pointer to a date/time"); \
- case AMOUNT: \
- throw_(value_error, "Cannot compare a pointer to an amount"); \
- case BALANCE: \
- throw_(value_error, "Cannot compare a pointer to a balance"); \
- case BALANCE_PAIR: \
- throw_(value_error, "Cannot compare a pointer to a balance pair"); \
- case STRING: \
- throw_(value_error, "Cannot compare a pointer to a string node"); \
- case XML_NODE: \
- throw_(value_error, "Cannot compare a pointer to an XML node"); \
- case POINTER: \
- return (*((void **) data) OP *((void **) val.data)); \
- case SEQUENCE: \
- throw_(value_error, "Cannot compare a pointer to a sequence"); \
- \
- default: \
- assert(0); \
- break; \
- } \
- break; \
- \
- case SEQUENCE: \
- throw_(value_error, "Cannot compare a value to a sequence"); \
- \
- default: \
- assert(0); \
- break; \
- } \
- return *this; \
+inline int compare_bool(const bool left, const bool right) {
+ return (! left && right ? -1 : (left && ! right ? 1 : 0));
}
+int value_t::compare(const value_t& val) const
+{
+ if (val.type == XML_NODE)
+ return compare((*(xml::node_t **) data)->to_value());
+
+ switch (type) {
+ case BOOLEAN:
+ switch (val.type) {
+ case BOOLEAN:
+ return compare_bool(*((bool *) data), *((bool *) val.data));
+
+ case INTEGER:
+ return compare_bool(*((bool *) data), bool(*((long *) val.data)));
+
+ case DATETIME:
+ throw_(value_error, "Cannot compare a boolean to a date/time");
+
+ case AMOUNT:
+ return compare_bool(*((bool *) data), bool(*((amount_t *) val.data)));
+
+ case BALANCE:
+ return compare_bool(*((bool *) data), bool(*((balance_t *) val.data)));
+
+ case BALANCE_PAIR:
+ return compare_bool(*((bool *) data), bool(*((balance_pair_t *) val.data)));
+
+ case STRING:
+ throw_(value_error, "Cannot compare a boolean to a string");
+ case POINTER:
+ throw_(value_error, "Cannot compare a boolean to a pointer");
+ case SEQUENCE:
+ throw_(value_error, "Cannot compare a boolean to a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case INTEGER:
+ switch (val.type) {
+ case BOOLEAN:
+ return *((long *) data) - ((long) *((bool *) val.data));
+
+ case INTEGER:
+ return *((long *) data) - *((long *) val.data);
+
+ case DATETIME:
+ throw_(value_error, "Cannot compare an integer to a date/time");
+
+ case AMOUNT:
+ return amount_t(*((long *) data)).compare(*((amount_t *) val.data));
+
+ case BALANCE:
+ return balance_t(*((long *) data)).compare(*((balance_t *) val.data));
+
+ case BALANCE_PAIR:
+ return balance_pair_t(*((long *) data)).compare(*((balance_pair_t *) val.data));
+
+ case STRING:
+ throw_(value_error, "Cannot compare an integer to a string");
+ case POINTER:
+ throw_(value_error, "Cannot compare an integer to a pointer");
+ case SEQUENCE:
+ throw_(value_error, "Cannot compare an integer to a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case DATETIME:
+ switch (val.type) {
+ case BOOLEAN:
+ throw_(value_error, "Cannot compare a date/time to a boolean");
+ case INTEGER:
+ throw_(value_error, "Cannot compare a date/time to an integer");
+
+ case DATETIME:
+ return (*((moment_t *) data) < *((moment_t *) val.data) ? -1 :
+ (*((moment_t *) data) > *((moment_t *) val.data) ? 1 : 0));
+
+ case AMOUNT:
+ throw_(value_error, "Cannot compare a date/time to an amount");
+ case BALANCE:
+ throw_(value_error, "Cannot compare a date/time to a balance");
+ case BALANCE_PAIR:
+ throw_(value_error, "Cannot compare a date/time to a balance pair");
+ case STRING:
+ throw_(value_error, "Cannot compare a date/time to a string");
+ case POINTER:
+ throw_(value_error, "Cannot compare a date/time to a pointer");
+ case SEQUENCE:
+ throw_(value_error, "Cannot compare a date/time to a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case AMOUNT:
+ switch (val.type) {
+ case BOOLEAN:
+ throw_(value_error, "Cannot compare an amount to a boolean");
+
+ case INTEGER:
+ return ((amount_t *) data)->compare(*((long *) val.data));
+
+ case DATETIME:
+ throw_(value_error, "Cannot compare an amount to a date/time");
+
+ case AMOUNT:
+ return ((amount_t *) data)->compare(*((amount_t *) val.data));
+
+ case BALANCE:
+ return balance_t(*((amount_t *) data)).compare(*((balance_t *) val.data));
+
+ case BALANCE_PAIR:
+ return balance_pair_t(*((amount_t *) data)).compare(*((balance_pair_t *) val.data));
+
+ case STRING:
+ throw_(value_error, "Cannot compare an amount to a string");
+ case POINTER:
+ throw_(value_error, "Cannot compare an amount to a pointer");
+ case SEQUENCE:
+ throw_(value_error, "Cannot compare an amount to a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case BALANCE:
+ switch (val.type) {
+ case BOOLEAN:
+ throw_(value_error, "Cannot compare a balance to a boolean");
+
+ case INTEGER:
+ return ((balance_t *) data)->compare(amount_t(*((long *) val.data)));
+
+ case DATETIME:
+ throw_(value_error, "Cannot compare a balance to a date/time");
+
+ case AMOUNT:
+ return ((balance_t *) data)->compare(*((amount_t *) val.data));
+
+ case BALANCE:
+ return ((balance_t *) data)->compare(*((balance_t *) val.data));
+
+ case BALANCE_PAIR:
+ return balance_pair_t(*((balance_t *) data)).
+ compare(((balance_pair_t *) val.data)->quantity);
+
+ case STRING:
+ throw_(value_error, "Cannot compare a balance to a string");
+ case POINTER:
+ throw_(value_error, "Cannot compare a balance to a pointer");
+ case SEQUENCE:
+ throw_(value_error, "Cannot compare a balance to a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case BALANCE_PAIR:
+ switch (val.type) {
+ case BOOLEAN:
+ throw_(value_error, "Cannot compare a balance pair to a boolean");
+
+ case INTEGER:
+ return ((balance_pair_t *) data)->compare(amount_t(*((long *) val.data)));
+
+ case DATETIME:
+ throw_(value_error, "Cannot compare a balance pair to a date/time");
+
+ case AMOUNT:
+ return ((balance_pair_t *) data)->compare(*((amount_t *) val.data));
+
+ case BALANCE:
+ return ((balance_pair_t *) data)->compare(*((balance_t *) val.data));
+
+ case BALANCE_PAIR:
+ return ((balance_pair_t *) data)->compare(*((balance_pair_t *) val.data));
+
+ case STRING:
+ throw_(value_error, "Cannot compare a balance pair to a string");
+ case POINTER:
+ throw_(value_error, "Cannot compare a balance pair to a pointer");
+ case SEQUENCE:
+ throw_(value_error, "Cannot compare a balance pair to a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case STRING:
+ switch (val.type) {
+ case BOOLEAN:
+ throw_(value_error, "Cannot compare a string to a boolean");
+ case INTEGER:
+ throw_(value_error, "Cannot compare a string to an integer");
+ case DATETIME:
+ throw_(value_error, "Cannot compare a string to a date/time");
+ case AMOUNT:
+ throw_(value_error, "Cannot compare a string to an amount");
+ case BALANCE:
+ throw_(value_error, "Cannot compare a string to a balance");
+ case BALANCE_PAIR:
+ throw_(value_error, "Cannot compare a string to a balance pair");
+
+ case STRING:
+ return (**((string **) data)).compare(**((string **) val.data));
+
+ case POINTER:
+ throw_(value_error, "Cannot compare a string to a pointer");
+ case SEQUENCE:
+ throw_(value_error, "Cannot compare a string to a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case XML_NODE:
+ switch (val.type) {
+ case BOOLEAN:
+ return (*(xml::node_t **) data)->to_value().compare(*this);
+ case INTEGER:
+ return (*(xml::node_t **) data)->to_value().compare(*this);
+ case DATETIME:
+ return (*(xml::node_t **) data)->to_value().compare(*this);
+ case AMOUNT:
+ return (*(xml::node_t **) data)->to_value().compare(*this);
+ case BALANCE:
+ return (*(xml::node_t **) data)->to_value().compare(*this);
+ case BALANCE_PAIR:
+ return (*(xml::node_t **) data)->to_value().compare(*this);
+ case STRING:
+ return (*(xml::node_t **) data)->to_value().compare(*this);
+
+ case POINTER:
+ throw_(value_error, "Cannot compare an XML node to a pointer");
+ case SEQUENCE:
+ throw_(value_error, "Cannot compare an XML node to a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case POINTER:
+ switch (val.type) {
+ case BOOLEAN:
+ throw_(value_error, "Cannot compare a pointer to a boolean");
+ case INTEGER:
+ throw_(value_error, "Cannot compare a pointer to an integer");
+ case DATETIME:
+ throw_(value_error, "Cannot compare a pointer to a date/time");
+ case AMOUNT:
+ throw_(value_error, "Cannot compare a pointer to an amount");
+ case BALANCE:
+ throw_(value_error, "Cannot compare a pointer to a balance");
+ case BALANCE_PAIR:
+ throw_(value_error, "Cannot compare a pointer to a balance pair");
+ case STRING:
+ throw_(value_error, "Cannot compare a pointer to a string node");
+ case POINTER:
+ throw_(value_error, "Cannot compare two pointers");
+ case SEQUENCE:
+ throw_(value_error, "Cannot compare a pointer to a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case SEQUENCE:
+ throw_(value_error, "Cannot compare a value to a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ return *this;
+}
+
+#if 0
DEF_VALUE_CMP_OP(==)
DEF_VALUE_CMP_OP(<)
DEF_VALUE_CMP_OP(<=)
DEF_VALUE_CMP_OP(>)
DEF_VALUE_CMP_OP(>=)
+#endif
void value_t::in_place_cast(type_t cast_type)
{
@@ -1820,6 +1784,36 @@ void value_t::in_place_negate()
}
}
+bool value_t::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;
+}
+
value_t value_t::value(const moment_t& moment) const
{
switch (type) {
diff --git a/src/value.h b/src/value.h
index 4c6e0f18..30cea4a0 100644
--- a/src/value.h
+++ b/src/value.h
@@ -19,7 +19,7 @@ namespace xml {
// fact that logic chains only need boolean values to continue, no
// memory allocations need to take place at all.
-class value_t
+class value_t : public ordered_field_operators<value_t>
{
public:
typedef std::vector<value_t> sequence_t;
@@ -304,97 +304,37 @@ class value_t
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;
- }
+ int compare(const value_t& val) const;
- 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) const {
+ return compare(val) == 0;
}
template <typename T>
- value_t operator/(const T& val) {
- return *this / value_t(val);
+ bool operator==(const T& val) const {
+ 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);
+ bool operator<(const value_t& val) const {
+ return compare(val) < 0;
}
-
template <typename T>
- bool operator<(const T& val) {
+ bool operator<(const T& val) const {
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;
+ operator bool() const;
+
+#if 0
+ operator long() const;
+ operator unsigned long() const;
+ operator double() const;
+ operator moment_t() const;
+ operator string() const;
+ operator char *() const;
+ operator amount_t() const;
+ operator balance_t() const;
+ operator balance_pair_t() const;
+#endif
void in_place_negate();
value_t negate() const {
@@ -406,35 +346,7 @@ class value_t
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;
- }
-
+ bool realzero() const;
value_t abs() const;
void in_place_cast(type_t cast_type);
value_t cost() const;
@@ -470,58 +382,7 @@ class value_t
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, !=)
-
+#if 0
template <typename T>
value_t::operator T() const
{
@@ -558,6 +419,7 @@ 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;
+#endif
std::ostream& operator<<(std::ostream& out, const value_t& val);
diff --git a/src/xmlparse.cc b/src/xmlparse.cc
index 51da13f4..94b76ad7 100644
--- a/src/xmlparse.cc
+++ b/src/xmlparse.cc
@@ -321,10 +321,15 @@ void xml_write_value(std::ostream& out, const value_t& value,
for (int i = 0; i < depth + 2; i++) out << ' ';
out << "<balance>\n";
- for (amounts_map::const_iterator i = bal->amounts.begin();
+#if 0
+ // jww (2007-04-30): Change this so that types know how to stream
+ // themselves to XML on their own.
+
+ for (balance_t::amounts_map::const_iterator i = bal->amounts.begin();
i != bal->amounts.end();
i++)
xml_write_amount(out, (*i).second, depth + 4);
+#endif
for (int i = 0; i < depth + 2; i++) out << ' ';
out << "</balance>\n";