diff --git a/src/common/typelistutil.hpp b/src/common/typelistutil.hpp index 4e382df3d..f7a716024 100644 --- a/src/common/typelistutil.hpp +++ b/src/common/typelistutil.hpp @@ -136,7 +136,7 @@ namespace lumiera > { public: - typedef InstantiateChained Next; + typedef InstantiateChained Next; typedef _X_ Unit; }; diff --git a/src/tool/try.cpp b/src/tool/try.cpp index da5ca97c0..85a3286a0 100644 --- a/src/tool/try.cpp +++ b/src/tool/try.cpp @@ -9,35 +9,235 @@ // 1/08 - check 64bit longs // 4/08 - comparison operators on shared_ptr // 4/08 - conversions on the value_type used for boost::any +// 5/08 - how to guard a downcasting access, so it is compiled in only if the involved types are convertible #include #include #include -#include +#include +#include +#include +#include +#include +#include using std::string; using std::cout; +using std::ostream; + + + 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; + + 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 + ) + }; + }; + + + template + struct EmptyVal + { + static X create() + { + cout << " NULL() " << __PRETTY_FUNCTION__ <<"\n"; + return X(); + } + }; + template + struct EmptyVal + { + static X*& create() + { + cout << " NULL & " << __PRETTY_FUNCTION__ <<"\n"; + static X* null(0); + return null; + } + }; + + + template + struct NullAccessor + { + typedef RET Ret; + + static RET access (...) { return ifEmpty(); } + static RET ifEmpty () { return EmptyVal::create(); } + }; + + template + struct AccessCasted : NullAccessor + { + using NullAccessor::access; + + template + static typename enable_if< use_dynamic_downcast, TAR>::type + access (ELM& elem) + { + cout << " dynamic " << __PRETTY_FUNCTION__ <<"\n"; + return dynamic_cast (elem); + } + + template + static typename enable_if< use_static_downcast, TAR>::type + access (ELM& elem) + { + cout << " static " << __PRETTY_FUNCTION__ <<"\n"; + return static_cast (elem); + } + + template + static typename enable_if< use_conversion, TAR>::type + access (ELM& elem) + { + cout << " convert " << __PRETTY_FUNCTION__ <<"\n"; + return elem; + } + + }; + -using boost::any; -using boost::any_cast; struct B {}; struct D : B {}; -int main (int argc, char* argv[]) +struct E : D + { + virtual ~E() {}; + }; +struct F : E {}; + + +ostream& operator<< (ostream& s, const B& b) { return s << "B{} adr="<<&b; } +ostream& operator<< (ostream& s, const D& d) { return s << "D{} adr="<<&d; } +ostream& operator<< (ostream& s, const E& e) { return s << "E{} adr="<<&e; } +ostream& operator<< (ostream& s, const F& f) { return s << "F{} adr="<<&f; } + +int +main (int argc, char* argv[]) { NOBUG_INIT; D d; D* pD =&d; + B* pB =pD; + D& rD = *pD; + B& rB = *pB; + + D*& rpD = pD; + B*& rpB = pB; + + F f; + E& rE = f; + E* pE = &f; + D* pDE = pE; - any aD (pD); - any_cast (aD); + cout << "is_base_of = " << is_base_of::value << "\n"; + cout << "is_base_of = " << is_base_of::value << "\n"; + cout << "is_base_of = " << is_base_of::value << "\n"; + + cout << "can_cast = " << can_cast::value << "\n"; + cout << "can_cast = " << can_cast::value << "\n"; + cout << "can_cast = " << can_cast::value << "\n"; + cout << "can_cast = " << can_cast::value << "\n"; + cout << "can_cast = " << can_cast::value << "\n"; + cout << "can_cast = " << can_cast::value << "\n"; + cout << "can_cast = " << can_cast::value << "\n"; + + cout << "can_cast = " << can_cast::value << "\n"; + cout << "can_cast = " << can_cast::value << "\n"; + + cout << "has_RTTI = " << has_RTTI::value << "\n"; + cout << "has_RTTI = " << has_RTTI::value << "\n"; + cout << "has_RTTI = " << has_RTTI::value << "\n"; + + + cout << "use_dynamic_downcast = " << use_dynamic_downcast::value << "\n"; + cout << "use_static_downcast = " << use_static_downcast::value << "\n"; + cout << "use_conversion = " << use_conversion::value << "\n"; + + cout << "use_static_downcast = " << use_static_downcast::value << "\n"; + cout << "use_static_downcast = " << use_static_downcast::value << "\n"; + cout << "use_dynamic_downcast = " << use_dynamic_downcast::value << "\n"; + + + cout << "Access(D as D&) --->" << AccessCasted::access(d) << "\n"; + cout << "Access(D& as D&) --->" << AccessCasted::access(rD) << "\n"; + cout << "Access(B& as D&) --->" << AccessCasted::access(rB) << "\n"; + cout << "Access(D* as D*) --->" << AccessCasted::access(pD) << "\n"; + cout << "Access(B* as D*) --->" << AccessCasted::access(pB) << "\n"; + cout << "Access(D*& as D*&) --->" << AccessCasted::access(rpD) << "\n"; + cout << "Access(B*& as D*&) --->" << AccessCasted::access(rpB) << "\n"; + + cout << "Access(D as B&) --->" << AccessCasted::access(d) << "\n"; + cout << "Access(D& as B&) --->" << AccessCasted::access(rD) << "\n"; + cout << "Access(B& as B&) --->" << AccessCasted::access(rB) << "\n"; + cout << "Access(D* as B*) --->" << AccessCasted::access(pD) << "\n"; + cout << "Access(B* as B*) --->" << AccessCasted::access(pB) << "\n"; + cout << "Access(D*& as B*&) --->" << AccessCasted::access(rpD) << "\n"; + cout << "Access(B*& as B*&) --->" << AccessCasted::access(rpB) << "\n"; + + cout << "Access(D as E&) --->" << AccessCasted::access(d) << "\n"; + cout << "Access(E& as F&) --->" << AccessCasted::access(rE) << "\n"; + cout << "Access(D(E)* as E*) --->" << AccessCasted::access(pDE) << "\n"; + cout << "Access(D(E)* as F*) --->" << AccessCasted::access(pDE) << "\n"; + cout << "Access(E* as F*) --->" << AccessCasted::access(pE) << "\n"; + cout << "\ngulp\n"; diff --git a/tests/components/proc/mobject/builder/buildertooltest.cpp b/tests/components/proc/mobject/builder/buildertooltest.cpp index f9adc1308..6495bb795 100644 --- a/tests/components/proc/mobject/builder/buildertooltest.cpp +++ b/tests/components/proc/mobject/builder/buildertooltest.cpp @@ -32,7 +32,15 @@ #include "proc/mobject/placement.hpp" #include "proc/mobject/explicitplacement.hpp" //////////TODO -#include +#include "common/typelistutil.hpp" + +#include +#include +#include +#include +#include + +//#include #include using std::string; using std::cout; @@ -65,8 +73,359 @@ namespace mobject - vieleicht einen allgemeinen Argument-Adapter nutzen? - Zielobjekt oder Wrapper als Argumenttyp? */ - struct Nothing {}; + + using boost::enable_if; + using boost::is_convertible; + + using lumiera::typelist::Types; + using lumiera::typelist::Node; + using lumiera::typelist::NullType; +// using lumiera::typelist::count; +// using lumiera::typelist::maxSize; + using lumiera::typelist::InstantiateChained; + + template + < class TYPES // List of Types + , template class _X_ // your-template-goes-here + , class BASE = NullType // Base class at end of chain + , uint i = 0 // incremented on each instantiaton + > + class InstantiateWithIndex; + + + template< template class _X_ + , class BASE + , uint i + > + class InstantiateWithIndex + : public BASE + { + public: + typedef BASE Unit; + typedef NullType Next; + enum{ COUNT = i }; + }; + + template + < class TY, typename TYPES + , template class _X_ + , class BASE + , uint i + > + class InstantiateWithIndex, _X_, BASE, i> + : public _X_< TY + , InstantiateWithIndex + , i + > + { + public: + typedef InstantiateWithIndex Next; + typedef _X_ Unit; + enum{ COUNT = Next::COUNT }; + }; + + template + struct count; + template<> + struct count + { + enum{ value = 0 }; + }; + template + struct count > + { + enum{ value = 1 + count::value }; + }; + + template + struct maxSize; + template<> + struct maxSize + { + enum{ value = 0 }; + }; + template + struct maxSize > + { + enum{ nextval = maxSize::value + , thisval = sizeof(TY) + , value = nextval > thisval? nextval:thisval + }; + }; + + + + template + struct Holder + { + T content; + + Holder (T const& src) : T(src) {} + + template + TAR get () { return static_cast (content); } + }; + + typedef Types < Placement* + , P* + > ::List + WrapperTypes; + + template + struct EmptyVal + { + static X create() + { + return X(); + } + }; + template + struct EmptyVal + { + static X*& create() + { + static X* null(0); + return null; + } + }; + + + const uint TYPECNT = count::value; + const size_t SIZE = maxSize::value; + + struct Buffer + { + char buffer_[SIZE]; + uint which; + + Buffer() : which(TYPECNT) {} + + void* + put (void) + { + deleteCurrent(); + return 0; + } + + void + deleteCurrent (); // depends on the Deleter, see below + }; + + template + struct Storage : BASE + { + T& + put (T const& toStore) + { + BASE::deleteCurrent(); // remove old content, if any + + T& storedObj = *new(BASE::buffer_) T (toStore); + this->which = idx; // remember the actual type selected + return storedObj; + } + + using BASE::put; + }; + + + + template + struct CaseSelect + { + typedef typename FUNCTOR::Ret Ret; + typedef Ret (*Func)(Buffer&); + + Func table_[TYPECNT]; + + CaseSelect () + { + for (uint i=0; i + static Ret + trampoline (Buffer& storage) + { + T& content = reinterpret_cast (storage.buffer_); + return FUNCTOR::access (content); + } + + template + void + create_thunk (uint idx) + { + Func thunk = &trampoline; + table_[idx] = thunk; + } + + Ret + invoke (Buffer& storage) + { + if (TYPECNT <= storage.which) + return FUNCTOR::ifEmpty (); + else + return (*table_[storage.which]) (storage); + } + }; + + + template< class T, class BASE, uint i > + struct CasePrepare + : BASE + { + CasePrepare () : BASE() + { +// BASE::table_[i] = &(BASE::template trampoline); + BASE::template create_thunk(i); + } + }; + + + template + typename FUNCTOR::Ret + access (Buffer& buf) + { + typedef InstantiateWithIndex< WrapperTypes + , CasePrepare + , CaseSelect + > + Accessor; + static Accessor select_case; + return select_case.invoke(buf); + } + + + struct Deleter + { + typedef void Ret; + + template + static void access (T& elem) { elem.~T(); } + + static void ifEmpty () { } + }; + + + void + Buffer::deleteCurrent () + { + access(*this); // remove old content, if any + which = TYPECNT; // mark as empty + } + + + + + + + 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; + + 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 + ) + }; + }; + + + + + + template + struct NullAccessor + { + typedef RET Ret; + + static RET access (...) { return ifEmpty(); } + static RET ifEmpty () { return EmptyVal::create(); } + }; + + template + struct AccessCasted : NullAccessor + { + using NullAccessor::access; + + template + static typename enable_if< use_dynamic_downcast, TAR>::type + access (ELM& elem) + { + return dynamic_cast (elem); + } + + template + static typename enable_if< use_static_downcast, TAR>::type + access (ELM& elem) + { + return static_cast (elem); + } + + template + static typename enable_if< use_conversion, TAR>::type + access (ELM& elem) + { + return elem; + } + + }; + + + + + + + + /** * helper to treat various sorts of smart-ptrs uniformly. * Implemented as a variant-type value object, it is preconfigured @@ -80,32 +439,33 @@ namespace mobject class WrapperPtr // NONCOPYABLE!! { - template - struct accessor; - - template class WRA, class TAR> - struct accessor< WRA > - : public boost::static_visitor*> - { - template WRA* operator() (X&) { return 0; } - template WRA* operator() (WRA& stored) { return static_cast*> (stored); } - }; private: + typedef InstantiateWithIndex< WrapperTypes + , Storage + , Buffer + > + VariantHolder; + /** storage: buffer holding either and "empty" marker, * or one of the configured pointer to wrapper types */ - boost::variant*, P*> holder_; + VariantHolder holder_; public: - void reset () { holder_ = Nothing(); } + void + reset () + { + access (holder_); + holder_.which = TYPECNT; + } template WrapperPtr& operator= (WRA* src) ///< store a ptr to the given wrapper, after casting to base { - if (src) holder_ = src; - else holder_ = Nothing(); + if (src) holder_.put (src); + else reset(); return *this; } @@ -113,8 +473,8 @@ namespace mobject WRA* get () ///< retrieve ptr and try to downcast to type WRA { - accessor acc; - WRA* res = boost::apply_visitor(acc, this->holder_); + typedef AccessCasted AccessWraP; + WRA* res = access(this->holder_); return res; } }; @@ -244,7 +604,8 @@ namespace mobject void treat (Clip& c) { Placement& pC = getPlacement(); - cout << "media is: "<< str(pC->getMedia()) <<"\n"; + cout << "media is: "<< str(pC->getMedia()) <<"\n" + << "Placement(adr) " << &pC <<"\n"; } void treat (AbstractMO&) { @@ -291,6 +652,7 @@ namespace mobject Placement clip = asset::Media::create("test-1", asset::VIDEO)->createClip(); + cout << "Placement(adr) " << &clip <<"\n"; apply (tool, clip); cout << "Placement(adr) " << &dumm <<"\n"; apply (tool, dummy);