From 5d056f032d5056cdcc51dd222a0f8197be7bee4c Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 28 Apr 2015 04:49:08 +0200 Subject: [PATCH] phase out the (now obsoleted) old Variant and AccessCasted implementation All relevant uses will rely on the more strict access policy implemented with the new util::AccessCasted. Along the same line of thinking, I've removed the "second try" convenience conversion from the typed get-Function of OpaqueHolder. Such an unbounded "convert it somehow" approach is almost never a good idea. Either, one knows by design the precise type to expect, or alternatively should rely on the base interface solely. ...with the sole exception of the usage in WrapperPointer, which in itself looks obsolete to me; we should better re-think the way we handle "wrapped" objects for the BuilderTools, once we actually start implementing the Builder Ticket #450 --- src/lib/access-casted-o.hpp | 160 +++++++++++++-------------- src/lib/opaque-holder.hpp | 75 ++++--------- src/lib/wrapperptr.hpp | 5 +- tests/library/opaque-holder-test.cpp | 7 +- 4 files changed, 108 insertions(+), 139 deletions(-) diff --git a/src/lib/access-casted-o.hpp b/src/lib/access-casted-o.hpp index 4b8080ff2..dcebac3f1 100644 --- a/src/lib/access-casted-o.hpp +++ b/src/lib/access-casted-o.hpp @@ -27,7 +27,7 @@ ** and the target type (type we need within the usage context). ** When instantiating AcessCasted, we get a template static function ** \c AcessCasted::access(SRC& elm), but the actual implementation - ** is chosen using boost::type_traits. If no sensible implementation can be + ** is chosen using std::type_traits. If no sensible implementation can be ** selected, \c EmptyVal::create() is invoked instead, which by default ** creates a NULL value or similar by using the no-argument ctor of the ** type TAR. Alternatively, you may define an specialisation of EmptyVal, @@ -45,89 +45,85 @@ #ifndef UTIL_ACCESS_CASTED_O_H #define UTIL_ACCESS_CASTED_O_H -#include -#include -#include -#include -#include -#include +#include namespace util { - using boost::remove_pointer; - using boost::remove_reference; - using boost::is_convertible; - using boost::is_polymorphic; - using boost::is_base_of; - using boost::enable_if; - - template - struct can_cast : boost::false_type {}; - - template - struct can_cast { enum { value = is_base_of::value };}; - - template - struct can_cast { enum { value = is_base_of::value };}; - - template - struct can_cast { enum { value = is_base_of::value };}; - - - template - struct has_RTTI - { - typedef typename remove_pointer< - typename remove_reference::type>::type TPlain; + namespace { + using std::remove_pointer; + using std::remove_reference; + using std::is_convertible; + using std::is_polymorphic; + using std::is_base_of; - enum { value = is_polymorphic::value }; - }; - - template - struct use_dynamic_downcast - { - enum { value = can_cast::value - && has_RTTI::value - && has_RTTI::value - }; - }; - - template - struct use_static_downcast - { - enum { value = can_cast::value - && ( !has_RTTI::value - || !has_RTTI::value - ) - }; - }; - - template - struct use_conversion - { - enum { value = is_convertible::value - && !( use_static_downcast::value - ||use_dynamic_downcast::value - ) - }; - }; - - - - ////////////////////////////////TODO: use lib::NullValue instead - template - struct EmptyVal - { - static X create() { return X(); } - }; - template - struct EmptyVal - { - static X*& create() { static X* nullP(0); return nullP; } - }; - + + template + struct can_cast : std::false_type {}; + + template + struct can_cast { enum { value = is_base_of::value };}; + + template + struct can_cast { enum { value = is_base_of::value };}; + + template + struct can_cast { enum { value = is_base_of::value };}; + + + template + struct hasRTTI + { + typedef typename remove_pointer< + typename remove_reference::type>::type TPlain; + + enum { value = is_polymorphic::value }; + }; + + template + struct use_dynamic_downcast + { + enum { value = can_cast::value + && hasRTTI::value + && hasRTTI::value + }; + }; + + template + struct use_static_downcast + { + enum { value = can_cast::value + && ( !hasRTTI::value + || !hasRTTI::value + ) + }; + }; + + template + struct use_conversion + { + enum { value = is_convertible::value + && !( use_static_downcast::value + ||use_dynamic_downcast::value + ) + }; + }; + + + + template + struct EmptyVal + { + static X create() { return X(); } + }; + template + struct EmptyVal + { + static X*& create() { static X* nullP(0); return nullP; } + }; + + } @@ -142,12 +138,12 @@ namespace util { }; template - struct AccessCasted : NullAccessor + struct AccessCasted_O : NullAccessor { using NullAccessor::access; template - static typename enable_if< use_dynamic_downcast, + static typename std::enable_if< use_dynamic_downcast::value, TAR >::type access (ELM& elem) { @@ -155,7 +151,7 @@ namespace util { } template - static typename enable_if< use_static_downcast, + static typename std::enable_if< use_static_downcast::value, TAR >::type access (ELM& elem) { @@ -163,7 +159,7 @@ namespace util { } template - static typename enable_if< use_conversion, + static typename std::enable_if< use_conversion::value, TAR >::type access (ELM& elem) { diff --git a/src/lib/opaque-holder.hpp b/src/lib/opaque-holder.hpp index 5afe4fbd0..ec8e418ab 100644 --- a/src/lib/opaque-holder.hpp +++ b/src/lib/opaque-holder.hpp @@ -69,7 +69,7 @@ #include "lib/error.hpp" #include "lib/bool-checkable.hpp" -#include "lib/access-casted-o.hpp" +#include "lib/access-casted.hpp" #include "lib/util.hpp" #include @@ -78,7 +78,8 @@ namespace lib { - using lumiera::error::LUMIERA_ERROR_WRONG_TYPE; + namespace error = lumiera::error; + using util::isSameObject; using util::unConst; @@ -131,26 +132,9 @@ namespace lib { if (asBase) return asBase; - throw lumiera::error::Logic ("Unable to convert concrete object to Base interface" - , LUMIERA_ERROR_WRONG_TYPE - ); - } - - template - static SUB* - access (Base* asBase) - { - // Because we don't know anything about the involved types, - // we need to exclude a brute force static cast - // (which might slice or reinterpret or even cause SEGV) - if (!util::use_static_downcast::value) - { - SUB* content = util::AccessCasted::access (asBase); - return content; - // might be NULL - } - else - return 0; + throw error::Logic ("Unable to convert concrete object to Base interface" + , error::LUMIERA_ERROR_WRONG_TYPE + ); } }; @@ -175,13 +159,6 @@ namespace lib { { return static_cast (&obj); } - - template - static SUB* - access (Base*) - { - return 0; - } }; @@ -241,7 +218,8 @@ namespace lib { BaseP getBase() const { - throw lumiera::error::Invalid("accessing empty holder"); + throw error::Invalid("accessing empty holder" + , error::LUMIERA_ERROR_BOTTOM_VALUE); } virtual void @@ -455,19 +433,12 @@ namespace lib { /** re-accessing the concrete contained object. - * When the specified type is exactly the same - * as used when storing the object, we can directly - * re-access the buffer. Otherwise, a conversion might - * be possible going through the Base type, depending - * on the actual types involved and the AccessPolicy. - * But, as we don't "know" the actual type of the object - * in storage, a \em static upcast to any type \em between - * the concrete object type and the base type has to be - * ruled out for safety reasons. When the contained object - * has RTTI, a \em dynamic cast can be performed in this - * situation. You might consider using visitor.hpp instead - * if this imposes a serious limitation. - * @throws lumiera::error::Logic when conversion/access fails + * This requires exact knowledge of the actual type + * of the element currently in storage. OpaqueHolder + * does not provide any "probing" or visitation mechanism. + * @remarks You might consider lib::Variant or some visitor instead. + * @throws lumiera::error::Logic when conversion/access fails + * @throws lumiera::error::Invalid when accessing an empty holder */ template SUB& get() const @@ -479,16 +450,14 @@ namespace lib { if (actual) return actual->get(); - // second try: maybe we can perform a dynamic downcast - // or direct conversion to the actual target type. - SUB* content = AccessPolicy::template access (asBase()); - if (content) - return *content; - - throw lumiera::error::Logic ("Attempt to access OpaqueHolder's contents " - "specifying incompatible target type" - , LUMIERA_ERROR_WRONG_TYPE - ); + if (this->empty()) + throw error::Invalid("accessing empty holder" + , error::LUMIERA_ERROR_BOTTOM_VALUE); + else + throw error::Logic ("Attempt to access OpaqueHolder's contents " + "specifying incompatible target type" + , error::LUMIERA_ERROR_WRONG_TYPE + ); } diff --git a/src/lib/wrapperptr.hpp b/src/lib/wrapperptr.hpp index 3cb4030ed..c2bd6a64c 100644 --- a/src/lib/wrapperptr.hpp +++ b/src/lib/wrapperptr.hpp @@ -58,8 +58,11 @@ namespace lumiera { * Later on, stored values can be retrieved either utilising static or dynamic casts; * error reporting is similar to the behaviour of dynamic_cast: when retrieving * a pointer, NULL is returned in case of mismatch. + * + * @deprecated not sure if this was a good idea anyway. Better re-think how to handle wrapped objects in visitation + * @todo really need to switch to the new lib::Variant and util::AccessCasted implementation ////////////////TICKET #450 */ - typedef lib::VariantO WrapperPtr; + typedef lib::VariantO WrapperPtr; diff --git a/tests/library/opaque-holder-test.cpp b/tests/library/opaque-holder-test.cpp index 017f215a2..da866abf2 100644 --- a/tests/library/opaque-holder-test.cpp +++ b/tests/library/opaque-holder-test.cpp @@ -41,8 +41,9 @@ namespace test{ using util::isnil; using util::for_each; using util::isSameObject; - using lumiera::error::LUMIERA_ERROR_INVALID; - using lumiera::error::LUMIERA_ERROR_ASSERTION; + using error::LUMIERA_ERROR_BOTTOM_VALUE; + using error::LUMIERA_ERROR_WRONG_TYPE; + using error::LUMIERA_ERROR_ASSERTION; using std::vector; using std::cout; @@ -216,7 +217,7 @@ namespace test{ oo.clear(); CHECK (!oo); CHECK (isnil(oo)); - VERIFY_ERROR (INVALID, oo.get() ); + VERIFY_ERROR (BOTTOM_VALUE, oo.get() ); #if false ///////////////////////////////////////////////////////////////////////////////////////////////TICKET #537 : restore throwing ASSERT VERIFY_ERROR (ASSERTION, oo->getIt() ); #endif ///////////////////////////////////////////////////////////////////////////////////////////////TICKET #537 : restore throwing ASSERT