⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fastdelegate.h

📁 AMOP 0.3 is an Automatic Mock Object for C++. By using ABI and template techniques, it can simulate
💻 H
📖 第 1 页 / 共 5 页
字号:
//  According to the standard, this can be done legally with reinterpret_cast<>.
//	For (non-standard) compilers which use member function pointers which vary in size 
//  depending on the class, we need to use	knowledge of the internal structure of a 
//  member function pointer, as used by the compiler. Template specialization is used
//  to distinguish between the sizes. Because some compilers don't support partial 
//	template specialisation, I use full specialisation of a wrapper struct.

// general case -- don't know how to convert it. Force a compile failure
template <int N>
struct SimplifyMemFunc {
	template <class X, class XFuncType, class GenericMemFuncType>
	inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, 
		GenericMemFuncType &bound_func) { 
		// Unsupported member function type -- force a compile failure.
	    // (it's illegal to have a array with negative size).
		typedef char ERROR_Unsupported_member_function_pointer_on_this_compiler[N-100];
		return 0; 
	}
};

// For compilers where all member func ptrs are the same size, everything goes here.
// For non-standard compilers, only single_inheritance classes go here.
template <>
struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE>  {	
	template <class X, class XFuncType, class GenericMemFuncType>
	inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, 
			GenericMemFuncType &bound_func) {
#if defined __DMC__  
		// Digital Mars doesn't allow you to cast between abitrary PMF's, 
		// even though the standard says you can. The 32-bit compiler lets you
		// static_cast through an int, but the DOS compiler doesn't.
		bound_func = horrible_cast<GenericMemFuncType>(function_to_bind);
#else 
        bound_func = reinterpret_cast<GenericMemFuncType>(function_to_bind);
#endif
        return reinterpret_cast<GenericClass *>(pthis);
	}
};

////////////////////////////////////////////////////////////////////////////////
//						Fast Delegates, part 1b:
//
//					Workarounds for Microsoft and Intel
//
////////////////////////////////////////////////////////////////////////////////


// Compilers with member function pointers which violate the standard (MSVC, Intel, Codeplay),
// need to be treated as a special case.
#ifdef FASTDLGT_MICROSOFT_MFP

// We use unions to perform horrible_casts. I would like to use #pragma pack(push, 1)
// at the start of each function for extra safety, but VC6 seems to ICE
// intermittently if you do this inside a template.

// __multiple_inheritance classes go here
// Nasty hack for Microsoft and Intel (IA32 and Itanium)
template<>
struct SimplifyMemFunc< SINGLE_MEMFUNCPTR_SIZE + sizeof(int) >  {
	template <class X, class XFuncType, class GenericMemFuncType>
	inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, 
		GenericMemFuncType &bound_func) { 
		// We need to use a horrible_cast to do this conversion.
		// In MSVC, a multiple inheritance member pointer is internally defined as:
        union {
			XFuncType func;
			struct {	 
				GenericMemFuncType funcaddress; // points to the actual member function
				int delta;	     // #BYTES to be added to the 'this' pointer
			}s;
        } u;
		// Check that the horrible_cast will work
		typedef int ERROR_CantUsehorrible_cast[sizeof(function_to_bind)==sizeof(u.s)? 1 : -1];
        u.func = function_to_bind;
		bound_func = u.s.funcaddress;
		return reinterpret_cast<GenericClass *>(reinterpret_cast<char *>(pthis) + u.s.delta); 
	}
};

// virtual inheritance is a real nuisance. It's inefficient and complicated.
// On MSVC and Intel, there isn't enough information in the pointer itself to
// enable conversion to a closure pointer. Earlier versions of this code didn't
// work for all cases, and generated a compile-time error instead.
// But a very clever hack invented by John M. Dlugosz solves this problem.
// My code is somewhat different to his: I have no asm code, and I make no 
// assumptions about the calling convention that is used.

