Added much documentation to amount.h
This commit is contained in:
parent
103881ff80
commit
de64861182
6 changed files with 857 additions and 603 deletions
906
src/amount.cc
906
src/amount.cc
File diff suppressed because it is too large
Load diff
523
src/amount.h
523
src/amount.h
|
|
@ -3,14 +3,14 @@
|
||||||
* @author John Wiegley
|
* @author John Wiegley
|
||||||
* @date Wed Apr 18 22:05:53 2007
|
* @date Wed Apr 18 22:05:53 2007
|
||||||
*
|
*
|
||||||
* @brief Types for handling commoditized math.
|
* @brief Basic type for handling commoditized math: amount_t.
|
||||||
*
|
*
|
||||||
* This file contains two of the most basic types in Ledger: amount_t
|
* This file contains the most basic numerical type in Ledger:
|
||||||
* commodity_t, and annotated_commodity_t. Both the commodity types
|
* amount_t, which relies upon commodity.h (commodity_t) for handling
|
||||||
* share a common base class, commodity_base_t. These four class
|
* commoditized amounts. This class allows Ledger to handle
|
||||||
* together allow Ledger to handle mathematical expressions involving
|
* mathematical expressions involving differing commodities, as well
|
||||||
* differing commodities, or in some cases math using no commodities
|
* as math using no commodities at all (such as increasing a dollar
|
||||||
* at all (such as increasing a dollar amount by a multiplier).
|
* amount by a multiplier).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -51,8 +51,6 @@
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
extern bool do_cleanup;
|
|
||||||
|
|
||||||
class commodity_t;
|
class commodity_t;
|
||||||
|
|
||||||
DECLARE_EXCEPTION(amount_error);
|
DECLARE_EXCEPTION(amount_error);
|
||||||
|
|
@ -79,45 +77,95 @@ class amount_t
|
||||||
public:
|
public:
|
||||||
class bigint_t;
|
class bigint_t;
|
||||||
|
|
||||||
// jww (2007-05-01): Change my uses of unsigned int to use this type
|
|
||||||
// for precision values. Or perhaps just std::size_t?
|
|
||||||
typedef uint_least16_t precision_t;
|
typedef uint_least16_t precision_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The initialize and shutdown methods ready the amount subsystem
|
||||||
|
* for use. Normally they are called by `ledger::initialize' and
|
||||||
|
* `ledger::shutdown'.
|
||||||
|
*/
|
||||||
static void initialize();
|
static void initialize();
|
||||||
static void shutdown();
|
static void shutdown();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `keep_base' member determines whether scalable commodities
|
||||||
|
* are automatically converted to their most reduced form when
|
||||||
|
* printing. The default is true.
|
||||||
|
*
|
||||||
|
* For example, Ledger supports time values specified in seconds
|
||||||
|
* (10s), hours (5.2h) or minutes. Internally, such amounts are
|
||||||
|
* always kept as quantities of seconds. However, when streaming
|
||||||
|
* the amount Ledger will convert it to its "least representation",
|
||||||
|
* which is "5.2h" in the second case. If `keep_base' is true, this
|
||||||
|
* amount is displayed as "18720s".
|
||||||
|
*/
|
||||||
|
static bool keep_base;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The following three members determine whether lot details are
|
||||||
|
* maintained when working with commoditized values. The default is
|
||||||
|
* false for all three.
|
||||||
|
*
|
||||||
|
* Let's say a user adds two values of the following form:
|
||||||
|
* 10 AAPL + 10 AAPL {$20}
|
||||||
|
*
|
||||||
|
* This expression adds ten shares of Apple stock with another ten
|
||||||
|
* shares that were purchased for $20 a share. If `keep_price' is
|
||||||
|
* false, the result of this expression will be an amount equal to
|
||||||
|
* 20 AAPL. If `keep_price' is true, the expression yields an
|
||||||
|
* exception for adding amounts with different commodities. In that
|
||||||
|
* case, a balance_t object must be used to store the combined sum.
|
||||||
|
*/
|
||||||
static bool keep_price;
|
static bool keep_price;
|
||||||
static bool keep_date;
|
static bool keep_date;
|
||||||
static bool keep_tag;
|
static bool keep_tag;
|
||||||
static bool keep_base;
|
|
||||||
|
/**
|
||||||
|
* The `full-strings' static member is currently only used by the
|
||||||
|
* unit testing code. It causes amounts written to streams to use
|
||||||
|
* the `to_fullstring' method rather than the `to_string' method, so
|
||||||
|
* that complete precision is always displayed, no matter what the
|
||||||
|
* precision of an individual commodity might be.
|
||||||
|
* @see to_string
|
||||||
|
* @see to_fullstring
|
||||||
|
*/
|
||||||
static bool full_strings;
|
static bool full_strings;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _init();
|
void _init();
|
||||||
void _copy(const amount_t& amt);
|
void _copy(const amount_t& amt);
|
||||||
void _release();
|
|
||||||
void _dup();
|
void _dup();
|
||||||
void _resize(precision_t prec);
|
void _resize(precision_t prec);
|
||||||
void _clear();
|
void _clear();
|
||||||
|
void _release();
|
||||||
|
|
||||||
bigint_t * quantity;
|
bigint_t * quantity;
|
||||||
commodity_t * commodity_;
|
commodity_t * commodity_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// constructors
|
/**
|
||||||
|
* Constructors. amount_t supports several forms of construction:
|
||||||
|
*
|
||||||
|
* amount_t() creates a value for which `is_null' is true, and which
|
||||||
|
* has no value or commodity. If used in value situations it will
|
||||||
|
* be zero, and its commodity equals `commodity_t::null_commodity'.
|
||||||
|
*
|
||||||
|
* amount_t(double), amount_t(unsigned long), amount_t(long) all
|
||||||
|
* convert from the respective numerics type to an amount. No
|
||||||
|
* precision or sign is lost in any of these conversions. The
|
||||||
|
* resulting commodity is always `commodity_t::null_commodity'.
|
||||||
|
*
|
||||||
|
* amount_t(string), amount_t(char*) both convert from a string
|
||||||
|
* representation of an amount, which may or may not include a
|
||||||
|
* commodity. This is the proper way to initialize an amount like
|
||||||
|
* '$100.00'.
|
||||||
|
*/
|
||||||
amount_t() : quantity(NULL), commodity_(NULL) {
|
amount_t() : quantity(NULL), commodity_(NULL) {
|
||||||
TRACE_CTOR(amount_t, "");
|
TRACE_CTOR(amount_t, "");
|
||||||
}
|
}
|
||||||
amount_t(const amount_t& amt) : quantity(NULL) {
|
|
||||||
TRACE_CTOR(amount_t, "copy");
|
|
||||||
if (amt.quantity)
|
|
||||||
_copy(amt);
|
|
||||||
else
|
|
||||||
commodity_ = NULL;
|
|
||||||
}
|
|
||||||
amount_t(const long val);
|
|
||||||
amount_t(const unsigned long val);
|
|
||||||
amount_t(const double val);
|
amount_t(const double val);
|
||||||
|
amount_t(const unsigned long val);
|
||||||
|
amount_t(const long val);
|
||||||
|
|
||||||
amount_t(const string& val) : quantity(NULL) {
|
amount_t(const string& val) : quantity(NULL) {
|
||||||
TRACE_CTOR(amount_t, "const string&");
|
TRACE_CTOR(amount_t, "const string&");
|
||||||
|
|
@ -128,19 +176,63 @@ public:
|
||||||
parse(val);
|
parse(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static creator function. Calling amount_t::exact(string) will
|
||||||
|
* create an amount whose display precision is never truncated, even
|
||||||
|
* if the amount uses a commodity (which normally causes "round on
|
||||||
|
* streaming" to occur). This function is mostly used by the
|
||||||
|
* debugging code. It is the proper way to initialize '$100.005',
|
||||||
|
* where display of the extra precision is required. If a regular
|
||||||
|
* constructor is used, this amount will stream as '$100.01', even
|
||||||
|
* though its internal value always equals $100.005.
|
||||||
|
*/
|
||||||
|
static amount_t exact(const string& value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destructor. Releases the reference count held for the underlying
|
||||||
|
* bigint_t object.
|
||||||
|
*/
|
||||||
~amount_t() {
|
~amount_t() {
|
||||||
TRACE_DTOR(amount_t);
|
TRACE_DTOR(amount_t);
|
||||||
if (quantity)
|
if (quantity)
|
||||||
_release();
|
_release();
|
||||||
}
|
}
|
||||||
|
|
||||||
static amount_t exact(const string& value);
|
/**
|
||||||
|
* Assignment and copy operators. An amount may be assigned or
|
||||||
// assignment operator
|
* copied. If a double, long or unsigned long is assigned to an
|
||||||
|
* amount, a temporary is constructed, and then the temporary is
|
||||||
|
* assigned to `this'. Both the value and the commodity are copied,
|
||||||
|
* causing the result to compare equal to the reference amount.
|
||||||
|
*
|
||||||
|
* Note: `quantity' must be initialized to NULL first, otherwise the
|
||||||
|
* `_copy' function will attempt to release the unitialized pointer.
|
||||||
|
*/
|
||||||
|
amount_t(const amount_t& amt) : quantity(NULL) {
|
||||||
|
TRACE_CTOR(amount_t, "copy");
|
||||||
|
if (amt.quantity)
|
||||||
|
_copy(amt);
|
||||||
|
else
|
||||||
|
commodity_ = NULL;
|
||||||
|
}
|
||||||
amount_t& operator=(const amount_t& amt);
|
amount_t& operator=(const amount_t& amt);
|
||||||
|
|
||||||
// comparisons between amounts
|
/**
|
||||||
|
* Comparison operators. The fundamental comparison operation for
|
||||||
|
* amounts is `compare', which returns a value less than, greater
|
||||||
|
* than or equal to zero. All the other comparison operators are
|
||||||
|
* defined in terms of this method. The only special detail is that
|
||||||
|
* `operator==' will fail immediately if amounts with different
|
||||||
|
* commodities are being compared. Otherwise, if the commodities
|
||||||
|
* are equivalent (@see keep_price, et al), then the amount
|
||||||
|
* quantities are compared numerically.
|
||||||
|
*
|
||||||
|
* Comparison between an amount and a double, long or unsigned long
|
||||||
|
* is allowed. In such cases the non-amount value is constructed as
|
||||||
|
* an amount temporary, which is then compared to `this'.
|
||||||
|
*/
|
||||||
int compare(const amount_t& amt) const;
|
int compare(const amount_t& amt) const;
|
||||||
|
|
||||||
bool operator==(const amount_t& amt) const;
|
bool operator==(const amount_t& amt) const;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
@ -156,24 +248,125 @@ public:
|
||||||
return compare(amt) > 0;
|
return compare(amt) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// in-place arithmetic
|
/**
|
||||||
|
* Binary arithmetic operators. Amounts support addition,
|
||||||
|
* subtraction, multiplication and division -- but not modulus,
|
||||||
|
* bitwise operations, or shifting. Arithmetic is also supported
|
||||||
|
* between amounts, double, long and unsigned long, in which case
|
||||||
|
* temporary amount are constructed for the life of the expression.
|
||||||
|
*
|
||||||
|
* Although only in-place operators are defined here, the remainder
|
||||||
|
* are provided by `boost::ordered_field_operators<>'.
|
||||||
|
*/
|
||||||
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);
|
||||||
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
|
/**
|
||||||
amount_t operator-() const {
|
* Unary arithmetic operators. There are several unary methods
|
||||||
return negate();
|
* support on amounts:
|
||||||
}
|
*
|
||||||
|
* negate(), also unary minus (- x), returns the negated value of an
|
||||||
|
* amount.
|
||||||
|
*
|
||||||
|
* abs() returns the absolute value of an amount. It is equivalent
|
||||||
|
* to: `(x < 0) ? - x : x'.
|
||||||
|
*
|
||||||
|
* round(precision_t) rounds an amount's internal value to the given
|
||||||
|
* precision.
|
||||||
|
*
|
||||||
|
* round() rounds an amount to its commodity's current display
|
||||||
|
* precision. This also changes the internal value of the amount.
|
||||||
|
*
|
||||||
|
* unround() yields an amount whose display precision is never
|
||||||
|
* truncated, even though its commodity normally displays only
|
||||||
|
* rounded values.
|
||||||
|
*
|
||||||
|
* reduce() reduces a value to its most basic commodity form, for
|
||||||
|
* amounts that utilize "scaling commodities". For example, an
|
||||||
|
* amount of 1h after reduction will be 3600s.
|
||||||
|
*
|
||||||
|
* unreduce(), if used with a "scaling commodity", yields the most
|
||||||
|
* compact form greater than 1.0. That is, 3599s will unreduce to
|
||||||
|
* 59.98m, while 3601 unreduces to 1h.
|
||||||
|
*
|
||||||
|
* value(moment_t) returns the history value of an amount, based on
|
||||||
|
* the price history of its commodity. For example, if the amount
|
||||||
|
* were 10 AAPL, and on Apr 10, 2000 each share of AAPL was worth
|
||||||
|
* $10, then call value() for that moment in time would yield the
|
||||||
|
* amount $100.00.
|
||||||
|
*
|
||||||
|
* Further, for the sake of efficiency and avoiding temporary
|
||||||
|
* objects, the following methods support "in-place" variants that
|
||||||
|
* act on the value itself and return a reference to the result
|
||||||
|
* (`*this'):
|
||||||
|
*
|
||||||
|
* in_place_negate()
|
||||||
|
* in_place_reduce()
|
||||||
|
* in_place_unreduce()
|
||||||
|
*/
|
||||||
amount_t negate() const {
|
amount_t negate() const {
|
||||||
amount_t temp = *this;
|
amount_t temp = *this;
|
||||||
temp.in_place_negate();
|
temp.in_place_negate();
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
void in_place_negate();
|
amount_t& in_place_negate();
|
||||||
|
|
||||||
|
amount_t operator-() const {
|
||||||
|
return negate();
|
||||||
|
}
|
||||||
|
|
||||||
|
amount_t abs() const {
|
||||||
|
if (sign() < 0)
|
||||||
|
return negate();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
amount_t round(precision_t prec) const;
|
||||||
|
amount_t round() const;
|
||||||
|
amount_t unround() const;
|
||||||
|
|
||||||
|
amount_t reduce() const {
|
||||||
|
amount_t temp(*this);
|
||||||
|
temp.in_place_reduce();
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
amount_t& in_place_reduce();
|
||||||
|
|
||||||
|
amount_t unreduce() const {
|
||||||
|
amount_t temp(*this);
|
||||||
|
temp.in_place_unreduce();
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
amount_t& in_place_unreduce();
|
||||||
|
|
||||||
|
amount_t value(const moment_t& moment) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Truth tests. An amount may be truth test in several ways:
|
||||||
|
*
|
||||||
|
* sign() returns an integer less than, greater than, or equal to
|
||||||
|
* zero depending on whether an amount is negative, zero, or greater
|
||||||
|
* than zero. Note that this function tests the actual value of the
|
||||||
|
* amount -- using its internal precision -- and not the display
|
||||||
|
* value. To test its display value, use: `round().sign()'.
|
||||||
|
*
|
||||||
|
* nonzero(), or operator bool, returns true if an amount's display
|
||||||
|
* value is not zero.
|
||||||
|
*
|
||||||
|
* zero() returns true if an amount's display value is zero. Thus,
|
||||||
|
* $0.0001 is considered zero().
|
||||||
|
*
|
||||||
|
* realzero() returns true if an amount's actual value is zero.
|
||||||
|
* $0.0001 is not considered realzero().
|
||||||
|
*
|
||||||
|
* is_null() returns true if an amount has no value and no
|
||||||
|
* commodity. This occurs only if an unitialized amount has never
|
||||||
|
* been assigned a value.
|
||||||
|
*/
|
||||||
|
int sign() const;
|
||||||
|
|
||||||
// test for truth, zero and non-zero
|
|
||||||
operator bool() const {
|
operator bool() const {
|
||||||
return nonzero();
|
return nonzero();
|
||||||
}
|
}
|
||||||
|
|
@ -181,22 +374,77 @@ public:
|
||||||
return ! zero();
|
return ! zero();
|
||||||
}
|
}
|
||||||
|
|
||||||
int sign() const;
|
|
||||||
bool zero() const;
|
bool zero() const;
|
||||||
bool realzero() const {
|
bool realzero() const {
|
||||||
return sign() == 0;
|
return sign() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// conversion methods
|
bool is_null() const {
|
||||||
long to_long() const;
|
return ! quantity && ! has_commodity();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conversion methods. An amount may be converted to the same types
|
||||||
|
* it can be constructed from -- with the exception of unsigned
|
||||||
|
* long. Implicit conversions are not allowed in C++ (though they
|
||||||
|
* are in Python), rather the following conversion methods must be
|
||||||
|
* called explicitly:
|
||||||
|
*
|
||||||
|
* to_double() returns an amount as a double. Note: precision is
|
||||||
|
* very likely to be lost in this conversion!
|
||||||
|
*
|
||||||
|
* to_long() returns an amount as a long integer. This is only
|
||||||
|
* useful if the amount is know to be of a small, integral value.
|
||||||
|
*
|
||||||
|
* to_string() returns an amount'ss "display value" as a string --
|
||||||
|
* after rounding the value according to the commodity's default
|
||||||
|
* precision. It is equivalent to: `round().to_fullstring()'.
|
||||||
|
*
|
||||||
|
* to_fullstring() returns an amount's "internal value" as a string,
|
||||||
|
* without any rounding.
|
||||||
|
*
|
||||||
|
* quantity_string() returns an amount's "display value", but
|
||||||
|
* without any commodity. Note that this is different from
|
||||||
|
* `number().to_string()', because in that case the commodity has
|
||||||
|
* been stripped and the full, internal precision of the amount
|
||||||
|
* would be displayed.
|
||||||
|
*/
|
||||||
double to_double() const;
|
double to_double() const;
|
||||||
|
long to_long() const;
|
||||||
string to_string() const;
|
string to_string() const;
|
||||||
string to_fullstring() const;
|
string to_fullstring() const;
|
||||||
string quantity_string() const;
|
string quantity_string() const;
|
||||||
|
|
||||||
// methods relating to the commodity
|
/**
|
||||||
bool is_null() const {
|
* Commodity-related methods. The following methods relate to an
|
||||||
return ! quantity && ! has_commodity();
|
* amount's commodity:
|
||||||
|
*
|
||||||
|
* has_commodity() returns true if the amount has a commodity.
|
||||||
|
*
|
||||||
|
* commodity() returns an amount's commodity. If the amount has no
|
||||||
|
* commodity, then the value returned will be equal to
|
||||||
|
* `commodity_t::null_commodity'.
|
||||||
|
*
|
||||||
|
* set_commodity(commodity_t) sets an amount's commodity to the
|
||||||
|
* given value. Note that this merely sets the current amount to
|
||||||
|
* that commodity, it does not "observe" the amount for possible
|
||||||
|
* changes in the maximum display precision of the commodity, the
|
||||||
|
* way that `parse' does.
|
||||||
|
*
|
||||||
|
* clear_commodity() sets an amount's commodity to null, such that
|
||||||
|
* has_commodity() afterwards returns false.
|
||||||
|
*
|
||||||
|
* number() returns a commodity-less version of an amount. This is
|
||||||
|
* useful for accessing just the numeric portion of an amount.
|
||||||
|
*/
|
||||||
|
bool has_commodity() const;
|
||||||
|
commodity_t& commodity() const;
|
||||||
|
|
||||||
|
void set_commodity(commodity_t& comm) {
|
||||||
|
commodity_ = &comm;
|
||||||
|
}
|
||||||
|
void clear_commodity() {
|
||||||
|
commodity_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
amount_t number() const {
|
amount_t number() const {
|
||||||
|
|
@ -207,16 +455,35 @@ public:
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_commodity() const;
|
/**
|
||||||
void set_commodity(commodity_t& comm) {
|
* Annotated commodity methods. An amount's commodity may be
|
||||||
commodity_ = &comm;
|
* annotated with special details, such as the price it was
|
||||||
}
|
* purchased for, when it was acquired, or an arbitrary note,
|
||||||
void clear_commodity() {
|
* identifying perhaps the lot number of an item.
|
||||||
commodity_ = NULL;
|
*
|
||||||
}
|
* annotate_commodity(amount_t price, [moment_t date, string tag])
|
||||||
|
* sets the annotations for the current amount's commodity. Only
|
||||||
commodity_t& commodity() const;
|
* the price argument is required, although it can be passed as
|
||||||
|
* `optional<amount_t>()' if no price is desired.
|
||||||
|
*
|
||||||
|
* strip_annotations([keep_price, keep_date, keep_tag]) returns an
|
||||||
|
* amount whose commodity's annotations have been stripped. The
|
||||||
|
* three `keep_' arguments determine which annotation detailed are
|
||||||
|
* kept, meaning that the default is to follow whatever
|
||||||
|
* amount_t::keep_price, amount_t::keep_date and amount_t::keep_tag
|
||||||
|
* have been set to (which all default to false).
|
||||||
|
*
|
||||||
|
* price() returns an amount's annotated commodity's price. This
|
||||||
|
* return value is of type `optional<amount_t>', so it must be
|
||||||
|
* tested for boolean truth to determine if an annotated price even
|
||||||
|
* existed.
|
||||||
|
*
|
||||||
|
* date() returns an amount's annotated commodity's date. This
|
||||||
|
* return value is of type `optional<moment_t>'.
|
||||||
|
*
|
||||||
|
* tag() returns an amount's annotated commodity's tag. This return
|
||||||
|
* value is of type `optional<string>'.
|
||||||
|
*/
|
||||||
void annotate_commodity(const optional<amount_t>& tprice,
|
void annotate_commodity(const optional<amount_t>& tprice,
|
||||||
const optional<moment_t>& tdate = optional<moment_t>(),
|
const optional<moment_t>& tdate = optional<moment_t>(),
|
||||||
const optional<string>& ttag = optional<string>());
|
const optional<string>& ttag = optional<string>());
|
||||||
|
|
@ -229,67 +496,128 @@ public:
|
||||||
optional<moment_t> date() const;
|
optional<moment_t> date() const;
|
||||||
optional<string> tag() const;
|
optional<string> tag() const;
|
||||||
|
|
||||||
// general methods
|
|
||||||
amount_t round(precision_t prec) const;
|
|
||||||
amount_t round() const;
|
|
||||||
amount_t unround() const;
|
|
||||||
amount_t value(const moment_t& moment) const;
|
|
||||||
|
|
||||||
amount_t abs() const {
|
|
||||||
if (sign() < 0)
|
|
||||||
return negate();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
amount_t reduce() const {
|
|
||||||
amount_t temp(*this);
|
|
||||||
temp.in_place_reduce();
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
void in_place_reduce();
|
|
||||||
|
|
||||||
bool valid() const;
|
|
||||||
|
|
||||||
// This function is special, and exists only to support a custom
|
|
||||||
// optimization in binary.cc (which offers a significant enough gain
|
|
||||||
// to be worth the trouble).
|
|
||||||
|
|
||||||
friend void clean_commodity_history(char * item_pool,
|
|
||||||
char * item_pool_end);
|
|
||||||
|
|
||||||
friend void parse_annotations(std::istream& in,
|
|
||||||
optional<amount_t>& price,
|
|
||||||
optional<moment_t>& date,
|
|
||||||
optional<string>& tag);
|
|
||||||
|
|
||||||
// Streaming interface
|
|
||||||
|
|
||||||
void dump(std::ostream& out) const {
|
|
||||||
out << "AMOUNT(";
|
|
||||||
print(out);
|
|
||||||
out << ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
#define AMOUNT_PARSE_NO_MIGRATE 0x01
|
#define AMOUNT_PARSE_NO_MIGRATE 0x01
|
||||||
#define AMOUNT_PARSE_NO_REDUCE 0x02
|
#define AMOUNT_PARSE_NO_REDUCE 0x02
|
||||||
|
|
||||||
void print(std::ostream& out, bool omit_commodity = false,
|
/**
|
||||||
bool full_precision = false) const;
|
* Parsing methods. The method `parse' is used to parse an amount
|
||||||
|
* from an input stream or a string. A global operator>> is also
|
||||||
|
* defined which simply calls parse on the input stream. The
|
||||||
|
* `parse' method has two forms:
|
||||||
|
*
|
||||||
|
* parse(istream, unsigned char flags) parses an amount from the
|
||||||
|
* given input stream.
|
||||||
|
*
|
||||||
|
* parse(string, unsigned char flags) parses an amount from the
|
||||||
|
* given string.
|
||||||
|
*
|
||||||
|
* The `flags' argument of both parsing may be one or more of the
|
||||||
|
* following:
|
||||||
|
*
|
||||||
|
* AMOUNT_PARSE_NO_MIGRATE means to not pay attention to the way an
|
||||||
|
* amount is used. Ordinarily, if an amount were $100.001, for
|
||||||
|
* example, it would cause the default display precision for $ to be
|
||||||
|
* "widened" to three decimal places. If AMOUNT_PARSE_NO_MIGRATE is
|
||||||
|
* used, the commodity's default display precision is not changed.
|
||||||
|
*
|
||||||
|
* AMOUNT_PARSE_NO_REDUCE means not to call in_place_reduce() on the
|
||||||
|
* resulting amount after it is parsed.
|
||||||
|
*
|
||||||
|
* These parsing methods observe the amounts they parse (unless
|
||||||
|
* AMOUNT_PARSE_NO_MIGRATE is true), and set the display details of
|
||||||
|
* the corresponding commodity accordingly. This way, amounts do
|
||||||
|
* not require commodities to be pre-defined in any way, but merely
|
||||||
|
* displays them back to the user in the same fashion as it saw them
|
||||||
|
* used.
|
||||||
|
*
|
||||||
|
* There is also a static convenience method called
|
||||||
|
* `parse_conversion' which can be used to define a relationship
|
||||||
|
* between scaling commodity values. For example, Ledger uses it to
|
||||||
|
* define the relationships among various time values:
|
||||||
|
*
|
||||||
|
* amount_t::parse_conversion("1.0m", "60s"); // a minute is 60 seconds
|
||||||
|
* amount_t::parse_conversion("1.0h", "60m"); // an hour is 60 minutes
|
||||||
|
*/
|
||||||
void parse(std::istream& in, unsigned char flags = 0);
|
void parse(std::istream& in, unsigned char flags = 0);
|
||||||
void parse(const string& str, unsigned char flags = 0) {
|
void parse(const string& str, unsigned char flags = 0) {
|
||||||
std::istringstream stream(str);
|
std::istringstream stream(str);
|
||||||
parse(stream, flags);
|
parse(stream, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_quantity(std::ostream& out) const;
|
static void parse_conversion(const string& larger_str,
|
||||||
|
const string& smaller_str);
|
||||||
|
|
||||||
void write(std::ostream& out) const;
|
/**
|
||||||
|
* Printing methods. An amount may be output to a stream using the
|
||||||
|
* `print' method. There is also a global operator<< defined which
|
||||||
|
* simply calls print for an amount on the given stream. There is
|
||||||
|
* one form of the print method, which takes one required argument
|
||||||
|
* and two arguments with default values:
|
||||||
|
*
|
||||||
|
* print(ostream, bool omit_commodity = false, bool full_precision =
|
||||||
|
* false) prits an amounts to the given output stream, using its
|
||||||
|
* commodity's default display characteristics. If `omit_commodity'
|
||||||
|
* is true, the commodity will not be displayed, only the amount
|
||||||
|
* (although the commodity's display precision is still used). If
|
||||||
|
* `full_precision' is true, the full internal precision of the
|
||||||
|
* amount is displayed, regardless of its commodity's display
|
||||||
|
* precision.
|
||||||
|
*/
|
||||||
|
void print(std::ostream& out, bool omit_commodity = false,
|
||||||
|
bool full_precision = false) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialization methods. An amount may be deserialized from an
|
||||||
|
* input stream or a character pointer, and it may be serialized to
|
||||||
|
* an output stream. The methods used are:
|
||||||
|
*
|
||||||
|
* read(istream) reads an amount from the given input stream. It
|
||||||
|
* must have been put there using `write(ostream)'.
|
||||||
|
*
|
||||||
|
* read(char *&) reads an amount from data which has been read from
|
||||||
|
* an input stream into a buffer. it advances the pointer passed in
|
||||||
|
* to the end of the deserialized amount.
|
||||||
|
*
|
||||||
|
* write(ostream) writes an amount to an output stream in a compact
|
||||||
|
* binary format.
|
||||||
|
*/
|
||||||
void read(std::istream& in);
|
void read(std::istream& in);
|
||||||
void read(char *& data);
|
void read(char *& data);
|
||||||
|
|
||||||
void write_quantity(std::ostream& out) const;
|
void write(std::ostream& out) const;
|
||||||
|
|
||||||
|
private:
|
||||||
void read_quantity(std::istream& in);
|
void read_quantity(std::istream& in);
|
||||||
void read_quantity(char *& data);
|
void read_quantity(char *& data);
|
||||||
|
void write_quantity(std::ostream& out) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Debugging methods. There are two methods defined to help with
|
||||||
|
* debugging:
|
||||||
|
*
|
||||||
|
* dump(ostream) dumps an amount to an output stream. There is
|
||||||
|
* little different from print(), it simply surrounds the display
|
||||||
|
* value with a marker, for example "AMOUNT($1.00)". This code is
|
||||||
|
* used by other dumping code elsewhere in Ledger.
|
||||||
|
*
|
||||||
|
* valid() returns true if an amount is valid. This ensures that if
|
||||||
|
* an amount has a commodity, it has a valid value pointer, for
|
||||||
|
* example, even if that pointer simply points to a zero value.
|
||||||
|
*/
|
||||||
|
void dump(std::ostream& out) const {
|
||||||
|
out << "AMOUNT(";
|
||||||
|
print(out);
|
||||||
|
out << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool valid() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend void parse_annotations(std::istream& in,
|
||||||
|
optional<amount_t>& price,
|
||||||
|
optional<moment_t>& date,
|
||||||
|
optional<string>& tag);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline amount_t amount_t::exact(const string& value) {
|
inline amount_t amount_t::exact(const string& value) {
|
||||||
|
|
@ -351,9 +679,6 @@ inline commodity_t& amount_t::commodity() const {
|
||||||
return has_commodity() ? *commodity_ : *commodity_t::null_commodity;
|
return has_commodity() ? *commodity_ : *commodity_t::null_commodity;
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_conversion(const string& larger_str,
|
|
||||||
const string& smaller_str);
|
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
||||||
#endif // _AMOUNT_H
|
#endif // _AMOUNT_H
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,6 @@ namespace ledger {
|
||||||
|
|
||||||
using namespace boost::python;
|
using namespace boost::python;
|
||||||
|
|
||||||
int py_amount_quantity(amount_t& amount)
|
|
||||||
{
|
|
||||||
std::ostringstream quant;
|
|
||||||
amount.print_quantity(quant);
|
|
||||||
return std::atol(quant.str().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void py_parse_1(amount_t& amount, const string& str,
|
void py_parse_1(amount_t& amount, const string& str,
|
||||||
unsigned char flags) {
|
unsigned char flags) {
|
||||||
amount.parse(str, flags);
|
amount.parse(str, flags);
|
||||||
|
|
|
||||||
|
|
@ -730,7 +730,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
|
||||||
case 'C': // a set of conversions
|
case 'C': // a set of conversions
|
||||||
if (char * p = std::strchr(line + 1, '=')) {
|
if (char * p = std::strchr(line + 1, '=')) {
|
||||||
*p++ = '\0';
|
*p++ = '\0';
|
||||||
parse_conversion(line + 1, p);
|
amount_t::parse_conversion(line + 1, p);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -600,6 +600,26 @@ void BasicAmountTestCase::testAbs()
|
||||||
CPPUNIT_ASSERT(x2.valid());
|
CPPUNIT_ASSERT(x2.valid());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BasicAmountTestCase::testReduction()
|
||||||
|
{
|
||||||
|
amount_t x1("60s");
|
||||||
|
amount_t x2("600s");
|
||||||
|
amount_t x3("6000s");
|
||||||
|
amount_t x4("360000s");
|
||||||
|
amount_t x5("10m"); // 600s
|
||||||
|
amount_t x6("100m"); // 6000s
|
||||||
|
amount_t x7("1000m"); // 60000s
|
||||||
|
amount_t x8("10000m"); // 600000s
|
||||||
|
amount_t x9("10h"); // 36000s
|
||||||
|
amount_t x10("100h"); // 360000s
|
||||||
|
amount_t x11("1000h"); // 3600000s
|
||||||
|
amount_t x12("10000h"); // 36000000s
|
||||||
|
|
||||||
|
assertEqual(x2, x5);
|
||||||
|
assertEqual(x3, x6);
|
||||||
|
assertEqual(x4, x10);
|
||||||
|
}
|
||||||
|
|
||||||
void BasicAmountTestCase::testPrinting()
|
void BasicAmountTestCase::testPrinting()
|
||||||
{
|
{
|
||||||
amount_t x0;
|
amount_t x0;
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ class BasicAmountTestCase : public CPPUNIT_NS::TestCase
|
||||||
CPPUNIT_TEST(testComparisons);
|
CPPUNIT_TEST(testComparisons);
|
||||||
CPPUNIT_TEST(testSign);
|
CPPUNIT_TEST(testSign);
|
||||||
CPPUNIT_TEST(testAbs);
|
CPPUNIT_TEST(testAbs);
|
||||||
|
CPPUNIT_TEST(testReduction);
|
||||||
CPPUNIT_TEST(testPrinting);
|
CPPUNIT_TEST(testPrinting);
|
||||||
|
|
||||||
CPPUNIT_TEST_SUITE_END();
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
|
@ -58,6 +59,7 @@ public:
|
||||||
void testComparisons();
|
void testComparisons();
|
||||||
void testSign();
|
void testSign();
|
||||||
void testAbs();
|
void testAbs();
|
||||||
|
void testReduction();
|
||||||
void testPrinting();
|
void testPrinting();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue