fastdelegate.h.svn-base

来自「ffshow源码」· SVN-BASE 代码 · 共 1,415 行 · 第 1/5 页

SVN-BASE
1,415
字号
//  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 failuretemplate <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;			#ifdef WIN64			#pragma pack(push,1)			#endif			struct {	 				GenericMemFuncType funcaddress; // points to the actual member function				int delta;	     // #BYTES to be added to the 'this' pointer			}s;			#ifdef WIN64			#pragma pack(pop)			#endif        } 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 heretemplate <>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.class DelegateMemento {protected: 

⌨️ 快捷键说明

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