ledger/src/commodity.h
John Wiegley 094794c640 Added a --european flag, to use commas for decimals
Ledger can often figure this out for itself, but this flag just makes it
the default behavior.  It is meant to be added to one's ~/.ledgerrc
file.
2009-11-02 02:39:31 -05:00

440 lines
11 KiB
C++

/*
* Copyright (c) 2003-2009, 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
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of New Artisans LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @addtogroup math
*/
/**
* @file commodity.h
* @author John Wiegley
*
* @ingroup math
*
* @brief Types for handling commodities
*
* This file contains one of the most basic types in Ledger:
* commodity_t, and its annotated cousin, annotated_commodity_t.
*/
#ifndef _COMMODITY_H
#define _COMMODITY_H
namespace ledger {
class keep_details_t;
DECLARE_EXCEPTION(commodity_error, std::runtime_error);
/**
* @brief Brief
*
* Long.
*/
struct price_point_t
{
datetime_t when;
amount_t price;
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & when;
ar & price;
}
#endif // HAVE_BOOST_SERIALIZATION
};
/**
* @brief Brief
*
* Long.
*/
class commodity_t
: public delegates_flags<uint_least16_t>,
public equality_comparable1<commodity_t, noncopyable>
{
friend class commodity_pool_t;
public:
class base_t : public noncopyable, public supports_flags<uint_least16_t>
{
base_t() {
TRACE_CTOR(base_t, "");
}
public:
typedef std::map<const datetime_t, amount_t> history_map;
struct history_t
{
history_map prices;
void add_price(commodity_t& source,
const datetime_t& date,
const amount_t& price,
const bool reflexive = true);
bool remove_price(const datetime_t& date);
optional<price_point_t>
find_price(const optional<datetime_t>& moment = none,
const optional<datetime_t>& oldest = none
#if defined(DEBUG_ON)
, const int indent = 0
#endif
) const;
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & prices;
}
#endif // HAVE_BOOST_SERIALIZATION
};
typedef std::map<commodity_t *, history_t> history_by_commodity_map;
struct varied_history_t
{
history_by_commodity_map histories;
void add_price(commodity_t& source,
const datetime_t& date,
const amount_t& price,
const bool reflexive = true);
bool remove_price(const datetime_t& date, commodity_t& commodity);
optional<price_point_t>
find_price(const commodity_t& source,
const optional<commodity_t&>& commodity = none,
const optional<datetime_t>& moment = none,
const optional<datetime_t>& oldest = none
#if defined(DEBUG_ON)
, const int indent = 0
#endif
) const;
optional<history_t&>
history(const optional<commodity_t&>& commodity = none);
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & histories;
}
#endif // HAVE_BOOST_SERIALIZATION
};
#define COMMODITY_STYLE_DEFAULTS 0x000
#define COMMODITY_STYLE_SUFFIXED 0x001
#define COMMODITY_STYLE_SEPARATED 0x002
#define COMMODITY_STYLE_EUROPEAN 0x004
#define COMMODITY_STYLE_THOUSANDS 0x008
#define COMMODITY_NOMARKET 0x010
#define COMMODITY_BUILTIN 0x020
#define COMMODITY_WALKED 0x040
#define COMMODITY_KNOWN 0x080
#define COMMODITY_PRIMARY 0x100
string symbol;
amount_t::precision_t precision;
optional<string> name;
optional<string> note;
optional<varied_history_t> varied_history;
optional<amount_t> smaller;
optional<amount_t> larger;
mutable bool searched;
static bool european_by_default;
public:
explicit base_t(const string& _symbol)
: supports_flags<uint_least16_t>(european_by_default ?
COMMODITY_STYLE_EUROPEAN :
COMMODITY_STYLE_DEFAULTS),
symbol(_symbol), precision(0), searched(false) {
TRACE_CTOR(base_t, "const string&");
}
~base_t() {
TRACE_DTOR(base_t);
}
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & boost::serialization::base_object<supports_flags<uint_least16_t> >(*this);
ar & symbol;
ar & precision;
ar & name;
ar & note;
ar & varied_history;
ar & smaller;
ar & larger;
}
#endif // HAVE_BOOST_SERIALIZATION
};
public:
static bool symbol_needs_quotes(const string& symbol);
typedef base_t::history_t history_t;
typedef base_t::history_map history_map;
typedef base_t::varied_history_t varied_history_t;
typedef base_t::history_by_commodity_map history_by_commodity_map;
shared_ptr<base_t> base;
commodity_pool_t * parent_;
optional<string> qualified_symbol;
optional<string> mapping_key_;
bool annotated;
public:
explicit commodity_t(commodity_pool_t * _parent,
const shared_ptr<base_t>& _base)
: delegates_flags<uint_least16_t>(*_base.get()), base(_base),
parent_(_parent), annotated(false) {
TRACE_CTOR(commodity_t, "commodity_pool_t *, shared_ptr<base_t>");
}
virtual ~commodity_t() {
TRACE_DTOR(commodity_t);
}
operator bool() const;
bool is_annotated() const {
return annotated;
}
virtual bool operator==(const commodity_t& comm) const {
if (comm.annotated)
return comm == *this;
return base.get() == comm.base.get();
}
virtual commodity_t& referent() {
return *this;
}
virtual const commodity_t& referent() const {
return *this;
}
virtual commodity_t& strip_annotations(const keep_details_t&) {
return *this;
}
virtual void write_annotations(std::ostream&) const {}
commodity_pool_t& parent() const {
return *parent_;
}
string base_symbol() const {
return base->symbol;
}
string symbol() const {
return qualified_symbol ? *qualified_symbol : base_symbol();
}
string mapping_key() const {
if (mapping_key_)
return *mapping_key_;
else
return base_symbol();
}
optional<string> name() const {
return base->name;
}
void set_name(const optional<string>& arg = none) {
base->name = arg;
}
optional<string> note() const {
return base->note;
}
void set_note(const optional<string>& arg = none) {
base->note = arg;
}
amount_t::precision_t precision() const {
return base->precision;
}
void set_precision(amount_t::precision_t arg) {
base->precision = arg;
}
optional<amount_t> smaller() const {
return base->smaller;
}
void set_smaller(const optional<amount_t>& arg = none) {
base->smaller = arg;
}
optional<amount_t> larger() const {
return base->larger;
}
void set_larger(const optional<amount_t>& arg = none) {
base->larger = arg;
}
optional<varied_history_t&> varied_history() {
if (base->varied_history)
return *base->varied_history;
return none;
}
optional<history_t&> history(const optional<commodity_t&>& commodity);
public:
// These methods provide a transparent pass-through to the underlying
// base->varied_history object.
void add_price(const datetime_t& date, const amount_t& price,
const bool reflexive = true) {
if (! base->varied_history)
base->varied_history = varied_history_t();
base->varied_history->add_price(*this, date, price, reflexive);
}
bool remove_price(const datetime_t& date, commodity_t& commodity) {
if (base->varied_history)
base->varied_history->remove_price(date, commodity);
return false;
}
optional<price_point_t>
find_price(const optional<commodity_t&>& commodity = none,
const optional<datetime_t>& moment = none,
const optional<datetime_t>& oldest = none
#if defined(DEBUG_ON)
, const int indent = 0
#endif
) const {
if (base->varied_history && ! has_flags(COMMODITY_WALKED)) {
const_cast<commodity_t&>(*this).add_flags(COMMODITY_WALKED);
optional<price_point_t> point =
base->varied_history->find_price(*this, commodity, moment, oldest
#if defined(DEBUG_ON)
, indent
#endif
);
const_cast<commodity_t&>(*this).drop_flags(COMMODITY_WALKED);
return point;
}
return none;
}
optional<price_point_t>
check_for_updated_price(const optional<price_point_t>& point,
const optional<datetime_t>& moment,
const optional<commodity_t&>& in_terms_of);
// Methods related to parsing, reading, writing, etc., the commodity
// itself.
static void parse_symbol(std::istream& in, string& symbol);
static void parse_symbol(char *& p, string& symbol);
static string parse_symbol(std::istream& in) {
string temp;
parse_symbol(in, temp);
return temp;
}
void print(std::ostream& out) const {
out << symbol();
}
bool valid() const;
#if defined(HAVE_BOOST_SERIALIZATION)
private:
supports_flags<uint_least16_t> temp_flags;
protected:
explicit commodity_t()
: delegates_flags<uint_least16_t>(temp_flags), parent_(NULL),
annotated(false) {
TRACE_CTOR(commodity_t, "");
}
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & boost::serialization::base_object<delegates_flags<uint_least16_t> >(*this);
ar & base;
ar & parent_;
ar & qualified_symbol;
ar & mapping_key_;
ar & annotated;
}
#endif // HAVE_BOOST_SERIALIZATION
};
inline std::ostream& operator<<(std::ostream& out, const commodity_t& comm) {
comm.print(out);
return out;
}
/**
* @brief Brief
*
* Long.
*/
struct compare_amount_commodities {
bool operator()(const amount_t * left, const amount_t * right) const;
};
} // namespace ledger
#endif // _COMMODITY_H