├── .gitignore ├── LICENSE ├── README.md └── src ├── FastDelegate ├── FastDelegate.hpp ├── official-v1.5 │ ├── Demo.cpp │ ├── FastDelegate.h │ └── FastDelegateBind.h └── unofficial-v2 │ └── FastDelegate.h ├── FastFunc └── FastFunc.hpp ├── SRDelegate └── SRDelegate.hpp ├── benchmark ├── FastDelegate.h ├── FastDelegateBind.h ├── delegate_performance_test.pro ├── delegate_performance_test.sln ├── delegate_performance_test.vcxproj └── main.cpp └── unit_test ├── TEST_FastFunc.cpp ├── TEST_SRDelegate.cpp ├── TEST_raw.cpp ├── catch.hpp ├── test_main.cpp ├── test_sample.cpp ├── test_sample.hpp ├── unit_test.pro ├── unit_test.sln ├── unit_test.vcxproj └── unit_test.vcxproj.filters /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # .NET Core 46 | project.lock.json 47 | project.fragment.lock.json 48 | artifacts/ 49 | **/Properties/launchSettings.json 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # Visual Studio code coverage results 117 | *.coverage 118 | *.coveragexml 119 | 120 | # NCrunch 121 | _NCrunch_* 122 | .*crunch*.local.xml 123 | nCrunchTemp_* 124 | 125 | # MightyMoose 126 | *.mm.* 127 | AutoTest.Net/ 128 | 129 | # Web workbench (sass) 130 | .sass-cache/ 131 | 132 | # Installshield output folder 133 | [Ee]xpress/ 134 | 135 | # DocProject is a documentation generator add-in 136 | DocProject/buildhelp/ 137 | DocProject/Help/*.HxT 138 | DocProject/Help/*.HxC 139 | DocProject/Help/*.hhc 140 | DocProject/Help/*.hhk 141 | DocProject/Help/*.hhp 142 | DocProject/Help/Html2 143 | DocProject/Help/html 144 | 145 | # Click-Once directory 146 | publish/ 147 | 148 | # Publish Web Output 149 | *.[Pp]ublish.xml 150 | *.azurePubxml 151 | # TODO: Comment the next line if you want to checkin your web deploy settings 152 | # but database connection strings (with potential passwords) will be unencrypted 153 | *.pubxml 154 | *.publishproj 155 | 156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 157 | # checkin your Azure Web App publish settings, but sensitive information contained 158 | # in these scripts will be unencrypted 159 | PublishScripts/ 160 | 161 | # NuGet Packages 162 | *.nupkg 163 | # The packages folder can be ignored because of Package Restore 164 | **/packages/* 165 | # except build/, which is used as an MSBuild target. 166 | !**/packages/build/ 167 | # Uncomment if necessary however generally it will be regenerated when needed 168 | #!**/packages/repositories.config 169 | # NuGet v3's project.json files produces more ignoreable files 170 | *.nuget.props 171 | *.nuget.targets 172 | 173 | # Microsoft Azure Build Output 174 | csx/ 175 | *.build.csdef 176 | 177 | # Microsoft Azure Emulator 178 | ecf/ 179 | rcf/ 180 | 181 | # Windows Store app package directories and files 182 | AppPackages/ 183 | BundleArtifacts/ 184 | Package.StoreAssociation.xml 185 | _pkginfo.txt 186 | 187 | # Visual Studio cache files 188 | # files ending in .cache can be ignored 189 | *.[Cc]ache 190 | # but keep track of directories ending in .cache 191 | !*.[Cc]ache/ 192 | 193 | # Others 194 | ClientBin/ 195 | ~$* 196 | *~ 197 | *.dbmdl 198 | *.dbproj.schemaview 199 | *.jfm 200 | *.pfx 201 | *.publishsettings 202 | node_modules/ 203 | orleans.codegen.cs 204 | 205 | # Since there are multiple workflows, uncomment next line to ignore bower_components 206 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 207 | #bower_components/ 208 | 209 | # RIA/Silverlight projects 210 | Generated_Code/ 211 | 212 | # Backup & report files from converting an old project file 213 | # to a newer Visual Studio version. Backup files are not needed, 214 | # because we have git ;-) 215 | _UpgradeReport_Files/ 216 | Backup*/ 217 | UpgradeLog*.XML 218 | UpgradeLog*.htm 219 | 220 | # SQL Server files 221 | *.mdf 222 | *.ldf 223 | 224 | # Business Intelligence projects 225 | *.rdl.data 226 | *.bim.layout 227 | *.bim_*.settings 228 | 229 | # Microsoft Fakes 230 | FakesAssemblies/ 231 | 232 | # GhostDoc plugin setting file 233 | *.GhostDoc.xml 234 | 235 | # Node.js Tools for Visual Studio 236 | .ntvs_analysis.dat 237 | 238 | # Visual Studio 6 build log 239 | *.plg 240 | 241 | # Visual Studio 6 workspace options file 242 | *.opt 243 | 244 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 245 | *.vbw 246 | 247 | # Visual Studio LightSwitch build output 248 | **/*.HTMLClient/GeneratedArtifacts 249 | **/*.DesktopClient/GeneratedArtifacts 250 | **/*.DesktopClient/ModelManifest.xml 251 | **/*.Server/GeneratedArtifacts 252 | **/*.Server/ModelManifest.xml 253 | _Pvt_Extensions 254 | 255 | # Paket dependency manager 256 | .paket/paket.exe 257 | paket-files/ 258 | 259 | # FAKE - F# Make 260 | .fake/ 261 | 262 | # JetBrains Rider 263 | .idea/ 264 | *.sln.iml 265 | 266 | # CodeRush 267 | .cr/ 268 | 269 | # Python Tools for Visual Studio (PTVS) 270 | __pycache__/ 271 | *.pyc 272 | 273 | # Cake - Uncomment if you are using it 274 | # tools/** 275 | # !tools/packages.config -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | C++ Delegate Library Collection 2 | =============================== 3 | 4 | This is a collection of C++ delegate libraries that I've discovered and collected so far. 5 | 6 | ## Library 7 | Here's the current list of delegate libraries in this repo (2014/06): 8 | * FastFunc: 9 | A C++11 re-implementation of Don Clugston's original FastDelegate by Paúl Jiménez(Ceniza)([CodeProject link](http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible)) 10 | ([Gist](https://gist.github.com/yxbh/997d5a7791e3fe18e94f)). 11 | Signature: `ssvu::FastFunc` 12 | 13 | * FastDelegate: 14 | A C++11 variadic template version of Don Clugston's original FastDelegate ([Source link](https://sites.google.com/site/ceniza666/cpp)) 15 | ([Original Implementation CodeProject link](http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible)). 16 | Signature: `fastdelegate::FastDelegate` 17 | 18 | * SRDelegate: 19 | A C++11 re-implementation of Sergey Ryazanov's "The Impossibly Fast C++ Delegates"([CodeProject link](http://www.codeproject.com/Articles/11015/The-Impossibly-Fast-C-Delegates)). 20 | Signature: `generic::delegate` 21 | 22 | 23 | ## Modification 24 | These libraries also contain my own personal modifications which include: 25 | * bugfixes 26 | * new features 27 | * VC workarounds (e.g. C++11 non-conformance workarounds). 28 | 29 | ## Test 30 | Unit tests using the Catch library are available to test how well the equality operators work. These are available under the unit_test directory. Both a VS2015 and a Qt project(outdated) are provided. VS solution is setted up to run the test post-build. 31 | 32 | The project originally used Boost unit test which was a pain to add in all the dependencies and keeping it up to date. Catch is header only and just as easy to use. 33 | 34 | ## Known Issues 35 | None AFAIK. 36 | 37 | ## Benchmark 38 | A benchmark is available to do performance comparison of function call performance for the libraries. It measures the function call performance. The benchmark also contains the original FastDelegate written by Don Clugston. 39 | 40 | Feel free to send in pull request and contribute. 41 | 42 | ### Test Cases 43 | Function types tested at the moment are below: 44 | * static global function (with and without parameter) 45 | * static member function (with and without parameter) 46 | * non-virtual member function (with and without parameter) 47 | * inlined functions 48 | 49 | ### Build 50 | A Qt project file is provided. It has been tested on a Win7 laptop and a Win8 desktop. 51 | 52 | A Visual Studio 2015 solution is also provided. This is tested on a Win10 desktop. 53 | 54 | Due to the fact that VC++ is still C++11 non-conformance, quite a bit of workaround had to be added to make the C++11 versions of the delegate libraries to work. What I've done is providing 2 copies of each of the affected libraries separated by #ifdef's within their respective header files. If the '_MSC_VER' is detected then the visual studio version containing the workarounds would be used. 55 | 56 | In Visual Studio, COMDAT Folding needs to be disabled in the linker ('/OPT:ICF' -> '/OPT:NOICF') in order for the libraries to work correctly. In our scenario, COMDAT Folding simply make the comparison operators work incorrectly. If you need equality operators in your delegates, you will have to disable it in your VS projects too. 57 | 58 | ## License 59 | Each library should be retained within the original license that they were distributed in. I do not claim credit for each library's original implementation, except for my own modification. 60 | 61 | If you are the oringnal author of any of the libraries and you wish to change the license or remove the library from this repository. Please drop me a message or raise an issue in the tracker. 62 | -------------------------------------------------------------------------------- /src/FastDelegate/FastDelegate.hpp: -------------------------------------------------------------------------------- 1 | // FastDelegate.hpp 2 | // Efficient delegates in C++ that generate only two lines of asm code! 3 | // Documentation is found at http://www.codeproject.com/cpp/FastDelegate.asp 4 | // 5 | // - Don Clugston, Mar 2004. 6 | // Major contributions were made by Jody Hagins. 7 | // Version 2.0 by Pa�l Jim�nez. 8 | // Version 2.0.1-2.0.2 by Benjamin YanXiang Huang 9 | // 10 | // History: 11 | // 24-Apr-04 1.0 * Submitted to CodeProject. 12 | // 28-Apr-04 1.1 * Prevent most unsafe uses of evil static function hack. 13 | // * Improved syntax for horrible_cast (thanks Paul Bludov). 14 | // * Tested on Metrowerks MWCC and Intel ICL (IA32) 15 | // * Compiled, but not run, on Comeau C++ and Intel Itanium ICL. 16 | // 27-Jun-04 1.2 * Now works on Borland C++ Builder 5.5 17 | // * Now works on /clr "managed C++" code on VC7, VC7.1 18 | // * Comeau C++ now compiles without warnings. 19 | // * Prevent the virtual inheritance case from being used on 20 | // VC6 and earlier, which generate incorrect code. 21 | // * Improved warning and error messages. Non-standard hacks 22 | // now have compile-time checks to make them safer. 23 | // * implicit_cast used instead of static_cast in many cases. 24 | // * If calling a const member function, a const class pointer can be used. 25 | // * MakeDelegate() global helper function added to simplify pass-by-value. 26 | // * Added fastdelegate.clear() 27 | // 16-Jul-04 1.2.1* Workaround for gcc bug (const member function pointers in templates) 28 | // 30-Oct-04 1.3 * Support for (non-void) return values. 29 | // * No more workarounds in client code! 30 | // MSVC and Intel now use a clever hack invented by John Dlugosz: 31 | // - The FASTDELEGATEDECLARE workaround is no longer necessary. 32 | // - No more warning messages for VC6 33 | // * Less use of macros. Error messages should be more comprehensible. 34 | // * Added include guards 35 | // * Added FastDelegate::empty() to test if invocation is safe (Thanks Neville Franks). 36 | // * Now tested on VS 2005 Express Beta, PGI C++ 37 | // 24-Dec-04 1.4 * Added DelegateMemento, to allow collections of disparate delegates. 38 | // * <,>,<=,>= comparison operators to allow storage in ordered containers. 39 | // * Substantial reduction of code size, especially the 'Closure' class. 40 | // * Standardised all the compiler-specific workarounds. 41 | // * MFP conversion now works for CodePlay (but not yet supported in the full code). 42 | // * Now compiles without warnings on _any_ supported compiler, including BCC 5.5.1 43 | // * New syntax: FastDelegate< int (char *, double) >. 44 | // 14-Feb-05 1.4.1* Now treats =0 as equivalent to .clear(), ==0 as equivalent to .empty(). (Thanks elfric). 45 | // * Now tested on Intel ICL for AMD64, VS2005 Beta for AMD64 and Itanium. 46 | // 30-Mar-05 1.5 * Safebool idiom: "if (dg)" is now equivalent to "if (!dg.empty())" 47 | // * Fully supported by CodePlay VectorC 48 | // * Bugfix for Metrowerks: empty() was buggy because a valid MFP can be 0 on MWCC! 49 | // * More optimal assignment,== and != operators for static function pointers. 50 | // 06-Feb-13 2.0 * GetMemento is now const 51 | // * Added hash method that makes use of new unchecked function unsafe_horrible_cast 52 | // * Removed VC6 code 53 | // * Use variadic templates (C++11) 54 | // * Added MakeDelegate for plain function pointers 55 | // * Use static_assert for compile-time checks (C++11) 56 | // 21-Jan-14 2.0.1* Fixed 2 typos (line 393 & 429) where a static_cast should have been a static_assert. 57 | // 21-Jun-14 2.0.2* Fixed incorrect union member name in the SimplifyMemFunc struct. 58 | 59 | #ifndef FASTDELEGATE_HPP 60 | #define FASTDELEGATE_HPP 61 | #if _MSC_VER > 1000 62 | #pragma once 63 | #endif // _MSC_VER > 1000 64 | 65 | #include // to allow <,> comparisons 66 | 67 | //////////////////////////////////////////////////////////////////////////////// 68 | // Configuration options 69 | // 70 | //////////////////////////////////////////////////////////////////////////////// 71 | 72 | // Uncomment the following #define for optimally-sized delegates. 73 | // In this case, the generated asm code is almost identical to the code you'd get 74 | // if the compiler had native support for delegates. 75 | // It will not work on systems where sizeof(dataptr) < sizeof(codeptr). 76 | // Thus, it will not work for DOS compilers using the medium model. 77 | // It will also probably fail on some DSP systems. 78 | #define FASTDELEGATE_USESTATICFUNCTIONHACK 79 | 80 | // Uncomment the next line to allow function declarator syntax. 81 | // It is automatically enabled for those compilers where it is known to work. 82 | //#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX 83 | 84 | //////////////////////////////////////////////////////////////////////////////// 85 | // Compiler identification for workarounds 86 | // 87 | //////////////////////////////////////////////////////////////////////////////// 88 | 89 | // Compiler identification. It's not easy to identify Visual C++ because 90 | // many vendors fraudulently define Microsoft's identifiers. 91 | #if defined(_MSC_VER) && !defined(__MWERKS__) && !defined(__VECTOR_C) && !defined(__ICL) && !defined(__BORLANDC__) 92 | #define FASTDLGT_ISMSVC 93 | #endif 94 | 95 | // Does the compiler uses Microsoft's member function pointer structure? 96 | // If so, it needs special treatment. 97 | // Metrowerks CodeWarrior, Intel, and CodePlay fraudulently define Microsoft's 98 | // identifier, _MSC_VER. We need to filter Metrowerks out. 99 | #if defined(_MSC_VER) && !defined(__MWERKS__) 100 | #define FASTDLGT_MICROSOFT_MFP 101 | 102 | #if !defined(__VECTOR_C) 103 | // CodePlay doesn't have the __single/multi/virtual_inheritance keywords 104 | #define FASTDLGT_HASINHERITANCE_KEYWORDS 105 | #endif 106 | #endif 107 | 108 | // Does it allow function declarator syntax? The following compilers are known to work: 109 | #if defined(FASTDLGT_ISMSVC) && (_MSC_VER >=1310) // VC 7.1 110 | #define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX 111 | #endif 112 | 113 | // Gcc(2.95+), and versions of Digital Mars, Intel and Comeau in common use. 114 | #if defined (__DMC__) || defined(__GNUC__) || defined(__ICL) || defined(__COMO__) 115 | #define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX 116 | #endif 117 | 118 | // It works on Metrowerks MWCC 3.2.2. From boost.Config it should work on earlier ones too. 119 | #if defined (__MWERKS__) 120 | #define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX 121 | #endif 122 | 123 | #ifdef __GNUC__ // Workaround GCC bug #8271 124 | // At present, GCC doesn't recognize constness of MFPs in templates 125 | #define FASTDELEGATE_GCC_BUG_8271 126 | #endif 127 | 128 | 129 | 130 | //////////////////////////////////////////////////////////////////////////////// 131 | // General tricks used in this code 132 | // 133 | // (a) Error messages are generated by typdefing an array of negative size to 134 | // generate compile-time errors. 135 | // (b) Warning messages on MSVC are generated by declaring unused variables, and 136 | // enabling the "variable XXX is never used" warning. 137 | // (c) Unions are used in a few compiler-specific cases to perform illegal casts. 138 | // (d) For Microsoft and Intel, when adjusting the 'this' pointer, it's cast to 139 | // (char *) first to ensure that the correct number of *bytes* are added. 140 | // 141 | //////////////////////////////////////////////////////////////////////////////// 142 | // Helper templates 143 | // 144 | //////////////////////////////////////////////////////////////////////////////// 145 | 146 | 147 | namespace fastdelegate { 148 | namespace detail { // we'll hide the implementation details in a nested namespace. 149 | 150 | // implicit_cast< > 151 | // I believe this was originally going to be in the C++ standard but 152 | // was left out by accident. It's even milder than static_cast. 153 | // I use it instead of static_cast<> to emphasize that I'm not doing 154 | // anything nasty. 155 | // Usage is identical to static_cast<> 156 | template 157 | inline OutputClass implicit_cast(InputClass input){ 158 | return input; 159 | } 160 | 161 | // horrible_cast< > 162 | // This is truly evil. It completely subverts C++'s type system, allowing you 163 | // to cast from any class to any other class. Technically, using a union 164 | // to perform the cast is undefined behaviour (even in C). But we can see if 165 | // it is OK by checking that the union is the same size as each of its members. 166 | // horrible_cast<> should only be used for compiler-specific workarounds. 167 | // Usage is identical to reinterpret_cast<>. 168 | 169 | // This union is declared outside the horrible_cast because BCC 5.5.1 170 | // can't inline a function with a nested class, and gives a warning. 171 | template 172 | union horrible_union{ 173 | OutputClass out; 174 | InputClass in; 175 | }; 176 | 177 | template 178 | inline OutputClass horrible_cast(const InputClass input){ 179 | horrible_union u; 180 | // Cause a compile-time error if in, out and u are not the same size. 181 | // If the compile fails here, it means the compiler has peculiar 182 | // unions which would prevent the cast from working. 183 | static_assert(sizeof(InputClass)==sizeof(u) && sizeof(InputClass)==sizeof(OutputClass), "Cannot use horrible_cast<>"); 184 | u.in = input; 185 | return u.out; 186 | } 187 | 188 | template 189 | inline OutputClass unsafe_horrible_cast(const InputClass input){ 190 | horrible_union u; 191 | u.in = input; 192 | return u.out; 193 | } 194 | 195 | //////////////////////////////////////////////////////////////////////////////// 196 | // Workarounds 197 | // 198 | //////////////////////////////////////////////////////////////////////////////// 199 | 200 | // Backwards compatibility: This macro used to be necessary in the virtual inheritance 201 | // case for Intel and Microsoft. Now it just forward-declares the class. 202 | #define FASTDELEGATEDECLARE(CLASSNAME) class CLASSNAME; 203 | 204 | // Prevent use of the static function hack with the DOS medium model. 205 | #ifdef __MEDIUM__ 206 | #undef FASTDELEGATE_USESTATICFUNCTIONHACK 207 | #endif 208 | 209 | typedef void DefaultVoid; 210 | 211 | // Translate from 'DefaultVoid' to 'void'. 212 | // Everything else is unchanged 213 | template 214 | struct DefaultVoidToVoid { typedef T type; }; 215 | 216 | template <> 217 | struct DefaultVoidToVoid { typedef void type; }; 218 | 219 | // Translate from 'void' into 'DefaultVoid' 220 | // Everything else is unchanged 221 | template 222 | struct VoidToDefaultVoid { typedef T type; }; 223 | 224 | template <> 225 | struct VoidToDefaultVoid { typedef DefaultVoid type; }; 226 | 227 | 228 | 229 | //////////////////////////////////////////////////////////////////////////////// 230 | // Fast Delegates, part 1: 231 | // 232 | // Conversion of member function pointer to a standard form 233 | // 234 | //////////////////////////////////////////////////////////////////////////////// 235 | 236 | // GenericClass is a fake class, ONLY used to provide a type. 237 | // It is vitally important that it is never defined, so that the compiler doesn't 238 | // think it can optimize the invocation. For example, Borland generates simpler 239 | // code if it knows the class only uses single inheritance. 240 | 241 | // Compilers using Microsoft's structure need to be treated as a special case. 242 | #ifdef FASTDLGT_MICROSOFT_MFP 243 | 244 | #ifdef FASTDLGT_HASINHERITANCE_KEYWORDS 245 | // For Microsoft and Intel, we want to ensure that it's the most efficient type of MFP 246 | // (4 bytes), even when the /vmg option is used. Declaring an empty class 247 | // would give 16 byte pointers in this case.... 248 | class __single_inheritance GenericClass; 249 | #endif 250 | // ...but for Codeplay, an empty class *always* gives 4 byte pointers. 251 | // If compiled with the /clr option ("managed C++"), the JIT compiler thinks 252 | // it needs to load GenericClass before it can call any of its functions, 253 | // (compiles OK but crashes at runtime!), so we need to declare an 254 | // empty class to make it happy. 255 | // Codeplay and VC4 can't cope with the unknown_inheritance case either. 256 | class GenericClass {}; 257 | #else 258 | class GenericClass; 259 | #endif 260 | 261 | // The size of a single inheritance member function pointer. 262 | const int SINGLE_MEMFUNCPTR_SIZE = sizeof(void (GenericClass::*)()); 263 | 264 | // SimplifyMemFunc< >::Convert() 265 | // 266 | // A template function that converts an arbitrary member function pointer into the 267 | // simplest possible form of member function pointer, using a supplied 'this' pointer. 268 | // According to the standard, this can be done legally with reinterpret_cast<>. 269 | // For (non-standard) compilers which use member function pointers which vary in size 270 | // depending on the class, we need to use knowledge of the internal structure of a 271 | // member function pointer, as used by the compiler. Template specialization is used 272 | // to distinguish between the sizes. Because some compilers don't support partial 273 | // template specialisation, I use full specialisation of a wrapper struct. 274 | 275 | // general case -- don't know how to convert it. Force a compile failure 276 | template 277 | struct SimplifyMemFunc { 278 | template 279 | inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, 280 | GenericMemFuncType &bound_func) { 281 | // Unsupported member function type -- force a compile failure. 282 | // (it's illegal to have a array with negative size). 283 | static_assert(N - 100, "Unsupported member function pointer on this compiler"); 284 | return 0; 285 | } 286 | }; 287 | 288 | // For compilers where all member func ptrs are the same size, everything goes here. 289 | // For non-standard compilers, only single_inheritance classes go here. 290 | template <> 291 | struct SimplifyMemFunc { 292 | template 293 | inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, 294 | GenericMemFuncType &bound_func) { 295 | #if defined __DMC__ 296 | // Digital Mars doesn't allow you to cast between abitrary PMF's, 297 | // even though the standard says you can. The 32-bit compiler lets you 298 | // static_cast through an int, but the DOS compiler doesn't. 299 | bound_func = horrible_cast(function_to_bind); 300 | #else 301 | bound_func = reinterpret_cast(function_to_bind); 302 | #endif 303 | return reinterpret_cast(pthis); 304 | } 305 | }; 306 | 307 | //////////////////////////////////////////////////////////////////////////////// 308 | // Fast Delegates, part 1b: 309 | // 310 | // Workarounds for Microsoft and Intel 311 | // 312 | //////////////////////////////////////////////////////////////////////////////// 313 | 314 | 315 | // Compilers with member function pointers which violate the standard (MSVC, Intel, Codeplay), 316 | // need to be treated as a special case. 317 | #ifdef FASTDLGT_MICROSOFT_MFP 318 | 319 | // We use unions to perform horrible_casts. I would like to use #pragma pack(push, 1) 320 | // at the start of each function for extra safety, but VC6 seems to ICE 321 | // intermittently if you do this inside a template. 322 | 323 | // __multiple_inheritance classes go here 324 | // Nasty hack for Microsoft and Intel (IA32 and Itanium) 325 | template<> 326 | struct SimplifyMemFunc< SINGLE_MEMFUNCPTR_SIZE + sizeof(int) > { 327 | template 328 | inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, 329 | GenericMemFuncType &bound_func) { 330 | // We need to use a horrible_cast to do this conversion. 331 | // In MSVC, a multiple inheritance member pointer is internally defined as: 332 | union { 333 | XFuncType func; 334 | struct { 335 | GenericMemFuncType funcaddress; // points to the actual member function 336 | int delta; // #BYTES to be added to the 'this' pointer 337 | }s; 338 | } u; 339 | // Check that the horrible_cast will work 340 | static_assert(sizeof(function_to_bind)==sizeof(u.s), "Cannot use horrible_cast<>"); 341 | u.func = function_to_bind; 342 | bound_func = u.s.funcaddress; 343 | return reinterpret_cast(reinterpret_cast(pthis) + u.s.delta); 344 | } 345 | }; 346 | 347 | // virtual inheritance is a real nuisance. It's inefficient and complicated. 348 | // On MSVC and Intel, there isn't enough information in the pointer itself to 349 | // enable conversion to a closure pointer. Earlier versions of this code didn't 350 | // work for all cases, and generated a compile-time error instead. 351 | // But a very clever hack invented by John M. Dlugosz solves this problem. 352 | // My code is somewhat different to his: I have no asm code, and I make no 353 | // assumptions about the calling convention that is used. 354 | 355 | // In VC++ and ICL, a virtual_inheritance member pointer 356 | // is internally defined as: 357 | struct MicrosoftVirtualMFP { 358 | void (GenericClass::*codeptr)(); // points to the actual member function 359 | int delta; // #bytes to be added to the 'this' pointer 360 | int vtable_index; // or 0 if no virtual inheritance 361 | }; 362 | // The CRUCIAL feature of Microsoft/Intel MFPs which we exploit is that the 363 | // m_codeptr member is *always* called, regardless of the values of the other 364 | // members. (This is *not* true for other compilers, eg GCC, which obtain the 365 | // function address from the vtable if a virtual function is being called). 366 | // Dlugosz's trick is to make the codeptr point to a probe function which 367 | // returns the 'this' pointer that was used. 368 | 369 | // Define a generic class that uses virtual inheritance. 370 | // It has a trival member function that returns the value of the 'this' pointer. 371 | struct GenericVirtualClass : virtual public GenericClass 372 | { 373 | typedef GenericVirtualClass * (GenericVirtualClass::*ProbePtrType)(); 374 | GenericVirtualClass * GetThis() { return this; } 375 | }; 376 | 377 | // __virtual_inheritance classes go here 378 | template <> 379 | struct SimplifyMemFunc 380 | { 381 | 382 | template 383 | inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, 384 | GenericMemFuncType &bound_func) { 385 | union { 386 | XFuncType func; 387 | GenericClass* (X::*ProbeFunc)(); 388 | MicrosoftVirtualMFP s; 389 | } u; 390 | u.func = function_to_bind; 391 | bound_func = reinterpret_cast(u.s.codeptr); 392 | union { 393 | GenericVirtualClass::ProbePtrType virtfunc; 394 | MicrosoftVirtualMFP s; 395 | } u2; 396 | // Check that the horrible_cast<>s will work 397 | static_assert(sizeof(function_to_bind)==sizeof(u.s) && sizeof(function_to_bind)==sizeof(u.ProbeFunc) && sizeof(u2.virtfunc)==sizeof(u2.s), "Cannot use horrible_cast<>"); 398 | /*typedef int ERROR_CantUsehorrible_cast[sizeof(function_to_bind)==sizeof(u.s) 399 | && sizeof(function_to_bind)==sizeof(u.ProbeFunc) 400 | && sizeof(u2.virtfunc)==sizeof(u2.s) ? 1 : -1];*/ 401 | // Unfortunately, taking the address of a MF prevents it from being inlined, so 402 | // this next line can't be completely optimised away by the compiler. 403 | u2.virtfunc = &GenericVirtualClass::GetThis; 404 | u.s.codeptr = u2.s.codeptr; 405 | return (pthis->*u.ProbeFunc)(); 406 | } 407 | }; 408 | 409 | // Nasty hack for Microsoft and Intel (IA32 and Itanium) 410 | // unknown_inheritance classes go here 411 | // This is probably the ugliest bit of code I've ever written. Look at the casts! 412 | // There is a compiler bug in MSVC6 which prevents it from using this code. 413 | template <> 414 | struct SimplifyMemFunc 415 | { 416 | template 417 | inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, 418 | GenericMemFuncType &bound_func) { 419 | // The member function pointer is 16 bytes long. We can't use a normal cast, but 420 | // we can use a union to do the conversion. 421 | union { 422 | XFuncType func; 423 | // In VC++ and ICL, an unknown_inheritance member pointer 424 | // is internally defined as: 425 | struct { 426 | GenericMemFuncType funcaddress; // points to the actual member function 427 | int delta; // #bytes to be added to the 'this' pointer 428 | int vtordisp; // #bytes to add to 'this' to find the vtable 429 | int vtable_index; // or 0 if no virtual inheritance 430 | } s; 431 | } u; 432 | // Check that the horrible_cast will work 433 | static_assert(sizeof(XFuncType)==sizeof(u.s), "Cannot use horrible_cast<>"); 434 | //typedef int ERROR_CantUsehorrible_cast[sizeof(XFuncType)==sizeof(u.s)? 1 : -1]; 435 | u.func = function_to_bind; 436 | bound_func = u.s.funcaddress; 437 | int virtual_delta = 0; 438 | if (u.s.vtable_index) { // Virtual inheritance is used 439 | // First, get to the vtable. 440 | // It is 'vtordisp' bytes from the start of the class. 441 | const int * vtable = *reinterpret_cast( 442 | reinterpret_cast(pthis) + u.s.vtordisp ); 443 | 444 | // 'vtable_index' tells us where in the table we should be looking. 445 | virtual_delta = u.s.vtordisp + *reinterpret_cast( 446 | reinterpret_cast(vtable) + u.s.vtable_index); 447 | } 448 | // The int at 'virtual_delta' gives us the amount to add to 'this'. 449 | // Finally we can add the three components together. Phew! 450 | return reinterpret_cast( 451 | reinterpret_cast(pthis) + u.s.delta + virtual_delta); 452 | }; 453 | }; 454 | 455 | #endif // MS/Intel hacks 456 | 457 | } // namespace detail 458 | 459 | //////////////////////////////////////////////////////////////////////////////// 460 | // Fast Delegates, part 2: 461 | // 462 | // Define the delegate storage, and cope with static functions 463 | // 464 | //////////////////////////////////////////////////////////////////////////////// 465 | 466 | // DelegateMemento -- an opaque structure which can hold an arbitary delegate. 467 | // It knows nothing about the calling convention or number of arguments used by 468 | // the function pointed to. 469 | // It supplies comparison operators so that it can be stored in STL collections. 470 | // It cannot be set to anything other than null, nor invoked directly: 471 | // it must be converted to a specific delegate. 472 | 473 | // Implementation: 474 | // There are two possible implementations: the Safe method and the Evil method. 475 | // DelegateMemento - Safe version 476 | // 477 | // This implementation is standard-compliant, but a bit tricky. 478 | // A static function pointer is stored inside the class. 479 | // Here are the valid values: 480 | // +-- Static pointer --+--pThis --+-- pMemFunc-+-- Meaning------+ 481 | // | 0 | 0 | 0 | Empty | 482 | // | !=0 |(dontcare)| Invoker | Static function| 483 | // | 0 | !=0 | !=0* | Method call | 484 | // +--------------------+----------+------------+----------------+ 485 | // * For Metrowerks, this can be 0. (first virtual function in a 486 | // single_inheritance class). 487 | // When stored stored inside a specific delegate, the 'dontcare' entries are replaced 488 | // with a reference to the delegate itself. This complicates the = and == operators 489 | // for the delegate class. 490 | 491 | // DelegateMemento - Evil version 492 | // 493 | // For compilers where data pointers are at least as big as code pointers, it is 494 | // possible to store the function pointer in the this pointer, using another 495 | // horrible_cast. In this case the DelegateMemento implementation is simple: 496 | // +--pThis --+-- pMemFunc-+-- Meaning---------------------+ 497 | // | 0 | 0 | Empty | 498 | // | !=0 | !=0* | Static function or method call| 499 | // +----------+------------+-------------------------------+ 500 | // * For Metrowerks, this can be 0. (first virtual function in a 501 | // single_inheritance class). 502 | // Note that the Sun C++ and MSVC documentation explicitly state that they 503 | // support static_cast between void * and function pointers. 504 | 505 | class DelegateMemento { 506 | protected: 507 | // the data is protected, not private, because many 508 | // compilers have problems with template friends. 509 | typedef void (detail::GenericClass::*GenericMemFuncType)(); // arbitrary MFP. 510 | detail::GenericClass *m_pthis; 511 | GenericMemFuncType m_pFunction; 512 | 513 | #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) 514 | typedef void (*GenericFuncPtr)(); // arbitrary code pointer 515 | GenericFuncPtr m_pStaticFunction; 516 | #endif 517 | 518 | public: 519 | #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) 520 | DelegateMemento() : m_pthis(0), m_pFunction(0), m_pStaticFunction(0) {}; 521 | void clear() { 522 | m_pthis=0; m_pFunction=0; m_pStaticFunction=0; 523 | } 524 | #else 525 | DelegateMemento() : m_pthis(0), m_pFunction(0) {}; 526 | void clear() { m_pthis=0; m_pFunction=0; } 527 | #endif 528 | public: 529 | #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) 530 | inline bool IsEqual (const DelegateMemento &x) const{ 531 | // We have to cope with the static function pointers as a special case 532 | if (m_pFunction!=x.m_pFunction) return false; 533 | // the static function ptrs must either both be equal, or both be 0. 534 | if (m_pStaticFunction!=x.m_pStaticFunction) return false; 535 | if (m_pStaticFunction!=0) return m_pthis==x.m_pthis; 536 | else return true; 537 | } 538 | #else // Evil Method 539 | inline bool IsEqual (const DelegateMemento &x) const{ 540 | return m_pthis==x.m_pthis && m_pFunction==x.m_pFunction; 541 | } 542 | #endif 543 | // Provide a strict weak ordering for DelegateMementos. 544 | inline bool IsLess(const DelegateMemento &right) const { 545 | // deal with static function pointers first 546 | #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) 547 | if (m_pStaticFunction !=0 || right.m_pStaticFunction!=0) 548 | return m_pStaticFunction < right.m_pStaticFunction; 549 | #endif 550 | if (m_pthis !=right.m_pthis) return m_pthis < right.m_pthis; 551 | // There are no ordering operators for member function pointers, 552 | // but we can fake one by comparing each byte. The resulting ordering is 553 | // arbitrary (and compiler-dependent), but it permits storage in ordered STL containers. 554 | return std::memcmp(&m_pFunction, &right.m_pFunction, sizeof(m_pFunction)) < 0; 555 | 556 | } 557 | // Provide a simple hashing method. 558 | inline size_t Hash() const { 559 | return reinterpret_cast(m_pthis) ^ detail::unsafe_horrible_cast(m_pFunction); 560 | } 561 | // BUGFIX (Mar 2005): 562 | // We can't just compare m_pFunction because on Metrowerks, 563 | // m_pFunction can be zero even if the delegate is not empty! 564 | inline bool operator ! () const // Is it bound to anything? 565 | { return m_pthis==0 && m_pFunction==0; } 566 | inline bool empty() const // Is it bound to anything? 567 | { return m_pthis==0 && m_pFunction==0; } 568 | public: 569 | DelegateMemento & operator = (const DelegateMemento &right) { 570 | SetMementoFrom(right); 571 | return *this; 572 | } 573 | inline bool operator <(const DelegateMemento &right) { 574 | return IsLess(right); 575 | } 576 | inline bool operator >(const DelegateMemento &right) { 577 | return right.IsLess(*this); 578 | } 579 | DelegateMemento (const DelegateMemento &right) : 580 | m_pthis(right.m_pthis), m_pFunction(right.m_pFunction) 581 | #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) 582 | , m_pStaticFunction (right.m_pStaticFunction) 583 | #endif 584 | {} 585 | protected: 586 | void SetMementoFrom(const DelegateMemento &right) { 587 | m_pFunction = right.m_pFunction; 588 | m_pthis = right.m_pthis; 589 | #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) 590 | m_pStaticFunction = right.m_pStaticFunction; 591 | #endif 592 | } 593 | }; 594 | 595 | 596 | // ClosurePtr<> 597 | // 598 | // A private wrapper class that adds function signatures to DelegateMemento. 599 | // It's the class that does most of the actual work. 600 | // The signatures are specified by: 601 | // GenericMemFunc: must be a type of GenericClass member function pointer. 602 | // StaticFuncPtr: must be a type of function pointer with the same signature 603 | // as GenericMemFunc. 604 | // UnvoidStaticFuncPtr: is the same as StaticFuncPtr, except on VC6 605 | // where it never returns void (returns DefaultVoid instead). 606 | 607 | // An outer class, FastDelegateN<>, handles the invoking and creates the 608 | // necessary typedefs. 609 | // This class does everything else. 610 | 611 | namespace detail { 612 | 613 | template < class GenericMemFunc, class StaticFuncPtr, class UnvoidStaticFuncPtr> 614 | class ClosurePtr : public DelegateMemento { 615 | public: 616 | // These functions are for setting the delegate to a member function. 617 | 618 | // Here's the clever bit: we convert an arbitrary member function into a 619 | // standard form. XMemFunc should be a member function of class X, but I can't 620 | // enforce that here. It needs to be enforced by the wrapper class. 621 | template < class X, class XMemFunc > 622 | inline void bindmemfunc(X *pthis, XMemFunc function_to_bind ) { 623 | m_pthis = SimplifyMemFunc< sizeof(function_to_bind) > 624 | ::Convert(pthis, function_to_bind, m_pFunction); 625 | #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) 626 | m_pStaticFunction = 0; 627 | #endif 628 | } 629 | // For const member functions, we only need a const class pointer. 630 | // Since we know that the member function is const, it's safe to 631 | // remove the const qualifier from the 'this' pointer with a const_cast. 632 | // VC6 has problems if we just overload 'bindmemfunc', so we give it a different name. 633 | template < class X, class XMemFunc> 634 | inline void bindconstmemfunc(const X *pthis, XMemFunc function_to_bind) { 635 | m_pthis= SimplifyMemFunc< sizeof(function_to_bind) > 636 | ::Convert(const_cast(pthis), function_to_bind, m_pFunction); 637 | #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) 638 | m_pStaticFunction = 0; 639 | #endif 640 | } 641 | #ifdef FASTDELEGATE_GCC_BUG_8271 // At present, GCC doesn't recognize constness of MFPs in templates 642 | template < class X, class XMemFunc> 643 | inline void bindmemfunc(const X *pthis, XMemFunc function_to_bind) { 644 | bindconstmemfunc(pthis, function_to_bind); 645 | #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) 646 | m_pStaticFunction = 0; 647 | #endif 648 | } 649 | #endif 650 | // These functions are required for invoking the stored function 651 | inline GenericClass *GetClosureThis() const { return m_pthis; } 652 | inline GenericMemFunc GetClosureMemPtr() const { return reinterpret_cast(m_pFunction); } 653 | 654 | // There are a few ways of dealing with static function pointers. 655 | // There's a standard-compliant, but tricky method. 656 | // There's also a straightforward hack, that won't work on DOS compilers using the 657 | // medium memory model. It's so evil that I can't recommend it, but I've 658 | // implemented it anyway because it produces very nice asm code. 659 | 660 | #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) 661 | 662 | // ClosurePtr<> - Safe version 663 | // 664 | // This implementation is standard-compliant, but a bit tricky. 665 | // I store the function pointer inside the class, and the delegate then 666 | // points to itself. Whenever the delegate is copied, these self-references 667 | // must be transformed, and this complicates the = and == operators. 668 | public: 669 | // The next two functions are for operator ==, =, and the copy constructor. 670 | // We may need to convert the m_pthis pointers, so that 671 | // they remain as self-references. 672 | template< class DerivedClass > 673 | inline void CopyFrom (DerivedClass *pParent, const DelegateMemento &x) { 674 | SetMementoFrom(x); 675 | if (m_pStaticFunction!=0) { 676 | // transform self references... 677 | m_pthis=reinterpret_cast(pParent); 678 | } 679 | } 680 | // For static functions, the 'static_function_invoker' class in the parent 681 | // will be called. The parent then needs to call GetStaticFunction() to find out 682 | // the actual function to invoke. 683 | template < class DerivedClass, class ParentInvokerSig > 684 | inline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker, 685 | StaticFuncPtr function_to_bind ) { 686 | if (function_to_bind==0) { // cope with assignment to 0 687 | m_pFunction=0; 688 | } else { 689 | bindmemfunc(pParent, static_function_invoker); 690 | } 691 | m_pStaticFunction=reinterpret_cast(function_to_bind); 692 | } 693 | inline UnvoidStaticFuncPtr GetStaticFunction() const { 694 | return reinterpret_cast(m_pStaticFunction); 695 | } 696 | #else 697 | 698 | // ClosurePtr<> - Evil version 699 | // 700 | // For compilers where data pointers are at least as big as code pointers, it is 701 | // possible to store the function pointer in the this pointer, using another 702 | // horrible_cast. Invocation isn't any faster, but it saves 4 bytes, and 703 | // speeds up comparison and assignment. If C++ provided direct language support 704 | // for delegates, they would produce asm code that was almost identical to this. 705 | // Note that the Sun C++ and MSVC documentation explicitly state that they 706 | // support static_cast between void * and function pointers. 707 | 708 | template< class DerivedClass > 709 | inline void CopyFrom (DerivedClass * /*pParent*/, const DelegateMemento &right) { 710 | SetMementoFrom(right); 711 | } 712 | // For static functions, the 'static_function_invoker' class in the parent 713 | // will be called. The parent then needs to call GetStaticFunction() to find out 714 | // the actual function to invoke. 715 | // ******** EVIL, EVIL CODE! ******* 716 | template < class DerivedClass, class ParentInvokerSig> 717 | inline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker, 718 | StaticFuncPtr function_to_bind) { 719 | if (function_to_bind==0) { // cope with assignment to 0 720 | m_pFunction=0; 721 | } else { 722 | // We'll be ignoring the 'this' pointer, but we need to make sure we pass 723 | // a valid value to bindmemfunc(). 724 | bindmemfunc(pParent, static_function_invoker); 725 | } 726 | 727 | // WARNING! Evil hack. We store the function in the 'this' pointer! 728 | // Ensure that there's a compilation failure if function pointers 729 | // and data pointers have different sizes. 730 | // If you get this error, you need to #undef FASTDELEGATE_USESTATICFUNCTIONHACK. 731 | static_assert(sizeof(GenericClass *)==sizeof(function_to_bind), "Cannot use evil method"); 732 | m_pthis = horrible_cast(function_to_bind); 733 | // MSVC, SunC++ and DMC accept the following (non-standard) code: 734 | // m_pthis = static_cast(static_cast(function_to_bind)); 735 | // BCC32, Comeau and DMC accept this method. MSVC7.1 needs __int64 instead of long 736 | // m_pthis = reinterpret_cast(reinterpret_cast(function_to_bind)); 737 | } 738 | // ******** EVIL, EVIL CODE! ******* 739 | // This function will be called with an invalid 'this' pointer!! 740 | // We're just returning the 'this' pointer, converted into 741 | // a function pointer! 742 | inline UnvoidStaticFuncPtr GetStaticFunction() const { 743 | // Ensure that there's a compilation failure if function pointers 744 | // and data pointers have different sizes. 745 | // If you get this error, you need to #undef FASTDELEGATE_USESTATICFUNCTIONHACK. 746 | static_assert(sizeof(UnvoidStaticFuncPtr)==sizeof(this), "Cannot use evil method"); 747 | return horrible_cast(this); 748 | } 749 | #endif // !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) 750 | 751 | // Does the closure contain this static function? 752 | inline bool IsEqualToStaticFuncPtr(StaticFuncPtr funcptr){ 753 | if (funcptr==0) return empty(); 754 | // For the Evil method, if it doesn't actually contain a static function, this will return an arbitrary 755 | // value that is not equal to any valid function pointer. 756 | else return funcptr==reinterpret_cast(GetStaticFunction()); 757 | } 758 | }; 759 | 760 | 761 | } // namespace detail 762 | 763 | //////////////////////////////////////////////////////////////////////////////// 764 | // Fast Delegates, part 3: 765 | // 766 | // Wrapper classes to ensure type safety 767 | // 768 | //////////////////////////////////////////////////////////////////////////////// 769 | 770 | 771 | // Once we have the member function conversion templates, it's easy to make the 772 | // wrapper classes. So that they will work with as many compilers as possible, 773 | // the classes are of the form 774 | // FastDelegate3 775 | // They can cope with any combination of parameters. The max number of parameters 776 | // allowed is 8, but it is trivial to increase this limit. 777 | // Note that we need to treat const member functions seperately. 778 | // All this class does is to enforce type safety, and invoke the delegate with 779 | // the correct list of parameters. 780 | 781 | // Because of the weird rule about the class of derived member function pointers, 782 | // you sometimes need to apply a downcast to the 'this' pointer. 783 | // This is the reason for the use of "implicit_cast(pthis)" in the code below. 784 | // If CDerivedClass is derived from CBaseClass, but doesn't override SimpleVirtualFunction, 785 | // without this trick you'd need to write: 786 | // MyDelegate(static_cast(&d), &CDerivedClass::SimpleVirtualFunction); 787 | // but with the trick you can write 788 | // MyDelegate(&d, &CDerivedClass::SimpleVirtualFunction); 789 | 790 | // RetType is the type the compiler uses in compiling the template. For VC6, 791 | // it cannot be void. DesiredRetType is the real type which is returned from 792 | // all of the functions. It can be void. 793 | 794 | // Implicit conversion to "bool" is achieved using the safe_bool idiom, 795 | // using member data pointers (MDP). This allows "if (dg)..." syntax 796 | // Because some compilers (eg codeplay) don't have a unique value for a zero 797 | // MDP, an extra padding member is added to the SafeBool struct. 798 | // Some compilers (eg VC6) won't implicitly convert from 0 to an MDP, so 799 | // in that case the static function constructor is not made explicit; this 800 | // allows "if (dg==0) ..." to compile. 801 | 802 | template 803 | class FastDelegateImpl { 804 | private: 805 | typedef typename detail::DefaultVoidToVoid::type DesiredRetType; 806 | typedef DesiredRetType (*StaticFunctionPtr)(Args...); 807 | typedef RetType (*UnvoidStaticFunctionPtr)(Args...); 808 | typedef RetType (detail::GenericClass::*GenericMemFn)(Args...); 809 | typedef detail::ClosurePtr ClosureType; 810 | ClosureType m_Closure; 811 | public: 812 | // Typedefs to aid generic programming 813 | typedef FastDelegateImpl type; 814 | 815 | // Construction and comparison functions 816 | FastDelegateImpl() { clear(); } 817 | FastDelegateImpl(const FastDelegateImpl &x) { 818 | m_Closure.CopyFrom(this, x.m_Closure); } 819 | void operator = (const FastDelegateImpl &x) { 820 | m_Closure.CopyFrom(this, x.m_Closure); } 821 | bool operator ==(const FastDelegateImpl &x) const { 822 | return m_Closure.IsEqual(x.m_Closure); } 823 | bool operator !=(const FastDelegateImpl &x) const { 824 | return !m_Closure.IsEqual(x.m_Closure); } 825 | bool operator <(const FastDelegateImpl &x) const { 826 | return m_Closure.IsLess(x.m_Closure); } 827 | bool operator >(const FastDelegateImpl &x) const { 828 | return x.m_Closure.IsLess(m_Closure); } 829 | // Binding to non-const member functions 830 | template < typename X, typename Y > 831 | FastDelegateImpl(Y *pthis, DesiredRetType (X::* function_to_bind)(Args... args) ) { 832 | m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } 833 | template < typename X, typename Y > 834 | inline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Args... args)) { 835 | m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } 836 | // Binding to const member functions. 837 | template < typename X, typename Y > 838 | FastDelegateImpl(const Y *pthis, DesiredRetType (X::* function_to_bind)(Args... args) const) { 839 | m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } 840 | template < typename X, typename Y > 841 | inline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Args... args) const) { 842 | m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } 843 | // Static functions. We convert them into a member function call. 844 | // This constructor also provides implicit conversion 845 | FastDelegateImpl(DesiredRetType (*function_to_bind)(Args... args) ) { 846 | bind(function_to_bind); } 847 | // for efficiency, prevent creation of a temporary 848 | void operator = (DesiredRetType (*function_to_bind)(Args... args) ) { 849 | bind(function_to_bind); } 850 | inline void bind(DesiredRetType (*function_to_bind)(Args... args)) { 851 | m_Closure.bindstaticfunc(this, &FastDelegateImpl::InvokeStaticFunction, 852 | function_to_bind); } 853 | // Invoke the delegate 854 | RetType operator() (Args... args) const { 855 | return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(args...); } 856 | // Implicit conversion to "bool" using the safe_bool idiom 857 | private: 858 | typedef struct SafeBoolStruct { 859 | int a_data_pointer_to_this_is_0_on_buggy_compilers; 860 | StaticFunctionPtr m_nonzero; 861 | } UselessTypedef; 862 | typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; 863 | public: 864 | operator unspecified_bool_type() const { 865 | return empty()? 0: &SafeBoolStruct::m_nonzero; 866 | } 867 | // necessary to allow ==0 to work despite the safe_bool idiom 868 | inline bool operator==(StaticFunctionPtr funcptr) { 869 | return m_Closure.IsEqualToStaticFuncPtr(funcptr); } 870 | inline bool operator!=(StaticFunctionPtr funcptr) { 871 | return !m_Closure.IsEqualToStaticFuncPtr(funcptr); } 872 | inline bool operator ! () const { // Is it bound to anything? 873 | return !m_Closure; } 874 | inline bool empty() const { 875 | return !m_Closure; } 876 | void clear() { m_Closure.clear();} 877 | // Conversion to and from the DelegateMemento storage class 878 | const DelegateMemento & GetMemento() const { return m_Closure; } 879 | void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); } 880 | 881 | private: // Invoker for static functions 882 | RetType InvokeStaticFunction(Args... args) const { 883 | return (*(m_Closure.GetStaticFunction()))(args...); } 884 | }; 885 | 886 | //////////////////////////////////////////////////////////////////////////////// 887 | // Fast Delegates, part 4: 888 | // 889 | // FastDelegate<> class (Original author: Jody Hagins) 890 | // Allows boost::function style syntax like: 891 | // FastDelegate< double (int, long) > 892 | // instead of: 893 | // FastDelegate2< int, long, double > 894 | // 895 | //////////////////////////////////////////////////////////////////////////////// 896 | 897 | #ifdef FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX 898 | 899 | // Declare FastDelegate as a class template. It will be specialized 900 | // later for all number of arguments. 901 | template 902 | class FastDelegate; 903 | 904 | template 905 | class FastDelegate 906 | // Inherit from FastDelegate1 so that it can be treated just like a FastDelegate1 907 | : public FastDelegateImpl < RetType, Args... > 908 | { 909 | public: 910 | // Make using the base type a bit easier via typedef. 911 | typedef FastDelegateImpl < RetType, Args... > BaseType; 912 | 913 | // Allow users access to the specific type of this delegate. 914 | typedef FastDelegate SelfType; 915 | 916 | // Mimic the base class constructors. 917 | FastDelegate() : BaseType() { } 918 | 919 | template < typename X, typename Y > 920 | FastDelegate(Y * pthis, 921 | RetType (X::* function_to_bind)( Args... args )) 922 | : BaseType(pthis, function_to_bind) { } 923 | 924 | template < typename X, typename Y > 925 | FastDelegate(const Y *pthis, 926 | RetType (X::* function_to_bind)( Args... args ) const) 927 | : BaseType(pthis, function_to_bind) 928 | { } 929 | 930 | FastDelegate(RetType (*function_to_bind)( Args... args )) 931 | : BaseType(function_to_bind) { } 932 | void operator = (const BaseType &x) { 933 | *static_cast(this) = x; } 934 | }; 935 | 936 | #endif //FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX 937 | 938 | //////////////////////////////////////////////////////////////////////////////// 939 | // Fast Delegates, part 5: 940 | // 941 | // MakeDelegate() helper function 942 | // 943 | // MakeDelegate(&x, &X::func) returns a fastdelegate of the type 944 | // necessary for calling x.func() with the correct number of arguments. 945 | // This makes it possible to eliminate many typedefs from user code. 946 | // 947 | //////////////////////////////////////////////////////////////////////////////// 948 | 949 | // Also declare overloads of a MakeDelegate() global function to 950 | // reduce the need for typedefs. 951 | // We need seperate overloads for const and non-const member functions. 952 | // Also, because of the weird rule about the class of derived member function pointers, 953 | // implicit downcasts may need to be applied later to the 'this' pointer. 954 | // That's why two classes (X and Y) appear in the definitions. Y must be implicitly 955 | // castable to X. 956 | 957 | template 958 | FastDelegate MakeDelegate(RetType (*func)(Args...)) { 959 | return FastDelegate(func); 960 | } 961 | 962 | template 963 | FastDelegate MakeDelegate(Y* x, RetType (X::*func)(Args...)) { 964 | return FastDelegate(x, func); 965 | } 966 | 967 | template 968 | FastDelegate MakeDelegate(Y* x, RetType (X::*func)(Args...) const) { 969 | return FastDelegate(x, func); 970 | } 971 | 972 | // clean up after ourselves... 973 | #undef FASTDLGT_RETTYPE 974 | 975 | } // namespace fastdelegate 976 | 977 | #endif // !defined(FASTDELEGATE_HPP) 978 | -------------------------------------------------------------------------------- /src/FastDelegate/official-v1.5/Demo.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "FastDelegate.h" 3 | // Demonstrate the syntax for FastDelegates. 4 | // -Don Clugston, May 2004. 5 | // It's a really boring example, but it shows the most important cases. 6 | 7 | // Declare some functions of varying complexity... 8 | void SimpleStaticFunction(int num, char *str) { 9 | printf("In SimpleStaticFunction. Num=%d, str = %s\n", num, str); 10 | } 11 | 12 | void SimpleVoidFunction() { 13 | printf("In SimpleVoidFunction with no parameters.\n"); 14 | } 15 | 16 | class CBaseClass { 17 | protected: 18 | char *m_name; 19 | public: 20 | CBaseClass(char *name) : m_name(name) {}; 21 | void SimpleMemberFunction(int num, char *str) { 22 | printf("In SimpleMemberFunction in %s. Num=%d, str = %s\n", m_name, num, str); } 23 | int SimpleMemberFunctionReturnsInt(int num, char *str) { 24 | printf("In SimpleMemberFunction in %s. Num=%d, str = %s\n", m_name, num, str); return -1; } 25 | void ConstMemberFunction(int num, char *str) const { 26 | printf("In ConstMemberFunction in %s. Num=%d, str = %s\n", m_name, num, str); } 27 | virtual void SimpleVirtualFunction(int num, char *str) { 28 | printf("In SimpleVirtualFunction in %s. Num=%d, str = %s\n", m_name, num, str); } 29 | static void StaticMemberFunction(int num, char *str) { 30 | printf("In StaticMemberFunction. Num=%d, str =%s\n", num, str); } 31 | }; 32 | 33 | class COtherClass { 34 | double rubbish; // to ensure this class has non-zero size. 35 | public: 36 | virtual void UnusedVirtualFunction(void) { } 37 | virtual void TrickyVirtualFunction(int num, char *str)=0; 38 | }; 39 | 40 | class VeryBigClass { 41 | int letsMakeThingsComplicated[400]; 42 | }; 43 | 44 | // This declaration ensures that we get a convoluted class heirarchy. 45 | class CDerivedClass : public VeryBigClass, virtual public COtherClass, virtual public CBaseClass 46 | { 47 | double m_somemember[8]; 48 | public: 49 | CDerivedClass() : CBaseClass("Base of Derived") { m_somemember[0]=1.2345; } 50 | void SimpleDerivedFunction(int num, char *str) { printf("In SimpleDerived. num=%d\n", num); } 51 | virtual void AnotherUnusedVirtualFunction(int num, char *str) {} 52 | virtual void TrickyVirtualFunction(int num, char *str) { 53 | printf("In Derived TrickyMemberFunction. Num=%d, str = %s\n", num, str); 54 | } 55 | }; 56 | 57 | using namespace fastdelegate; 58 | 59 | int main(void) 60 | { 61 | // Delegates with up to 8 parameters are supported. 62 | // Here's the case for a void function. 63 | // We declare a delegate and attach it to SimpleVoidFunction() 64 | printf("-- FastDelegate demo --\nA no-parameter delegate is declared using FastDelegate0\n\n"); 65 | 66 | FastDelegate0<> noparameterdelegate(&SimpleVoidFunction); 67 | 68 | noparameterdelegate(); // invoke the delegate - this calls SimpleVoidFunction() 69 | 70 | printf("\n-- Examples using two-parameter delegates (int, char *) --\n\n"); 71 | 72 | // By default, the return value is void. 73 | typedef FastDelegate2 MyDelegate; 74 | 75 | // If you want to have a non-void return value, put it at the end. 76 | typedef FastDelegate2 IntMyDelegate; 77 | 78 | 79 | MyDelegate funclist[12]; // delegates are initialized to empty 80 | CBaseClass a("Base A"); 81 | CBaseClass b("Base B"); 82 | CDerivedClass d; 83 | CDerivedClass c; 84 | 85 | IntMyDelegate newdeleg; 86 | newdeleg = MakeDelegate(&a, &CBaseClass::SimpleMemberFunctionReturnsInt); 87 | 88 | // Binding a simple member function 89 | funclist[0].bind(&a, &CBaseClass::SimpleMemberFunction); 90 | 91 | // You can also bind static (free) functions 92 | funclist[1].bind(&SimpleStaticFunction); 93 | // and static member functions 94 | funclist[2].bind(&CBaseClass::StaticMemberFunction); 95 | // and const member functions (these only need a const class pointer). 96 | funclist[11].bind( (const CBaseClass *)&a, &CBaseClass::ConstMemberFunction); 97 | funclist[3].bind( &a, &CBaseClass::ConstMemberFunction); 98 | // and virtual member functions 99 | funclist[4].bind(&b, &CBaseClass::SimpleVirtualFunction); 100 | 101 | // You can also use the = operator. For static functions, a fastdelegate 102 | // looks identical to a simple function pointer. 103 | funclist[5] = &CBaseClass::StaticMemberFunction; 104 | 105 | // The weird rule about the class of derived member function pointers is avoided. 106 | // For MSVC, you can use &CDerivedClass::SimpleVirtualFunction here, but DMC will complain. 107 | // Note that as well as .bind(), you can also use the MakeDelegate() 108 | // global function. 109 | funclist[6] = MakeDelegate(&d, &CBaseClass::SimpleVirtualFunction); 110 | 111 | // The worst case is an abstract virtual function of a virtually-derived class 112 | // with at least one non-virtual base class. This is a VERY obscure situation, 113 | // which you're unlikely to encounter in the real world. 114 | // FastDelegate versions prior to 1.3 had problems with this case on VC6. 115 | // Now, it works without problems on all compilers. 116 | funclist[7].bind(&c, &CDerivedClass::TrickyVirtualFunction); 117 | // BUT... in such cases you should be using the base class as an 118 | // interface, anyway. 119 | funclist[8].bind(&c, &COtherClass::TrickyVirtualFunction); 120 | // Calling a function that was first declared in the derived class is straightforward 121 | funclist[9] = MakeDelegate(&c, &CDerivedClass::SimpleDerivedFunction); 122 | 123 | // You can also bind directly using the constructor 124 | MyDelegate dg(&b, &CBaseClass::SimpleVirtualFunction); 125 | 126 | char *msg = "Looking for equal delegate"; 127 | for (int i=0; i<12; i++) { 128 | printf("%d :", i); 129 | // The == and != operators are provided 130 | // Note that they work even for inline functions. 131 | if (funclist[i]==dg) { msg = "Found equal delegate"; }; 132 | // operator ! can be used to test for an empty delegate 133 | // You can also use the .empty() member function. 134 | if (!funclist[i]) { 135 | printf("Delegate is empty\n"); 136 | } else { 137 | // Invocation generates optimal assembly code. 138 | funclist[i](i, msg); 139 | }; 140 | } 141 | return 0; 142 | } 143 | 144 | -------------------------------------------------------------------------------- /src/FastDelegate/official-v1.5/FastDelegateBind.h: -------------------------------------------------------------------------------- 1 | // FastDelegateBind.h 2 | // Helper file for FastDelegates. Provides bind() function, enabling 3 | // FastDelegates to be rapidly compared to programs using boost::function and boost::bind. 4 | // 5 | // Documentation is found at http://www.codeproject.com/cpp/FastDelegate.asp 6 | // 7 | // Original author: Jody Hagins. 8 | // Minor changes by Don Clugston. 9 | // 10 | // Warning: The arguments to 'bind' are ignored! No actual binding is performed. 11 | // The behaviour is equivalent to boost::bind only when the basic placeholder 12 | // arguments _1, _2, _3, etc are used in order. 13 | // 14 | // HISTORY: 15 | // 1.4 Dec 2004. Initial release as part of FastDelegate 1.4. 16 | 17 | 18 | #ifndef FASTDELEGATEBIND_H 19 | #define FASTDELEGATEBIND_H 20 | #if _MSC_VER > 1000 21 | #pragma once 22 | #endif // _MSC_VER > 1000 23 | 24 | //////////////////////////////////////////////////////////////////////////////// 25 | // FastDelegate bind() 26 | // 27 | // bind() helper function for boost compatibility. 28 | // (Original author: Jody Hagins). 29 | // 30 | // Add another helper, so FastDelegate can be a dropin replacement 31 | // for boost::bind (in a fair number of cases). 32 | // Note the elipses, because boost::bind() takes place holders 33 | // but FastDelegate does not care about them. Getting the place holder 34 | // mechanism to work, and play well with boost is a bit tricky, so 35 | // we do the "easy" thing... 36 | // Assume we have the following code... 37 | // using boost::bind; 38 | // bind(&Foo:func, &foo, _1, _2); 39 | // we should be able to replace the "using" with... 40 | // using fastdelegate::bind; 41 | // and everything should work fine... 42 | //////////////////////////////////////////////////////////////////////////////// 43 | 44 | #ifdef FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX 45 | 46 | namespace fastdelegate { 47 | 48 | //N=0 49 | template 50 | FastDelegate< RetType ( ) > 51 | bind( 52 | RetType (X::*func)( ), 53 | Y * y, 54 | ...) 55 | { 56 | return FastDelegate< RetType ( ) >(y, func); 57 | } 58 | 59 | template 60 | FastDelegate< RetType ( ) > 61 | bind( 62 | RetType (X::*func)( ) const, 63 | Y * y, 64 | ...) 65 | { 66 | return FastDelegate< RetType ( ) >(y, func); 67 | } 68 | 69 | //N=1 70 | template 71 | FastDelegate< RetType ( Param1 p1 ) > 72 | bind( 73 | RetType (X::*func)( Param1 p1 ), 74 | Y * y, 75 | ...) 76 | { 77 | return FastDelegate< RetType ( Param1 p1 ) >(y, func); 78 | } 79 | 80 | template 81 | FastDelegate< RetType ( Param1 p1 ) > 82 | bind( 83 | RetType (X::*func)( Param1 p1 ) const, 84 | Y * y, 85 | ...) 86 | { 87 | return FastDelegate< RetType ( Param1 p1 ) >(y, func); 88 | } 89 | 90 | //N=2 91 | template 92 | FastDelegate< RetType ( Param1 p1, Param2 p2 ) > 93 | bind( 94 | RetType (X::*func)( Param1 p1, Param2 p2 ), 95 | Y * y, 96 | ...) 97 | { 98 | return FastDelegate< RetType ( Param1 p1, Param2 p2 ) >(y, func); 99 | } 100 | 101 | template 102 | FastDelegate< RetType ( Param1 p1, Param2 p2 ) > 103 | bind( 104 | RetType (X::*func)( Param1 p1, Param2 p2 ) const, 105 | Y * y, 106 | ...) 107 | { 108 | return FastDelegate< RetType ( Param1 p1, Param2 p2 ) >(y, func); 109 | } 110 | 111 | //N=3 112 | template 113 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3 ) > 114 | bind( 115 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3 ), 116 | Y * y, 117 | ...) 118 | { 119 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3 ) >(y, func); 120 | } 121 | 122 | template 123 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3 ) > 124 | bind( 125 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3 ) const, 126 | Y * y, 127 | ...) 128 | { 129 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3 ) >(y, func); 130 | } 131 | 132 | //N=4 133 | template 134 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) > 135 | bind( 136 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ), 137 | Y * y, 138 | ...) 139 | { 140 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) >(y, func); 141 | } 142 | 143 | template 144 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) > 145 | bind( 146 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) const, 147 | Y * y, 148 | ...) 149 | { 150 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) >(y, func); 151 | } 152 | 153 | //N=5 154 | template 155 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) > 156 | bind( 157 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ), 158 | Y * y, 159 | ...) 160 | { 161 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) >(y, func); 162 | } 163 | 164 | template 165 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) > 166 | bind( 167 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) const, 168 | Y * y, 169 | ...) 170 | { 171 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) >(y, func); 172 | } 173 | 174 | //N=6 175 | template 176 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) > 177 | bind( 178 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ), 179 | Y * y, 180 | ...) 181 | { 182 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) >(y, func); 183 | } 184 | 185 | template 186 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) > 187 | bind( 188 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) const, 189 | Y * y, 190 | ...) 191 | { 192 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) >(y, func); 193 | } 194 | 195 | //N=7 196 | template 197 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) > 198 | bind( 199 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ), 200 | Y * y, 201 | ...) 202 | { 203 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) >(y, func); 204 | } 205 | 206 | template 207 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) > 208 | bind( 209 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) const, 210 | Y * y, 211 | ...) 212 | { 213 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) >(y, func); 214 | } 215 | 216 | //N=8 217 | template 218 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) > 219 | bind( 220 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ), 221 | Y * y, 222 | ...) 223 | { 224 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) >(y, func); 225 | } 226 | 227 | template 228 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) > 229 | bind( 230 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) const, 231 | Y * y, 232 | ...) 233 | { 234 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) >(y, func); 235 | } 236 | 237 | 238 | #endif //FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX 239 | 240 | } // namespace fastdelegate 241 | 242 | #endif // !defined(FASTDELEGATEBIND_H) 243 | 244 | -------------------------------------------------------------------------------- /src/FastDelegate/unofficial-v2/FastDelegate.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yxbh/Cpp-Delegate-Library-Collection/022a26331d0a8c8724d5f276adc020b12546a7fe/src/FastDelegate/unofficial-v2/FastDelegate.h -------------------------------------------------------------------------------- /src/FastFunc/FastFunc.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SSVU_FASTFUNC 2 | #define SSVU_FASTFUNC 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifdef _MSC_VER 13 | 14 | namespace ssvu 15 | { 16 | namespace Internal 17 | { 18 | class __single_inheritance AnyClass; 19 | class AnyClass {}; 20 | using AnyPtrThis = AnyClass*; 21 | using AnyPtrFunc = void(AnyClass::*)(); 22 | template using AnyPtrFuncT = TReturn(AnyClass::*)(TArgs...); 23 | template using AnyPtrStaticFuncT = TReturn(*)(TArgs...); 24 | 25 | constexpr std::size_t SingleMemFuncPtrSize{sizeof(void(AnyClass::*)())}; 26 | 27 | template union HorribleUnion { TOut out; TIn in; }; 28 | template inline TOut horrible_cast(TIn mIn) noexcept { HorribleUnion u; static_assert(sizeof(TIn) == sizeof(u) && sizeof(TIn) == sizeof(TOut), "Cannot use horrible_cast<>"); u.in = mIn; return u.out; } 29 | template inline TOut unsafe_horrible_cast(TIn mIn) noexcept { HorribleUnion u; u.in = mIn; return u.out; } 30 | 31 | template 32 | struct SimplifyMemFunc 33 | { 34 | static constexpr std::size_t invalid_size_value = TN; 35 | template 36 | inline static AnyPtrThis convert(const TThis*, TFunc, AnyPtrFunc&) noexcept 37 | { 38 | static_assert(false, "Unsupported member function pointer on this compiler"); 39 | return 0; 40 | } 41 | }; 42 | template<> 43 | struct SimplifyMemFunc 44 | { 45 | template 46 | inline static AnyPtrThis convert(const TThis* mThis, TFunc mFunc, AnyPtrFunc& mFuncOut) noexcept 47 | { 48 | mFuncOut = reinterpret_cast(mFunc); 49 | return reinterpret_cast(const_cast(mThis)); 50 | } 51 | }; 52 | /* 53 | Besides the standard conforming version above, the VC++ compiler has variable function pointer size depending 54 | on function type, which is is not standard conforming. The original FastDelegate handled this but the FastFunc 55 | ignored VC++ compliance issue. The FastDelegate solution is ported forward into this version to make it work. 56 | Note: using the /vmg flag could make things work but it also breaks delegate equality comparison for! 57 | */ 58 | template<> 59 | struct SimplifyMemFunc 60 | { 61 | template 62 | inline static AnyPtrThis convert(const TThis* mThis, TFunc mFunc, AnyPtrFunc& mFuncOut) noexcept 63 | { 64 | union { 65 | TFunc func; 66 | struct { 67 | AnyPtrFunc funcaddress; // points to the actual member function 68 | int delta; // #BYTES to be added to the 'this' pointer 69 | }s; 70 | } u; 71 | // Check that the horrible_cast will work 72 | static_assert(sizeof(mFunc) == sizeof(u.s), "Cannot use horrible_cast<>"); 73 | u.func = mFunc; 74 | mFuncOut = u.s.funcaddress; 75 | return reinterpret_cast(reinterpret_cast(const_cast(mThis))+u.s.delta); 76 | } 77 | }; 78 | struct MicrosoftVirtualMFP { 79 | void (AnyClass::*codeptr)(); // points to the actual member function 80 | int delta; // #bytes to be added to the 'this' pointer 81 | int vtable_index; // or 0 if no virtual inheritance 82 | }; 83 | 84 | struct GenericVirtualClass : virtual public AnyClass 85 | { 86 | typedef GenericVirtualClass * (GenericVirtualClass::*ProbePtrType)(); 87 | GenericVirtualClass * GetThis() { return this; } 88 | }; 89 | template<> 90 | struct SimplifyMemFunc 91 | { 92 | template 93 | inline static AnyPtrThis convert(const TThis* mThis, TFunc mFunc, AnyPtrFunc& mFuncOut) noexcept 94 | { 95 | union { 96 | TFunc func; 97 | AnyClass* (TThis::*ProbeFunc)(); 98 | MicrosoftVirtualMFP s; 99 | } u; 100 | u.func = mFunc; 101 | mFuncOut = reinterpret_cast(u.s.codeptr); 102 | union { 103 | GenericVirtualClass::ProbePtrType virtfunc; 104 | MicrosoftVirtualMFP s; 105 | } u2; 106 | // Check that the horrible_cast<>s will work 107 | static_assert(sizeof(mFunc) == sizeof(u.s) && sizeof(mFunc) == sizeof(u.ProbeFunc) && sizeof(u2.virtfunc) == sizeof(u2.s), "Cannot use horrible_cast<>"); 108 | // Unfortunately, taking the address of a MF prevents it from being inlined, so 109 | // this next line can't be completely optimised away by the compiler. 110 | u2.virtfunc = &GenericVirtualClass::GetThis; 111 | u.s.codeptr = u2.s.codeptr; 112 | return (const_cast(mThis)->*u.ProbeFunc)(); 113 | } 114 | }; 115 | template<> 116 | struct SimplifyMemFunc 117 | { 118 | template 119 | inline static AnyPtrThis convert(const TThis* mThis, TFunc mFunc, AnyPtrFunc& mFuncOut) noexcept 120 | { 121 | // The member function pointer is 16 bytes long. We can't use a normal cast, but 122 | // we can use a union to do the conversion. 123 | union { 124 | TFunc func; 125 | // In VC++ and ICL, an unknown_inheritance member pointer 126 | // is internally defined as: 127 | struct { 128 | AnyPtrFunc funcaddress; // points to the actual member function 129 | int delta; // #bytes to be added to the 'this' pointer 130 | int vtordisp; // #bytes to add to 'this' to find the vtable 131 | int vtable_index; // or 0 if no virtual inheritance 132 | } s; 133 | } u; 134 | // Check that the horrible_cast will work 135 | static_assert(sizeof(TFunc) == sizeof(u.s), "Cannot use horrible_cast<>"); 136 | u.func = mFunc; 137 | mFuncOut = u.s.funcaddress; 138 | int virtual_delta = 0; 139 | if (u.s.vtable_index) { // Virtual inheritance is used 140 | // First, get to the vtable. 141 | // It is 'vtordisp' bytes from the start of the class. 142 | const int * vtable = *reinterpret_cast(reinterpret_cast(mThis)+u.s.vtordisp); 143 | 144 | // 'vtable_index' tells us where in the table we should be looking. 145 | virtual_delta = u.s.vtordisp + *reinterpret_cast(reinterpret_cast(vtable)+u.s.vtable_index); 146 | } 147 | // The int at 'virtual_delta' gives us the amount to add to 'this'. 148 | // Finally we can add the three components together. Phew! 149 | return reinterpret_cast(reinterpret_cast(const_cast(mThis))+u.s.delta + virtual_delta); 150 | } 151 | }; 152 | 153 | template 154 | struct Closure 155 | { 156 | private: 157 | using PtrFuncT = AnyPtrFuncT; 158 | using PtrStaticFuncT = AnyPtrStaticFuncT; 159 | AnyPtrThis ptrThis{nullptr}; 160 | AnyPtrFunc ptrFunction{nullptr}; 161 | 162 | public: 163 | template inline void bind(TThis* mThis, TFunc mFunc) noexcept { ptrThis = ssvu::Internal::SimplifyMemFunc::convert(mThis, mFunc, ptrFunction); } 164 | template inline void bind(TThis* mThis, TInvoker mInvoker, PtrStaticFuncT mFunc) noexcept 165 | { 166 | if(mFunc == nullptr) ptrFunction = nullptr; else bind(mThis, mInvoker); 167 | ptrThis = horrible_cast(mFunc); 168 | } 169 | 170 | inline bool operator==(std::nullptr_t) const noexcept { return ptrThis == nullptr && ptrFunction == nullptr; } 171 | inline bool operator==(const Closure& mRhs) const noexcept { return ptrThis == mRhs.ptrThis && ptrFunction == mRhs.ptrFunction; } 172 | inline bool operator==(PtrStaticFuncT mPtr) const noexcept { return mPtr == nullptr ? *this == nullptr : mPtr == reinterpret_cast(getStaticFunc()); } 173 | inline bool operator!=(std::nullptr_t) const noexcept { return !operator==(nullptr); } 174 | inline bool operator!=(const Closure& mRhs) const noexcept { return !operator==(mRhs); } 175 | inline bool operator!=(PtrStaticFuncT mPtr) const noexcept { return !operator==(mPtr); } 176 | inline bool operator<(const Closure& mRhs) const { return ptrThis != mRhs.ptrThis ? ptrThis < mRhs.ptrThis : std::memcmp(&ptrFunction, &mRhs.ptrFunction, sizeof(ptrFunction)) < 0; } 177 | inline bool operator>(const Closure& mRhs) const { return !operator<(mRhs); } 178 | 179 | inline std::size_t getHash() const noexcept { return reinterpret_cast(ptrThis) ^ Internal::unsafe_horrible_cast(ptrFunction); } 180 | inline AnyPtrThis getPtrThis() const noexcept { return ptrThis; } 181 | inline PtrFuncT getPtrFunction() const noexcept { return reinterpret_cast(ptrFunction); } 182 | inline PtrStaticFuncT getStaticFunc() const noexcept { return horrible_cast(this); } 183 | }; 184 | 185 | template 186 | class FastFuncImpl 187 | { 188 | protected: 189 | using PtrStaticFuncT = AnyPtrStaticFuncT; 190 | private: 191 | Closure closure; 192 | inline TReturn invokeStaticFunc(TArgs... mArgs) const { return (*(closure.getStaticFunc()))(std::forward(mArgs)...); } 193 | 194 | protected: 195 | template inline void bind(TThis* mThis, TFunc mFunc) noexcept { closure.bind(mThis, mFunc); } 196 | template inline void bind(TFunc mFunc) noexcept { closure.bind(this, &FastFuncImpl::invokeStaticFunc, mFunc); } 197 | 198 | public: 199 | inline FastFuncImpl() noexcept = default; 200 | inline FastFuncImpl(std::nullptr_t) noexcept { } 201 | inline FastFuncImpl(PtrStaticFuncT mFunc) noexcept { bind(mFunc); } 202 | template inline FastFuncImpl(X* mThis, Y mFunc) noexcept { bind(mThis, mFunc); } 203 | 204 | 205 | inline FastFuncImpl& operator=(PtrStaticFuncT mFunc) noexcept { bind(mFunc); } 206 | inline TReturn operator()(TArgs... mArgs) const { return (closure.getPtrThis()->*(closure.getPtrFunction()))(std::forward(mArgs)...); } 207 | 208 | inline bool operator==(std::nullptr_t) const noexcept { return closure == nullptr; } 209 | inline bool operator==(const FastFuncImpl& mImpl) const noexcept { return closure == mImpl.closure; } 210 | inline bool operator==(PtrStaticFuncT mFuncPtr) const noexcept { return closure == mFuncPtr; } 211 | inline bool operator!=(std::nullptr_t) const noexcept { return !operator==(nullptr); } 212 | inline bool operator!=(const FastFuncImpl& mImpl) const noexcept { return !operator==(mImpl); } 213 | inline bool operator!=(PtrStaticFuncT mFuncPtr) const noexcept { return !operator==(mFuncPtr); } 214 | inline bool operator<(const FastFuncImpl& mImpl) const { return closure < mImpl.closure; } 215 | inline bool operator>(const FastFuncImpl& mImpl) const { return !operator<(mImpl); } 216 | }; 217 | } 218 | 219 | template struct MemFuncToFunc; 220 | template struct MemFuncToFunc { using Type = TReturn(*)(TArgs...); }; 221 | 222 | #define ENABLE_IF_CONV_TO_FUN_PTR(x) typename std::enable_if::type::operator())>::Type, x>::value>::type* = nullptr 223 | #define ENABLE_IF_NOT_CONV_TO_FUN_PTR(x) typename std::enable_if::type::operator())>::Type, x>::value>::type* = nullptr 224 | #define ENABLE_IF_SAME_TYPE(x, y) typename = typename std::enable_if::type>{}>::type 225 | 226 | template class FastFunc; 227 | template 228 | class FastFunc 229 | : public Internal::FastFuncImpl 230 | { 231 | private: 232 | using BaseType = Internal::FastFuncImpl; 233 | std::shared_ptr storage; 234 | template inline static void funcDeleter(void* mPtr) { static_cast(mPtr)->~T(); operator delete(mPtr); } 235 | 236 | public: 237 | // using BaseType::BaseType; 238 | inline FastFunc(std::nullptr_t) noexcept {} 239 | inline FastFunc(PtrStaticFuncT mFunc) noexcept : BaseType(mFunc) {} 240 | template inline FastFunc(X* mThis, Y mFunc) noexcept : BaseType(mThis, mFunc) {} 241 | 242 | inline FastFunc() noexcept = default; 243 | 244 | template 245 | inline FastFunc(TFunc&& mFunc, ENABLE_IF_CONV_TO_FUN_PTR(TFunc)) 246 | { 247 | using FuncType = typename std::decay::type; 248 | this->bind(&mFunc, &FuncType::operator()); 249 | } 250 | template 251 | inline FastFunc(TFunc&& mFunc, ENABLE_IF_NOT_CONV_TO_FUN_PTR(TFunc)) 252 | : storage(operator new(sizeof(TFunc)), funcDeleter::type>) 253 | { 254 | using FuncType = typename std::decay::type; 255 | new (storage.get()) FuncType(std::forward(mFunc)); 256 | this->bind(storage.get(), &FuncType::operator()); 257 | } 258 | }; 259 | 260 | #undef ENABLE_IF_CONV_TO_FUN_PTR 261 | #undef ENABLE_IF_NOT_CONV_TO_FUN_PTR 262 | #undef ENABLE_IF_SAME_TYPE 263 | } 264 | 265 | #else 266 | 267 | namespace ssvu 268 | { 269 | namespace Internal 270 | { 271 | class AnyClass; 272 | using AnyPtrThis = AnyClass*; 273 | using AnyPtrFunc = void(AnyClass::*)(); 274 | template using AnyPtrFuncT = TReturn(AnyClass::*)(TArgs...); 275 | template using AnyPtrStaticFuncT = TReturn(*)(TArgs...); 276 | 277 | constexpr std::size_t SingleMemFuncPtrSize{ sizeof(void(AnyClass::*)()) }; 278 | 279 | template union HorribleUnion { TOut out; TIn in; }; 280 | template inline TOut horrible_cast(TIn mIn) noexcept{ HorribleUnion u; static_assert(sizeof(TIn) == sizeof(u) && sizeof(TIn) == sizeof(TOut), "Cannot use horrible_cast<>"); u.in = mIn; return u.out; } 281 | template inline TOut unsafe_horrible_cast(TIn mIn) noexcept{ HorribleUnion u; u.in = mIn; return u.out; } 282 | 283 | template 284 | struct SimplifyMemFunc 285 | { 286 | template 287 | inline static AnyPtrThis convert(const TThis*, TFunc, AnyPtrFunc&) noexcept 288 | { 289 | static_assert(TN - 100, "Unsupported member function pointer on this compiler"); 290 | return 0; 291 | } 292 | }; 293 | template<> 294 | struct SimplifyMemFunc 295 | { 296 | template 297 | inline static AnyPtrThis convert(const TThis* mThis, TFunc mFunc, AnyPtrFunc& mFuncOut) noexcept 298 | { 299 | mFuncOut = reinterpret_cast(mFunc); 300 | return reinterpret_cast(const_cast(mThis)); 301 | } 302 | }; 303 | 304 | template 305 | struct Closure 306 | { 307 | private: 308 | using PtrFuncT = AnyPtrFuncT; 309 | using PtrStaticFuncT = AnyPtrStaticFuncT; 310 | AnyPtrThis ptrThis{ nullptr }; 311 | AnyPtrFunc ptrFunction{ nullptr }; 312 | 313 | public: 314 | template inline void bind(TThis* mThis, TFunc mFunc) noexcept{ ptrThis = SimplifyMemFunc::convert(mThis, mFunc, ptrFunction); } 315 | template inline void bind(TThis* mThis, TInvoker mInvoker, PtrStaticFuncT mFunc) noexcept 316 | { 317 | if (mFunc == nullptr) ptrFunction = nullptr; else bind(mThis, mInvoker); 318 | ptrThis = horrible_cast(mFunc); 319 | } 320 | 321 | inline bool operator==(std::nullptr_t) const noexcept{ return ptrThis == nullptr && ptrFunction == nullptr; } 322 | inline bool operator==(const Closure& mRhs) const noexcept{ return ptrThis == mRhs.ptrThis && ptrFunction == mRhs.ptrFunction; } 323 | inline bool operator==(PtrStaticFuncT mPtr) const noexcept{ return mPtr == nullptr ? *this == nullptr : mPtr == reinterpret_cast(getStaticFunc()); } 324 | inline bool operator!=(std::nullptr_t) const noexcept{ return !operator==(nullptr); } 325 | inline bool operator!=(const Closure& mRhs) const noexcept{ return !operator==(mRhs); } 326 | inline bool operator!=(PtrStaticFuncT mPtr) const noexcept{ return !operator==(mPtr); } 327 | inline bool operator<(const Closure& mRhs) const { return ptrThis != mRhs.ptrThis ? ptrThis < mRhs.ptrThis : std::memcmp(&ptrFunction, &mRhs.ptrFunction, sizeof(ptrFunction)) < 0; } 328 | inline bool operator>(const Closure& mRhs) const { return !operator<(mRhs); } 329 | 330 | inline std::size_t getHash() const noexcept{ return reinterpret_cast(ptrThis) ^ Internal::unsafe_horrible_cast(ptrFunction); } 331 | inline AnyPtrThis getPtrThis() const noexcept{ return ptrThis; } 332 | inline PtrFuncT getPtrFunction() const noexcept{ return reinterpret_cast(ptrFunction); } 333 | inline PtrStaticFuncT getStaticFunc() const noexcept{ return horrible_cast(this); } 334 | }; 335 | 336 | template 337 | class FastFuncImpl 338 | { 339 | private: 340 | using PtrStaticFuncT = AnyPtrStaticFuncT; 341 | Closure closure; 342 | inline TReturn invokeStaticFunc(TArgs... mArgs) const { return (*(closure.getStaticFunc()))(std::forward(mArgs)...); } 343 | 344 | protected: 345 | template inline void bind(TThis* mThis, TFunc mFunc) noexcept{ closure.bind(mThis, mFunc); } 346 | template inline void bind(TFunc mFunc) noexcept{ closure.bind(this, &FastFuncImpl::invokeStaticFunc, mFunc); } 347 | 348 | public: 349 | inline FastFuncImpl() noexcept = default; 350 | inline FastFuncImpl(std::nullptr_t) noexcept{} 351 | inline FastFuncImpl(PtrStaticFuncT mFunc) noexcept{ bind(mFunc); } 352 | template inline FastFuncImpl(X* mThis, Y mFunc) noexcept{ bind(mThis, mFunc); } 353 | 354 | 355 | inline FastFuncImpl& operator=(PtrStaticFuncT mFunc) noexcept{ bind(mFunc); } 356 | inline TReturn operator()(TArgs... mArgs) const { return (closure.getPtrThis()->*(closure.getPtrFunction()))(std::forward(mArgs)...); } 357 | 358 | inline bool operator==(std::nullptr_t) const noexcept{ return closure == nullptr; } 359 | inline bool operator==(const FastFuncImpl& mImpl) const noexcept{ return closure == mImpl.closure; } 360 | inline bool operator==(PtrStaticFuncT mFuncPtr) const noexcept{ return closure == mFuncPtr; } 361 | inline bool operator!=(std::nullptr_t) const noexcept{ return !operator==(nullptr); } 362 | inline bool operator!=(const FastFuncImpl& mImpl) const noexcept{ return !operator==(mImpl); } 363 | inline bool operator!=(PtrStaticFuncT mFuncPtr) const noexcept{ return !operator==(mFuncPtr); } 364 | inline bool operator<(const FastFuncImpl& mImpl) const { return closure < mImpl.closure; } 365 | inline bool operator>(const FastFuncImpl& mImpl) const { return !operator<(mImpl); } 366 | }; 367 | } 368 | 369 | template struct MemFuncToFunc; 370 | template struct MemFuncToFunc { using Type = TReturn(*)(TArgs...); }; 371 | 372 | #define ENABLE_IF_CONV_TO_FUN_PTR(x) typename std::enable_if::type::operator())>::Type, x>::value>::type* = nullptr 373 | #define ENABLE_IF_NOT_CONV_TO_FUN_PTR(x) typename std::enable_if::type::operator())>::Type, x>::value>::type* = nullptr 374 | #define ENABLE_IF_SAME_TYPE(x, y) typename = typename std::enable_if::type>{}>::type 375 | 376 | template class FastFunc; 377 | template 378 | class FastFunc 379 | : public Internal::FastFuncImpl 380 | { 381 | private: 382 | using BaseType = Internal::FastFuncImpl; 383 | std::shared_ptr storage; 384 | template inline static void funcDeleter(void* mPtr) { static_cast(mPtr)->~T(); operator delete(mPtr); } 385 | 386 | public: 387 | using BaseType::BaseType; 388 | 389 | inline FastFunc() noexcept = default; 390 | 391 | template 392 | inline FastFunc(TFunc&& mFunc, ENABLE_IF_CONV_TO_FUN_PTR(TFunc)) 393 | { 394 | using FuncType = typename std::decay::type; 395 | this->bind(&mFunc, &FuncType::operator()); 396 | } 397 | template 398 | inline FastFunc(TFunc&& mFunc, ENABLE_IF_NOT_CONV_TO_FUN_PTR(TFunc)) 399 | : storage(operator new(sizeof(TFunc)), funcDeleter::type>) 400 | { 401 | using FuncType = typename std::decay::type; 402 | new (storage.get()) FuncType(std::forward(mFunc)); 403 | this->bind(storage.get(), &FuncType::operator()); 404 | } 405 | }; 406 | 407 | #undef ENABLE_IF_CONV_TO_FUN_PTR 408 | #undef ENABLE_IF_NOT_CONV_TO_FUN_PTR 409 | #undef ENABLE_IF_SAME_TYPE 410 | } 411 | 412 | #endif 413 | 414 | #endif -------------------------------------------------------------------------------- /src/SRDelegate/SRDelegate.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file SRDelegate.hpp 3 | * 4 | * This is a C++11 implementation by janezz55(code.google) for the original "The Impossibly Fast C++ Delegates" authored by Sergey Ryazanov. 5 | * 6 | * This is originally a modified copy checkouted from https://code.google.com/p/cpppractice/source/browse/trunk/delegate.hpp on 2014/06/07. 7 | * Last change in the chunk was r370 on Feb 9, 2014. 8 | * The current version is based on the latest (20170123) commit on user1095108's generic library github repo at the following commit: https://github.com/user1095108/generic/commit/5078f7343e1d0751248ed7aff14660ef604446cb 9 | * 10 | * The following modifications were added by Benjamin YanXiang Huang 11 | * - replace light_ptr with std::shared_ptr. 12 | * - renamed src file. 13 | * - minor VC workaround for template type initilisation. 14 | * - patch to allow inline function comparison. 15 | * 16 | * Reference: 17 | * - http://codereview.stackexchange.com/questions/14730/impossibly-fast-delegate-in-c11 18 | * - http://www.codeproject.com/Articles/11015/The-Impossibly-Fast-C-Delegates 19 | * - https://code.google.com/p/cpppractice/source/browse/trunk/delegate.hpp 20 | * - https://github.com/janezz55/generic/blob/master/delegate.hpp 21 | */ 22 | 23 | #pragma once 24 | #ifndef DELEGATE_HPP 25 | # define DELEGATE_HPP 26 | 27 | #include 28 | 29 | #include 30 | 31 | #include 32 | 33 | #include 34 | 35 | #include 36 | 37 | #include 38 | 39 | namespace generic 40 | { 41 | 42 | template class delegate; 43 | 44 | template 45 | class delegate 46 | { 47 | using stub_ptr_type = R(*)(void*, A&&...); 48 | 49 | delegate(void* const o, stub_ptr_type const m) noexcept : 50 | object_ptr_(o), 51 | stub_ptr_(m) 52 | { 53 | } 54 | 55 | public: 56 | delegate() = default; 57 | 58 | delegate(delegate const&) = default; 59 | 60 | delegate(delegate&&) = default; 61 | 62 | delegate(::std::nullptr_t const) noexcept : delegate() { } 63 | 64 | template {}>::type> 66 | explicit delegate(C const* const o) noexcept : 67 | object_ptr_(const_cast(o)) 68 | { 69 | } 70 | 71 | template {}>::type> 73 | explicit delegate(C const& o) noexcept : 74 | object_ptr_(const_cast(&o)) 75 | { 76 | } 77 | 78 | template 79 | delegate(C* const object_ptr, R(C::* const method_ptr)(A...)) 80 | { 81 | *this = from(object_ptr, method_ptr); 82 | } 83 | 84 | template 85 | delegate(C* const object_ptr, R(C::* const method_ptr)(A...) const) 86 | { 87 | *this = from(object_ptr, method_ptr); 88 | } 89 | 90 | template 91 | delegate(C& object, R(C::* const method_ptr)(A...)) 92 | { 93 | *this = from(object, method_ptr); 94 | } 95 | 96 | template 97 | delegate(C const& object, R(C::* const method_ptr)(A...) const) 98 | { 99 | *this = from(object, method_ptr); 100 | } 101 | 102 | template < 103 | typename T, 104 | typename = typename ::std::enable_if< 105 | !::std::is_same::type>::value 106 | >::type 107 | > 108 | delegate(T&& f) : 109 | store_(operator new(sizeof(typename ::std::decay::type)), 110 | functor_deleter::type>), 111 | store_size_(sizeof(typename ::std::decay::type)) 112 | { 113 | using functor_type = typename ::std::decay::type; 114 | 115 | new (store_.get()) functor_type(::std::forward(f)); 116 | 117 | object_ptr_ = store_.get(); 118 | 119 | stub_ptr_ = functor_stub; 120 | 121 | deleter_ = deleter_stub; 122 | } 123 | 124 | delegate& operator=(delegate const&) = default; 125 | 126 | delegate& operator=(delegate&&) = default; 127 | 128 | template 129 | delegate& operator=(R(C::* const rhs)(A...)) 130 | { 131 | return *this = from(static_cast(object_ptr_), rhs); 132 | } 133 | 134 | template 135 | delegate& operator=(R(C::* const rhs)(A...) const) 136 | { 137 | return *this = from(static_cast(object_ptr_), rhs); 138 | } 139 | 140 | template < 141 | typename T, 142 | typename = typename ::std::enable_if< 143 | !::std::is_same::type>{} 144 | >::type 145 | > 146 | delegate& operator=(T&& f) 147 | { 148 | using functor_type = typename ::std::decay::type; 149 | 150 | if ((sizeof(functor_type) > store_size_) || !store_.unique()) 151 | { 152 | store_.reset(operator new(sizeof(functor_type)), 153 | functor_deleter); 154 | 155 | store_size_ = sizeof(functor_type); 156 | } 157 | else 158 | { 159 | deleter_(store_.get()); 160 | } 161 | 162 | new (store_.get()) functor_type(::std::forward(f)); 163 | 164 | object_ptr_ = store_.get(); 165 | 166 | stub_ptr_ = functor_stub; 167 | 168 | deleter_ = deleter_stub; 169 | 170 | return *this; 171 | } 172 | 173 | template 174 | static delegate from() noexcept 175 | { 176 | return{ nullptr, function_stub }; 177 | } 178 | 179 | template 180 | static delegate from(C* const object_ptr) noexcept 181 | { 182 | return{ object_ptr, method_stub }; 183 | } 184 | 185 | template 186 | static delegate from(C const* const object_ptr) noexcept 187 | { 188 | return{ const_cast(object_ptr), const_method_stub }; 189 | } 190 | 191 | template 192 | static delegate from(C& object) noexcept 193 | { 194 | return{ &object, method_stub }; 195 | } 196 | 197 | template 198 | static delegate from(C const& object) noexcept 199 | { 200 | return{ const_cast(&object), const_method_stub }; 201 | } 202 | 203 | template 204 | static delegate from(T&& f) 205 | { 206 | return ::std::forward(f); 207 | } 208 | 209 | static delegate from(R(*const function_ptr)(A...)) 210 | { 211 | return function_ptr; 212 | } 213 | 214 | template 215 | using member_pair = 216 | ::std::pair; 217 | 218 | template 219 | using const_member_pair = 220 | ::std::pair; 221 | 222 | template 223 | static delegate from(C* const object_ptr, 224 | R(C::* const method_ptr)(A...)) 225 | { 226 | return member_pair(object_ptr, method_ptr); 227 | } 228 | 229 | template 230 | static delegate from(C const* const object_ptr, 231 | R(C::* const method_ptr)(A...) const) 232 | { 233 | return const_member_pair(object_ptr, method_ptr); 234 | } 235 | 236 | template 237 | static delegate from(C& object, R(C::* const method_ptr)(A...)) 238 | { 239 | return member_pair(&object, method_ptr); 240 | } 241 | 242 | template 243 | static delegate from(C const& object, 244 | R(C::* const method_ptr)(A...) const) 245 | { 246 | return const_member_pair(&object, method_ptr); 247 | } 248 | 249 | void reset() { stub_ptr_ = nullptr; store_.reset(); } 250 | 251 | void reset_stub() noexcept { stub_ptr_ = nullptr; } 252 | 253 | void swap(delegate& other) noexcept { ::std::swap(*this, other); } 254 | 255 | bool operator==(delegate const& rhs) const noexcept 256 | { 257 | // comparison between functor and non-functor is left as undefined at the moment. 258 | if (store_size_ && rhs.store_size_ && // both functors 259 | store_size_ == rhs.store_size_) 260 | return (std::memcmp(store_.get(), rhs.store_.get(), store_size_) == 0) && (stub_ptr_ == rhs.stub_ptr_); 261 | return (object_ptr_ == rhs.object_ptr_) && (stub_ptr_ == rhs.stub_ptr_); 262 | } 263 | 264 | bool operator!=(delegate const& rhs) const noexcept 265 | { 266 | return !operator==(rhs); 267 | } 268 | 269 | bool operator<(delegate const& rhs) const noexcept 270 | { 271 | return (object_ptr_ < rhs.object_ptr_) || 272 | ((object_ptr_ == rhs.object_ptr_) && (stub_ptr_ < rhs.stub_ptr_)); 273 | } 274 | 275 | bool operator==(::std::nullptr_t const) const noexcept 276 | { 277 | return !stub_ptr_; 278 | } 279 | 280 | bool operator!=(::std::nullptr_t const) const noexcept 281 | { 282 | return stub_ptr_; 283 | } 284 | 285 | explicit operator bool() const noexcept { return stub_ptr_; } 286 | 287 | R operator()(A... args) const 288 | { 289 | // assert(stub_ptr); 290 | return stub_ptr_(object_ptr_, ::std::forward(args)...); 291 | } 292 | 293 | private: 294 | friend struct ::std::hash; 295 | 296 | using deleter_type = void(*)(void*); 297 | 298 | void* object_ptr_; 299 | stub_ptr_type stub_ptr_{}; 300 | 301 | deleter_type deleter_; 302 | 303 | std::shared_ptr store_; 304 | ::std::size_t store_size_; 305 | 306 | template 307 | static void functor_deleter(void* const p) 308 | { 309 | static_cast(p)->~T(); 310 | 311 | operator delete(p); 312 | } 313 | 314 | template 315 | static void deleter_stub(void* const p) 316 | { 317 | static_cast(p)->~T(); 318 | } 319 | 320 | template 321 | static R function_stub(void* const, A&&... args) 322 | { 323 | return function_ptr(::std::forward(args)...); 324 | } 325 | 326 | template 327 | static R method_stub(void* const object_ptr, A&&... args) 328 | { 329 | return (static_cast(object_ptr)->*method_ptr)( 330 | ::std::forward(args)...); 331 | } 332 | 333 | template 334 | static R const_method_stub(void* const object_ptr, A&&... args) 335 | { 336 | return (static_cast(object_ptr)->*method_ptr)( 337 | ::std::forward(args)...); 338 | } 339 | 340 | template 341 | struct is_member_pair : std::false_type { }; 342 | 343 | template 344 | struct is_member_pair< ::std::pair > : std::true_type 346 | { 347 | }; 348 | 349 | template 350 | struct is_const_member_pair : std::false_type { }; 351 | 352 | template 353 | struct is_const_member_pair< ::std::pair > : std::true_type 355 | { 356 | }; 357 | 358 | template 359 | static typename ::std::enable_if< 360 | !(is_member_pair::value || // VC14 throws error here when aggregate initialization is used. i.e. is_member_pair{} 361 | is_const_member_pair::value), // VC14 throws error here when aggregate initialization is used. i.e. is_const_member_pair::value 362 | R 363 | >::type 364 | functor_stub(void* const object_ptr, A&&... args) 365 | { 366 | return (*static_cast(object_ptr))(::std::forward(args)...); 367 | } 368 | 369 | template 370 | static typename ::std::enable_if< 371 | is_member_pair::value || // VC14 throws error here when aggregate initialization is used. i.e. is_member_pair{} 372 | is_const_member_pair::value, // VC14 throws error here when aggregate initialization is used. i.e. is_const_member_pair::value 373 | R 374 | >::type 375 | functor_stub(void* const object_ptr, A&&... args) 376 | { 377 | return (static_cast(object_ptr)->first->* 378 | static_cast(object_ptr)->second)(::std::forward(args)...); 379 | } 380 | }; 381 | 382 | } 383 | 384 | namespace std 385 | { 386 | template 387 | struct hash<::generic::delegate > 388 | { 389 | size_t operator()(::generic::delegate const& d) const noexcept 390 | { 391 | auto const seed(hash()(d.object_ptr_)); 392 | 393 | return hash()(d.stub_ptr_) + 394 | 0x9e3779b9 + (seed << 6) + (seed >> 2); 395 | } 396 | }; 397 | } 398 | 399 | #endif // DELEGATE_HPP 400 | -------------------------------------------------------------------------------- /src/benchmark/FastDelegateBind.h: -------------------------------------------------------------------------------- 1 | // FastDelegateBind.h 2 | // Helper file for FastDelegates. Provides bind() function, enabling 3 | // FastDelegates to be rapidly compared to programs using boost::function and boost::bind. 4 | // 5 | // Documentation is found at http://www.codeproject.com/cpp/FastDelegate.asp 6 | // 7 | // Original author: Jody Hagins. 8 | // Minor changes by Don Clugston. 9 | // 10 | // Warning: The arguments to 'bind' are ignored! No actual binding is performed. 11 | // The behaviour is equivalent to boost::bind only when the basic placeholder 12 | // arguments _1, _2, _3, etc are used in order. 13 | // 14 | // HISTORY: 15 | // 1.4 Dec 2004. Initial release as part of FastDelegate 1.4. 16 | 17 | 18 | #ifndef FASTDELEGATEBIND_H 19 | #define FASTDELEGATEBIND_H 20 | #if _MSC_VER > 1000 21 | #pragma once 22 | #endif // _MSC_VER > 1000 23 | 24 | //////////////////////////////////////////////////////////////////////////////// 25 | // FastDelegate bind() 26 | // 27 | // bind() helper function for boost compatibility. 28 | // (Original author: Jody Hagins). 29 | // 30 | // Add another helper, so FastDelegate can be a dropin replacement 31 | // for boost::bind (in a fair number of cases). 32 | // Note the elipses, because boost::bind() takes place holders 33 | // but FastDelegate does not care about them. Getting the place holder 34 | // mechanism to work, and play well with boost is a bit tricky, so 35 | // we do the "easy" thing... 36 | // Assume we have the following code... 37 | // using boost::bind; 38 | // bind(&Foo:func, &foo, _1, _2); 39 | // we should be able to replace the "using" with... 40 | // using fastdelegate::bind; 41 | // and everything should work fine... 42 | //////////////////////////////////////////////////////////////////////////////// 43 | 44 | #ifdef FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX 45 | 46 | namespace fastdelegate_org { // previous namespace is fastdelegate 47 | 48 | //N=0 49 | template 50 | FastDelegate< RetType ( ) > 51 | bind( 52 | RetType (X::*func)( ), 53 | Y * y, 54 | ...) 55 | { 56 | return FastDelegate< RetType ( ) >(y, func); 57 | } 58 | 59 | template 60 | FastDelegate< RetType ( ) > 61 | bind( 62 | RetType (X::*func)( ) const, 63 | Y * y, 64 | ...) 65 | { 66 | return FastDelegate< RetType ( ) >(y, func); 67 | } 68 | 69 | //N=1 70 | template 71 | FastDelegate< RetType ( Param1 p1 ) > 72 | bind( 73 | RetType (X::*func)( Param1 p1 ), 74 | Y * y, 75 | ...) 76 | { 77 | return FastDelegate< RetType ( Param1 p1 ) >(y, func); 78 | } 79 | 80 | template 81 | FastDelegate< RetType ( Param1 p1 ) > 82 | bind( 83 | RetType (X::*func)( Param1 p1 ) const, 84 | Y * y, 85 | ...) 86 | { 87 | return FastDelegate< RetType ( Param1 p1 ) >(y, func); 88 | } 89 | 90 | //N=2 91 | template 92 | FastDelegate< RetType ( Param1 p1, Param2 p2 ) > 93 | bind( 94 | RetType (X::*func)( Param1 p1, Param2 p2 ), 95 | Y * y, 96 | ...) 97 | { 98 | return FastDelegate< RetType ( Param1 p1, Param2 p2 ) >(y, func); 99 | } 100 | 101 | template 102 | FastDelegate< RetType ( Param1 p1, Param2 p2 ) > 103 | bind( 104 | RetType (X::*func)( Param1 p1, Param2 p2 ) const, 105 | Y * y, 106 | ...) 107 | { 108 | return FastDelegate< RetType ( Param1 p1, Param2 p2 ) >(y, func); 109 | } 110 | 111 | //N=3 112 | template 113 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3 ) > 114 | bind( 115 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3 ), 116 | Y * y, 117 | ...) 118 | { 119 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3 ) >(y, func); 120 | } 121 | 122 | template 123 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3 ) > 124 | bind( 125 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3 ) const, 126 | Y * y, 127 | ...) 128 | { 129 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3 ) >(y, func); 130 | } 131 | 132 | //N=4 133 | template 134 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) > 135 | bind( 136 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ), 137 | Y * y, 138 | ...) 139 | { 140 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) >(y, func); 141 | } 142 | 143 | template 144 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) > 145 | bind( 146 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) const, 147 | Y * y, 148 | ...) 149 | { 150 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) >(y, func); 151 | } 152 | 153 | //N=5 154 | template 155 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) > 156 | bind( 157 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ), 158 | Y * y, 159 | ...) 160 | { 161 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) >(y, func); 162 | } 163 | 164 | template 165 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) > 166 | bind( 167 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) const, 168 | Y * y, 169 | ...) 170 | { 171 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) >(y, func); 172 | } 173 | 174 | //N=6 175 | template 176 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) > 177 | bind( 178 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ), 179 | Y * y, 180 | ...) 181 | { 182 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) >(y, func); 183 | } 184 | 185 | template 186 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) > 187 | bind( 188 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) const, 189 | Y * y, 190 | ...) 191 | { 192 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) >(y, func); 193 | } 194 | 195 | //N=7 196 | template 197 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) > 198 | bind( 199 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ), 200 | Y * y, 201 | ...) 202 | { 203 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) >(y, func); 204 | } 205 | 206 | template 207 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) > 208 | bind( 209 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) const, 210 | Y * y, 211 | ...) 212 | { 213 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) >(y, func); 214 | } 215 | 216 | //N=8 217 | template 218 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) > 219 | bind( 220 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ), 221 | Y * y, 222 | ...) 223 | { 224 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) >(y, func); 225 | } 226 | 227 | template 228 | FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) > 229 | bind( 230 | RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) const, 231 | Y * y, 232 | ...) 233 | { 234 | return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) >(y, func); 235 | } 236 | 237 | 238 | #endif //FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX 239 | 240 | } // namespace fastdelegate 241 | 242 | #endif // !defined(FASTDELEGATEBIND_H) 243 | 244 | -------------------------------------------------------------------------------- /src/benchmark/delegate_performance_test.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | CONFIG += console 3 | CONFIG -= app_bundle 4 | CONFIG -= qt 5 | 6 | 7 | #CONFIG += console 8 | CONFIG += c++11 9 | 10 | SOURCES += main.cpp 11 | 12 | HEADERS += \ 13 | FastFunc.hpp \ 14 | FastDelegate.h \ 15 | FastDelegateBind.h \ 16 | SRDelegate.hpp \ 17 | FastDelegatePJ.hpp 18 | -------------------------------------------------------------------------------- /src/benchmark/delegate_performance_test.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.30501.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "delegate_performance_test", "delegate_performance_test.vcxproj", "{CD701DB4-3C7E-4A65-9E7C-DEE48D5FD75D}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Debug|x64 = Debug|x64 12 | Release|Win32 = Release|Win32 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {CD701DB4-3C7E-4A65-9E7C-DEE48D5FD75D}.Debug|Win32.ActiveCfg = Debug|Win32 17 | {CD701DB4-3C7E-4A65-9E7C-DEE48D5FD75D}.Debug|Win32.Build.0 = Debug|Win32 18 | {CD701DB4-3C7E-4A65-9E7C-DEE48D5FD75D}.Debug|x64.ActiveCfg = Debug|x64 19 | {CD701DB4-3C7E-4A65-9E7C-DEE48D5FD75D}.Debug|x64.Build.0 = Debug|x64 20 | {CD701DB4-3C7E-4A65-9E7C-DEE48D5FD75D}.Release|Win32.ActiveCfg = Release|Win32 21 | {CD701DB4-3C7E-4A65-9E7C-DEE48D5FD75D}.Release|Win32.Build.0 = Release|Win32 22 | {CD701DB4-3C7E-4A65-9E7C-DEE48D5FD75D}.Release|x64.ActiveCfg = Release|x64 23 | {CD701DB4-3C7E-4A65-9E7C-DEE48D5FD75D}.Release|x64.Build.0 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /src/benchmark/delegate_performance_test.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {CD701DB4-3C7E-4A65-9E7C-DEE48D5FD75D} 23 | Win32Proj 24 | delegate_performance_test 25 | 26 | 27 | 28 | Application 29 | true 30 | v140 31 | Unicode 32 | 33 | 34 | Application 35 | true 36 | v140 37 | Unicode 38 | 39 | 40 | Application 41 | false 42 | v140 43 | true 44 | Unicode 45 | 46 | 47 | Application 48 | false 49 | v140 50 | true 51 | Unicode 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | true 71 | 72 | 73 | true 74 | 75 | 76 | false 77 | 78 | 79 | false 80 | 81 | 82 | 83 | 84 | 85 | Level3 86 | Disabled 87 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 88 | true 89 | $(IntDir)/%(RelativeDir)/ 90 | ../;%(AdditionalIncludeDirectories) 91 | 92 | 93 | Console 94 | true 95 | false 96 | 97 | 98 | 99 | 100 | 101 | 102 | Level3 103 | Disabled 104 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 105 | true 106 | $(IntDir)/%(RelativeDir)/ 107 | ../;%(AdditionalIncludeDirectories) 108 | 109 | 110 | Console 111 | true 112 | false 113 | 114 | 115 | 116 | 117 | Level3 118 | 119 | 120 | MaxSpeed 121 | true 122 | true 123 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 124 | true 125 | AnySuitable 126 | true 127 | true 128 | $(IntDir)/%(RelativeDir)/ 129 | Speed 130 | ../;%(AdditionalIncludeDirectories) 131 | 132 | 133 | Console 134 | true 135 | false 136 | true 137 | 138 | 139 | 140 | 141 | Level3 142 | 143 | 144 | MaxSpeed 145 | true 146 | true 147 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 148 | true 149 | AnySuitable 150 | true 151 | true 152 | $(IntDir)/%(RelativeDir)/ 153 | Speed 154 | ../;%(AdditionalIncludeDirectories) 155 | 156 | 157 | Console 158 | true 159 | false 160 | true 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /src/benchmark/main.cpp: -------------------------------------------------------------------------------- 1 | // original FastDelegate by Don Clugston. 2 | #include "FastDelegate.h" 3 | #include "FastDelegateBind.h" 4 | 5 | // V2 (C++11 implementation) of Don Clugston's FastDelegate by Pa�l Jim�nez.. 6 | #include 7 | 8 | // A C++11 implementation of Don Clugston's FastDelegate by Vittorio Romeo 9 | #include 10 | 11 | // A C++ implmenetation of Sergey Ryazanov's "The Impossibly Fast C++ Delegates" 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | // Code snippet for the function definitions used in the benchmarks. 22 | /* 23 | int x, y; 24 | x = 1; 25 | y = 2; 26 | int z = x + y; 27 | z = z; 28 | */ 29 | 30 | /* 31 | int x, y; 32 | assert(p_spEvent->getType() == TestEvent::Type); 33 | auto event = std::static_pointer_cast(p_spEvent); 34 | x = event->getData(); 35 | y = event->getData(); 36 | int z = x + y; 37 | z = z; 38 | */ 39 | 40 | using EventType = int; 41 | 42 | class IEvent 43 | { 44 | public: 45 | IEvent(void) = default; 46 | IEvent(const IEvent & p_rIEvent) = delete; 47 | IEvent(const IEvent && p_rIEvent) = delete; 48 | IEvent & operator=(const IEvent & p_rIEvent) = delete; 49 | IEvent & operator=(const IEvent && p_rrIEvent) = delete; 50 | virtual ~IEvent(void) = default; 51 | 52 | virtual EventType getType(void) const = 0; 53 | virtual std::string getName(void) const = 0; 54 | 55 | }; // IEvent class 56 | 57 | using EventSPtr = std::shared_ptr; 58 | 59 | class TestEvent 60 | : public IEvent 61 | { 62 | public: 63 | static const EventType Type = 0x4a6ee2cf; 64 | 65 | private: 66 | int m_Data = 100; 67 | 68 | public: 69 | TestEvent(void) = default; 70 | virtual ~TestEvent(void) = default; 71 | 72 | virtual EventType getType(void) const final 73 | { return TestEvent::Type; } 74 | virtual std::string getName(void) const final 75 | { return "TestEvent"; } 76 | 77 | int getData(void) const 78 | { return m_Data; } 79 | 80 | }; // TestEvent class 81 | 82 | class Foo 83 | { 84 | public: 85 | static void staticMemFunc(void) 86 | { 87 | int x, y; 88 | x = 1; 89 | y = 2; 90 | int z = x + y; 91 | z = z; 92 | } 93 | 94 | static void staticMemFunc2(EventSPtr p_spEvent) 95 | { 96 | int x, y; 97 | assert(p_spEvent->getType() == TestEvent::Type); 98 | const auto event = std::static_pointer_cast(p_spEvent); 99 | x = event->getData(); 100 | y = event->getData(); 101 | int z = x + y; 102 | z = z; 103 | } 104 | 105 | void memFunc(void) const 106 | { 107 | int x, y; 108 | x = 1; 109 | y = 2; 110 | int z = x + y; 111 | z = z; 112 | } 113 | 114 | void memFunc2(EventSPtr p_spEvent) const 115 | { 116 | int x, y; 117 | assert(p_spEvent->getType() == TestEvent::Type); 118 | auto event = std::static_pointer_cast(p_spEvent); 119 | x = event->getData(); 120 | y = event->getData(); 121 | int z = x + y; 122 | z = z; 123 | } 124 | }; 125 | 126 | static void staticGlobalFunc(void) 127 | { 128 | int x, y; 129 | x = 1; 130 | y = 2; 131 | int z = x + y; 132 | z = z; 133 | } 134 | 135 | static void staticGlobalFunc2(EventSPtr p_spEvent) 136 | { 137 | int x, y; 138 | assert(p_spEvent->getType() == TestEvent::Type); 139 | auto event = std::static_pointer_cast(p_spEvent); 140 | x = event->getData(); 141 | y = event->getData(); 142 | int z = x + y; 143 | z = z; 144 | } 145 | 146 | static const int ITERATION_COUNT = 100 * 1000 * 1000; // number of iterations 147 | 148 | using Clock = std::chrono::high_resolution_clock; 149 | using Milliseconds = std::chrono::milliseconds; 150 | 151 | namespace internal 152 | { 153 | Clock::time_point before, after; 154 | } 155 | 156 | static void beginBenchmark(void) 157 | { 158 | internal::before = Clock::now(); 159 | } 160 | 161 | static void endBenchmark(const char * const test_name = "") 162 | { 163 | internal::after = Clock::now(); 164 | const auto duration = std::chrono::duration_cast(internal::after-internal::before); 165 | std::clog << std::setw(20) << test_name << " : " << duration.count() << "ms\n"; 166 | } 167 | 168 | static void newLine(void) 169 | { 170 | std::clog << '\n'; 171 | } 172 | 173 | static void writeLine(const char * const msg) 174 | { 175 | std::clog << msg << '\n'; 176 | } 177 | 178 | void benchmarkFunctionsWithNoParameters(void) 179 | { 180 | Foo foo; 181 | 182 | std::function memFunc1 = std::bind(&Foo::memFunc, &foo); 183 | ssvu::FastFunc memFunc2 = ssvu::FastFunc(&foo, &Foo::memFunc); 184 | fastdelegate_org::FastDelegate memFunc3 = fastdelegate_org::bind(&Foo::memFunc, &foo); 185 | fastdelegate::FastDelegate memFunc4 = fastdelegate::MakeDelegate(&foo, &Foo::memFunc); 186 | generic::delegate memFunc5 = generic::delegate::from(&foo); 187 | 188 | std::function staticClassFunc1 = std::bind(&Foo::staticMemFunc); 189 | ssvu::FastFunc staticClassFunc2 = ssvu::FastFunc(&Foo::staticMemFunc); 190 | fastdelegate_org::FastDelegate0<> staticClassFunc3 = fastdelegate_org::FastDelegate0<>(&Foo::staticMemFunc); 191 | fastdelegate::FastDelegate staticClassFunc4 = fastdelegate::MakeDelegate(&Foo::staticMemFunc); 192 | generic::delegate staticClassFunc5 = generic::delegate::from<&Foo::staticMemFunc>(); 193 | 194 | std::function staticGlobalFunc1 = std::bind(&::staticGlobalFunc); 195 | ssvu::FastFunc staticGlobalFunc2 = ssvu::FastFunc(&::staticGlobalFunc); 196 | fastdelegate_org::FastDelegate staticGlobalFunc3 = fastdelegate_org::FastDelegate(&::staticGlobalFunc); 197 | fastdelegate::FastDelegate staticGlobalFunc4 = fastdelegate::MakeDelegate(&::staticGlobalFunc); 198 | generic::delegate staticGlobalFunc5 = generic::delegate::from<&::staticGlobalFunc>(); 199 | 200 | ::newLine(); 201 | ::writeLine("[member function]"); 202 | 203 | ::beginBenchmark(); 204 | for (int i = 0; i < ITERATION_COUNT; ++i) foo.memFunc(); 205 | ::endBenchmark("raw"); 206 | 207 | ::beginBenchmark(); 208 | for (int i = 0; i < ITERATION_COUNT; ++i) memFunc1(); 209 | ::endBenchmark("std::function"); 210 | 211 | ::beginBenchmark(); 212 | for (int i = 0; i < ITERATION_COUNT; ++i) memFunc2(); 213 | ::endBenchmark("ssuv::FastFunc"); 214 | 215 | ::beginBenchmark(); 216 | for (int i = 0; i < ITERATION_COUNT; ++i) memFunc3(); 217 | ::endBenchmark("FastDelegate"); 218 | 219 | ::beginBenchmark(); 220 | for (int i = 0; i < ITERATION_COUNT; ++i) memFunc4(); 221 | ::endBenchmark("FastDelegate C++11"); 222 | 223 | ::beginBenchmark(); 224 | for (int i = 0; i < ITERATION_COUNT; ++i) memFunc5(); 225 | ::endBenchmark("SR Delegate C++11"); 226 | 227 | ::newLine(); 228 | ::writeLine("[static class function]"); 229 | 230 | ::beginBenchmark(); 231 | for (int i = 0; i < ITERATION_COUNT; ++i) Foo::staticMemFunc(); 232 | ::endBenchmark("raw"); 233 | 234 | ::beginBenchmark(); 235 | for (int i = 0; i < ITERATION_COUNT; ++i) staticClassFunc1(); 236 | ::endBenchmark("std::function"); 237 | 238 | ::beginBenchmark(); 239 | for (int i = 0; i < ITERATION_COUNT; ++i) staticClassFunc2(); 240 | ::endBenchmark("ssuv::FastFunc"); 241 | 242 | ::beginBenchmark(); 243 | for (int i = 0; i < ITERATION_COUNT; ++i) staticClassFunc3(); 244 | ::endBenchmark("FastDelegate"); 245 | 246 | ::beginBenchmark(); 247 | for (int i = 0; i < ITERATION_COUNT; ++i) staticClassFunc4(); 248 | ::endBenchmark("FastDelegate C++11"); 249 | 250 | ::beginBenchmark(); 251 | for (int i = 0; i < ITERATION_COUNT; ++i) staticClassFunc5(); 252 | ::endBenchmark("SR Delegate C++11"); 253 | 254 | ::newLine(); 255 | ::writeLine("[static global function]"); 256 | 257 | ::beginBenchmark(); 258 | for (int i = 0; i < ITERATION_COUNT; ++i) ::staticGlobalFunc(); 259 | ::endBenchmark("raw"); 260 | 261 | ::beginBenchmark(); 262 | for (int i = 0; i < ITERATION_COUNT; ++i) staticGlobalFunc1(); 263 | ::endBenchmark("std::function"); 264 | 265 | ::beginBenchmark(); 266 | for (int i = 0; i < ITERATION_COUNT; ++i) staticGlobalFunc2(); 267 | ::endBenchmark("ssuv::FastFunc"); 268 | 269 | ::beginBenchmark(); 270 | for (int i = 0; i < ITERATION_COUNT; ++i) staticGlobalFunc3(); 271 | ::endBenchmark("FastDelegate"); 272 | 273 | ::beginBenchmark(); 274 | for (int i = 0; i < ITERATION_COUNT; ++i) staticGlobalFunc4(); 275 | ::endBenchmark("FastDelegate C++11"); 276 | 277 | ::beginBenchmark(); 278 | for (int i = 0; i < ITERATION_COUNT; ++i) staticGlobalFunc5(); 279 | ::endBenchmark("SR Delegate C++11"); 280 | 281 | ::newLine(); 282 | } 283 | 284 | static void benchmarkFunctionsWithParameters(void) 285 | { 286 | Foo foo; 287 | EventSPtr event_sptr = std::make_shared(); 288 | 289 | std::function memFunc1 = std::bind(&Foo::memFunc2, &foo, std::placeholders::_1); 290 | ssvu::FastFunc memFunc2 = ssvu::FastFunc(&foo, &Foo::memFunc2); 291 | fastdelegate_org::FastDelegate memFunc3 = fastdelegate_org::bind(&Foo::memFunc2, &foo, std::placeholders::_1); 292 | fastdelegate::FastDelegate memFunc4 = fastdelegate::MakeDelegate(&foo, &Foo::memFunc2); 293 | generic::delegate memFunc5 = generic::delegate::from(&foo); 294 | 295 | std::function staticClassFunc1 = std::bind(&Foo::staticMemFunc2, std::placeholders::_1); 296 | ssvu::FastFunc staticClassFunc2 = ssvu::FastFunc(&Foo::staticMemFunc2); 297 | fastdelegate_org::FastDelegate1 staticClassFunc3 = fastdelegate_org::FastDelegate1(&Foo::staticMemFunc2); 298 | fastdelegate::FastDelegate staticClassFunc4 = fastdelegate::MakeDelegate(&Foo::staticMemFunc2); 299 | generic::delegate staticClassFunc5 = generic::delegate::from<&Foo::staticMemFunc2>(); 300 | 301 | std::function staticGlobalFunc1 = std::bind(&::staticGlobalFunc2, std::placeholders::_1); 302 | ssvu::FastFunc staticGlobalFunc2 = ssvu::FastFunc(&::staticGlobalFunc2); 303 | fastdelegate_org::FastDelegate1 staticGlobalFunc3 = fastdelegate_org::FastDelegate1(&::staticGlobalFunc2); 304 | fastdelegate::FastDelegate staticGlobalFunc4 = fastdelegate::MakeDelegate(&::staticGlobalFunc2); 305 | generic::delegate staticGlobalFunc5 = generic::delegate::from<&::staticGlobalFunc2>(); 306 | 307 | ::newLine(); 308 | ::writeLine("[member function]"); 309 | 310 | ::beginBenchmark(); 311 | for (int i = 0; i < ITERATION_COUNT; ++i) foo.memFunc2(event_sptr); 312 | ::endBenchmark("raw"); 313 | 314 | ::beginBenchmark(); 315 | for (int i = 0; i < ITERATION_COUNT; ++i) memFunc1(event_sptr); 316 | ::endBenchmark("std::function"); 317 | 318 | ::beginBenchmark(); 319 | for (int i = 0; i < ITERATION_COUNT; ++i) memFunc2(event_sptr); 320 | ::endBenchmark("ssuv::FastFunc"); 321 | 322 | ::beginBenchmark(); 323 | for (int i = 0; i < ITERATION_COUNT; ++i) memFunc3(event_sptr); 324 | ::endBenchmark("FastDelegate"); 325 | 326 | ::beginBenchmark(); 327 | for (int i = 0; i < ITERATION_COUNT; ++i) memFunc4(event_sptr); 328 | ::endBenchmark("FastDelegate C++11"); 329 | 330 | ::beginBenchmark(); 331 | for (int i = 0; i < ITERATION_COUNT; ++i) memFunc5(event_sptr); 332 | ::endBenchmark("SR Delegate C++11"); 333 | 334 | ::newLine(); 335 | ::writeLine("[static class function]"); 336 | 337 | ::beginBenchmark(); 338 | for (int i = 0; i < ITERATION_COUNT; ++i) Foo::staticMemFunc2(event_sptr); 339 | ::endBenchmark("raw"); 340 | 341 | ::beginBenchmark(); 342 | for (int i = 0; i < ITERATION_COUNT; ++i) staticClassFunc1(event_sptr); 343 | ::endBenchmark("std::function"); 344 | 345 | ::beginBenchmark(); 346 | for (int i = 0; i < ITERATION_COUNT; ++i) staticClassFunc2(event_sptr); 347 | ::endBenchmark("ssuv::FastFunc"); 348 | 349 | ::beginBenchmark(); 350 | for (int i = 0; i < ITERATION_COUNT; ++i) staticClassFunc3(event_sptr); 351 | ::endBenchmark("FastDelegate"); 352 | 353 | ::beginBenchmark(); 354 | for (int i = 0; i < ITERATION_COUNT; ++i) staticClassFunc4(event_sptr); 355 | ::endBenchmark("FastDelegate C++11"); 356 | 357 | ::beginBenchmark(); 358 | for (int i = 0; i < ITERATION_COUNT; ++i) staticClassFunc5(event_sptr); 359 | ::endBenchmark("SR Delegate C++11"); 360 | 361 | ::newLine(); 362 | ::writeLine("[static global function]"); 363 | 364 | ::beginBenchmark(); 365 | for (int i = 0; i < ITERATION_COUNT; ++i) ::staticGlobalFunc2(event_sptr); 366 | ::endBenchmark("raw"); 367 | 368 | ::beginBenchmark(); 369 | for (int i = 0; i < ITERATION_COUNT; ++i) staticGlobalFunc1(event_sptr); 370 | ::endBenchmark("std::function"); 371 | 372 | ::beginBenchmark(); 373 | for (int i = 0; i < ITERATION_COUNT; ++i) staticGlobalFunc2(event_sptr); 374 | ::endBenchmark("ssuv::FastFunc"); 375 | 376 | ::beginBenchmark(); 377 | for (int i = 0; i < ITERATION_COUNT; ++i) staticGlobalFunc3(event_sptr); 378 | ::endBenchmark("FastDelegate"); 379 | 380 | ::beginBenchmark(); 381 | for (int i = 0; i < ITERATION_COUNT; ++i) staticGlobalFunc4(event_sptr); 382 | ::endBenchmark("FastDelegate C++11"); 383 | 384 | ::beginBenchmark(); 385 | for (int i = 0; i < ITERATION_COUNT; ++i) staticGlobalFunc5(event_sptr); 386 | ::endBenchmark("SR Delegate C++11"); 387 | 388 | ::newLine(); 389 | } 390 | 391 | int main() 392 | { 393 | std::clog << "Hello World!\n"; 394 | 395 | std::clog << "######################################\n"; 396 | ::benchmarkFunctionsWithNoParameters(); 397 | std::clog << "######################################\n"; 398 | ::benchmarkFunctionsWithParameters(); 399 | std::clog << "######################################\n"; 400 | 401 | bool ret{false}; 402 | 403 | void (*func_raw1)(void) = &staticGlobalFunc; 404 | void (*func_raw2)(void) = &staticGlobalFunc; 405 | std::clog << "raw equality test : " << (func_raw1 == func_raw2) << '\n'; 406 | 407 | generic::delegate func1 = generic::delegate::from<&staticGlobalFunc>(); 408 | generic::delegate func2 = generic::delegate::from<&staticGlobalFunc>(); 409 | generic::delegate func11 = generic::delegate::from<&Foo::staticMemFunc>(); 410 | std::clog << "SR Delegate C++11 equality test : " << (func1 == func2) << '\n'; 411 | std::clog << "SR Delegate C++11 inequality test : " << (func1 == func11) << '\n'; 412 | 413 | Foo foo; 414 | generic::delegate func9 = generic::delegate::from(&foo); 415 | generic::delegate func10 = generic::delegate::from(&foo); 416 | std::clog << "SR Delegate C++11 equality test : " << (func9 == func10) << '\n'; 417 | 418 | ssvu::FastFunc func3 = &staticGlobalFunc; 419 | ssvu::FastFunc func4 = &staticGlobalFunc; 420 | ssvu::FastFunc func13 = &Foo::staticMemFunc; 421 | std::clog << "FastFunc C++11 equality test : " << (func3 == func4) << '\n'; 422 | std::clog << "FastFunc C++11 inequality test : " << (func3 == func13) << '\n'; 423 | 424 | fastdelegate::FastDelegate func5 = &staticGlobalFunc; 425 | fastdelegate::FastDelegate func6 = &staticGlobalFunc; 426 | fastdelegate::FastDelegate func12 = &Foo::staticMemFunc; 427 | std::clog << "FastDelegate C++11 equality test : " << (func5 == func6) << '\n'; 428 | std::clog << "FastDelegate C++11 inequality test : " << (func5 == func12) << '\n'; 429 | 430 | fastdelegate::FastDelegate func7 = &staticGlobalFunc2; 431 | fastdelegate::FastDelegate func8 = &staticGlobalFunc2; 432 | std::clog << "FastDelegate C++11 equality test : " << (func7 == func8) << '\n'; 433 | 434 | std::clog << "Press Enter to exit...\n"; 435 | std::cin.get(); 436 | return 0; 437 | } 438 | 439 | -------------------------------------------------------------------------------- /src/unit_test/TEST_FastFunc.cpp: -------------------------------------------------------------------------------- 1 | #include "test_sample.hpp" 2 | #include 3 | #include "catch.hpp" 4 | 5 | #define TAG "FastFunc" 6 | 7 | TEST_CASE(TAG) 8 | { 9 | 10 | SECTION("equality_freeFuncNoParam") 11 | { 12 | auto freeFuncA_1 = ssvu::FastFunc(&rawFreeFuncNoParamA); 13 | auto freeFuncA_2 = ssvu::FastFunc(&rawFreeFuncNoParamA); 14 | REQUIRE(freeFuncA_1 == freeFuncA_2); 15 | 16 | auto inlineFreeFuncA_1 = ssvu::FastFunc(&rawInlineFreeFuncNoParamA); 17 | auto inlineFreeFuncA_2 = ssvu::FastFunc(&rawInlineFreeFuncNoParamA); 18 | REQUIRE(inlineFreeFuncA_1 == inlineFreeFuncA_2); 19 | 20 | auto inlineFreeFuncParamA_1 = ssvu::FastFunc(&rawInlineFreeFuncWithParamA); 21 | auto inlineFreeFuncParamA_2 = ssvu::FastFunc(&rawInlineFreeFuncWithParamA); 22 | REQUIRE(inlineFreeFuncParamA_1 == inlineFreeFuncParamA_2); 23 | } 24 | 25 | SECTION("inequality_freeFuncNoParam") 26 | { 27 | auto freeFuncA = ssvu::FastFunc(&rawFreeFuncNoParamA); 28 | auto freeFuncB = ssvu::FastFunc(&rawFreeFuncNoParamB); 29 | REQUIRE(freeFuncA != freeFuncB); 30 | 31 | auto inlineFreeFuncA = ssvu::FastFunc(&rawInlineFreeFuncNoParamA); 32 | auto inlineFreeFuncB = ssvu::FastFunc(&rawInlineFreeFuncNoParamB); 33 | REQUIRE(inlineFreeFuncA != inlineFreeFuncB); 34 | 35 | auto inlineFreeFuncParamA = ssvu::FastFunc(&rawInlineFreeFuncWithParamA); 36 | auto inlineFreeFuncParamB = ssvu::FastFunc(&rawInlineFreeFuncWithParamB); 37 | REQUIRE(inlineFreeFuncParamA != inlineFreeFuncParamB); 38 | } 39 | 40 | SECTION("lambda", TAG) 41 | { 42 | ssvu::FastFunc lambda_1([](void) { return; }); 43 | ssvu::FastFunc lambda_2([](void) { return; }); 44 | auto lambda_3 = ssvu::FastFunc([](void) { return; }); 45 | ssvu::FastFunc lambda_4 = [](void) { return; }; 46 | REQUIRE(lambda_1 != lambda_2); 47 | REQUIRE(lambda_1 != lambda_3); 48 | REQUIRE(lambda_1 != lambda_4); 49 | } 50 | 51 | SECTION("equality_staticMemFuncNoParam") 52 | { 53 | auto singleInheritStaticmemFuncNoParamA_1 = ssvu::FastFunc(&SingleInheritBaseClass::rawStaticMemFuncNoParamA); 54 | auto singleInheritStaticmemFuncNoParamA_2 = ssvu::FastFunc(&SingleInheritBaseClass::rawStaticMemFuncNoParamA); 55 | REQUIRE(singleInheritStaticmemFuncNoParamA_1 == singleInheritStaticmemFuncNoParamA_2); 56 | } 57 | 58 | SECTION("inequality_staticMemFuncNoParam") 59 | { 60 | auto singleInheritStaticmemFuncNoParamA = ssvu::FastFunc(&SingleInheritBaseClass::rawStaticMemFuncNoParamA); 61 | auto singleInheritStaticmemFuncNoParamB = ssvu::FastFunc(&SingleInheritBaseClass::rawStaticMemFuncNoParamB); 62 | REQUIRE(singleInheritStaticmemFuncNoParamA != singleInheritStaticmemFuncNoParamB); 63 | } 64 | 65 | SECTION("equality_memFunc") 66 | { 67 | SingleInheritBaseClass single_inhert_base_obj; 68 | auto singleInheritBMemFuncA_1 = ssvu::FastFunc(&single_inhert_base_obj, &SingleInheritBaseClass::rawMemFuncNoParamA); 69 | auto singleInheritBMemFuncA_2 = ssvu::FastFunc(&single_inhert_base_obj, &SingleInheritBaseClass::rawMemFuncNoParamA); 70 | REQUIRE(singleInheritBMemFuncA_1 == singleInheritBMemFuncA_2); 71 | auto singleInheritBMemFuncParamA_1 = ssvu::FastFunc(&single_inhert_base_obj, &SingleInheritBaseClass::rawMemFuncWithParamA); 72 | auto singleInheritBMemFuncParamA_2 = ssvu::FastFunc(&single_inhert_base_obj, &SingleInheritBaseClass::rawMemFuncWithParamA); 73 | REQUIRE(singleInheritBMemFuncParamA_1 == singleInheritBMemFuncParamA_2); 74 | 75 | SingleInheritBaseClass single_inhert_obj; 76 | auto singleInheritMemFuncA_1 = ssvu::FastFunc(&single_inhert_obj, &SingleInheritBaseClass::rawMemFuncNoParamA); 77 | auto singleInheritMemFuncA_2 = ssvu::FastFunc(&single_inhert_obj, &SingleInheritBaseClass::rawMemFuncNoParamA); 78 | REQUIRE(singleInheritMemFuncA_1 == singleInheritMemFuncA_2); 79 | auto singleInheritMemFuncParamA_1 = ssvu::FastFunc(&single_inhert_obj, &SingleInheritBaseClass::rawMemFuncWithParamA); 80 | auto singleInheritMemFuncParamA_2 = ssvu::FastFunc(&single_inhert_obj, &SingleInheritBaseClass::rawMemFuncWithParamA); 81 | REQUIRE(singleInheritMemFuncParamA_1 == singleInheritMemFuncParamA_2); 82 | } 83 | 84 | SECTION("inequality_memFunc") 85 | { 86 | SingleInheritBaseClass single_inhert_base_obj; 87 | auto singleInheritBMemFuncA = ssvu::FastFunc(&single_inhert_base_obj, &SingleInheritBaseClass::rawMemFuncNoParamA); 88 | auto singleInheritBMemFuncB = ssvu::FastFunc(&single_inhert_base_obj, &SingleInheritBaseClass::rawMemFuncNoParamB); 89 | REQUIRE(singleInheritBMemFuncA != singleInheritBMemFuncB); 90 | auto singleInheritBMemFuncParamA = ssvu::FastFunc(&single_inhert_base_obj, &SingleInheritBaseClass::rawMemFuncWithParamA); 91 | auto singleInheritBMemFuncParamB = ssvu::FastFunc(&single_inhert_base_obj, &SingleInheritBaseClass::rawMemFuncWithParamB); 92 | REQUIRE(singleInheritBMemFuncParamA != singleInheritBMemFuncParamB); 93 | 94 | SingleInheritClass single_inhert_obj; 95 | auto singleInheritMemFuncA = ssvu::FastFunc(&single_inhert_obj, &SingleInheritClass::rawMemFuncNoParamA); 96 | auto singleInheritMemFuncB = ssvu::FastFunc(&single_inhert_obj, &SingleInheritClass::rawMemFuncNoParamB); 97 | REQUIRE(singleInheritMemFuncA != singleInheritMemFuncB); 98 | auto singleInheritMemFuncParamA = ssvu::FastFunc(&single_inhert_obj, &SingleInheritClass::rawMemFuncWithParamA); 99 | auto singleInheritMemFuncParamB = ssvu::FastFunc(&single_inhert_obj, &SingleInheritClass::rawMemFuncWithParamB); 100 | REQUIRE(singleInheritMemFuncParamA != singleInheritMemFuncParamB); 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /src/unit_test/TEST_SRDelegate.cpp: -------------------------------------------------------------------------------- 1 | #include "test_sample.hpp" 2 | #include 3 | 4 | #include "catch.hpp" 5 | 6 | #define TAG "SRDelegate_Cpp11" 7 | 8 | TEST_CASE() 9 | { 10 | 11 | SECTION("custom") 12 | { 13 | auto inlineFreeFuncA_3 = generic::delegate(&rawInlineFreeFuncNoParamA); 14 | auto inlineFreeFuncA_4 = generic::delegate(&rawInlineFreeFuncNoParamA); 15 | 16 | auto singleInheritStaticmemFuncNoParamA_1 = generic::delegate::from(&SingleInheritBaseClass::rawStaticMemFuncNoParamA); 17 | auto singleInheritStaticmemFuncNoParamA_2 = generic::delegate(&SingleInheritBaseClass::rawStaticMemFuncNoParamA); 18 | REQUIRE(inlineFreeFuncA_3 != singleInheritStaticmemFuncNoParamA_1); 19 | REQUIRE(inlineFreeFuncA_3 != singleInheritStaticmemFuncNoParamA_2); 20 | REQUIRE(singleInheritStaticmemFuncNoParamA_1 == singleInheritStaticmemFuncNoParamA_2); 21 | 22 | auto inlineFreeFuncB_1 = generic::delegate(&rawInlineFreeFuncNoParamB); 23 | REQUIRE(inlineFreeFuncA_3 != inlineFreeFuncB_1); 24 | } 25 | 26 | SECTION("inlineFreeFuncWithParam") 27 | { 28 | auto inlineFreeFuncA_1 = generic::delegate::from<&rawInlineFreeFuncNoParamA>(); 29 | auto inlineFreeFuncA_2 = generic::delegate::from<&rawInlineFreeFuncNoParamA>(); 30 | REQUIRE(inlineFreeFuncA_1 == inlineFreeFuncA_2); 31 | REQUIRE(inlineFreeFuncA_2 == inlineFreeFuncA_1); 32 | 33 | auto inlineFreeFuncParamA_1 = generic::delegate(&rawInlineFreeFuncWithParamA); 34 | auto inlineFreeFuncParamA_2 = generic::delegate(&rawInlineFreeFuncWithParamA); 35 | auto inlineFreeFuncParamB_1 = generic::delegate(&rawInlineFreeFuncWithParamB); 36 | REQUIRE(inlineFreeFuncParamA_1 == inlineFreeFuncParamA_2); 37 | REQUIRE(inlineFreeFuncParamA_2 == inlineFreeFuncParamA_1); 38 | REQUIRE(inlineFreeFuncParamA_1 != inlineFreeFuncParamB_1); 39 | REQUIRE(inlineFreeFuncParamB_1 != inlineFreeFuncParamA_1); 40 | 41 | auto inlineFreeFuncA_3 = generic::delegate(&rawInlineFreeFuncNoParamA); 42 | auto inlineFreeFuncA_4 = generic::delegate(&rawInlineFreeFuncNoParamA); 43 | generic::delegate inlineFreeFuncA_5 = &rawInlineFreeFuncNoParamA; 44 | auto inlineFreeFuncA_6 = generic::delegate::from(&rawInlineFreeFuncNoParamA); 45 | //REQUIRE(inlineFreeFuncA_1 == inlineFreeFuncA_3); // fails 46 | //REQUIRE(inlineFreeFuncA_1 == inlineFreeFuncA_5); // fails 47 | //REQUIRE(inlineFreeFuncA_1 == inlineFreeFuncA_6); // fails 48 | //REQUIRE(inlineFreeFuncA_3 == inlineFreeFuncA_5); // fails 49 | REQUIRE(inlineFreeFuncA_3 == inlineFreeFuncA_6); 50 | REQUIRE(inlineFreeFuncA_3 == inlineFreeFuncA_4); 51 | REQUIRE(inlineFreeFuncA_5 == inlineFreeFuncA_6); 52 | } 53 | 54 | SECTION("equality_freeFuncNoParam") 55 | { 56 | auto freeFuncA_1 = generic::delegate::from<&rawFreeFuncNoParamA>(); 57 | auto freeFuncA_2 = generic::delegate::from<&rawFreeFuncNoParamA>(); 58 | REQUIRE(freeFuncA_1 == freeFuncA_2); 59 | 60 | auto inlineFreeFuncA_1 = generic::delegate::from<&rawInlineFreeFuncNoParamA>(); 61 | auto inlineFreeFuncA_2 = generic::delegate::from<&rawInlineFreeFuncNoParamA>(); 62 | REQUIRE(inlineFreeFuncA_1 == inlineFreeFuncA_2); 63 | 64 | auto inlineFreeFuncParamA_1 = generic::delegate::from<&rawInlineFreeFuncWithParamA>(); 65 | auto inlineFreeFuncParamA_2 = generic::delegate::from<&rawInlineFreeFuncWithParamA>(); 66 | REQUIRE(inlineFreeFuncParamA_1 == inlineFreeFuncParamA_2); 67 | } 68 | 69 | SECTION("inequality_freeFuncNoParam") 70 | { 71 | auto freeFuncA = generic::delegate::from<&rawFreeFuncNoParamA>(); 72 | auto freeFuncB = generic::delegate::from<&rawFreeFuncNoParamB>(); 73 | REQUIRE(freeFuncA != freeFuncB); 74 | 75 | auto inlineFreeFuncA = generic::delegate::from<&rawInlineFreeFuncNoParamA>(); 76 | auto inlineFreeFuncB = generic::delegate::from<&rawInlineFreeFuncNoParamB>(); 77 | REQUIRE(inlineFreeFuncA != inlineFreeFuncB); 78 | 79 | auto inlineFreeFuncParamA = generic::delegate::from<&rawInlineFreeFuncWithParamA>(); 80 | auto inlineFreeFuncParamB = generic::delegate::from<&rawInlineFreeFuncWithParamB>(); 81 | REQUIRE(inlineFreeFuncParamA != inlineFreeFuncParamB); 82 | } 83 | 84 | SECTION("lambda") 85 | { 86 | generic::delegate lambda_1([]() { int i = 1 + 1; return; }); 87 | generic::delegate lambda_2([]() { int i = 1 + 1; return; }); 88 | auto lambda_3 = generic::delegate::from([]() { return; }); 89 | generic::delegate lambda_4 = []() { int i = 1 + 1; return; }; 90 | REQUIRE(lambda_1 != lambda_2); 91 | REQUIRE(lambda_1 != lambda_3); 92 | REQUIRE(lambda_1 != lambda_4); 93 | } 94 | 95 | SECTION("equality_staticMemFuncNoParam") 96 | { 97 | auto singleInheritStaticmemFuncNoParamA_1 = generic::delegate::from<&SingleInheritBaseClass::rawStaticMemFuncNoParamA>(); 98 | auto singleInheritStaticmemFuncNoParamA_2 = generic::delegate::from<&SingleInheritBaseClass::rawStaticMemFuncNoParamA>(); 99 | REQUIRE(singleInheritStaticmemFuncNoParamA_1 == singleInheritStaticmemFuncNoParamA_2); 100 | } 101 | 102 | SECTION("inequality_staticMemFuncNoParam") 103 | { 104 | auto singleInheritStaticmemFuncNoParamA = generic::delegate::from<&SingleInheritBaseClass::rawStaticMemFuncNoParamA>(); 105 | auto singleInheritStaticmemFuncNoParamB = generic::delegate::from<&SingleInheritBaseClass::rawStaticMemFuncNoParamB>(); 106 | REQUIRE(singleInheritStaticmemFuncNoParamA != singleInheritStaticmemFuncNoParamB); 107 | } 108 | 109 | SECTION("equality_memFunc") 110 | { 111 | SingleInheritBaseClass single_inhert_base_obj; 112 | auto singleInheritBMemFuncA_1 = generic::delegate::from(&single_inhert_base_obj); 113 | auto singleInheritBMemFuncA_2 = generic::delegate::from(&single_inhert_base_obj); 114 | REQUIRE(singleInheritBMemFuncA_1 == singleInheritBMemFuncA_2); 115 | auto singleInheritBMemFuncParamA_1 = generic::delegate::from(&single_inhert_base_obj); 116 | auto singleInheritBMemFuncParamA_2 = generic::delegate::from(&single_inhert_base_obj); 117 | REQUIRE(singleInheritBMemFuncParamA_1 == singleInheritBMemFuncParamA_2); 118 | 119 | SingleInheritClass single_inhert_obj; 120 | auto singleInheritMemFuncA_1 = generic::delegate::from(&single_inhert_obj); 121 | auto singleInheritMemFuncA_2 = generic::delegate::from(&single_inhert_obj); 122 | REQUIRE(singleInheritMemFuncA_1 == singleInheritMemFuncA_2); 123 | auto singleInheritMemFuncParamA_1 = generic::delegate::from(&single_inhert_obj); 124 | auto singleInheritMemFuncParamA_2 = generic::delegate::from(&single_inhert_obj); 125 | REQUIRE(singleInheritMemFuncParamA_1 == singleInheritMemFuncParamA_2); 126 | } 127 | 128 | SECTION("inequality_memFunc") 129 | { 130 | SingleInheritBaseClass single_inhert_base_obj; 131 | auto singleInheritBMemFuncA = generic::delegate::from(&single_inhert_base_obj); 132 | auto singleInheritBMemFuncB = generic::delegate::from(&single_inhert_base_obj); 133 | REQUIRE(singleInheritBMemFuncA != singleInheritBMemFuncB); 134 | auto singleInheritBMemFuncParamA = generic::delegate::from(&single_inhert_base_obj); 135 | auto singleInheritBMemFuncParamB = generic::delegate::from(&single_inhert_base_obj); 136 | REQUIRE(singleInheritBMemFuncParamA != singleInheritBMemFuncParamB); 137 | 138 | SingleInheritClass single_inhert_obj; 139 | auto singleInheritMemFuncA = generic::delegate::from(&single_inhert_obj); 140 | auto singleInheritMemFuncB = generic::delegate::from(&single_inhert_obj); 141 | REQUIRE(singleInheritMemFuncA != singleInheritMemFuncB); 142 | auto singleInheritMemFuncParamA = generic::delegate::from(&single_inhert_obj); 143 | auto singleInheritMemFuncParamB = generic::delegate::from(&single_inhert_obj); 144 | REQUIRE(singleInheritMemFuncParamA != singleInheritMemFuncParamB); 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /src/unit_test/TEST_raw.cpp: -------------------------------------------------------------------------------- 1 | #include "test_sample.hpp" 2 | 3 | #include "catch.hpp" 4 | 5 | #define TAG "raw" 6 | 7 | TEST_CASE(TAG) 8 | { 9 | 10 | SECTION("equality") 11 | { 12 | REQUIRE(&rawFreeFuncNoParamA == &rawFreeFuncNoParamA); 13 | REQUIRE(&rawFreeFuncNoParamB == &rawFreeFuncNoParamB); 14 | 15 | REQUIRE(&rawInlineFreeFuncNoParamA == &rawInlineFreeFuncNoParamA); 16 | REQUIRE(&rawInlineFreeFuncNoParamB == &rawInlineFreeFuncNoParamB); 17 | } 18 | 19 | SECTION("inequality") 20 | { 21 | REQUIRE(&rawFreeFuncNoParamA != &rawFreeFuncNoParamB); 22 | REQUIRE(&rawFreeFuncNoParamB != &rawFreeFuncNoParamA); 23 | 24 | REQUIRE(&rawInlineFreeFuncNoParamA != &rawInlineFreeFuncNoParamB); 25 | REQUIRE(&rawInlineFreeFuncNoParamB != &rawInlineFreeFuncNoParamA); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/unit_test/test_main.cpp: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN 2 | #include "catch.hpp" -------------------------------------------------------------------------------- /src/unit_test/test_sample.cpp: -------------------------------------------------------------------------------- 1 | #include "test_sample.hpp" 2 | 3 | void rawFreeFuncNoParamA(void) 4 | { 5 | int i = 1 + 1; 6 | int a = i + 1; 7 | int b = a * i; 8 | b = b * 2; 9 | } 10 | 11 | void rawFreeFuncNoParamB(void) 12 | { 13 | return; 14 | } 15 | 16 | void SingleInheritBaseClass::rawStaticMemFuncNoParamA(void) 17 | { 18 | 19 | } 20 | 21 | void SingleInheritBaseClass::rawStaticMemFuncNoParamB(void) 22 | { 23 | 24 | } 25 | 26 | void SingleInheritBaseClass::rawMemFuncNoParamA(void) 27 | { 28 | 29 | } 30 | 31 | void SingleInheritBaseClass::rawMemFuncNoParamB(void) 32 | { 33 | 34 | } 35 | 36 | void SingleInheritBaseClass::rawMemFuncWithParamA(EventSPtr) 37 | { 38 | 39 | } 40 | 41 | void SingleInheritBaseClass::rawMemFuncWithParamB(EventSPtr) 42 | { 43 | 44 | } 45 | 46 | void SingleInheritClass::rawMemFuncNoParamA(void) 47 | { 48 | 49 | } 50 | 51 | void SingleInheritClass::rawMemFuncNoParamB(void) 52 | { 53 | 54 | } 55 | 56 | void SingleInheritClass::rawMemFuncWithParamA(EventSPtr) 57 | { 58 | 59 | } 60 | 61 | void SingleInheritClass::rawMemFuncWithParamB(EventSPtr) 62 | { 63 | 64 | } -------------------------------------------------------------------------------- /src/unit_test/test_sample.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | using EventType = int; 8 | 9 | class IEvent 10 | { 11 | public: 12 | IEvent(void) = default; 13 | IEvent(const IEvent & p_rIEvent) = delete; 14 | IEvent(const IEvent && p_rIEvent) = delete; 15 | IEvent & operator=(const IEvent & p_rIEvent) = delete; 16 | IEvent & operator=(const IEvent && p_rrIEvent) = delete; 17 | virtual ~IEvent(void) = default; 18 | 19 | virtual EventType getType(void) const = 0; 20 | virtual std::string getName(void) const = 0; 21 | 22 | }; // IEvent class 23 | 24 | using EventSPtr = std::shared_ptr; 25 | 26 | class TestEvent 27 | : public IEvent 28 | { 29 | public: 30 | static const EventType Type = 0x4a6ee2cf; 31 | 32 | private: 33 | int m_Data = 100; 34 | 35 | public: 36 | TestEvent(void) = default; 37 | virtual ~TestEvent(void) = default; 38 | 39 | virtual EventType getType(void) const final 40 | { 41 | return TestEvent::Type; 42 | } 43 | virtual std::string getName(void) const final 44 | { 45 | return "TestEvent"; 46 | } 47 | 48 | int getData(void) const 49 | { 50 | return m_Data; 51 | } 52 | 53 | }; // TestEvent class 54 | 55 | 56 | extern void rawFreeFuncNoParamA(void); 57 | extern void rawFreeFuncNoParamB(void); 58 | extern void rawFreeFuncWithParamA(EventSPtr); 59 | extern void rawFreeFuncWithParamB(EventSPtr); 60 | inline void rawInlineFreeFuncNoParamA(void) 61 | { 62 | std::clog << "inline free function A\n"; 63 | } 64 | inline void rawInlineFreeFuncNoParamB(void) 65 | { 66 | std::clog << "inline free function B\n"; 67 | } 68 | inline void rawInlineFreeFuncWithParamA(EventSPtr evt) 69 | { 70 | const auto name = evt->getName(); 71 | } 72 | inline void rawInlineFreeFuncWithParamB(EventSPtr evt) 73 | { 74 | const auto name = evt->getName(); 75 | } 76 | 77 | class SingleInheritBaseClass 78 | { 79 | public: 80 | static void rawStaticMemFuncNoParamA(void); 81 | static void rawStaticMemFuncNoParamB(void); 82 | 83 | void rawMemFuncNoParamA(void); 84 | void rawMemFuncNoParamB(void); 85 | void rawMemFuncWithParamA(EventSPtr); 86 | void rawMemFuncWithParamB(EventSPtr); 87 | 88 | }; 89 | 90 | class SingleInheritClass 91 | : public SingleInheritBaseClass 92 | { 93 | public: 94 | virtual void rawMemFuncNoParamA(void); 95 | virtual void rawMemFuncNoParamB(void); 96 | virtual void rawMemFuncWithParamA(EventSPtr); 97 | virtual void rawMemFuncWithParamB(EventSPtr); 98 | 99 | }; -------------------------------------------------------------------------------- /src/unit_test/unit_test.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | CONFIG += console 3 | CONFIG -= app_bundle 4 | CONFIG -= qt 5 | 6 | CONFIG += c++11 7 | 8 | SOURCES += \ 9 | TEST_FastFunc.cpp \ 10 | test_main.cpp \ 11 | TEST_raw.cpp \ 12 | test_sample.cpp \ 13 | TEST_SRDelegate.cpp 14 | 15 | HEADERS += \ 16 | test_sample.hpp \ 17 | catch.hpp 18 | 19 | # 20 | # Build ouput 21 | # 22 | BUILDDIRWIN32DBG = ../../build/Win32-Debug 23 | BUILDDIRWIN32REL = ../../build/Win32-Release 24 | BUILDDIRUNIXDBG = ../../build/Unix-Debug 25 | BUILDDIRUNIXREL = ../../build/Unix-Release 26 | CONFIG(debug, debug|release) { # Debug build dirs 27 | win32: DESTDIR = $${BUILDDIRWIN32DBG}/ 28 | win32: OBJECTS_DIR = $${BUILDDIRWIN32DBG}/obj 29 | win32: MOC_DIR = $${BUILDDIRWIN32DBG}/moc 30 | win32: RCC_DIR = $${BUILDDIRWIN32DBG}/rsc 31 | win32: UI_DIR = $${BUILDDIRWIN32DBG}/ui 32 | unix: DESTDIR = $${BUILDDIRUNIXDBG}/obj 33 | unix: OBJECTS_DIR = $${BUILDDIRUNIXDBG}/obj 34 | unix: MOC_DIR = $${BUILDDIRUNIXDBG}/moc 35 | unix: RCC_DIR = $${BUILDDIRUNIXDBG}/rsc 36 | unix: UI_DIR = $${BUILDDIRUNIXDBG}/ui 37 | } else { # Release build dirs 38 | win32: DESTDIR = $${BUILDDIRWIN32REL}/ 39 | win32: OBJECTS_DIR = $${BUILDDIRWIN32REL}/obj 40 | win32: MOC_DIR = $${BUILDDIRWIN32REL}/moc 41 | win32: RCC_DIR = $${BUILDDIRWIN32REL}/rsc 42 | win32: UI_DIR = $${BUILDDIRWIN32REL}/ui 43 | unix: DESTDIR = $${BUILDDIRUNIXREL}/ 44 | unix: OBJECTS_DIR = $${BUILDDIRUNIXREL}/obj 45 | unix: MOC_DIR = $${BUILDDIRUNIXREL}/moc 46 | unix: RCC_DIR = $${BUILDDIRUNIXREL}/rsc 47 | unix: UI_DIR = $${BUILDDIRUNIXREL}/ui 48 | } 49 | # 50 | 51 | # 52 | # Library include paths 53 | # 54 | INCLUDEPATH += \ 55 | ../ \ # delegate libraries 56 | # 57 | -------------------------------------------------------------------------------- /src/unit_test/unit_test.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.30501.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unit_test", "unit_test.vcxproj", "{7F7E75F2-AD87-4FE3-818A-92A96D2D2A38}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Debug|x64 = Debug|x64 12 | Release|Win32 = Release|Win32 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {7F7E75F2-AD87-4FE3-818A-92A96D2D2A38}.Debug|Win32.ActiveCfg = Debug|Win32 17 | {7F7E75F2-AD87-4FE3-818A-92A96D2D2A38}.Debug|Win32.Build.0 = Debug|Win32 18 | {7F7E75F2-AD87-4FE3-818A-92A96D2D2A38}.Debug|x64.ActiveCfg = Debug|x64 19 | {7F7E75F2-AD87-4FE3-818A-92A96D2D2A38}.Debug|x64.Build.0 = Debug|x64 20 | {7F7E75F2-AD87-4FE3-818A-92A96D2D2A38}.Release|Win32.ActiveCfg = Release|Win32 21 | {7F7E75F2-AD87-4FE3-818A-92A96D2D2A38}.Release|Win32.Build.0 = Release|Win32 22 | {7F7E75F2-AD87-4FE3-818A-92A96D2D2A38}.Release|x64.ActiveCfg = Release|x64 23 | {7F7E75F2-AD87-4FE3-818A-92A96D2D2A38}.Release|x64.Build.0 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /src/unit_test/unit_test.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {7F7E75F2-AD87-4FE3-818A-92A96D2D2A38} 23 | Win32Proj 24 | unit_test 25 | 26 | 27 | 28 | Application 29 | true 30 | v140 31 | Unicode 32 | 33 | 34 | Application 35 | true 36 | v140 37 | Unicode 38 | 39 | 40 | Application 41 | false 42 | v140 43 | true 44 | Unicode 45 | 46 | 47 | Application 48 | false 49 | v140 50 | true 51 | Unicode 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | true 71 | ..\..\build\$(Platform)\$(Configuration)\ 72 | $(SolutionDir)\..\..\build\$(Platform)\$(Configuration)\ 73 | 74 | 75 | true 76 | ..\..\build\$(Platform)\$(Configuration)\ 77 | $(SolutionDir)\..\..\build\$(Platform)\$(Configuration)\ 78 | 79 | 80 | false 81 | ..\..\build\$(Platform)\$(Configuration)\ 82 | $(SolutionDir)\..\..\$(Platform)\$(Configuration)\ 83 | 84 | 85 | false 86 | ..\..\build\$(Platform)\$(Configuration)\ 87 | $(SolutionDir)\..\..\$(Platform)\$(Configuration)\ 88 | 89 | 90 | 91 | 92 | 93 | Level3 94 | Disabled 95 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 96 | true 97 | ../;%(AdditionalIncludeDirectories) 98 | 99 | 100 | Console 101 | true 102 | %(AdditionalLibraryDirectories) 103 | %(AdditionalDependencies) 104 | 105 | 106 | "$(TargetDir)\$(TargetName).exe" 107 | 108 | 109 | Auto run test 110 | 111 | 112 | 113 | 114 | 115 | 116 | Level3 117 | Disabled 118 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 119 | true 120 | ../;%(AdditionalIncludeDirectories) 121 | 122 | 123 | Console 124 | true 125 | %(AdditionalLibraryDirectories) 126 | %(AdditionalDependencies) 127 | 128 | 129 | "$(TargetDir)\$(TargetName).exe" 130 | 131 | 132 | Auto run test 133 | 134 | 135 | 136 | 137 | Level3 138 | 139 | 140 | MaxSpeed 141 | true 142 | true 143 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 144 | true 145 | ../;%(AdditionalIncludeDirectories) 146 | 147 | 148 | Console 149 | true 150 | false 151 | true 152 | %(AdditionalLibraryDirectories) 153 | %(AdditionalDependencies) 154 | 155 | 156 | "$(TargetDir)\$(TargetName).exe" 157 | 158 | 159 | Auto run test 160 | 161 | 162 | 163 | 164 | Level3 165 | 166 | 167 | MaxSpeed 168 | true 169 | true 170 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 171 | true 172 | ../;%(AdditionalIncludeDirectories) 173 | 174 | 175 | Console 176 | true 177 | false 178 | true 179 | %(AdditionalLibraryDirectories) 180 | %(AdditionalDependencies) 181 | 182 | 183 | "$(TargetDir)\$(TargetName).exe" 184 | 185 | 186 | Auto run test 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /src/unit_test/unit_test.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | --------------------------------------------------------------------------------