In the middle of switching to using boost/operators.hpp
This commit is contained in:
parent
e70b80d6fe
commit
230e03166f
17 changed files with 1476 additions and 2006 deletions
|
|
@ -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 \
|
||||
|
|
|
|||
58
Makefile.in
58
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
|
||||
|
|
|
|||
703
src/amount.cc
703
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
void amount_t::_copy(const amount_t& amt)
|
||||
{
|
||||
if (quantity != amt.quantity) {
|
||||
if (quantity)
|
||||
_release();
|
||||
|
||||
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);
|
||||
}
|
||||
} 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);
|
||||
quantity = amt.quantity;
|
||||
DEBUG("amounts.refs",
|
||||
quantity << " ref++, now " << (quantity->ref + 1));
|
||||
quantity->ref++;
|
||||
}
|
||||
}
|
||||
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);
|
||||
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 {
|
||||
mpz_ui_pow_ui(divisor, 10, prec - quantity->prec);
|
||||
mpz_mul(MPZ(quantity), MPZ(quantity), 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;
|
||||
if (! amt.quantity)
|
||||
return 0;
|
||||
return - amt.sign();
|
||||
}
|
||||
else if (quantity->ref > 1) {
|
||||
_release();
|
||||
quantity = new bigint_t;
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
// 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++;
|
||||
}
|
||||
}
|
||||
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
|
||||
|
|
|
|||
566
src/amount.h
566
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,17 +118,63 @@ 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();
|
||||
}
|
||||
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
// 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);
|
||||
amount_t& operator-=(const amount_t& amt);
|
||||
amount_t& operator*=(const amount_t& amt);
|
||||
amount_t& operator/=(const amount_t& amt);
|
||||
|
||||
// unary negation
|
||||
void in_place_negate();
|
||||
amount_t negate() const {
|
||||
amount_t temp = *this;
|
||||
temp.in_place_negate();
|
||||
return temp;
|
||||
}
|
||||
amount_t operator-() const {
|
||||
return negate();
|
||||
}
|
||||
|
||||
// test for zero and non-zero
|
||||
int sign() const;
|
||||
bool zero() const;
|
||||
bool realzero() const {
|
||||
return sign() == 0;
|
||||
}
|
||||
operator bool() const {
|
||||
return ! zero();
|
||||
}
|
||||
|
||||
// Methods relating to this amount's commodity
|
||||
|
||||
bool is_null() const {
|
||||
return ! quantity && ! has_commodity();
|
||||
}
|
||||
|
||||
amount_t number() const {
|
||||
if (! has_commodity())
|
||||
return *this;
|
||||
|
|
@ -154,183 +205,29 @@ class amount_t
|
|||
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);
|
||||
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);
|
||||
|
||||
// general methods
|
||||
amount_t round(unsigned int prec) const;
|
||||
amount_t round() const;
|
||||
amount_t unround() const;
|
||||
|
||||
// in-place arithmetic
|
||||
amount_t& operator+=(const amount_t& amt);
|
||||
amount_t& operator-=(const amount_t& amt);
|
||||
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 {
|
||||
amount_t temp = *this;
|
||||
temp.in_place_negate();
|
||||
return temp;
|
||||
}
|
||||
amount_t operator-() const {
|
||||
return negate();
|
||||
}
|
||||
|
||||
// test for zero and non-zero
|
||||
int sign() const;
|
||||
bool zero() const;
|
||||
bool realzero() const {
|
||||
return sign() == 0;
|
||||
}
|
||||
operator bool() const {
|
||||
return ! zero();
|
||||
}
|
||||
#if 0
|
||||
// string and numeric conversions
|
||||
operator string() const {
|
||||
return to_string();
|
||||
}
|
||||
|
||||
operator long() const;
|
||||
operator double() const;
|
||||
#endif
|
||||
|
||||
string to_string() const;
|
||||
string to_fullstring() const;
|
||||
string quantity_string() const;
|
||||
|
||||
// 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 operator>(const amount_t& amt) const {
|
||||
return compare(amt) > 0;
|
||||
}
|
||||
bool operator>=(const amount_t& amt) const {
|
||||
return compare(amt) >= 0;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
// 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; \
|
||||
} \
|
||||
}
|
||||
|
||||
AMOUNT_CMP_INT(<)
|
||||
AMOUNT_CMP_INT(<=)
|
||||
AMOUNT_CMP_INT(>)
|
||||
AMOUNT_CMP_INT(>=)
|
||||
AMOUNT_CMP_INT(==)
|
||||
|
||||
template <typename T>
|
||||
bool operator!=(T num) const {
|
||||
return ! (*this == num);
|
||||
}
|
||||
|
||||
// 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
|
||||
#include "commodity.h"
|
||||
|
||||
typedef std::map<const moment_t, amount_t> history_map;
|
||||
typedef std::pair<const moment_t, amount_t> history_pair;
|
||||
namespace ledger {
|
||||
|
||||
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);
|
||||
|
||||
friend class amount_t;
|
||||
};
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
475
src/balance.h
475
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,
|
||||
|
|
|
|||
418
src/commodity.cc
Normal file
418
src/commodity.cc
Normal file
|
|
@ -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
|
||||
328
src/commodity.h
Normal file
328
src/commodity.h
Normal file
|
|
@ -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
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
670
src/value.cc
670
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) {
|
||||
|
|
|
|||
192
src/value.h
192
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);
|
||||
}
|
||||
int compare(const value_t& val) const;
|
||||
|
||||
value_t operator+(const value_t& val) {
|
||||
value_t temp(*this);
|
||||
temp += val;
|
||||
return temp;
|
||||
}
|
||||
value_t operator-(const value_t& val) {
|
||||
value_t temp(*this);
|
||||
temp -= val;
|
||||
return temp;
|
||||
}
|
||||
value_t operator*(const value_t& val) {
|
||||
value_t temp(*this);
|
||||
temp *= val;
|
||||
return temp;
|
||||
}
|
||||
value_t operator/(const value_t& val) {
|
||||
value_t temp(*this);
|
||||
temp /= val;
|
||||
return temp;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
value_t operator+(const T& val) {
|
||||
return *this + value_t(val);
|
||||
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);
|
||||
}
|
||||
template <typename T>
|
||||
value_t operator*(const T& val) {
|
||||
return *this * value_t(val);
|
||||
}
|
||||
template <typename T>
|
||||
value_t operator/(const T& val) {
|
||||
return *this / value_t(val);
|
||||
}
|
||||
|
||||
bool operator<(const value_t& val);
|
||||
bool operator<=(const value_t& val);
|
||||
bool operator>(const value_t& val);
|
||||
bool operator>=(const value_t& val);
|
||||
bool operator==(const value_t& val);
|
||||
bool operator!=(const value_t& val) {
|
||||
return ! (*this == val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator<(const T& val) {
|
||||
return *this < value_t(val);
|
||||
}
|
||||
template <typename T>
|
||||
bool operator<=(const T& val) {
|
||||
return *this <= value_t(val);
|
||||
}
|
||||
template <typename T>
|
||||
bool operator>(const T& val) {
|
||||
return *this > value_t(val);
|
||||
}
|
||||
template <typename T>
|
||||
bool operator>=(const T& val) {
|
||||
return *this >= value_t(val);
|
||||
}
|
||||
template <typename T>
|
||||
bool operator==(const T& val) {
|
||||
bool operator==(const T& val) const {
|
||||
return *this == value_t(val);
|
||||
}
|
||||
|
||||
bool operator<(const value_t& val) const {
|
||||
return compare(val) < 0;
|
||||
}
|
||||
template <typename T>
|
||||
bool operator!=(const T& val) {
|
||||
return ! (*this == val);
|
||||
bool operator<(const T& val) const {
|
||||
return *this < value_t(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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue