File indexing completed on 2024-09-22 04:53:10

0001 #ifndef __MOCKITOPP_DYNAMIC_OBJECT_HPP__
0002 #define __MOCKITOPP_DYNAMIC_OBJECT_HPP__
0003 
0004 #include <mockitopp/exceptions.hpp>
0005 #include <mockitopp/detail/stubbing/dynamic_vfunction.hpp>
0006 #include <mockitopp/detail/stubbing/proxy_vfunction.hpp>
0007 #include <mockitopp/detail/util/remove_member_function_pointer_cv.hpp>
0008 
0009 namespace mockitopp
0010 {
0011    namespace detail
0012    {
0013       /**
0014        * helper class to find the vtable offset given a member function pointer
0015        */
0016       struct vtable_offset_helper
0017       {
0018          template <typename T>
0019          static int get(T ptr2member)
0020          {
0021             vtable_offset_helper f;
0022 #pragma GCC diagnostic push
0023 #pragma GCC diagnostic ignored "-Wcast-function-type"
0024             return (f.*reinterpret_cast<int (vtable_offset_helper::*)()>(ptr2member))();
0025 #pragma GCC diagnostic pop
0026          }
0027 
0028 include(`mockitopp/detail/m4/REPEAT.m4')dnl
0029 define(`DEFINE_VTABLE_OFFSET_HELPER_FUNCTION', `        virtual int offset$1() { return $1; }
0030 ')dnl
0031 M4_REPEAT(MOCKITOPP_MAX_VIRTUAL_FUNCTIONS, `DEFINE_VTABLE_OFFSET_HELPER_FUNCTION')dnl
0032 
0033          virtual ~vtable_offset_helper() {}
0034       };
0035 
0036       /**
0037        * implementation class for pseduo-dynamically defining an interface
0038        */
0039       struct dynamic_object
0040       {
0041          struct vtable {
0042             void* vbase_offset;
0043             void* vcall_offset;
0044             void* offset_to_top;
0045             void* type_info;
0046             void* functions[MOCKITOPP_MAX_VIRTUAL_FUNCTIONS];
0047          };
0048 
0049          void*   vtable_object_ptr;
0050          void*   vtable_mocks[MOCKITOPP_MAX_VIRTUAL_FUNCTIONS];
0051          vtable* vtable_actual_ptr;
0052 
0053          dynamic_object()
0054             : vtable_actual_ptr(new vtable)
0055          {
0056             vtable_actual_ptr->vbase_offset  = 0;
0057             vtable_actual_ptr->vcall_offset  = 0;
0058             vtable_actual_ptr->offset_to_top = 0;
0059             vtable_actual_ptr->type_info     = 0;
0060             for(int i = 0; i < MOCKITOPP_MAX_VIRTUAL_FUNCTIONS; i++)
0061             {
0062                vtable_actual_ptr->functions[i] = horrible_cast<void*>(&dynamic_object::missing_vfunction);
0063                vtable_mocks[i] = 0;
0064             }
0065             vtable_object_ptr = vtable_actual_ptr->functions;
0066          }
0067 
0068          ~dynamic_object()
0069          {
0070             for(int i = 0; i < MOCKITOPP_MAX_VIRTUAL_FUNCTIONS; i++)
0071             {
0072                if(vtable_mocks[i] != 0)
0073                   { delete reinterpret_cast<dynamic_vfunction_base*>(vtable_mocks[i]); }
0074             }
0075             delete vtable_actual_ptr;
0076          }
0077 
0078          template <typename M>
0079          dynamic_vfunction<typename remove_member_function_pointer_cv<M>::type>& define_function(M ptr2member)
0080          {
0081             int offset = vtable_offset_helper::get(ptr2member);
0082             if(vtable_mocks[offset] == 0)
0083             {
0084                vtable_actual_ptr->functions[offset] = proxy_vfunction_factory<M>::get(ptr2member);
0085                vtable_mocks[offset] = new dynamic_vfunction<typename remove_member_function_pointer_cv<M>::type>();
0086             }
0087             return *reinterpret_cast<dynamic_vfunction<typename remove_member_function_pointer_cv<M>::type>*>(vtable_mocks[offset]);
0088          }
0089 
0090          void missing_vfunction()
0091             { throw missing_implementation_exception(); }
0092       };
0093    } // namespace detail
0094 } // namespace mockitopp
0095 
0096 #endif //__MOCKITOPP_DYNAMIC_OBJECT_HPP__