1 /*
2  * Copyright (c) 2003-2018, John Wiegley.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * - Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  *
11  * - Redistributions in binary form must reproduce the above copyright
12  *   notice, this list of conditions and the following disclaimer in the
13  *   documentation and/or other materials provided with the distribution.
14  *
15  * - Neither the name of New Artisans LLC nor the names of its
16  *   contributors may be used to endorse or promote products derived from
17  *   this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /**
33  * @addtogroup math
34  */
35 
36 /**
37  * @file   balance.h
38  * @author John Wiegley
39  *
40  * @ingroup math
41  *
42  * @brief  Basic type for adding multiple commodities together
43  *
44  * Unlike the amount_t class, which throws an exception if amounts of
45  * differing commodities are added or subtracted, the balance_t class
46  * is designed to allow this, tracking the amounts of each component
47  * commodity separately.
48  */
49 #ifndef _BALANCE_H
50 #define _BALANCE_H
51 
52 #include "amount.h"
53 
54 namespace ledger {
55 
56 DECLARE_EXCEPTION(balance_error, std::runtime_error);
57 
58 /**
59  * @class balance_t
60  *
61  * @brief A wrapper around amount_t allowing addition of multiple commodities.
62  *
63  * The balance_t class is appopriate for keeping a running balance
64  * where amounts of multiple commodities may be involved.
65  */
66 class balance_t
67   : public equality_comparable<balance_t,
68            equality_comparable<balance_t, amount_t,
69            equality_comparable<balance_t, double,
70            equality_comparable<balance_t, unsigned long,
71            equality_comparable<balance_t, long,
72            additive<balance_t,
73            additive<balance_t, amount_t,
74            additive<balance_t, double,
75            additive<balance_t, unsigned long,
76            additive<balance_t, long,
77            multiplicative<balance_t, amount_t,
78            multiplicative<balance_t, double,
79            multiplicative<balance_t, unsigned long,
80            multiplicative<balance_t, long> > > > > > > > > > > > > >
81 {
82 public:
83   typedef std::unordered_map<commodity_t *, amount_t> amounts_map;
84   typedef std::vector<const amount_t *> amounts_array;
85 
86   amounts_map amounts;
87 
88   /**
89    * Constructors.  balance_t supports similar forms of construction
90    * to amount_t.
91    *
92    * balance_t() creates an empty balance to which amounts or other
93    * balances may be added or subtracted.
94    *
95    * balance_t(amount_t) constructs a balance whose starting value is
96    * equal to the given amount.
97    *
98    * balance_t(double), balance_t(unsigned long) and balance_t(long)
99    * will construct an amount from their arguments and then construct
100    * a balance whose starting value is equal to that amount.  This
101    * initial balance will have no commodity.
102    *
103    * balance_t(string) and balance_t(const char *) both convert from a
104    * string representation of an amount to a balance whose initial
105    * value is that amount.  This is the proper way to initialize a
106    * balance like '$100.00'.
107    */
balance_t()108   balance_t() {
109     TRACE_CTOR(balance_t, "");
110   }
balance_t(const amount_t & amt)111   balance_t(const amount_t& amt) {
112     if (amt.is_null())
113       throw_(balance_error,
114              _("Cannot initialize a balance from an uninitialized amount"));
115     if (! amt.is_realzero())
116       amounts.insert(amounts_map::value_type(&amt.commodity(), amt));
117     TRACE_CTOR(balance_t, "const amount_t&");
118   }
119   balance_t(const double val);
120   balance_t(const unsigned long val);
121   balance_t(const long val);
122 
balance_t(const string & val)123   explicit balance_t(const string& val) {
124     amount_t temp(val);
125     amounts.insert(amounts_map::value_type(&temp.commodity(), temp));
126     TRACE_CTOR(balance_t, "const string&");
127   }
balance_t(const char * val)128   explicit balance_t(const char * val) {
129     amount_t temp(val);
130     amounts.insert(amounts_map::value_type(&temp.commodity(), temp));
131     TRACE_CTOR(balance_t, "const char *");
132   }
133 
134   /**
135    * Destructor.  Destroys all of the accumulated amounts in the
136    * balance.
137    */
~balance_t()138   ~balance_t() {
139     TRACE_DTOR(balance_t);
140   }
141 
142   /**
143    * Assignment and copy operators.  An balance may be assigned or copied.
144    */
balance_t(const balance_t & bal)145   balance_t(const balance_t& bal) : amounts(bal.amounts) {
146     TRACE_CTOR(balance_t, "copy");
147   }
148 
149   balance_t& operator=(const balance_t& bal) {
150     if (this != &bal)
151       amounts = bal.amounts;
152     return *this;
153   }
154   balance_t& operator=(const amount_t& amt) {
155     if (amt.is_null())
156       throw_(balance_error,
157              _("Cannot assign an uninitialized amount to a balance"));
158 
159     amounts.clear();
160     if (! amt.is_realzero())
161       amounts.insert(amounts_map::value_type(&amt.commodity(), amt));
162 
163     return *this;
164   }
165 
166   balance_t& operator=(const string& str) {
167     return *this = balance_t(str);
168   }
169   balance_t& operator=(const char * str) {
170     return *this = balance_t(str);
171   }
172 
173   /**
174    * Comparison operators.  Balances are fairly restrictive in terms
175    * of how they may be compared.  They may be compared for equality
176    * or inequality, but this is all, since the concept of "less than"
177    * or "greater than" makes no sense when amounts of multiple
178    * commodities are involved.
179    *
180    * Balances may also be compared to amounts, in which case the sum
181    * of the balance must equal the amount exactly.
182    *
183    * If a comparison between balances is desired, the balances must
184    * first be rendered to value equivalent amounts using the `value'
185    * method, to determine a market valuation at some specific moment
186    * in time.
187    */
188   bool operator==(const balance_t& bal) const {
189     return amounts == bal.amounts;
190   }
191   bool operator==(const amount_t& amt) const {
192     if (amt.is_null())
193       throw_(balance_error,
194              _("Cannot compare a balance to an uninitialized amount"));
195 
196     if (amt.is_realzero())
197       return amounts.empty();
198     else
199       return amounts.size() == 1 && amounts.begin()->second == amt;
200   }
201 
202   template <typename T>
203   bool operator==(const T& val) const {
204     return *this == amount_t(val);
205   }
206 
207   /**
208    * Binary arithmetic operators.  Balances support addition and
209    * subtraction of other balances or amounts, but multiplication and
210    * division are restricted to uncommoditized amounts only.
211    */
212   balance_t& operator+=(const balance_t& bal);
213   balance_t& operator+=(const amount_t& amt);
214   balance_t& operator+=(const double val) {
215     return *this += amount_t(val);
216   }
217   balance_t& operator+=(const unsigned long val) {
218     return *this += amount_t(val);
219   }
220   balance_t& operator+=(const long val) {
221     return *this += amount_t(val);
222   }
223 
224   balance_t& operator-=(const balance_t& bal);
225   balance_t& operator-=(const amount_t& amt);
226   balance_t& operator-=(const double val) {
227     return *this -= amount_t(val);
228   }
229   balance_t& operator-=(const unsigned long val) {
230     return *this -= amount_t(val);
231   }
232   balance_t& operator-=(const long val) {
233     return *this -= amount_t(val);
234   }
235 
236   balance_t& operator*=(const amount_t& amt);
237   balance_t& operator*=(const double val) {
238     return *this *= amount_t(val);
239   }
240   balance_t& operator*=(const unsigned long val) {
241     return *this *= amount_t(val);
242   }
243   balance_t& operator*=(const long val) {
244     return *this *= amount_t(val);
245   }
246 
247   balance_t& operator/=(const amount_t& amt);
248   balance_t& operator/=(const double val) {
249     return *this /= amount_t(val);
250   }
251   balance_t& operator/=(const unsigned long val) {
252     return *this /= amount_t(val);
253   }
254   balance_t& operator/=(const long val) {
255     return *this /= amount_t(val);
256   }
257 
258   /**
259    * Unary arithmetic operators.  There are only a few unary methods
260    * support on balance:
261    *
262    * negate(), also unary minus (- x), returns a balance all of whose
263    * component amounts have been negated.  In order words, it inverts
264    * the sign of all member amounts.
265    *
266    * abs() returns a balance where no component amount is negative.
267    *
268    * reduce() reduces the values in a balance to their most basic
269    * commodity forms, for amounts that utilize "scaling commodities".
270    * For example, a balance of 1h and 1m after reduction will be
271    * 3660s.
272    *
273    * unreduce(), if used with amounts that use "scaling commodities",
274    * yields the most compact form greater than 1.0 for each component
275    * amount.  That is, a balance of 10m and 1799s will unreduce to
276    * 39.98m.
277    *
278    * value(optional<datetime_t>) returns the total historical value for
279    * a balance -- the default moment returns a value based on the most
280    * recently known price -- based on the price history of its
281    * component commodities.  See amount_t::value for an example.
282    *
283    * Further, for the sake of efficiency and avoiding temporary
284    * objects, the following methods support "in-place" variants act on
285    * the balance itself and return a reference to the result
286    * (`*this'):
287    *
288    * in_place_negate()
289    * in_place_reduce()
290    * in_place_unreduce()
291    */
negated()292   balance_t negated() const {
293     balance_t temp(*this);
294     temp.in_place_negate();
295     return temp;
296   }
in_place_negate()297   void in_place_negate() {
298     foreach (amounts_map::value_type& pair, amounts)
299       pair.second.in_place_negate();
300   }
301   balance_t operator-() const {
302     return negated();
303   }
304 
abs()305   balance_t abs() const {
306     balance_t temp;
307     foreach (const amounts_map::value_type& pair, amounts)
308       temp += pair.second.abs();
309     return temp;
310   }
311 
rounded()312   balance_t rounded() const {
313     balance_t temp(*this);
314     temp.in_place_round();
315     return temp;
316   }
in_place_round()317   void in_place_round() {
318     foreach (amounts_map::value_type& pair, amounts)
319       pair.second.in_place_round();
320   }
321 
roundto(int places)322   balance_t roundto(int places) const {
323     balance_t temp(*this);
324     temp.in_place_roundto(places);
325     return temp;
326   }
327 
in_place_roundto(int places)328   void in_place_roundto(int places) {
329     foreach (amounts_map::value_type& pair, amounts)
330       pair.second.in_place_roundto(places);
331   }
332 
truncated()333   balance_t truncated() const {
334     balance_t temp(*this);
335     temp.in_place_truncate();
336     return temp;
337   }
in_place_truncate()338   void in_place_truncate() {
339     foreach (amounts_map::value_type& pair, amounts)
340       pair.second.in_place_truncate();
341   }
342 
floored()343   balance_t floored() const {
344     balance_t temp(*this);
345     temp.in_place_floor();
346     return temp;
347   }
in_place_floor()348   void in_place_floor() {
349     foreach (amounts_map::value_type& pair, amounts)
350       pair.second.in_place_floor();
351   }
352 
ceilinged()353   balance_t ceilinged() const {
354     balance_t temp(*this);
355     temp.in_place_ceiling();
356     return temp;
357   }
in_place_ceiling()358   void in_place_ceiling() {
359     foreach (amounts_map::value_type& pair, amounts)
360       pair.second.in_place_ceiling();
361   }
362 
363 
unrounded()364   balance_t unrounded() const {
365     balance_t temp(*this);
366     temp.in_place_unround();
367     return temp;
368   }
in_place_unround()369   void in_place_unround() {
370     foreach (amounts_map::value_type& pair, amounts)
371       pair.second.in_place_unround();
372   }
373 
reduced()374   balance_t reduced() const {
375     balance_t temp(*this);
376     temp.in_place_reduce();
377     return temp;
378   }
in_place_reduce()379   void in_place_reduce() {
380     // A temporary must be used here because reduction may cause
381     // multiple component amounts to collapse to the same commodity.
382     balance_t temp;
383     foreach (const amounts_map::value_type& pair, amounts)
384       temp += pair.second.reduced();
385     *this = temp;
386   }
387 
unreduced()388   balance_t unreduced() const {
389     balance_t temp(*this);
390     temp.in_place_unreduce();
391     return temp;
392   }
in_place_unreduce()393   void in_place_unreduce() {
394     // A temporary must be used here because unreduction may cause
395     // multiple component amounts to collapse to the same commodity.
396     balance_t temp;
397     foreach (const amounts_map::value_type& pair, amounts)
398       temp += pair.second.unreduced();
399     *this = temp;
400   }
401 
402   optional<balance_t>
403   value(const datetime_t&   moment      = datetime_t(),
404         const commodity_t * in_terms_of = NULL) const;
405 
406   /**
407    * Truth tests.  An balance may be truth test in two ways:
408    *
409    * is_nonzero(), or operator bool, returns true if a balance's
410    * display value is not zero.
411    *
412    * is_zero() returns true if an balance's display value is zero.
413    * Thus, a balance containing $0.0001 is considered zero if the
414    * current display precision for dollars is two decimal places.
415    *
416    * is_realzero() returns true if an balance's actual value is zero.
417    * Thus, a balance containing $0.0001 is never considered realzero.
418    *
419    * is_empty() returns true if a balance has no amounts within it.
420    * This can occur after a balance has been default initialized, or
421    * if the exact amount it contains is subsequently subtracted from
422    * it.
423    */
424   operator bool() const {
425     return is_nonzero();
426   }
427 
is_nonzero()428   bool is_nonzero() const {
429     if (is_empty())
430       return false;
431 
432     foreach (const amounts_map::value_type& pair, amounts)
433       if (pair.second.is_nonzero())
434         return true;
435     return false;
436   }
437 
is_zero()438   bool is_zero() const {
439     if (is_empty())
440       return true;
441 
442     foreach (const amounts_map::value_type& pair, amounts)
443       if (! pair.second.is_zero())
444         return false;
445     return true;
446   }
447 
is_realzero()448   bool is_realzero() const {
449     if (is_empty())
450       return true;
451 
452     foreach (const amounts_map::value_type& pair, amounts)
453       if (! pair.second.is_realzero())
454         return false;
455     return true;
456   }
457 
is_empty()458   bool is_empty() const {
459     return amounts.size() == 0;
460   }
single_amount()461   bool single_amount() const {
462     return amounts.size() == 1;
463   }
464 
465   /**
466    * Conversion methods.  A balance can be converted to an amount, but
467    * only if contains a single component amount.
468    */
string()469   operator string() const {
470     return to_string();
471   }
to_string()472   string to_string() const {
473     std::ostringstream buf;
474     print(buf);
475     return buf.str();
476   }
477 
to_amount()478   amount_t to_amount() const {
479     if (is_empty())
480       throw_(balance_error, _("Cannot convert an empty balance to an amount"));
481     else if (amounts.size() == 1)
482       return amounts.begin()->second;
483     else
484       throw_(balance_error,
485              _("Cannot convert a balance with multiple commodities to an amount"));
486     return amount_t();
487   }
488 
489   /**
490    * Commodity-related methods.  Balances support two
491    * commodity-related methods:
492    *
493    * commodity_count() returns the number of different commodities
494    * stored in the balance.
495    *
496    * commodity_amount(optional<commodity_t>) returns an (optional)
497    * amount for the given commodity within the balance; if no
498    * commodity is specified, it returns the (optional) uncommoditized
499    * component of the balance.  If no matching element can be found,
500    * boost::none is returned.
501    */
commodity_count()502   std::size_t commodity_count() const {
503     return amounts.size();
504   }
505 
506   optional<amount_t>
507   commodity_amount(const optional<const commodity_t&>& commodity = none) const;
508 
509   amounts_map::iterator find_by_name(const commodity_t& comm);
510   amounts_map::const_iterator find_by_name(const commodity_t& comm) const;
511 
number()512   balance_t number() const {
513     balance_t temp;
514     foreach (const amounts_map::value_type& pair, amounts)
515       temp += pair.second.number();
516     return temp;
517   }
518 
519   /**
520    * Annotated commodity methods.  The amounts contained by a balance
521    * may use annotated commodities.  The `strip_annotations' method
522    * will return a balance all of whose component amount have had
523    * their commodity annotations likewise stripped.  See
524    * amount_t::strip_annotations for more details.
525    */
526   balance_t strip_annotations(const keep_details_t& what_to_keep) const;
527 
528   /**
529    * Given a balance, insert a commodity-wise sort of the amounts into the
530    * given amounts_array.
531    */
532   void sorted_amounts(amounts_array& sorted) const;
533 
534   /**
535    * Iteration primitives.  `map_sorted_amounts' allows one to visit
536    * each amount in balance in the proper order for displaying to the
537    * user.  Mostly used by `print' and other routinse where the sort
538    * order of the amounts' commodities is significant.
539    */
540   void map_sorted_amounts(function<void(const amount_t&)> fn) const;
541 
542   /**
543    * Printing methods.  A balance may be output to a stream using the
544    * `print' method.  There is also a global operator<< defined which
545    * simply calls print for a balance on the given stream.  There is
546    * one form of the print method, which takes two required arguments
547    * and one arguments with a default value:
548    *
549    * print(ostream, int first_width, int latter_width) prints a
550    * balance to the given output stream, using each commodity's
551    * default display characteristics.  The first_width parameter
552    * specifies the width that should be used for printing amounts
553    * (since they are likely to vary in width).  The latter_width, if
554    * specified, gives the width to be used for each line after the
555    * first.  This is useful when printing in a column which falls at
556    * the right-hand side of the screen.
557    *
558    * In addition to the width constraints, balances will also print
559    * with commodities in alphabetized order, regardless of the
560    * relative amounts of those commodities.  There is no option to
561    * change this behavior.
562    */
563   void print(std::ostream&       out,
564              const int           first_width  = -1,
565              const int           latter_width = -1,
566              const uint_least8_t flags        = AMOUNT_PRINT_NO_FLAGS) const;
567 
568   /**
569    * Debugging methods.  There are two methods defined to help with
570    * debugging:
571    *
572    * dump(ostream) dumps a balance to an output stream.  There is
573    * little different from print(), it simply surrounds the display
574    * value with a marker, for example "BALANCE($1.00, DM 12.00)".
575    * This code is used by other dumping code elsewhere in Ledger.
576    *
577    * valid() returns true if the amounts within the balance are valid.
578    */
dump(std::ostream & out)579   void dump(std::ostream& out) const {
580     out << "BALANCE(";
581     bool first = true;
582     foreach (const amounts_map::value_type& pair, amounts) {
583       if (first)
584         first = false;
585       else
586         out << ", ";
587       pair.second.print(out);
588     }
589     out << ")";
590   }
591 
valid()592   bool valid() const {
593     foreach (const amounts_map::value_type& pair, amounts)
594       if (! pair.second.valid()) {
595         DEBUG("ledger.validate", "balance_t: ! pair.second.valid()");
596         return false;
597       }
598     return true;
599   }
600 };
601 
602 inline std::ostream& operator<<(std::ostream& out, const balance_t& bal) {
603   bal.print(out, 12);
604   return out;
605 }
606 
607 void put_balance(property_tree::ptree& pt, const balance_t& bal);
608 
609 balance_t average_lot_prices(const balance_t& bal);
610 
611 } // namespace ledger
612 
613 #endif // _BALANCE_H
614