diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/amount.cc | 266 | ||||
-rw-r--r-- | src/amount.h | 12 | ||||
-rw-r--r-- | src/commodity.h | 16 |
3 files changed, 153 insertions, 141 deletions
diff --git a/src/amount.cc b/src/amount.cc index 6558a1cd..65720ddd 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -56,18 +56,28 @@ bool amount_t::keep_tag = false; bool amount_t::full_strings = false; +#ifndef THREADSAFE +/** + * These global temporaries are pre-initialized for the sake of + * efficiency, and reused over and over again. + */ +static mpz_t temp; +static mpz_t divisor; +#endif + +struct amount_t::bigint_t +{ #define BIGINT_BULK_ALLOC 0x01 #define BIGINT_KEEP_PREC 0x02 -class amount_t::bigint_t -{ - public: mpz_t val; precision_t prec; flags_t flags; uint_least16_t ref; uint_fast32_t index; +#define MPZ(bigint) ((bigint)->val) + bigint_t() : prec(0), flags(0), ref(1), index(0) { TRACE_CTOR(bigint_t, ""); mpz_init(val); @@ -82,22 +92,13 @@ class amount_t::bigint_t TRACE_CTOR(bigint_t, "copy"); mpz_init_set(val, other.val); } - ~bigint_t(); + ~bigint_t() { + TRACE_DTOR(bigint_t); + assert(ref == 0); + mpz_clear(val); + } }; -#define MPZ(x) ((x)->val) - -#ifndef THREADSAFE -static mpz_t temp; // these are the global temp variables -static mpz_t divisor; -#endif - -inline amount_t::bigint_t::~bigint_t() { - TRACE_DTOR(bigint_t); - assert(ref == 0); - mpz_clear(val); -} - void amount_t::initialize() { mpz_init(temp); @@ -582,6 +583,11 @@ amount_t& amount_t::operator/=(const amount_t& amt) } +amount_t::precision_t amount_t::precision() const +{ + return quantity->prec; +} + amount_t& amount_t::in_place_negate() { if (quantity) { @@ -805,135 +811,137 @@ annotation_t amount_t::annotation_details() const return annotation_t(); } -static void parse_quantity(std::istream& in, string& value) -{ - char buf[256]; - char c = peek_next_nonws(in); - READ_INTO(in, buf, 255, c, - std::isdigit(c) || c == '-' || c == '.' || c == ','); - - int len = std::strlen(buf); - while (len > 0 && ! std::isdigit(buf[len - 1])) { - buf[--len] = '\0'; - in.unget(); - } - - value = buf; -} - -// Invalid commodity characters: -// SPACE, TAB, NEWLINE, RETURN -// 0-9 . , ; - + * / ^ ? : & | ! = -// < > { } [ ] ( ) @ - -int invalid_chars[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -/* 00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, -/* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -/* 20 */ 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, -/* 30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -/* 40 */ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -/* 50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, -/* 60 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -/* 70 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, -/* 80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -/* 90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -/* a0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -/* b0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -/* c0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -/* d0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -/* e0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -/* f0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; +namespace { + void parse_quantity(std::istream& in, string& value) + { + char buf[256]; + char c = peek_next_nonws(in); + READ_INTO(in, buf, 255, c, + std::isdigit(c) || c == '-' || c == '.' || c == ','); -static void parse_commodity(std::istream& in, string& symbol) -{ - char buf[256]; - char c = peek_next_nonws(in); - if (c == '"') { - in.get(c); - READ_INTO(in, buf, 255, c, c != '"'); - if (c == '"') - in.get(c); - else - throw_(amount_error, "Quoted commodity symbol lacks closing quote"); - } else { - READ_INTO(in, buf, 255, c, ! invalid_chars[(unsigned char)c]); - } - symbol = buf; -} + int len = std::strlen(buf); + while (len > 0 && ! std::isdigit(buf[len - 1])) { + buf[--len] = '\0'; + in.unget(); + } -bool parse_annotations(std::istream& in, annotation_t& details) -{ - do { + value = buf; + } + + // Invalid commodity characters: + // SPACE, TAB, NEWLINE, RETURN + // 0-9 . , ; - + * / ^ ? : & | ! = + // < > { } [ ] ( ) @ + + int invalid_chars[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* 00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, + /* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 20 */ 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, + /* 30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 40 */ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, + /* 60 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 70 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, + /* 80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* a0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* b0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* c0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* d0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* e0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* f0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + + static void parse_commodity(std::istream& in, string& symbol) + { char buf[256]; char c = peek_next_nonws(in); - if (c == '{') { - if (details.price) - throw_(amount_error, "Commodity specifies more than one price"); - + if (c == '"') { in.get(c); - READ_INTO(in, buf, 255, c, c != '}'); - if (c == '}') + READ_INTO(in, buf, 255, c, c != '"'); + if (c == '"') in.get(c); else - throw_(amount_error, "Commodity price lacks closing brace"); + throw_(amount_error, "Quoted commodity symbol lacks closing quote"); + } else { + READ_INTO(in, buf, 255, c, ! invalid_chars[(unsigned char)c]); + } + symbol = buf; + } - amount_t temp; - temp.parse(buf, AMOUNT_PARSE_NO_MIGRATE); - temp.in_place_reduce(); + bool parse_annotations(std::istream& in, annotation_t& details) + { + do { + char buf[256]; + char c = peek_next_nonws(in); + if (c == '{') { + if (details.price) + throw_(amount_error, "Commodity specifies more than one price"); - // Since this price will maintain its own precision, make sure - // it is at least as large as the base commodity, since the user - // may have only specified {$1} or something similar. + in.get(c); + READ_INTO(in, buf, 255, c, c != '}'); + if (c == '}') + in.get(c); + else + throw_(amount_error, "Commodity price lacks closing brace"); - if (temp.has_commodity() && - temp.quantity->prec < temp.commodity().precision()) - temp = temp.round(); // no need to retain individual precision + amount_t temp; + temp.parse(buf, AMOUNT_PARSE_NO_MIGRATE); + temp.in_place_reduce(); - details.price = temp; - } - else if (c == '[') { - if (details.date) - throw_(amount_error, "Commodity specifies more than one date"); + // Since this price will maintain its own precision, make sure + // it is at least as large as the base commodity, since the user + // may have only specified {$1} or something similar. + + if (temp.has_commodity() && + temp.precision() < temp.commodity().precision()) + temp = temp.round(); // no need to retain individual precision + + details.price = temp; + } + else if (c == '[') { + if (details.date) + throw_(amount_error, "Commodity specifies more than one date"); - in.get(c); - READ_INTO(in, buf, 255, c, c != ']'); - if (c == ']') in.get(c); - else - throw_(amount_error, "Commodity date lacks closing bracket"); + READ_INTO(in, buf, 255, c, c != ']'); + if (c == ']') + in.get(c); + else + throw_(amount_error, "Commodity date lacks closing bracket"); - details.date = parse_datetime(buf); - } - else if (c == '(') { - if (details.tag) - throw_(amount_error, "Commodity specifies more than one tag"); + details.date = parse_datetime(buf); + } + else if (c == '(') { + if (details.tag) + throw_(amount_error, "Commodity specifies more than one tag"); - in.get(c); - READ_INTO(in, buf, 255, c, c != ')'); - if (c == ')') in.get(c); - else - throw_(amount_error, "Commodity tag lacks closing parenthesis"); + READ_INTO(in, buf, 255, c, c != ')'); + if (c == ')') + in.get(c); + else + throw_(amount_error, "Commodity tag lacks closing parenthesis"); - details.tag = buf; - } - else { - break; - } - } while (true); - - DEBUG("amounts.commodities", - "Parsed commodity annotations: " - << " price " - << (details.price ? details.price->to_string() : "NONE") << " " - << " date " - << (details.date ? *details.date : moment_t()) << " " - << " tag " - << (details.tag ? *details.tag : "NONE")); - - return details; + details.tag = buf; + } + else { + break; + } + } while (true); + + DEBUG("amounts.commodities", + "Parsed commodity annotations: " + << " price " + << (details.price ? details.price->to_string() : "NONE") << " " + << " date " + << (details.date ? *details.date : moment_t()) << " " + << " tag " + << (details.tag ? *details.tag : "NONE")); + + return details; + } } void amount_t::parse(std::istream& in, flags_t flags) diff --git a/src/amount.h b/src/amount.h index 3b94a802..6f5137ab 100644 --- a/src/amount.h +++ b/src/amount.h @@ -148,7 +148,7 @@ protected: void _clear(); void _release(); - class bigint_t; + struct bigint_t; bigint_t * quantity; commodity_t * commodity_; @@ -278,6 +278,11 @@ public: * Unary arithmetic operators. There are several unary methods * support on amounts: * + * precision() return an amount's current, internal precision. To + * find the precision it will be displayed at -- assuming it was not + * created using the static method `amount_t::exact' -- refer to + * commodity().precision. + * * negate(), also unary minus (- x), returns the negated value of an * amount. * @@ -318,6 +323,8 @@ public: * in_place_reduce() * in_place_unreduce() */ + precision_t precision() const; + amount_t negate() const { amount_t temp = *this; temp.in_place_negate(); @@ -624,9 +631,6 @@ public: } bool valid() const; - -private: - friend bool parse_annotations(std::istream& in, annotation_t& details); }; inline amount_t amount_t::exact(const string& value) { diff --git a/src/commodity.h b/src/commodity.h index 9efa0051..93c1f3be 100644 --- a/src/commodity.h +++ b/src/commodity.h @@ -73,14 +73,14 @@ class commodity_t #define COMMODITY_STYLE_NOMARKET 0x10 #define COMMODITY_STYLE_BUILTIN 0x20 - flags_t flags; - string symbol; - amount_t::precision_t precision; - optional<string> name; - optional<string> note; - optional<history_t> history; - optional<amount_t> smaller; - optional<amount_t> larger; + flags_t flags; + string symbol; + amount_t::precision_t precision; + optional<string> name; + optional<string> note; + optional<history_t> history; + optional<amount_t> smaller; + optional<amount_t> larger; public: explicit base_t() |