// In VC++ and ICL, a virtual_inheritance member pointer 
// is internally defined as:
struct MicrosoftVirtualMFP {
	void (GenericClass::*codeptr)(); // points to the actual member function
	int delta;		// #bytes to be added to the 'this' pointer
	int vtable_index; // or 0 if no virtual inheritance
};
// The CRUCIAL feature of Microsoft/Intel MFPs which we exploit is that the
// m_codeptr member is *always* called, regardless of the values of the other
// members. (This is *not* true for other compilers, eg GCC, which obtain the
// function address from the vtable if a virtual function is being called).
// Dlugosz's trick is to make the codeptr point to a probe function which
// returns the 'this' pointer that was used.

// Define a generic class that uses virtual inheritance.
// It has a trival member function that returns the value of the 'this' pointer.
struct GenericVirtualClass : virtual public GenericClass
{
	typedef GenericVirtualClass * (GenericVirtualClass::*ProbePtrType)();
	GenericVirtualClass * GetThis() { return this; }
};

// __virtual_inheritance classes go here
template <>
struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 2*sizeof(int) >
{

	template <class X, class XFuncType, class GenericMemFuncType>
	inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, 
		GenericMemFuncType &bound_func) {
		union {
			XFuncType func;
			GenericClass* (X::*ProbeFunc)();
			MicrosoftVirtualMFP s;
		} u;
		u.func = function_to_bind;
		bound_func = reinterpret_cast<GenericMemFuncType>(u.s.codeptr);
		union {
			GenericVirtualClass::ProbePtrType virtfunc;
			MicrosoftVirtualMFP s;
		} u2;
		// Check that the horrible_cast<>s will work
		typedef int ERROR_CantUsehorrible_cast[sizeof(function_to_bind)==sizeof(u.s)
			&& sizeof(function_to_bind)==sizeof(u.ProbeFunc)
			&& sizeof(u2.virtfunc)==sizeof(u2.s) ? 1 : -1];
   // Unfortunately, taking the address of a MF prevents it from being inlined, so 
   // this next line can't be completely optimised away by the compiler.
		u2.virtfunc = &GenericVirtualClass::GetThis;
		u.s.codeptr = u2.s.codeptr;
		return (pthis->*u.ProbeFunc)();
	}
};

#if (_MSC_VER <1300)

// Nasty hack for Microsoft Visual C++ 6.0
// unknown_inheritance classes go here
// There is a compiler bug in MSVC6 which generates incorrect code in this case!!
template <>
struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 3*sizeof(int) >
{
	template <class X, class XFuncType, class GenericMemFuncType>
	inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, 
		GenericMemFuncType &bound_func) {
		// There is an apalling but obscure compiler bug in MSVC6 and earlier:
		// vtable_index and 'vtordisp' are always set to 0 in the 
		// unknown_inheritance case!
		// This means that an incorrect function could be called!!!
		// Compiling with the /vmg option leads to potentially incorrect code.
		// This is probably the reason that the IDE has a user interface for specifying
		// the /vmg option, but it is disabled -  you can only specify /vmg on 
		// the command line. In VC1.5 and earlier, the compiler would ICE if it ever
		// encountered this situation.
		// It is OK to use the /vmg option if /vmm or /vms is specified.

		// Fortunately, the wrong function is only called in very obscure cases.
		// It only occurs when a derived class overrides a virtual function declared 
		// in a virtual base class, and the member function 
		// points to the *Derived* version of that function. The problem can be
		// completely averted in 100% of cases by using the *Base class* for the 
		// member fpointer. Ie, if you use the base class as an interface, you'll
		// stay out of trouble.
		// Occasionally, you might want to point directly to a derived class function
		// that isn't an override of a base class. In this case, both vtable_index 
		// and 'vtordisp' are zero, but a virtual_inheritance pointer will be generated.
		// We can generate correct code in this case. To prevent an incorrect call from
		// ever being made, on MSVC6 we generate a warning, and call a function to 
		// make the program crash instantly. 
		typedef char ERROR_VC6CompilerBug[-100];
		return 0; 
	}
};


#else 

