summaryrefslogtreecommitdiff
path: root/src/value.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/value.cc')
-rw-r--r--src/value.cc140
1 files changed, 104 insertions, 36 deletions
diff --git a/src/value.cc b/src/value.cc
index 2446c97a..c14a7104 100644
--- a/src/value.cc
+++ b/src/value.cc
@@ -724,7 +724,7 @@ value_t& value_t::operator/=(const value_t& val)
return *this;
case AMOUNT:
if (as_balance().single_amount()) {
- in_place_simplify();
+ in_place_cast(AMOUNT);
as_amount_lval() /= val.as_amount();
return *this;
}
@@ -1228,7 +1228,7 @@ void value_t::in_place_cast(type_t cast_type)
case STRING:
switch (cast_type) {
case INTEGER: {
- if (all(as_string(), is_digit())) {
+ if (all(as_string(), is_any_of("-0123456789"))) {
set_long(lexical_cast<long>(as_string()));
return;
}
@@ -1266,8 +1266,8 @@ void value_t::in_place_cast(type_t cast_type)
}
add_error_context(_("While converting %1:") << *this);
- throw_(value_error, _("Cannot convert %1 to %2")
- << label() << label(cast_type));
+ throw_(value_error,
+ _("Cannot convert %1 to %2") << label() << label(cast_type));
}
void value_t::in_place_negate()
@@ -1399,25 +1399,30 @@ bool value_t::is_zero() const
return false;
}
-value_t value_t::value(const optional<datetime_t>& moment,
- const optional<commodity_t&>& in_terms_of) const
+value_t value_t::value(const datetime_t& moment,
+ const commodity_t * in_terms_of) const
{
switch (type()) {
case INTEGER:
return NULL_VALUE;
case AMOUNT:
- if (optional<amount_t> val =
- as_amount().value(moment, in_terms_of))
+ if (optional<amount_t> val = as_amount().value(moment, in_terms_of))
return *val;
return NULL_VALUE;
case BALANCE:
- if (optional<balance_t> bal =
- as_balance().value(moment, in_terms_of))
+ if (optional<balance_t> bal = as_balance().value(moment, in_terms_of))
return *bal;
return NULL_VALUE;
+ case SEQUENCE: {
+ value_t temp;
+ foreach (const value_t& value, as_sequence())
+ temp.push_back(value.value(moment, in_terms_of));
+ return temp;
+ }
+
default:
break;
}
@@ -1427,37 +1432,100 @@ value_t value_t::value(const optional<datetime_t>& moment,
return NULL_VALUE;
}
-value_t value_t::price() const
+value_t value_t::exchange_commodities(const std::string& commodities,
+ const bool add_prices,
+ const datetime_t& moment)
{
- switch (type()) {
- case AMOUNT:
- return as_amount().price();
- case BALANCE:
- return as_balance().price();
- default:
- return *this;
+ if (type() == SEQUENCE) {
+ value_t temp;
+ foreach (value_t& value, as_sequence_lval())
+ temp.push_back(value.exchange_commodities(commodities, add_prices, moment));
+ return temp;
}
-}
-value_t value_t::exchange_commodities(const std::string& commodities,
- const bool add_prices,
- const optional<datetime_t>& moment)
-{
- scoped_array<char> buf(new char[commodities.length() + 1]);
-
- std::strcpy(buf.get(), commodities.c_str());
-
- for (char * p = std::strtok(buf.get(), ",");
- p;
- p = std::strtok(NULL, ",")) {
- if (commodity_t * commodity =
- commodity_pool_t::current_pool->parse_price_expression(p, add_prices,
- moment)) {
- value_t result = value(moment, *commodity);
- if (! result.is_null())
- return result;
+ // If we are repricing to just a single commodity, with no price
+ // expression, skip the expensive logic below.
+ if (commodities.find(',') == string::npos &&
+ commodities.find('=') == string::npos)
+ return value(moment, commodity_pool_t::current_pool->find_or_create(commodities));
+
+ std::vector<commodity_t *> comms;
+ std::vector<bool> force;
+
+ typedef tokenizer<char_separator<char> > tokenizer;
+ tokenizer tokens(commodities, char_separator<char>(","));
+
+ foreach (const string& name, tokens) {
+ string::size_type name_len = name.length();
+
+ if (commodity_t * commodity = commodity_pool_t::current_pool
+ ->parse_price_expression(name[name_len - 1] == '!' ?
+ string(name, 0, name_len - 1) :
+ name, add_prices, moment)) {
+ DEBUG("commodity.exchange", "Pricing for commodity: " << commodity->symbol());
+ comms.push_back(&commodity->referent());
+ force.push_back(name[name_len - 1] == '!');
}
}
+
+ std::size_t index = 0;
+ foreach (commodity_t * comm, comms) {
+ switch (type()) {
+ case AMOUNT:
+ DEBUG("commodity.exchange", "We have an amount: " << as_amount_lval());
+ if (! force[index] &&
+ std::find(comms.begin(), comms.end(),
+ &as_amount_lval().commodity().referent()) != comms.end())
+ break;
+
+ DEBUG("commodity.exchange", "Referent doesn't match, pricing...");
+ if (optional<amount_t> val = as_amount_lval().value(moment, comm)) {
+ DEBUG("commodity.exchange", "Re-priced amount is: " << *val);
+ return *val;
+ }
+ DEBUG("commodity.exchange", "Was unable to find a price");
+ break;
+
+ case BALANCE: {
+ balance_t temp;
+ bool repriced = false;
+
+ DEBUG("commodity.exchange", "We have a balance: " << as_balance_lval());
+ foreach (const balance_t::amounts_map::value_type& pair,
+ as_balance_lval().amounts) {
+ DEBUG("commodity.exchange", "We have a balance amount of commodity: "
+ << pair.first->symbol() << " == "
+ << pair.second.commodity().symbol());
+ if (! force[index] &&
+ std::find(comms.begin(), comms.end(),
+ &pair.first->referent()) != comms.end()) {
+ temp += pair.second;
+ } else {
+ DEBUG("commodity.exchange", "Referent doesn't match, pricing...");
+ if (optional<amount_t> val = pair.second.value(moment, comm)) {
+ DEBUG("commodity.exchange", "Re-priced member amount is: " << *val);
+ temp += *val;
+ repriced = true;
+ } else {
+ DEBUG("commodity.exchange", "Was unable to find price");
+ temp += pair.second;
+ }
+ }
+ }
+
+ if (repriced) {
+ DEBUG("commodity.exchange", "Re-priced balance is: " << temp);
+ return temp;
+ }
+ }
+
+ default:
+ break;
+ }
+
+ ++index;
+ }
+
return *this;
}