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

0001 /*
0002  * SPDX-FileCopyrightText: 2008 Trevor Pounds
0003  * SPDX-License-Identifier: MIT
0004  */
0005 
0006 #ifndef __MOCKITOPP_DYNAMIC_OBJECT_HPP__
0007 #define __MOCKITOPP_DYNAMIC_OBJECT_HPP__
0008 
0009 #include <mockitopp/exceptions.hpp>
0010 #include <mockitopp/detail/stubbing/dynamic_vfunction.hpp>
0011 #include <mockitopp/detail/stubbing/proxy_vfunction.hpp>
0012 #include <mockitopp/detail/util/remove_member_function_pointer_cv.hpp>
0013 
0014 namespace mockitopp
0015 {
0016    namespace detail
0017    {
0018       /**
0019        * helper class to find the vtable offset given a member function pointer
0020        */
0021       struct vtable_offset_helper
0022       {
0023          template <typename T>
0024          static int get(T ptr2member)
0025          {
0026             vtable_offset_helper f;
0027 #pragma GCC diagnostic push
0028 #pragma GCC diagnostic ignored "-Wcast-function-type"
0029             return (f.*reinterpret_cast<int (vtable_offset_helper::*)()>(ptr2member))();
0030 #pragma GCC diagnostic pop
0031          }
0032 
0033          virtual int offset0() { return 0; }
0034          virtual int offset1() { return 1; }
0035          virtual int offset2() { return 2; }
0036          virtual int offset3() { return 3; }
0037          virtual int offset4() { return 4; }
0038          virtual int offset5() { return 5; }
0039          virtual int offset6() { return 6; }
0040          virtual int offset7() { return 7; }
0041          virtual int offset8() { return 8; }
0042          virtual int offset9() { return 9; }
0043          virtual int offset10() { return 10; }
0044          virtual int offset11() { return 11; }
0045          virtual int offset12() { return 12; }
0046          virtual int offset13() { return 13; }
0047          virtual int offset14() { return 14; }
0048          virtual int offset15() { return 15; }
0049          virtual int offset16() { return 16; }
0050          virtual int offset17() { return 17; }
0051          virtual int offset18() { return 18; }
0052          virtual int offset19() { return 19; }
0053          virtual int offset20() { return 20; }
0054          virtual int offset21() { return 21; }
0055          virtual int offset22() { return 22; }
0056          virtual int offset23() { return 23; }
0057          virtual int offset24() { return 24; }
0058          virtual int offset25() { return 25; }
0059          virtual int offset26() { return 26; }
0060          virtual int offset27() { return 27; }
0061          virtual int offset28() { return 28; }
0062          virtual int offset29() { return 29; }
0063          virtual int offset30() { return 30; }
0064          virtual int offset31() { return 31; }
0065          virtual int offset32() { return 32; }
0066          virtual int offset33() { return 33; }
0067          virtual int offset34() { return 34; }
0068          virtual int offset35() { return 35; }
0069          virtual int offset36() { return 36; }
0070          virtual int offset37() { return 37; }
0071          virtual int offset38() { return 38; }
0072          virtual int offset39() { return 39; }
0073          virtual int offset40() { return 40; }
0074          virtual int offset41() { return 41; }
0075          virtual int offset42() { return 42; }
0076          virtual int offset43() { return 43; }
0077          virtual int offset44() { return 44; }
0078          virtual int offset45() { return 45; }
0079          virtual int offset46() { return 46; }
0080          virtual int offset47() { return 47; }
0081          virtual int offset48() { return 48; }
0082          virtual int offset49() { return 49; }
0083 
0084          virtual ~vtable_offset_helper() {}
0085       };
0086 
0087       /**
0088        * implementation class for pseduo-dynamically defining an interface
0089        */
0090       struct dynamic_object
0091       {
0092          struct vtable {
0093             void* vbase_offset;
0094             void* vcall_offset;
0095             void* offset_to_top;
0096             void* type_info;
0097             void* functions[50];
0098          };
0099 
0100          void*   vtable_object_ptr;
0101          void*   vtable_mocks[50];
0102          vtable* vtable_actual_ptr;
0103 
0104          dynamic_object()
0105             : vtable_actual_ptr(new vtable)
0106          {
0107             vtable_actual_ptr->vbase_offset  = 0;
0108             vtable_actual_ptr->vcall_offset  = 0;
0109             vtable_actual_ptr->offset_to_top = 0;
0110             vtable_actual_ptr->type_info     = 0;
0111             for(int i = 0; i < 50; i++)
0112             {
0113                vtable_actual_ptr->functions[i] = horrible_cast<void*>(&dynamic_object::missing_vfunction);
0114                vtable_mocks[i] = 0;
0115             }
0116             vtable_object_ptr = vtable_actual_ptr->functions;
0117          }
0118 
0119          ~dynamic_object()
0120          {
0121             for(int i = 0; i < 50; i++)
0122             {
0123                if(vtable_mocks[i] != 0)
0124                   { delete reinterpret_cast<dynamic_vfunction_base*>(vtable_mocks[i]); }
0125             }
0126             delete vtable_actual_ptr;
0127          }
0128 
0129          template <typename M>
0130          dynamic_vfunction<typename remove_member_function_pointer_cv<M>::type>& define_function(M ptr2member)
0131          {
0132             int offset = vtable_offset_helper::get(ptr2member);
0133             if(vtable_mocks[offset] == 0)
0134             {
0135                vtable_actual_ptr->functions[offset] = proxy_vfunction_factory<M>::get(ptr2member);
0136                vtable_mocks[offset] = new dynamic_vfunction<typename remove_member_function_pointer_cv<M>::type>();
0137             }
0138             return *reinterpret_cast<dynamic_vfunction<typename remove_member_function_pointer_cv<M>::type>*>(vtable_mocks[offset]);
0139          }
0140 
0141          void missing_vfunction()
0142             { throw missing_implementation_exception(); }
0143 
0144       private:
0145          dynamic_object(const dynamic_object &);
0146          dynamic_object &operator=(const dynamic_object &);
0147       };
0148    } // namespace detail
0149 } // namespace mockitopp
0150 
0151 #endif //__MOCKITOPP_DYNAMIC_OBJECT_HPP__