From d726624e60caa77354c7d4ef03cb564064316916 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Tue, 10 Feb 2009 04:24:06 -0400 Subject: [PATCH] Changed value_t to use boost::any (more type-safe). --- src/value.cc | 187 +++++++-------------------------------------------- src/value.h | 157 +++++++++++++++++++++--------------------- 2 files changed, 104 insertions(+), 240 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(data)) - datetime_t(*reinterpret_cast - (const_cast(rhs.data))); - break; - - case DATE: - new(reinterpret_cast(data)) - date_t(*reinterpret_cast(const_cast(rhs.data))); - break; - - case AMOUNT: - new(reinterpret_cast(data)) - amount_t(*reinterpret_cast - (const_cast(rhs.data))); - break; - case BALANCE: - *reinterpret_cast(data) = - new balance_t(**reinterpret_cast - (const_cast(rhs.data))); + data = new balance_t(*boost::get(rhs.data)); break; - - case STRING: - new(reinterpret_cast(data)) - string(*reinterpret_cast(const_cast(rhs.data))); - break; - - case MASK: - new(reinterpret_cast(data)) - mask_t(*reinterpret_cast(const_cast(rhs.data))); - break; - case SEQUENCE: - *reinterpret_cast(data) = - new sequence_t(**reinterpret_cast - (const_cast(rhs.data))); + data = new sequence_t(*boost::get(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(data)->~amount_t(); - break; - case BALANCE: - checked_delete(*reinterpret_cast(data)); - break; - case STRING: - reinterpret_cast(data)->~string(); - break; - case MASK: - reinterpret_cast(data)->~mask_t(); - break; - case SEQUENCE: - checked_delete(*reinterpret_cast(data)); - break; - case POINTER: - reinterpret_cast(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(true_value->data) = true; + boost::get(true_value->data) = true; false_value = new storage_t; false_value->type = BOOLEAN; - *reinterpret_cast(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(true_value->data) = false; } void value_t::shutdown() @@ -171,13 +73,6 @@ void value_t::shutdown() false_value = intrusive_ptr(); } -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 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 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 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 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(data)); + break; + case SEQUENCE: + checked_delete(boost::get(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; @@ -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 _clear() { - if (! storage || storage->refc > 1) - storage = new storage_t; - else - storage->destroy(); + void _dup() { + assert(storage); + if (storage->refc > 1) + storage = new storage_t(*storage.get()); } - void _reset() { - if (storage) - storage = intrusive_ptr(); + void _clear() { + if (! storage || storage->refc > 1) { + storage = new 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(storage->data); + return boost::get(storage->data); } const bool& as_boolean() const { assert(is_boolean()); - return *reinterpret_cast(storage->data); + return boost::get(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(storage->data); + return boost::get(storage->data); } const datetime_t& as_datetime() const { assert(is_datetime()); - return *reinterpret_cast(storage->data); + return boost::get(storage->data); } void set_datetime(const datetime_t& val) { set_type(DATETIME); - new(reinterpret_cast(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(storage->data); + return boost::get(storage->data); } const date_t& as_date() const { assert(is_date()); - return *reinterpret_cast(storage->data); + return boost::get(storage->data); } void set_date(const date_t& val) { set_type(DATE); - new(reinterpret_cast(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(storage->data); + return boost::get(storage->data); } const long& as_long() const { assert(is_long()); - return *reinterpret_cast(storage->data); + return boost::get(storage->data); } void set_long(const long val) { set_type(INTEGER); - *reinterpret_cast(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(storage->data)); - assert(amt.valid()); - return amt; + return boost::get(storage->data); } const amount_t& as_amount() const { assert(is_amount()); - amount_t& amt(*reinterpret_cast(storage->data)); - assert(amt.valid()); - return amt; + return boost::get(storage->data); } void set_amount(const amount_t& val) { assert(val.valid()); set_type(AMOUNT); - new(reinterpret_cast(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(storage->data)); - assert(bal.valid()); - return bal; + return *boost::get(storage->data); } const balance_t& as_balance() const { assert(is_balance()); - balance_t& bal(**reinterpret_cast(storage->data)); - assert(bal.valid()); - return bal; + return *boost::get(storage->data); } void set_balance(const balance_t& val) { assert(val.valid()); set_type(BALANCE); - *reinterpret_cast(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(storage->data); + return boost::get(storage->data); } const string& as_string() const { assert(is_string()); - return *reinterpret_cast(storage->data); + return boost::get(storage->data); } void set_string(const string& val = "") { set_type(STRING); - new(reinterpret_cast(storage->data)) string(val); + storage->data = val; } void set_string(const char * val = "") { set_type(STRING); - new(reinterpret_cast(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(storage->data); + return boost::get(storage->data); } const mask_t& as_mask() const { assert(is_mask()); - return *reinterpret_cast(storage->data); + return boost::get(storage->data); } void set_mask(const string& val) { set_type(MASK); - new(reinterpret_cast(storage->data)) mask_t(val); + storage->data = mask_t(val); } void set_mask(const mask_t& val) { set_type(MASK); - new(reinterpret_cast(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(storage->data); + return *boost::get(storage->data); } const sequence_t& as_sequence() const { assert(is_sequence()); - return **reinterpret_cast(storage->data); + return *boost::get(storage->data); } void set_sequence(const sequence_t& val) { set_type(SEQUENCE); - *reinterpret_cast(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(storage->data); + return boost::get(storage->data); } template T * as_pointer_lval() { - assert(is_pointer()); - _dup(); - return any_cast(*reinterpret_cast(storage->data)); + return any_cast(as_any_pointer_lval()); } template T& as_ref_lval() { - assert(is_pointer()); - _dup(); - return *any_cast(*reinterpret_cast(storage->data)); + return *as_pointer_lval(); } const boost::any& as_any_pointer() const { assert(is_pointer()); - return *reinterpret_cast(storage->data); + return boost::get(storage->data); } template T * as_pointer() const { - assert(is_pointer()); - return any_cast(*reinterpret_cast(storage->data)); + return any_cast(as_any_pointer()); } template T& as_ref() const { - assert(is_pointer()); - return *any_cast(*reinterpret_cast(storage->data)); + return *as_pointer(); } void set_any_pointer(const boost::any& val) { set_type(POINTER); - new(reinterpret_cast(storage->data)) boost::any(val); + storage->data = val; } template void set_pointer(T * val) { set_type(POINTER); - new(reinterpret_cast(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(*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(); }