summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2009-02-10 04:24:06 -0400
committerJohn Wiegley <johnw@newartisans.com>2009-02-10 04:24:06 -0400
commitd726624e60caa77354c7d4ef03cb564064316916 (patch)
tree31beac5e1eb8348ca6cb24717debaf6d72a97694 /src
parent6d4c3ffde57ad710be8ecff3675a13ddb9c44379 (diff)
downloadfork-ledger-d726624e60caa77354c7d4ef03cb564064316916.tar.gz
fork-ledger-d726624e60caa77354c7d4ef03cb564064316916.tar.bz2
fork-ledger-d726624e60caa77354c7d4ef03cb564064316916.zip
Changed value_t to use boost::any (more type-safe).
Diffstat (limited to 'src')
-rw-r--r--src/value.cc187
-rw-r--r--src/value.h155
2 files changed, 103 insertions, 239 deletions
diff --git a/src/value.cc b/src/value.cc
index d28883a4..482dca21 100644
--- a/src/value.cc
+++ b/src/value.cc
@@ -41,128 +41,30 @@ value_t::storage_t& value_t::storage_t::operator=(const value_t::storage_t& rhs)
type = rhs.type;
switch (type) {
- case DATETIME:
- new(reinterpret_cast<datetime_t *>(data))
- datetime_t(*reinterpret_cast<datetime_t *>
- (const_cast<char *>(rhs.data)));
- break;
-
- case DATE:
- new(reinterpret_cast<date_t *>(data))
- date_t(*reinterpret_cast<date_t *>(const_cast<char *>(rhs.data)));
- break;
-
- case AMOUNT:
- new(reinterpret_cast<amount_t *>(data))
- amount_t(*reinterpret_cast<amount_t *>
- (const_cast<char *>(rhs.data)));
- break;
-
case BALANCE:
- *reinterpret_cast<balance_t **>(data) =
- new balance_t(**reinterpret_cast<balance_t **>
- (const_cast<char *>(rhs.data)));
- break;
-
- case STRING:
- new(reinterpret_cast<string *>(data))
- string(*reinterpret_cast<string *>(const_cast<char *>(rhs.data)));
- break;
-
- case MASK:
- new(reinterpret_cast<mask_t *>(data))
- mask_t(*reinterpret_cast<mask_t *>(const_cast<char *>(rhs.data)));
+ data = new balance_t(*boost::get<balance_t *>(rhs.data));
break;
-
case SEQUENCE:
- *reinterpret_cast<sequence_t **>(data) =
- new sequence_t(**reinterpret_cast<sequence_t **>
- (const_cast<char *>(rhs.data)));
+ data = new sequence_t(*boost::get<sequence_t *>(rhs.data));
break;
default:
- // The rest are fundamental types, which can be copied using
- // std::memcpy
- std::memcpy(data, rhs.data, sizeof(data));
+ data = rhs.data;
break;
}
return *this;
}
-void value_t::storage_t::destroy()
-{
- switch (type) {
- case AMOUNT:
- reinterpret_cast<amount_t *>(data)->~amount_t();
- break;
- case BALANCE:
- checked_delete(*reinterpret_cast<balance_t **>(data));
- break;
- case STRING:
- reinterpret_cast<string *>(data)->~string();
- break;
- case MASK:
- reinterpret_cast<mask_t *>(data)->~mask_t();
- break;
- case SEQUENCE:
- checked_delete(*reinterpret_cast<sequence_t **>(data));
- break;
- case POINTER:
- reinterpret_cast<boost::any *>(data)->~any();
- break;
-
- default:
- break;
- }
- type = VOID;
-}
-
void value_t::initialize()
{
-#if defined(DEBUG_ON)
- LOGGER("value.init");
-#endif
-
true_value = new storage_t;
true_value->type = BOOLEAN;
- *reinterpret_cast<bool *>(true_value->data) = true;
+ boost::get<bool>(true_value->data) = true;
false_value = new storage_t;
false_value->type = BOOLEAN;
- *reinterpret_cast<bool *>(false_value->data) = false;
-
- BOOST_STATIC_ASSERT(sizeof(amount_t) >= sizeof(bool));
- BOOST_STATIC_ASSERT(sizeof(amount_t) >= sizeof(datetime_t));
- BOOST_STATIC_ASSERT(sizeof(amount_t) >= sizeof(date_t));
- BOOST_STATIC_ASSERT(sizeof(amount_t) >= sizeof(long));
- BOOST_STATIC_ASSERT(sizeof(amount_t) >= sizeof(amount_t));
- BOOST_STATIC_ASSERT(sizeof(amount_t) >= sizeof(balance_t *));
- BOOST_STATIC_ASSERT(sizeof(amount_t) >= sizeof(string));
- BOOST_STATIC_ASSERT(sizeof(amount_t) >= sizeof(mask_t));
- BOOST_STATIC_ASSERT(sizeof(amount_t) >= sizeof(sequence_t *));
- BOOST_STATIC_ASSERT(sizeof(amount_t) >= sizeof(boost::any));
-
- DEBUG_(std::setw(3) << std::right << sizeof(bool)
- << " sizeof(bool)");
- DEBUG_(std::setw(3) << std::right << sizeof(datetime_t)
- << " sizeof(datetime_t)");
- DEBUG_(std::setw(3) << std::right << sizeof(date_t)
- << " sizeof(date_t)");
- DEBUG_(std::setw(3) << std::right << sizeof(long)
- << " sizeof(long)");
- DEBUG_(std::setw(3) << std::right << sizeof(amount_t)
- << " sizeof(amount_t)");
- DEBUG_(std::setw(3) << std::right << sizeof(balance_t *)
- << " sizeof(balance_t *)");
- DEBUG_(std::setw(3) << std::right << sizeof(string)
- << " sizeof(string)");
- DEBUG_(std::setw(3) << std::right << sizeof(mask_t)
- << " sizeof(mask_t)");
- DEBUG_(std::setw(3) << std::right << sizeof(sequence_t *)
- << " sizeof(sequence_t *)");
- DEBUG_(std::setw(3) << std::right << sizeof(boost::any)
- << " sizeof(boost::any)");
+ boost::get<bool>(true_value->data) = false;
}
void value_t::shutdown()
@@ -171,13 +73,6 @@ void value_t::shutdown()
false_value = intrusive_ptr<storage_t>();
}
-void value_t::_dup()
-{
- assert(storage);
- if (storage->refc > 1)
- storage = new storage_t(*storage.get());
-}
-
value_t::operator bool() const
{
switch (type()) {
@@ -1263,69 +1158,33 @@ value_t value_t::unrounded() const
return NULL_VALUE;
}
-#if 0
-value_t value_t::annotated_price() const
+void value_t::annotate(const annotation_t& details)
{
- switch (type()) {
- case AMOUNT: {
- optional<amount_t> temp = as_amount().annotation_details().price;
- if (! temp)
- return false;
- return *temp;
- }
-
- default:
- break;
- }
-
- throw_(value_error, "Cannot find the annotated price of " << label());
- return NULL_VALUE;
+ if (is_amount())
+ as_amount_lval().annotate(details);
+ else
+ throw_(value_error, "Cannot annotate " << label());
}
-value_t value_t::annotated_date() const
+bool value_t::is_annotated() const
{
- switch (type()) {
- case DATETIME:
- return *this;
- case DATE:
- return *this;
-
- case AMOUNT: {
- optional<datetime_t> temp = as_amount().annotation_details().date;
- if (! temp)
- return false;
- return *temp;
- }
-
- default:
- break;
- }
-
- throw_(value_error, "Cannot find the annotated date of " << label());
- return NULL_VALUE;
+ if (is_amount())
+ return as_amount().is_annotated();
+ else
+ throw_(value_error,
+ "Cannot determine whether " << label() << " is annotated");
+ return false;
}
-value_t value_t::annotated_tag() const
+annotation_t& value_t::annotation()
{
- switch (type()) {
- case AMOUNT: {
- optional<string> temp = as_amount().annotation_details().tag;
- if (! temp)
- return false;
- return string_value(*temp);
+ if (is_amount())
+ return as_amount_lval().annotation();
+ else {
+ throw_(value_error, "Cannot request annotation of " << label());
+ return as_amount_lval().annotation(); // quiet g++ warning
}
-
- case STRING:
- return *this;
-
- default:
- break;
- }
-
- throw_(value_error, "Cannot find the annotated tag of " << label());
- return NULL_VALUE;
}
-#endif
value_t value_t::strip_annotations(const keep_details_t& what_to_keep) const
{
diff --git a/src/value.h b/src/value.h
index b9f8fcae..c49846d6 100644
--- a/src/value.h
+++ b/src/value.h
@@ -125,7 +125,18 @@ private:
* The `type' member holds the value_t::type_t value representing
* the type of the object stored.
*/
- char data[sizeof(amount_t)];
+ variant<bool, // BOOLEAN
+ datetime_t, // DATETIME
+ date_t, // DATE
+ long, // INTEGER
+ amount_t, // AMOUNT
+ balance_t *, // BALANCE
+ string, // STRING
+ mask_t, // MASK
+ sequence_t *, // SEQUENCE
+ boost::any // POINTER
+ > data;
+
type_t type;
/**
@@ -157,10 +168,18 @@ private:
TRACE_DTOR(value_t::storage_t);
DEBUG("value.storage.refcount", "Destroying " << this);
assert(refc == 0);
- destroy();
- }
- void destroy();
+ switch (type) {
+ case BALANCE:
+ checked_delete(boost::get<balance_t *>(data));
+ break;
+ case SEQUENCE:
+ checked_delete(boost::get<sequence_t *>(data));
+ break;
+ default:
+ break;
+ }
+ }
private:
/**
@@ -202,7 +221,7 @@ private:
};
/**
- * The actual data for each value_t is kept in the `storage' member.
+ * The actual data for each value_t is kept in reference counted storage.
* Data is modified using a copy-on-write policy.
*/
intrusive_ptr<storage_t> storage;
@@ -213,20 +232,19 @@ private:
*
* _clear() removes our pointer to the current value and initializes
* a new storage bin for things to be stored in.
- *
- * _reset() makes the current object appear as if it were
- * uninitialized.
*/
- void _dup();
+ void _dup() {
+ assert(storage);
+ if (storage->refc > 1)
+ storage = new storage_t(*storage.get());
+ }
void _clear() {
- if (! storage || storage->refc > 1)
+ if (! storage || storage->refc > 1) {
storage = new storage_t;
- else
- storage->destroy();
- }
- void _reset() {
- if (storage)
- storage = intrusive_ptr<storage_t>();
+ } else {
+ storage->data = false; // destruct any other type
+ storage->type = VOID;
+ }
}
/**
@@ -455,7 +473,7 @@ private:
void set_type(type_t new_type) {
assert(new_type >= VOID && new_type <= POINTER);
if (new_type == VOID) {
- _reset();
+ storage.reset();
assert(is_null());
} else {
_clear();
@@ -500,11 +518,11 @@ public:
bool& as_boolean_lval() {
assert(is_boolean());
_dup();
- return *reinterpret_cast<bool *>(storage->data);
+ return boost::get<bool>(storage->data);
}
const bool& as_boolean() const {
assert(is_boolean());
- return *reinterpret_cast<bool *>(storage->data);
+ return boost::get<bool>(storage->data);
}
void set_boolean(const bool val) {
set_type(BOOLEAN);
@@ -517,15 +535,15 @@ public:
datetime_t& as_datetime_lval() {
assert(is_datetime());
_dup();
- return *reinterpret_cast<datetime_t *>(storage->data);
+ return boost::get<datetime_t>(storage->data);
}
const datetime_t& as_datetime() const {
assert(is_datetime());
- return *reinterpret_cast<datetime_t *>(storage->data);
+ return boost::get<datetime_t>(storage->data);
}
void set_datetime(const datetime_t& val) {
set_type(DATETIME);
- new(reinterpret_cast<datetime_t *>(storage->data)) datetime_t(val);
+ storage->data = val;
}
bool is_date() const {
@@ -534,15 +552,15 @@ public:
date_t& as_date_lval() {
assert(is_date());
_dup();
- return *reinterpret_cast<date_t *>(storage->data);
+ return boost::get<date_t>(storage->data);
}
const date_t& as_date() const {
assert(is_date());
- return *reinterpret_cast<date_t *>(storage->data);
+ return boost::get<date_t>(storage->data);
}
void set_date(const date_t& val) {
set_type(DATE);
- new(reinterpret_cast<date_t *>(storage->data)) date_t(val);
+ storage->data = val;
}
bool is_long() const {
@@ -551,15 +569,15 @@ public:
long& as_long_lval() {
assert(is_long());
_dup();
- return *reinterpret_cast<long *>(storage->data);
+ return boost::get<long>(storage->data);
}
const long& as_long() const {
assert(is_long());
- return *reinterpret_cast<long *>(storage->data);
+ return boost::get<long>(storage->data);
}
void set_long(const long val) {
set_type(INTEGER);
- *reinterpret_cast<long *>(storage->data) = val;
+ storage->data = val;
}
bool is_amount() const {
@@ -568,20 +586,16 @@ public:
amount_t& as_amount_lval() {
assert(is_amount());
_dup();
- amount_t& amt(*reinterpret_cast<amount_t *>(storage->data));
- assert(amt.valid());
- return amt;
+ return boost::get<amount_t>(storage->data);
}
const amount_t& as_amount() const {
assert(is_amount());
- amount_t& amt(*reinterpret_cast<amount_t *>(storage->data));
- assert(amt.valid());
- return amt;
+ return boost::get<amount_t>(storage->data);
}
void set_amount(const amount_t& val) {
assert(val.valid());
set_type(AMOUNT);
- new(reinterpret_cast<amount_t *>(storage->data)) amount_t(val);
+ storage->data = val;
}
bool is_balance() const {
@@ -590,20 +604,16 @@ public:
balance_t& as_balance_lval() {
assert(is_balance());
_dup();
- balance_t& bal(**reinterpret_cast<balance_t **>(storage->data));
- assert(bal.valid());
- return bal;
+ return *boost::get<balance_t *>(storage->data);
}
const balance_t& as_balance() const {
assert(is_balance());
- balance_t& bal(**reinterpret_cast<balance_t **>(storage->data));
- assert(bal.valid());
- return bal;
+ return *boost::get<balance_t *>(storage->data);
}
void set_balance(const balance_t& val) {
assert(val.valid());
set_type(BALANCE);
- *reinterpret_cast<balance_t **>(storage->data) = new balance_t(val);
+ storage->data = new balance_t(val);
}
bool is_string() const {
@@ -612,19 +622,19 @@ public:
string& as_string_lval() {
assert(is_string());
_dup();
- return *reinterpret_cast<string *>(storage->data);
+ return boost::get<string>(storage->data);
}
const string& as_string() const {
assert(is_string());
- return *reinterpret_cast<string *>(storage->data);
+ return boost::get<string>(storage->data);
}
void set_string(const string& val = "") {
set_type(STRING);
- new(reinterpret_cast<string *>(storage->data)) string(val);
+ storage->data = val;
}
void set_string(const char * val = "") {
set_type(STRING);
- new(reinterpret_cast<string *>(storage->data)) string(val);
+ storage->data = string(val);
}
bool is_mask() const {
@@ -633,19 +643,19 @@ public:
mask_t& as_mask_lval() {
assert(is_mask());
_dup();
- return *reinterpret_cast<mask_t *>(storage->data);
+ return boost::get<mask_t>(storage->data);
}
const mask_t& as_mask() const {
assert(is_mask());
- return *reinterpret_cast<mask_t *>(storage->data);
+ return boost::get<mask_t>(storage->data);
}
void set_mask(const string& val) {
set_type(MASK);
- new(reinterpret_cast<mask_t *>(storage->data)) mask_t(val);
+ storage->data = mask_t(val);
}
void set_mask(const mask_t& val) {
set_type(MASK);
- new(reinterpret_cast<mask_t *>(storage->data)) mask_t(val);
+ storage->data = val;
}
bool is_sequence() const {
@@ -654,15 +664,15 @@ public:
sequence_t& as_sequence_lval() {
assert(is_sequence());
_dup();
- return **reinterpret_cast<sequence_t **>(storage->data);
+ return *boost::get<sequence_t *>(storage->data);
}
const sequence_t& as_sequence() const {
assert(is_sequence());
- return **reinterpret_cast<sequence_t **>(storage->data);
+ return *boost::get<sequence_t *>(storage->data);
}
void set_sequence(const sequence_t& val) {
set_type(SEQUENCE);
- *reinterpret_cast<sequence_t **>(storage->data) = new sequence_t(val);
+ storage->data = new sequence_t(val);
}
/**
@@ -679,42 +689,36 @@ public:
boost::any& as_any_pointer_lval() {
assert(is_pointer());
_dup();
- return *reinterpret_cast<boost::any *>(storage->data);
+ return boost::get<boost::any>(storage->data);
}
template <typename T>
T * as_pointer_lval() {
- assert(is_pointer());
- _dup();
- return any_cast<T *>(*reinterpret_cast<boost::any *>(storage->data));
+ return any_cast<T *>(as_any_pointer_lval());
}
template <typename T>
T& as_ref_lval() {
- assert(is_pointer());
- _dup();
- return *any_cast<T *>(*reinterpret_cast<boost::any *>(storage->data));
+ return *as_pointer_lval<T>();
}
const boost::any& as_any_pointer() const {
assert(is_pointer());
- return *reinterpret_cast<boost::any *>(storage->data);
+ return boost::get<boost::any>(storage->data);
}
template <typename T>
T * as_pointer() const {
- assert(is_pointer());
- return any_cast<T *>(*reinterpret_cast<boost::any *>(storage->data));
+ return any_cast<T *>(as_any_pointer());
}
template <typename T>
T& as_ref() const {
- assert(is_pointer());
- return *any_cast<T *>(*reinterpret_cast<boost::any *>(storage->data));
+ return *as_pointer<T>();
}
void set_any_pointer(const boost::any& val) {
set_type(POINTER);
- new(reinterpret_cast<boost::any *>(storage->data)) boost::any(val);
+ storage->data = val;
}
template <typename T>
void set_pointer(T * val) {
set_type(POINTER);
- new(reinterpret_cast<boost::any *>(storage->data)) boost::any(val);
+ storage->data = boost::any(val);
}
/**
@@ -765,12 +769,13 @@ public:
/**
* Annotated commodity methods.
*/
-#if 0
- // These helper methods only apply to AMOUNT values.
- value_t annotated_price() const;
- value_t annotated_date() const;
- value_t annotated_tag() const;
-#endif
+ void annotate(const annotation_t& details);
+ bool is_annotated() const;
+
+ annotation_t& annotation();
+ const annotation_t& annotation() const {
+ return const_cast<value_t&>(*this).annotation();
+ }
value_t strip_annotations(const keep_details_t& what_to_keep) const;
@@ -821,14 +826,14 @@ public:
assert(! is_null());
if (! is_sequence()) {
- _reset();
+ storage.reset();
} else {
as_sequence_lval().pop_back();
const sequence_t& seq(as_sequence());
std::size_t new_size = seq.size();
if (new_size == 0)
- _reset();
+ storage.reset();
else if (new_size == 1)
*this = seq.front();
}