// Nasty hack for Microsoft and Intel (IA32 and Itanium)
// unknown_inheritance classes go here 
// This is probably the ugliest bit of code I've ever written. Look at the casts!
// There is a compiler bug in MSVC6 which prevents it from using this code.
template <>
struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 3*sizeof(int) >
{
	template <class X, class XFuncType, class GenericMemFuncType>
	inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, 
			GenericMemFuncType &bound_func) {
		// The member function pointer is 16 bytes long. We can't use a normal cast, but
		// we can use a union to do the conversion.
		union {
			XFuncType func;
			// In VC++ and ICL, an unknown_inheritance member pointer 
			// is internally defined as:
			struct {
				GenericMemFuncType m_funcaddress; // points to the actual member function
				int delta;		// #bytes to be added to the 'this' pointer
				int vtordisp;		// #bytes to add to 'this' to find the vtable
				int vtable_index; // or 0 if no virtual inheritance
			} s;
		} u;
		// Check that the horrible_cast will work
		typedef int ERROR_CantUsehorrible_cast[sizeof(XFuncType)==sizeof(u.s)? 1 : -1];
		u.func = function_to_bind;
		bound_func = u.s.funcaddress;
		int virtual_delta = 0;
		if (u.s.vtable_index) { // Virtual inheritance is used
			// First, get to the vtable. 
			// It is 'vtordisp' bytes from the start of the class.
			const int * vtable = *reinterpret_cast<const int *const*>(
				reinterpret_cast<const char *>(pthis) + u.s.vtordisp );

			// 'vtable_index' tells us where in the table we should be looking.
			virtual_delta = u.s.vtordisp + *reinterpret_cast<const int *>( 
				reinterpret_cast<const char *>(vtable) + u.s.vtable_index);
		}
		// The int at 'virtual_delta' gives us the amount to add to 'this'.
        // Finally we can add the three components together. Phew!
        return reinterpret_cast<GenericClass *>(
			reinterpret_cast<char *>(pthis) + u.s.delta + virtual_delta);
	};
};
#endif // MSVC 7 and greater

#endif // MS/Intel hacks

}  // namespace detail

////////////////////////////////////////////////////////////////////////////////
//						Fast Delegates, part 2:
//
//	Define the delegate storage, and cope with static functions
//
////////////////////////////////////////////////////////////////////////////////

// DelegateMemento -- an opaque structure which can hold an arbitary delegate.
// It knows nothing about the calling convention or number of arguments used by
// the function pointed to.
// It supplies comparison operators so that it can be stored in STL collections.
// It cannot be set to anything other than null, nor invoked directly: 
//   it must be converted to a specific delegate.

// Implementation:
// There are two possible implementations: the Safe method and the Evil method.
//				DelegateMemento - Safe version
//
// This implementation is standard-compliant, but a bit tricky.
// A static function pointer is stored inside the class. 
// Here are the valid values:
// +-- Static pointer --+--pThis --+-- pMemFunc-+-- Meaning------+
// |   0				|  0       |   0        | Empty          |
// |   !=0              |(dontcare)|  Invoker   | Static function|
// |   0                |  !=0     |  !=0*      | Method call    |
// +--------------------+----------+------------+----------------+
//  * For Metrowerks, this can be 0. (first virtual function in a 
//       single_inheritance class).
// When stored stored inside a specific delegate, the 'dontcare' entries are replaced
// with a reference to the delegate itself. This complicates the = and == operators
// for the delegate class.

//				DelegateMemento - Evil version
//
// For compilers where data pointers are at least as big as code pointers, it is 
// possible to store the function pointer in the this pointer, using another 
// horrible_cast. In this case the DelegateMemento implementation is simple:
// +--pThis --+-- pMemFunc-+-- Meaning---------------------+
// |    0     |  0         | Empty                         |
// |  !=0     |  !=0*      | Static function or method call|
// +----------+------------+-------------------------------+
//  * For Metrowerks, this can be 0. (first virtual function in a 
//       single_inheritance class).
// Note that the Sun C++ and MSVC documentation explicitly state that they 
// support static_cast between void * and function pointers.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -