diff options
Diffstat (limited to 'src/pool.cc')
-rw-r--r-- | src/pool.cc | 267 |
1 files changed, 99 insertions, 168 deletions
diff --git a/src/pool.cc b/src/pool.cc index 65edbd6a..61b5bef2 100644 --- a/src/pool.cc +++ b/src/pool.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2010, John Wiegley. All rights reserved. + * Copyright (c) 2003-2012, 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 @@ -35,6 +35,7 @@ #include "commodity.h" #include "annotate.h" #include "pool.h" +#include "history.h" #include "quotes.h" namespace ledger { @@ -46,16 +47,16 @@ commodity_pool_t::commodity_pool_t() quote_leeway(86400), get_quotes(false), get_commodity_quote(commodity_quote_from_script) { - TRACE_CTOR(commodity_pool_t, ""); null_commodity = create(""); null_commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET); + TRACE_CTOR(commodity_pool_t, ""); } commodity_t * commodity_pool_t::create(const string& symbol) { shared_ptr<commodity_t::base_t> base_commodity(new commodity_t::base_t(symbol)); - std::auto_ptr<commodity_t> commodity(new commodity_t(this, base_commodity)); + shared_ptr<commodity_t> commodity(new commodity_t(this, base_commodity)); DEBUG("pool.commodities", "Creating base commodity " << symbol); @@ -66,25 +67,19 @@ commodity_t * commodity_pool_t::create(const string& symbol) *commodity->qualified_symbol += "\""; } - DEBUG("pool.commodities", - "Creating commodity '" << commodity->symbol() << "'"); + DEBUG("pool.commodities", "Creating commodity '" << symbol << "'"); - std::pair<commodities_map::iterator, bool> result - = commodities.insert(commodities_map::value_type(commodity->mapping_key(), - commodity.get())); +#if defined(DEBUG_ON) + std::pair<commodities_map::iterator, bool> result = +#endif + commodities.insert(commodities_map::value_type(symbol, commodity)); +#if defined(DEBUG_ON) assert(result.second); +#endif - return commodity.release(); -} - -commodity_t * commodity_pool_t::find_or_create(const string& symbol) -{ - DEBUG("pool.commodities", "Find-or-create commodity " << symbol); + commodity_price_history.add_commodity(*commodity.get()); - commodity_t * commodity = find(symbol); - if (commodity) - return commodity; - return create(symbol); + return commodity.get(); } commodity_t * commodity_pool_t::find(const string& symbol) @@ -93,91 +88,111 @@ commodity_t * commodity_pool_t::find(const string& symbol) commodities_map::const_iterator i = commodities.find(symbol); if (i != commodities.end()) - return (*i).second; + return (*i).second.get(); return NULL; } -commodity_t * -commodity_pool_t::create(const string& symbol, const annotation_t& details) +commodity_t * commodity_pool_t::find_or_create(const string& symbol) { - commodity_t * new_comm = create(symbol); - if (! new_comm) - return NULL; - - if (details) - return find_or_create(*new_comm, details); - else - return new_comm; + DEBUG("pool.commodities", "Find-or-create commodity " << symbol); + if (commodity_t * commodity = find(symbol)) + return commodity; + return create(symbol); } -string commodity_pool_t::make_qualified_name(const commodity_t& comm, - const annotation_t& details) +commodity_t * commodity_pool_t::alias(const string& name, commodity_t& referent) { - assert(details); + commodities_map::const_iterator i = commodities.find(referent.base_symbol()); + assert(i != commodities.end()); - if (details.price && details.price->sign() < 0) - throw_(amount_error, _("A commodity's price may not be negative")); + std::pair<commodities_map::iterator, bool> result + = commodities.insert(commodities_map::value_type(name, (*i).second)); + assert(result.second); - std::ostringstream name; - comm.print(name); - details.print(name, comm.pool().keep_base); + return (*result.first).second.get(); +} -#if defined(DEBUG_ON) - if (comm.qualified_symbol) - DEBUG("pool.commodities", "make_qualified_name for " - << *comm.qualified_symbol << std::endl << details); -#endif - DEBUG("pool.commodities", "qualified_name is " << name.str()); +commodity_t * +commodity_pool_t::create(const string& symbol, const annotation_t& details) +{ + DEBUG("pool.commodities", "commodity_pool_t::create[ann] " + << "symbol " << symbol << std::endl << details); - return name.str(); + if (details) + return create(*find_or_create(symbol), details); + else + return create(symbol); } commodity_t * commodity_pool_t::find(const string& symbol, const annotation_t& details) { - commodity_t * comm = find(symbol); - if (! comm) + DEBUG("pool.commodities", "commodity_pool_t::find[ann] " + << "symbol " << symbol << std::endl << details); + + annotated_commodities_map::const_iterator i = + annotated_commodities.find + (annotated_commodities_map::key_type(symbol, details)); + if (i != annotated_commodities.end()) { + DEBUG("pool.commodities", "commodity_pool_t::find[ann] found " + << "symbol " << (*i).second->base_symbol() << std::endl + << as_annotated_commodity(*(*i).second.get()).details); + return (*i).second.get(); + } else { return NULL; + } +} - if (details) { - string name = make_qualified_name(*comm, details); +commodity_t * +commodity_pool_t::find_or_create(const string& symbol, + const annotation_t& details) +{ + DEBUG("pool.commodities", "commodity_pool_t::find_or_create[ann] " + << "symbol " << symbol << std::endl << details); - if (commodity_t * ann_comm = find(name)) { + if (details) { + if (commodity_t * ann_comm = find(symbol, details)) { assert(ann_comm->annotated && as_annotated_commodity(*ann_comm).details); return ann_comm; + } else { + return create(symbol, details); } - return NULL; } else { - return comm; + return find_or_create(symbol); } } commodity_t * -commodity_pool_t::find_or_create(const string& symbol, - const annotation_t& details) +commodity_pool_t::find_or_create(commodity_t& comm, const annotation_t& details) { - commodity_t * comm = find_or_create(symbol); - if (! comm) - return NULL; + DEBUG("pool.commodities", "commodity_pool_t::find_or_create[ann:comm] " + << "symbol " << comm.base_symbol() << std::endl << details); - if (details) - return find_or_create(*comm, details); - else - return comm; + if (details) { + if (commodity_t * ann_comm = find(comm.base_symbol(), details)) { + assert(ann_comm->annotated && as_annotated_commodity(*ann_comm).details); + return ann_comm; + } else { + return create(comm, details); + } + } else { + return &comm; + } } -commodity_t * +annotated_commodity_t * commodity_pool_t::create(commodity_t& comm, - const annotation_t& details, - const string& mapping_key) + const annotation_t& details) { + DEBUG("pool.commodities", "commodity_pool_t::create[ann:comm] " + << "symbol " << comm.base_symbol() << std::endl << details); + assert(comm); assert(! comm.has_annotation()); assert(details); - assert(! mapping_key.empty()); - unique_ptr<commodity_t> commodity - (new annotated_commodity_t(&comm, details)); + shared_ptr<annotated_commodity_t> + commodity(new annotated_commodity_t(&comm, details)); comm.add_flags(COMMODITY_SAW_ANNOTATED); if (details.price) { @@ -187,39 +202,21 @@ commodity_pool_t::create(commodity_t& comm, comm.add_flags(COMMODITY_SAW_ANN_PRICE_FLOAT); } - commodity->qualified_symbol = comm.symbol(); - assert(! commodity->qualified_symbol->empty()); - DEBUG("pool.commodities", "Creating annotated commodity " - << "symbol " << commodity->symbol() - << " key " << mapping_key << std::endl << details); + << "symbol " << commodity->base_symbol() + << std::endl << details); - // Add the fully annotated name to the map, so that this symbol may - // quickly be found again. - commodity->mapping_key_ = mapping_key; - - std::pair<commodities_map::iterator, bool> result - = commodities.insert(commodities_map::value_type(mapping_key, - commodity.get())); +#if defined(DEBUG_ON) + std::pair<annotated_commodities_map::iterator, bool> result = +#endif + annotated_commodities.insert(annotated_commodities_map::value_type + (annotated_commodities_map::key_type + (comm.base_symbol(), details), commodity)); +#if defined(DEBUG_ON) assert(result.second); +#endif - return commodity.release(); -} - -commodity_t * commodity_pool_t::find_or_create(commodity_t& comm, - const annotation_t& details) -{ - assert(comm); - assert(details); - - string name = make_qualified_name(comm, details); - assert(! name.empty()); - - if (commodity_t * ann_comm = find(name)) { - assert(ann_comm->annotated && as_annotated_commodity(*ann_comm).details); - return ann_comm; - } - return create(comm, details, name); + return commodity.get(); } void commodity_pool_t::exchange(commodity_t& commodity, @@ -240,6 +237,7 @@ cost_breakdown_t commodity_pool_t::exchange(const amount_t& amount, const amount_t& cost, const bool is_per_unit, + const bool add_price, const optional<datetime_t>& moment, const optional<string>& tag) { @@ -261,6 +259,9 @@ commodity_pool_t::exchange(const amount_t& amount, amount_t per_unit_cost = (is_per_unit || amount.is_realzero()) ? cost.abs() : (cost / amount).abs(); + if (! cost.has_commodity()) + per_unit_cost.clear_commodity(); + DEBUG("commodity.prices.add", "exchange: per-unit-cost = " << per_unit_cost); // Do not record commodity exchanges where amount's commodity has a @@ -269,8 +270,10 @@ commodity_pool_t::exchange(const amount_t& amount, if (! per_unit_cost.is_realzero() && (current_annotation == NULL || ! (current_annotation->price && - current_annotation->has_flags(ANNOTATION_PRICE_FIXATED)))) + current_annotation->has_flags(ANNOTATION_PRICE_FIXATED))) && + commodity.referent() != per_unit_cost.commodity().referent()) { exchange(commodity, per_unit_cost, moment ? *moment : CURRENT_TIME()); + } cost_breakdown_t breakdown; breakdown.final_cost = ! is_per_unit ? cost : cost * amount.abs(); @@ -382,76 +385,4 @@ commodity_pool_t::parse_price_expression(const std::string& str, return NULL; } -void commodity_pool_t::print_pricemap(std::ostream& out, - const keep_details_t& keep, - const optional<datetime_t>& moment) -{ - typedef std::map<commodity_t *, commodity_t *> comm_map_t; - - comm_map_t comm_map; - - foreach (const commodities_map::value_type& comm_pair, commodities) { - commodity_t * comm(&comm_pair.second->strip_annotations(keep)); - comm_map.insert(comm_map_t::value_type(comm, NULL)); - } - - out << "digraph commodities {\n"; - - foreach (const comm_map_t::value_type& comm_pair, comm_map) { - commodity_t * comm(comm_pair.first); - if (comm->has_flags(COMMODITY_BUILTIN)) - continue; - - out << " "; - if (commodity_t::symbol_needs_quotes(comm->symbol())) - out << comm->symbol() << ";\n"; - else - out << "\"" << comm->symbol() << "\";\n"; - - if (! comm->has_flags(COMMODITY_NOMARKET) && - (! commodity_pool_t::current_pool->default_commodity || - comm != commodity_pool_t::current_pool->default_commodity)) { - if (optional<commodity_t::varied_history_t&> vhist = - comm->varied_history()) { - foreach (const commodity_t::history_by_commodity_map::value_type& pair, - vhist->histories) { - datetime_t most_recent; - amount_t most_recent_amt; - foreach (const commodity_t::history_map::value_type& inner_pair, - pair.second.prices) { - if ((most_recent.is_not_a_date_time() || - inner_pair.first > most_recent) && - (! moment || inner_pair.first <= moment)) { - most_recent = inner_pair.first; - most_recent_amt = inner_pair.second; - } - } - - if (! most_recent.is_not_a_date_time()) { - out << " "; - if (commodity_t::symbol_needs_quotes(comm->symbol())) - out << comm->symbol(); - else - out << "\"" << comm->symbol() << "\""; - - out << " -> "; - - if (commodity_t::symbol_needs_quotes(pair.first->symbol())) - out << pair.first->symbol(); - else - out << "\"" << pair.first->symbol() << "\""; - - out << " [label=\"" - << most_recent_amt.number() << "\\n" - << format_date(most_recent.date(), FMT_WRITTEN) - << "\" fontcolor=\"#008e28\"];\n"; - } - } - } - } - } - - out << "}\n"; -} - } // namespace ledger |