Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "StdAfx.h"
- #include <hash_map>
- #include <iostream>
- #include <memory>
- #include <assert.h>
- #include <boost/type_traits/is_base_of.hpp>
- #include <boost/functional/hash/extensions.hpp> // support for std::pair hashing
- namespace std
- {
- using boost::hash_value; // support for std::pair hashing
- }
- using namespace boost;
- // -----------------------------------
- // Objects
- //
- class IObject
- {
- template< class T > friend T *FastObjectCast( IObject * );
- virtual const void *_type_id() = 0;
- public:
- virtual void Method() = 0;
- };
- // IObject inheritance is not sticky required actually (we just want INamedObject to be compatible with IObject)
- struct INamedObject : IObject { virtual std::string &Name() = 0; };
- struct Object1 : IObject { virtual void Method(){ std::cout << "Object1" << std::endl; } };
- struct Object2 : IObject { virtual void Method(){ std::cout << "Object2" << std::endl; } };
- struct Object3 : Object1 { virtual void Method(){ std::cout << "Object3" << std::endl; } };
- struct Object4 : Object3 { virtual void Method(){ std::cout << "Object4" << std::endl; } };
- // -----------------------------------
- // Factory Internals
- //
- // Appends name interface implementation
- template< class Base >
- class NameMixin : public Base, public INamedObject
- {
- static_assert( is_base_of< IObject, Base >::value, "Base must be derived from IObject!" );
- static_assert( !is_base_of< INamedObject, Base >::value, "Named mixin can't be present twice in hierarchy!" );
- public:
- NameMixin( const std::string &name ) : name( name ) {}
- virtual std::string &Name(){ return name; }
- virtual void Method(){ return Base::Method(); } // needed because INamedObject derived from IObject
- private:
- std::string name;
- };
- struct id_mixin_tag {};
- template< class U >
- const void *resolve_type_id(){ return &typeid( U ); }
- // Appends type id interface implementatoion
- template< class Base >
- class IdMixin : public Base, public id_mixin_tag
- {
- static_assert( is_base_of< IObject, Base >::value, "Base must be derived from IObject!" );
- static_assert( !is_base_of< id_mixin_tag, Base >::value, "Id mixin can't be present twice in hierarchy!" );
- virtual const void *_type_id(){ static const void *pRes = resolve_type_id< IdMixin< Base > >(); return pRes; };
- public:
- IdMixin() {}
- template< class T > IdMixin( T &&rr ) : Base( std::forward< T >( rr ) ) {}
- };
- // ---------------------------------------------
- // Factory Internals - Objects Creation/Casts
- //
- template< class Object >
- std::unique_ptr< IObject > CreateObject()
- {
- static_assert( !is_base_of< INamedObject, Object >::value, "Named mixin can't appear here!" );
- return std::unique_ptr< IObject >( new IdMixin< Object >() );
- }
- template< class Object >
- std::unique_ptr< IObject > CreateObject( const std::string &name )
- {
- return std::unique_ptr< IObject >( static_cast< Object * >( new IdMixin< NameMixin< Object > >( name ) ) );
- }
- std::hash_map< std::pair< const void */*from_type*/, const void */*to_type*/ >, int /* offset */ > aCastMap;
- template< class T >
- T *FastObjectCast( IObject *p )
- {
- // 1. try cached
- auto ids = std::make_pair( p->_type_id(), resolve_type_id< T >() );
- const int UndefinedOffset = -1;
- auto it = aCastMap.find( ids );
- if( it != aCastMap.end() )
- {
- int nOffset = it->second;
- if( nOffset == UndefinedOffset ) return nullptr; // cast failed
- return reinterpret_cast< T * >( reinterpret_cast< char * >( p ) + nOffset );
- }
- // 2. no cach - do cast and fill cache
- T *pRes = dynamic_cast< T * >( p );
- int nOffset = UndefinedOffset;
- if( pRes ) nOffset = reinterpret_cast< char * >( pRes ) - reinterpret_cast< char * >( p );
- bool bRes = aCastMap.insert( std::make_pair( ids, nOffset ) ).second;
- assert( bRes );
- return pRes;
- }
- // -----------------------------------
- // Tests
- //
- void main()
- {
- typedef std::unique_ptr< IObject > ptr;
- ptr ob1 = CreateObject< Object1 >();
- ptr ob2 = CreateObject< Object2 >();
- ptr ob3 = CreateObject< Object3 >();
- ptr ob4 = CreateObject< Object4 >();
- ptr nob1 = CreateObject< Object1 >( "1" );
- ptr nob2 = CreateObject< Object2 >( "2" );
- ptr nob3 = CreateObject< Object3 >( "3" );
- ptr nob4 = CreateObject< Object4 >( "4" );
- std::cout << "1" << std::endl;
- {
- Object1 *p = FastObjectCast< Object1 >( ob1.get() );
- assert( p == FastObjectCast< Object1 >( ob1.get() ) );
- assert( !FastObjectCast< Object2 >( ob1.get() ) );
- assert( !FastObjectCast< Object2 >( ob1.get() ) );
- assert( !FastObjectCast< Object3 >( ob1.get() ) );
- assert( !FastObjectCast< Object3 >( ob1.get() ) );
- assert( !FastObjectCast< Object4 >( ob1.get() ) );
- assert( !FastObjectCast< Object4 >( ob1.get() ) );
- assert( !FastObjectCast< INamedObject >( ob1.get() ) );
- assert( !FastObjectCast< INamedObject >( ob1.get() ) );
- p->Method();
- }
- std::cout << "2" << std::endl;
- {
- Object2 *p = FastObjectCast< Object2 >( ob2.get() );
- assert( p == FastObjectCast< Object2 >( ob2.get() ) );
- assert( !FastObjectCast< Object1 >( ob2.get() ) );
- assert( !FastObjectCast< Object1 >( ob2.get() ) );
- assert( !FastObjectCast< Object3 >( ob2.get() ) );
- assert( !FastObjectCast< Object3 >( ob2.get() ) );
- assert( !FastObjectCast< Object4 >( ob2.get() ) );
- assert( !FastObjectCast< Object4 >( ob2.get() ) );
- assert( !FastObjectCast< INamedObject >( ob2.get() ) );
- assert( !FastObjectCast< INamedObject >( ob2.get() ) );
- p->Method();
- }
- std::cout << "3" << std::endl;
- {
- Object1 *p = FastObjectCast< Object1 >( ob3.get() );
- assert( p == FastObjectCast< Object1 >( ob3.get() ) );
- assert( !FastObjectCast< Object2 >( ob3.get() ) );
- assert( !FastObjectCast< Object2 >( ob3.get() ) );
- Object3 *g = FastObjectCast< Object3 >( ob3.get() );
- assert( g );
- assert( g == FastObjectCast< Object3 >( ob3.get() ) );
- assert( !FastObjectCast< Object4 >( ob3.get() ) );
- assert( !FastObjectCast< Object4 >( ob3.get() ) );
- assert( !FastObjectCast< INamedObject >( ob3.get() ) );
- assert( !FastObjectCast< INamedObject >( ob3.get() ) );
- p->Method();
- g->Method();
- }
- std::cout << "4" << std::endl;
- {
- Object1 *p = FastObjectCast< Object1 >( ob4.get() );
- assert( p == FastObjectCast< Object1 >( ob4.get() ) );
- assert( !FastObjectCast< Object2 >( ob4.get() ) );
- assert( !FastObjectCast< Object2 >( ob4.get() ) );
- Object3 *g = FastObjectCast< Object3 >( ob4.get() );
- assert( g );
- assert( g == FastObjectCast< Object3 >( ob4.get() ) );
- Object4 *q = FastObjectCast< Object4 >( ob4.get() );
- assert( q == FastObjectCast< Object4 >( ob4.get() ) );
- assert( !FastObjectCast< INamedObject >( ob4.get() ) );
- assert( !FastObjectCast< INamedObject >( ob4.get() ) );
- p->Method();
- g->Method();
- q->Method();
- }
- std::cout << std::endl;
- std::cout << "1" << std::endl;
- {
- Object1 *p = FastObjectCast< Object1 >( nob1.get() );
- assert( p == FastObjectCast< Object1 >( nob1.get() ) );
- assert( !FastObjectCast< Object2 >( nob1.get() ) );
- assert( !FastObjectCast< Object2 >( nob1.get() ) );
- assert( !FastObjectCast< Object3 >( nob1.get() ) );
- assert( !FastObjectCast< Object3 >( nob1.get() ) );
- assert( !FastObjectCast< Object4 >( nob1.get() ) );
- assert( !FastObjectCast< Object4 >( nob1.get() ) );
- INamedObject *x = FastObjectCast< INamedObject >( nob1.get() );
- assert( x == FastObjectCast< INamedObject >( nob1.get() ) );
- x->Method();
- p->Method();
- }
- std::cout << "2" << std::endl;
- {
- Object2 *p = FastObjectCast< Object2 >( nob2.get() );
- assert( p == FastObjectCast< Object2 >( nob2.get() ) );
- assert( !FastObjectCast< Object1 >( nob2.get() ) );
- assert( !FastObjectCast< Object1 >( nob2.get() ) );
- assert( !FastObjectCast< Object3 >( nob2.get() ) );
- assert( !FastObjectCast< Object3 >( nob2.get() ) );
- assert( !FastObjectCast< Object4 >( nob2.get() ) );
- assert( !FastObjectCast< Object4 >( nob2.get() ) );
- INamedObject *x = FastObjectCast< INamedObject >( nob2.get() );
- assert( x == FastObjectCast< INamedObject >( nob2.get() ) );
- x->Method();
- p->Method();
- }
- std::cout << "3" << std::endl;
- {
- Object1 *p = FastObjectCast< Object1 >( nob3.get() );
- assert( p == FastObjectCast< Object1 >( nob3.get() ) );
- assert( !FastObjectCast< Object2 >( nob3.get() ) );
- assert( !FastObjectCast< Object2 >( nob3.get() ) );
- Object3 *g = FastObjectCast< Object3 >( nob3.get() );
- assert( g );
- assert( g == FastObjectCast< Object3 >( nob3.get() ) );
- assert( !FastObjectCast< Object4 >( nob3.get() ) );
- assert( !FastObjectCast< Object4 >( nob3.get() ) );
- INamedObject *x = FastObjectCast< INamedObject >( nob3.get() );
- assert( x == FastObjectCast< INamedObject >( nob3.get() ) );
- x->Method();
- p->Method();
- g->Method();
- }
- std::cout << "4" << std::endl;
- {
- Object1 *p = FastObjectCast< Object1 >( nob4.get() );
- assert( p == FastObjectCast< Object1 >( nob4.get() ) );
- assert( !FastObjectCast< Object2 >( nob4.get() ) );
- assert( !FastObjectCast< Object2 >( nob4.get() ) );
- Object3 *g = FastObjectCast< Object3 >( nob4.get() );
- assert( g );
- assert( g == FastObjectCast< Object3 >( nob4.get() ) );
- Object4 *q = FastObjectCast< Object4 >( nob4.get() );
- assert( q == FastObjectCast< Object4 >( nob4.get() ) );
- INamedObject *x = FastObjectCast< INamedObject >( nob4.get() );
- assert( x == FastObjectCast< INamedObject >( nob4.get() ) );
- x->Method();
- p->Method();
- g->Method();
- q->Method();
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement