Advertisement
Guest User

RE. RTTI vs Шаблонная магия

a guest
Jul 18th, 2012
178
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.35 KB | None | 0 0
  1. #include "StdAfx.h"
  2.  
  3. #include <hash_map>
  4. #include <iostream>
  5. #include <memory>
  6. #include <assert.h>
  7.  
  8. #include <boost/type_traits/is_base_of.hpp>
  9. #include <boost/functional/hash/extensions.hpp> // support for std::pair hashing
  10.  
  11. namespace std
  12. {
  13.     using boost::hash_value; // support for std::pair hashing
  14. }
  15.  
  16. using namespace boost;
  17.  
  18. // -----------------------------------
  19. // Objects
  20. //
  21.  
  22. class IObject
  23. {
  24.     template< class T > friend T *FastObjectCast( IObject * );
  25.     virtual const void *_type_id() = 0;
  26. public:    
  27.     virtual void Method() = 0;
  28. };
  29.  
  30. // IObject inheritance is not sticky required actually (we just want INamedObject to be compatible with IObject)
  31. struct INamedObject : IObject { virtual std::string &Name() = 0; };
  32.  
  33. struct Object1 : IObject { virtual void Method(){ std::cout << "Object1" << std::endl; } };
  34. struct Object2 : IObject { virtual void Method(){ std::cout << "Object2" << std::endl; } };
  35. struct Object3 : Object1 { virtual void Method(){ std::cout << "Object3" << std::endl; } };
  36. struct Object4 : Object3 { virtual void Method(){ std::cout << "Object4" << std::endl; } };
  37.  
  38. // -----------------------------------
  39. // Factory Internals
  40. //
  41.  
  42. // Appends name interface implementation
  43. template< class Base >
  44. class NameMixin : public Base, public INamedObject
  45. {
  46.     static_assert( is_base_of< IObject, Base >::value, "Base must be derived from IObject!" );
  47.     static_assert( !is_base_of< INamedObject, Base >::value, "Named mixin can't be present twice in hierarchy!" );
  48. public:
  49.     NameMixin( const std::string &name ) : name( name ) {}
  50.     virtual std::string &Name(){ return name; }
  51.     virtual void Method(){ return Base::Method(); } // needed because INamedObject derived from IObject
  52. private:
  53.     std::string name;
  54. };
  55.  
  56. struct id_mixin_tag {};
  57.  
  58. template< class U >
  59. const void *resolve_type_id(){ return &typeid( U ); }
  60.  
  61. // Appends type id interface implementatoion
  62. template< class Base >
  63. class IdMixin : public Base, public id_mixin_tag
  64. {
  65.     static_assert( is_base_of< IObject, Base >::value, "Base must be derived from IObject!" );
  66.     static_assert( !is_base_of< id_mixin_tag, Base >::value, "Id mixin can't be present twice in hierarchy!" );
  67.     virtual const void *_type_id(){ static const void *pRes = resolve_type_id< IdMixin< Base > >(); return pRes; };
  68. public:
  69.     IdMixin() {}
  70.     template< class T > IdMixin( T &&rr ) : Base( std::forward< T >( rr ) ) {}
  71. };
  72.  
  73. // ---------------------------------------------
  74. // Factory Internals - Objects Creation/Casts
  75. //
  76.  
  77. template< class Object >
  78. std::unique_ptr< IObject > CreateObject()
  79. {
  80.     static_assert( !is_base_of< INamedObject, Object >::value, "Named mixin can't appear here!" );
  81.     return std::unique_ptr< IObject >( new IdMixin< Object >() );
  82. }
  83.  
  84. template< class Object >
  85. std::unique_ptr< IObject > CreateObject( const std::string &name )
  86. {
  87.     return std::unique_ptr< IObject >( static_cast< Object * >( new IdMixin< NameMixin< Object > >( name ) ) );
  88. }
  89.  
  90. std::hash_map< std::pair< const void */*from_type*/, const void */*to_type*/ >, int /* offset */ > aCastMap;
  91.  
  92. template< class T >
  93. T *FastObjectCast( IObject *p )
  94. {
  95.     // 1. try cached
  96.     auto ids = std::make_pair( p->_type_id(), resolve_type_id< T >() );
  97.     const int UndefinedOffset = -1;
  98.     auto it = aCastMap.find( ids );
  99.     if( it != aCastMap.end() )
  100.     {
  101.         int nOffset = it->second;
  102.         if( nOffset == UndefinedOffset ) return nullptr; // cast failed
  103.         return reinterpret_cast< T * >( reinterpret_cast< char * >( p ) + nOffset );
  104.     }
  105.     // 2. no cach - do cast and fill cache
  106.     T *pRes = dynamic_cast< T * >( p );
  107.     int nOffset = UndefinedOffset;
  108.     if( pRes ) nOffset = reinterpret_cast< char * >( pRes ) - reinterpret_cast< char * >( p );
  109.     bool bRes = aCastMap.insert( std::make_pair( ids, nOffset ) ).second;
  110.     assert( bRes );
  111.     return pRes;
  112. }
  113.  
  114. // -----------------------------------
  115. // Tests
  116. //
  117.  
  118. void main()
  119. {
  120.     typedef std::unique_ptr< IObject > ptr;
  121.  
  122.     ptr ob1 = CreateObject< Object1 >();
  123.     ptr ob2 = CreateObject< Object2 >();
  124.     ptr ob3 = CreateObject< Object3 >();
  125.     ptr ob4 = CreateObject< Object4 >();
  126.  
  127.     ptr nob1 = CreateObject< Object1 >( "1" );
  128.     ptr nob2 = CreateObject< Object2 >( "2" );
  129.     ptr nob3 = CreateObject< Object3 >( "3" );
  130.     ptr nob4 = CreateObject< Object4 >( "4" );
  131.  
  132.     std::cout << "1" << std::endl;
  133.     {
  134.         Object1 *p = FastObjectCast< Object1 >( ob1.get() );
  135.         assert( p == FastObjectCast< Object1 >( ob1.get() ) );
  136.         assert( !FastObjectCast< Object2 >( ob1.get() ) );
  137.         assert( !FastObjectCast< Object2 >( ob1.get() ) );
  138.         assert( !FastObjectCast< Object3 >( ob1.get() ) );
  139.         assert( !FastObjectCast< Object3 >( ob1.get() ) );
  140.         assert( !FastObjectCast< Object4 >( ob1.get() ) );
  141.         assert( !FastObjectCast< Object4 >( ob1.get() ) );
  142.         assert( !FastObjectCast< INamedObject >( ob1.get() ) );
  143.         assert( !FastObjectCast< INamedObject >( ob1.get() ) );
  144.         p->Method();
  145.     }
  146.     std::cout << "2" << std::endl;
  147.     {
  148.         Object2 *p = FastObjectCast< Object2 >( ob2.get() );
  149.         assert( p == FastObjectCast< Object2 >( ob2.get() ) );
  150.         assert( !FastObjectCast< Object1 >( ob2.get() ) );
  151.         assert( !FastObjectCast< Object1 >( ob2.get() ) );
  152.         assert( !FastObjectCast< Object3 >( ob2.get() ) );
  153.         assert( !FastObjectCast< Object3 >( ob2.get() ) );
  154.         assert( !FastObjectCast< Object4 >( ob2.get() ) );
  155.         assert( !FastObjectCast< Object4 >( ob2.get() ) );
  156.         assert( !FastObjectCast< INamedObject >( ob2.get() ) );
  157.         assert( !FastObjectCast< INamedObject >( ob2.get() ) );
  158.         p->Method();
  159.     }
  160.     std::cout << "3" << std::endl;
  161.     {
  162.         Object1 *p = FastObjectCast< Object1 >( ob3.get() );
  163.         assert( p == FastObjectCast< Object1 >( ob3.get() ) );
  164.         assert( !FastObjectCast< Object2 >( ob3.get() ) );
  165.         assert( !FastObjectCast< Object2 >( ob3.get() ) );
  166.         Object3 *g = FastObjectCast< Object3 >( ob3.get() );
  167.         assert( g );
  168.         assert( g == FastObjectCast< Object3 >( ob3.get() ) );
  169.         assert( !FastObjectCast< Object4 >( ob3.get() ) );
  170.         assert( !FastObjectCast< Object4 >( ob3.get() ) );
  171.         assert( !FastObjectCast< INamedObject >( ob3.get() ) );
  172.         assert( !FastObjectCast< INamedObject >( ob3.get() ) );
  173.         p->Method();
  174.         g->Method();
  175.     }
  176.     std::cout << "4" << std::endl;
  177.     {
  178.         Object1 *p = FastObjectCast< Object1 >( ob4.get() );
  179.         assert( p == FastObjectCast< Object1 >( ob4.get() ) );
  180.         assert( !FastObjectCast< Object2 >( ob4.get() ) );
  181.         assert( !FastObjectCast< Object2 >( ob4.get() ) );
  182.         Object3 *g = FastObjectCast< Object3 >( ob4.get() );
  183.         assert( g );
  184.         assert( g == FastObjectCast< Object3 >( ob4.get() ) );
  185.         Object4 *q = FastObjectCast< Object4 >( ob4.get() );
  186.         assert( q == FastObjectCast< Object4 >( ob4.get() ) );
  187.         assert( !FastObjectCast< INamedObject >( ob4.get() ) );
  188.         assert( !FastObjectCast< INamedObject >( ob4.get() ) );
  189.         p->Method();
  190.         g->Method();
  191.         q->Method();
  192.     }
  193.  
  194.     std::cout << std::endl;
  195.     std::cout << "1" << std::endl;
  196.     {
  197.         Object1 *p = FastObjectCast< Object1 >( nob1.get() );
  198.         assert( p == FastObjectCast< Object1 >( nob1.get() ) );
  199.         assert( !FastObjectCast< Object2 >( nob1.get() ) );
  200.         assert( !FastObjectCast< Object2 >( nob1.get() ) );
  201.         assert( !FastObjectCast< Object3 >( nob1.get() ) );
  202.         assert( !FastObjectCast< Object3 >( nob1.get() ) );
  203.         assert( !FastObjectCast< Object4 >( nob1.get() ) );
  204.         assert( !FastObjectCast< Object4 >( nob1.get() ) );
  205.         INamedObject *x = FastObjectCast< INamedObject >( nob1.get() );
  206.         assert( x == FastObjectCast< INamedObject >( nob1.get() ) );
  207.         x->Method();
  208.         p->Method();
  209.     }
  210.     std::cout << "2" << std::endl;
  211.     {
  212.         Object2 *p = FastObjectCast< Object2 >( nob2.get() );
  213.         assert( p == FastObjectCast< Object2 >( nob2.get() ) );
  214.         assert( !FastObjectCast< Object1 >( nob2.get() ) );
  215.         assert( !FastObjectCast< Object1 >( nob2.get() ) );
  216.         assert( !FastObjectCast< Object3 >( nob2.get() ) );
  217.         assert( !FastObjectCast< Object3 >( nob2.get() ) );
  218.         assert( !FastObjectCast< Object4 >( nob2.get() ) );
  219.         assert( !FastObjectCast< Object4 >( nob2.get() ) );
  220.         INamedObject *x = FastObjectCast< INamedObject >( nob2.get() );
  221.         assert( x == FastObjectCast< INamedObject >( nob2.get() ) );
  222.         x->Method();
  223.         p->Method();
  224.     }
  225.     std::cout << "3" << std::endl;
  226.     {
  227.         Object1 *p = FastObjectCast< Object1 >( nob3.get() );
  228.         assert( p == FastObjectCast< Object1 >( nob3.get() ) );
  229.         assert( !FastObjectCast< Object2 >( nob3.get() ) );
  230.         assert( !FastObjectCast< Object2 >( nob3.get() ) );
  231.         Object3 *g = FastObjectCast< Object3 >( nob3.get() );
  232.         assert( g );
  233.         assert( g == FastObjectCast< Object3 >( nob3.get() ) );
  234.         assert( !FastObjectCast< Object4 >( nob3.get() ) );
  235.         assert( !FastObjectCast< Object4 >( nob3.get() ) );
  236.         INamedObject *x = FastObjectCast< INamedObject >( nob3.get() );
  237.         assert( x == FastObjectCast< INamedObject >( nob3.get() ) );
  238.         x->Method();
  239.         p->Method();
  240.         g->Method();
  241.     }
  242.     std::cout << "4" << std::endl;
  243.     {
  244.         Object1 *p = FastObjectCast< Object1 >( nob4.get() );
  245.         assert( p == FastObjectCast< Object1 >( nob4.get() ) );
  246.         assert( !FastObjectCast< Object2 >( nob4.get() ) );
  247.         assert( !FastObjectCast< Object2 >( nob4.get() ) );
  248.         Object3 *g = FastObjectCast< Object3 >( nob4.get() );
  249.         assert( g );
  250.         assert( g == FastObjectCast< Object3 >( nob4.get() ) );
  251.         Object4 *q = FastObjectCast< Object4 >( nob4.get() );
  252.         assert( q == FastObjectCast< Object4 >( nob4.get() ) );
  253.         INamedObject *x = FastObjectCast< INamedObject >( nob4.get() );
  254.         assert( x == FastObjectCast< INamedObject >( nob4.get() ) );
  255.         x->Method();
  256.         p->Method();
  257.         g->Method();
  258.         q->Method();
  259.     }
  260. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement