summaryrefslogtreecommitdiff
path: root/amount.h
diff options
context:
space:
mode:
Diffstat (limited to 'amount.h')
-rw-r--r--amount.h244
1 files changed, 244 insertions, 0 deletions
diff --git a/amount.h b/amount.h
new file mode 100644
index 00000000..bfcea2c2
--- /dev/null
+++ b/amount.h
@@ -0,0 +1,244 @@
+#ifndef _AMOUNT_H
+#define _AMOUNT_H
+
+#include <map>
+#include <string>
+#include <ctime>
+#include <iostream>
+#include <sstream>
+
+namespace ledger {
+
+class commodity_t;
+
+class amount_t
+{
+ typedef void * base_type;
+
+ void _init();
+ void _copy(const amount_t& amt);
+ void _clear();
+
+ public:
+ base_type quantity; // amount, to MAX_PRECISION
+ commodity_t * commodity;
+
+ bool valid() const {
+ if (quantity)
+ return commodity != NULL;
+ else
+ return commodity == NULL;
+ }
+
+ // constructors
+ amount_t(commodity_t * _commodity = NULL)
+ : quantity(NULL), commodity(_commodity) {}
+
+ amount_t(const amount_t& amt) : quantity(NULL) {
+ if (amt.quantity)
+ _copy(amt);
+ else
+ commodity = amt.commodity;
+ }
+ amount_t(const std::string& value) {
+ _init();
+ std::istringstream str(value);
+ str >> *this;
+ }
+ amount_t(const bool value);
+ amount_t(const int value);
+ amount_t(const unsigned int value);
+ amount_t(const double value);
+
+ // destructor
+ ~amount_t() {
+ if (quantity)
+ _clear();
+ }
+
+ // assignment operator
+ amount_t& operator=(const amount_t& amt);
+ amount_t& operator=(const std::string& value);
+ amount_t& operator=(const bool value);
+ amount_t& operator=(const int value);
+ amount_t& operator=(const unsigned int value);
+ amount_t& operator=(const double value);
+
+ // general methods
+ amount_t round(int precision = -1) 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);
+ amount_t& operator-=(const amount_t& amt);
+
+ // 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;
+ }
+ amount_t operator-(const amount_t& amt) const {
+ amount_t temp = *this;
+ temp -= amt;
+ return temp;
+ }
+
+ // unary negation
+ amount_t& negate();
+ amount_t negated() const {
+ amount_t temp = *this;
+ temp.negate();
+ return temp;
+ }
+ amount_t operator-() const {
+ return negated();
+ }
+
+ // test for non-zero (use ! for zero)
+ operator bool() const;
+
+ // comparisons to zero
+ bool operator<(const int num) const;
+ bool operator<=(const int num) const;
+ bool operator>(const int num) const;
+ bool operator>=(const int num) const;
+
+ // comparisons between amounts
+ bool operator<(const amount_t& amt) const;
+ bool operator<=(const amount_t& amt) const;
+ bool operator>(const amount_t& amt) const;
+ bool operator>=(const amount_t& amt) const;
+ bool operator==(const amount_t& amt) const;
+ bool operator!=(const amount_t& amt) const {
+ if (commodity != amt.commodity)
+ return true;
+ return ! (*this == amt);
+ }
+
+ amount_t value(const std::time_t moment) const;
+
+ operator std::string() const;
+
+ void parse(std::istream& in);
+ void parse(const std::string& str) {
+ std::istringstream stream(str);
+ parse(stream);
+ }
+
+ void write_quantity(std::ostream& out) const;
+ void read_quantity(std::istream& in);
+
+ friend std::istream& operator>>(std::istream& in, amount_t& amt);
+};
+
+void parse_quantity(std::istream& in, std::string& value);
+void parse_commodity(std::istream& in, std::string& symbol);
+
+inline amount_t abs(const amount_t& amt) {
+ return amt < 0 ? amt.negated() : amt;
+}
+
+inline std::istream& operator>>(std::istream& in, amount_t& amt) {
+ amt.parse(in);
+ return in;
+}
+
+std::ostream& operator<<(std::ostream& out, const amount_t& amt);
+
+
+#define COMMODITY_STYLE_DEFAULTS 0x00
+#define COMMODITY_STYLE_SUFFIXED 0x01
+#define COMMODITY_STYLE_SEPARATED 0x02
+#define COMMODITY_STYLE_EUROPEAN 0x04
+#define COMMODITY_STYLE_THOUSANDS 0x08
+#define COMMODITY_STYLE_CONSULTED 0x10
+#define COMMODITY_STYLE_NOMARKET 0x20
+
+typedef std::map<const std::time_t, amount_t> history_map;
+typedef std::pair<const std::time_t, amount_t> history_pair;
+
+typedef std::map<const std::string, commodity_t *> commodities_map;
+typedef std::pair<const std::string, commodity_t *> commodities_pair;
+
+class commodity_t
+{
+ public:
+ std::string symbol;
+ std::string name;
+ std::string note;
+ unsigned int precision;
+ unsigned int flags;
+ history_map history;
+ amount_t conversion;
+ unsigned long ident;
+
+ // If set, this global function pointer is called to determine
+ // whether prices have been updated in the meanwhile.
+
+ static void (*updater)(commodity_t * commodity,
+ const std::time_t date,
+ const amount_t& price,
+ const std::time_t moment);
+
+ // This map remembers all commodities that have been
+ // defined thus far.
+
+ static commodities_map commodities;
+ static commodity_t * null_commodity;
+
+ static void add_commodity(commodity_t * commodity,
+ const std::string symbol = "") {
+ commodities.insert(commodities_pair((symbol.empty() ?
+ commodity->symbol : symbol),
+ commodity));
+ }
+ static bool remove_commodity(commodity_t * commodity) {
+ commodities_map::size_type n = commodities.erase(commodity->symbol);
+ return n > 0;
+ }
+ static commodity_t * find_commodity(const std::string& symbol,
+ bool auto_create = false);
+
+ // Now the per-object constructor and methods
+
+ commodity_t(const std::string& _symbol = "",
+ unsigned int _precision = 2,
+ unsigned int _flags = COMMODITY_STYLE_DEFAULTS)
+ : symbol(_symbol), precision(_precision), flags(_flags) {}
+
+ void add_price(const std::time_t date, const amount_t& price) {
+ history.insert(history_pair(date, price));
+ }
+ bool remove_price(const std::time_t date) {
+ history_map::size_type n = history.erase(date);
+ return n > 0;
+ }
+
+ void set_conversion(const amount_t& price) {
+ conversion = price;
+ }
+
+ amount_t value(const std::time_t moment = std::time(NULL));
+};
+
+} // namespace ledger
+
+#endif // _AMOUNT_H