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 + -
显示快捷键?