├── .gitattributes ├── .gitignore ├── README.md └── delegates ├── delegate.h └── delegate.impl.hpp /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | # ========================= 31 | # Operating System Files 32 | # ========================= 33 | 34 | # OSX 35 | # ========================= 36 | 37 | .DS_Store 38 | .AppleDouble 39 | .LSOverride 40 | 41 | # Thumbnails 42 | ._* 43 | 44 | # Files that might appear in the root of a volume 45 | .DocumentRevisions-V100 46 | .fseventsd 47 | .Spotlight-V100 48 | .TemporaryItems 49 | .Trashes 50 | .VolumeIcon.icns 51 | 52 | # Directories potentially created on remote AFP share 53 | .AppleDB 54 | .AppleDesktop 55 | Network Trash Folder 56 | Temporary Items 57 | .apdisk 58 | 59 | # Windows 60 | # ========================= 61 | 62 | # Windows image file caches 63 | Thumbs.db 64 | ehthumbs.db 65 | 66 | # Folder config file 67 | Desktop.ini 68 | 69 | # Recycle Bin used on file shares 70 | $RECYCLE.BIN/ 71 | 72 | # Windows Installer files 73 | *.cab 74 | *.msi 75 | *.msm 76 | *.msp 77 | 78 | # Windows shortcuts 79 | *.lnk 80 | src/.vscode/.browse.VC.db 81 | src/.vscode/.BROWSE.VC.DB-shm 82 | src/.vscode/launch.json 83 | *.DB-wal 84 | 85 | # Visual Studio Code files 86 | *.vscode* 87 | 88 | # Visual Studio files 89 | *.vs* 90 | 91 | # old library 92 | /old/* 93 | /slib/* 94 | *.tar 95 | 96 | # cppcheck files 97 | *.a1 98 | *.cppcheck 99 | 100 | # tests binaries 101 | /tests/bin/* 102 | 103 | # cmake generated files 104 | *out/* 105 | *build/* 106 | 107 | # fuse 108 | *.fuse_* 109 | 110 | 111 | cvs 112 | 113 | *~ 114 | *.bak 115 | *.o 116 | *.a 117 | *.lo 118 | *.la 119 | *.user 120 | *.suo 121 | *.sdf 122 | *.opensdf 123 | 124 | bin/ 125 | obj/ 126 | ipch/ 127 | 128 | *.obj 129 | *.log 130 | out/build/x64-Debug/.cmake/api/v1/query/client-MicrosoftVS/query.json 131 | CMakeSettings.json 132 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fast delegates for C++ 2 | 3 | Extended original cross platform fast delegates for C++ (C++98 compatible). 4 | 5 | [![C/C++ CI](https://github.com/oktonion/Cpp-fast-delegates/actions/workflows/c-cpp.yml/badge.svg?branch=tests)](https://github.com/oktonion/Cpp-fast-delegates/actions/workflows/c-cpp.yml) 6 | [![codecov](https://codecov.io/gh/oktonion/Cpp-fast-delegates/branch/tests/graph/badge.svg)](https://codecov.io/gh/oktonion/Cpp-fast-delegates) 7 | 8 | In this delegates you could store: 9 | 1) global function 10 | 2) global function with class object (both const obj and non-const) 11 | 3) static function of class (same as two above actually) 12 | 4) member function of class with class object (both const obj and non-const) 13 | 14 | Calls to functions stored are extremely fast (like call to original function). Delegate takes minimum memory, are crossplatform and C++98, C++11, C++14 and later standart compatible. 15 | 16 | # What are we talking about? 17 | f.e. we have some functions (class functions, global functions, constant or not, whatever...) with same arguments and return value: 18 | ``` 19 | int func(std::string, size_t&); // regular function 20 | int func(SomeClass*, std::string, size_t&); // same but with class pointer 21 | int func(SomeOtherClass*, std::string, size_t&); // same but with class pointer 22 | int func(const SomeClass*, std::string, size_t&); // same but with class const pointer 23 | int func(const SomeOtherClass*, std::string, size_t&); // same but with class const pointer 24 | 25 | int SomeClass::mfunc(std::string, size_t&); // class member function 26 | int SomeClass::mcfunc(std::string, size_t&) const; // class member const function 27 | static int SomeClass::sfunc(std::string, size_t&); // class member static function 28 | static int SomeClass::sfunc(SomeOtherClass*, std::string, size_t&); // same but with class pointer 29 | static int SomeClass::sfunc(const SomeClass*, std::string, size_t&); // same but with class const pointer 30 | 31 | int SomeOtherClass::mfunc(std::string, size_t&); // class member function 32 | int SomeOtherClass::mcfunc(std::string, size_t&) const; // class member const function 33 | static int SomeOtherClass::sfunc(std::string, size_t&); // class member static function 34 | static int SomeOtherClass::sfunc(SomeOtherClass*, std::string, size_t&); // same but with class pointer 35 | static int SomeOtherClass::sfunc(const SomeClass*, std::string, size_t&); // same but with class const pointer 36 | 37 | // any other class actually... 38 | ``` 39 | and there is one delegate to rule them all: 40 | ``` 41 | // could contain any of functions above (with class pointer if needed): 42 | 43 | delegate allmighty_delegate; 44 | 45 | ``` 46 | 47 | # How to use: 48 | ``` 49 | #include "delegates\delegate.h" 50 | 51 | ... 52 | 53 | using namespace delegates; 54 | ``` 55 | then: 56 | 57 | ``` 58 | int func(unsigned char val1, size_t &val2) {/*some actual work*/ return 0;} 59 | 60 | ... 61 | 62 | delegate d2(&func); 63 | 64 | ... 65 | 66 | size_t val = 50; 67 | int t = d2(2, val); // calling 'func' by delegate 68 | ``` 69 | more fun with saving class object: 70 | 71 | ``` 72 | int func(unsigned char val1, size_t &val2) {/*some actual work*/ return 0;} 73 | 74 | struct Dummy 75 | { 76 | int mfunc(unsigned char val1, size_t &val2) {/*some actual class work*/ return 0;} 77 | 78 | static int sfunc(unsigned char val1, size_t &val2) {/*some actual static work*/ return 0;} 79 | }; 80 | 81 | int gfunc(Dummy *pdummy, unsigned char val1, size_t &val2) {/*some actual class or global work*/ return 0;} 82 | int const_gfunc(const Dummy *pdummy, unsigned char val1, size_t &val2) {/*some actual class or global work*/ return 0;} 83 | 84 | ... 85 | 86 | delegate d2(&func); // same delegate 87 | 88 | ... 89 | 90 | size_t val = 50; 91 | int t = d2(2, val); // calling 'func' by delegate 92 | 93 | Dummy dummy; 94 | d2.bind(&dummy, &Dummy::mfunc); // binding to specific object 95 | t = d2(2, val); // calling 'dummy->mfunc' by delegate 96 | 97 | d2.bind(&Dummy::sfunc); // same as just regular 'func' (first example) 98 | t = d2(2, val); // calling 'Dummy::sfunc' by delegate 99 | 100 | d2.bind(&dummy, &gfunc); // binding to specific object but global function taking 'object_type' 101 | t = d2(2, val); // calling 'gfunc' by delegate with pointer to 'dummy' as first argument 102 | 103 | d2.bind(&dummy, &const_gfunc); // binding to specific object but const global function taking 'object_type' 104 | t = d2(2, val); // calling 'const_gfunc' by delegate with const pointer to 'dummy' as first argument 105 | ``` 106 | 107 | also you could use 'bind' to create delegate: 108 | 109 | ``` 110 | int func(unsigned char val1, size_t &val2) {/*some actual work*/ return 0;} 111 | 112 | ... 113 | 114 | delegate d2; // same delegate again 115 | 116 | d2 = bind(&func); 117 | ``` 118 | -------------------------------------------------------------------------------- /delegates/delegate.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef DELEGATE_H 3 | #define DELEGATE_H 4 | #if _MSC_VER > 1000 5 | #pragma once 6 | #endif // _MSC_VER > 1000 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace delegates 15 | { 16 | namespace detail 17 | { 18 | struct DefaultVoid; 19 | 20 | namespace type_traits 21 | { 22 | typedef char yes_type; 23 | struct no_type 24 | { 25 | char d[8]; 26 | }; 27 | 28 | template 29 | T& declref(); 30 | 31 | template struct priority_tag : priority_tag < N - 1 > {}; 32 | template<> struct priority_tag<0> {}; 33 | 34 | struct any { template any(const T&) {} }; 35 | 36 | template 37 | yes_type is_convertable_tester(T, priority_tag<1>); 38 | template 39 | no_type is_convertable_tester(any, priority_tag<0>); 40 | 41 | template 42 | struct is_convertable 43 | { 44 | static const bool value = 45 | sizeof(is_convertable_tester(declref(), priority_tag<1>())) == sizeof(yes_type); 46 | }; 47 | 48 | template 49 | struct conditional 50 | { 51 | typedef IfTrueT type; 52 | }; 53 | 54 | template 55 | struct conditional 56 | { 57 | typedef IfFalseT type; 58 | }; 59 | 60 | template 61 | struct is_const { 62 | static const bool value = false; 63 | }; 64 | template 65 | struct is_const { 66 | static const bool value = true; 67 | }; 68 | 69 | template 70 | struct is_void { 71 | static const bool value = false; 72 | }; 73 | template<> 74 | struct is_void { 75 | static const bool value = true; 76 | }; 77 | } 78 | 79 | template 80 | struct disable_if_not_convertable 81 | : type_traits::conditional< 82 | type_traits::is_convertable::value, 83 | T, 84 | DefaultVoid 85 | > 86 | { }; 87 | 88 | template 89 | struct disable_if_const 90 | : type_traits::conditional< 91 | type_traits::is_const::value, 92 | DefaultVoid, 93 | T 94 | > 95 | { }; 96 | 97 | class virtual_class 98 | { 99 | protected: 100 | virtual ~virtual_class() {} 101 | virtual int v_func(int) {return 0;} 102 | float func(double) {return 0.f;} 103 | }; 104 | 105 | class virtual_class2 106 | { 107 | protected: 108 | virtual int pure_v_func2(int) = 0; 109 | virtual int v_func2(int) {return 0;} 110 | float func2(double) {return 0.f;} 111 | }; 112 | 113 | class virtual_class_child 114 | : virtual_class 115 | , virtual_class2 116 | { 117 | int pure_v_func2(int) {return 0;} 118 | virtual int v_func(int) {return 0;} 119 | float func_child(double) {return 0.f;} 120 | ~virtual_class_child() {} 121 | }; 122 | 123 | enum comparison_type { 124 | less, equal, greater 125 | }; 126 | 127 | template 128 | inline 129 | bool compare(const T &lhs, const T &rhs, comparison_type op) 130 | { 131 | switch (op) 132 | { 133 | case equal: return std::equal_to()(lhs, rhs); 134 | case less: return std::less()(lhs, rhs); 135 | case greater: return std::greater()(lhs, rhs); 136 | } 137 | return false; 138 | } 139 | 140 | template 141 | inline 142 | bool compare_less(const T &lhs, const T &rhs) 143 | { return std::less()(lhs, rhs); } 144 | 145 | template 146 | inline 147 | bool compare_greater(const T &lhs, const T &rhs) 148 | { return std::greater()(lhs, rhs); } 149 | 150 | template 151 | inline 152 | bool compare_equal(const T &lhs, const T &rhs) 153 | { return std::equal_to()(lhs, rhs); } 154 | } 155 | 156 | template < 157 | class ReturnT = detail::DefaultVoid, 158 | class Param1T = detail::DefaultVoid, 159 | class Param2T = detail::DefaultVoid, 160 | class Param3T = detail::DefaultVoid, 161 | class Param4T = detail::DefaultVoid, 162 | class Param5T = detail::DefaultVoid, 163 | class Param6T = detail::DefaultVoid, 164 | class Param7T = detail::DefaultVoid, 165 | class Param8T = detail::DefaultVoid, 166 | class ParamPamPam = detail::DefaultVoid 167 | > 168 | class delegate; 169 | } 170 | 171 | #define DELEGATE_PARAM_COUNT 0 172 | #define DELEGATE_TEMPLATE_PARAMS 173 | #define DELEGATE_TEMPLATE_ARGS 174 | #define DELEGATE_PARAMS 175 | #define DELEGATE_ARGS 176 | 177 | #include "delegate.impl.hpp" 178 | 179 | #undef DELEGATE_PARAM_COUNT 180 | #undef DELEGATE_TEMPLATE_PARAMS 181 | #undef DELEGATE_TEMPLATE_ARGS 182 | #undef DELEGATE_PARAMS 183 | #undef DELEGATE_ARGS 184 | 185 | #define DELEGATE_PARAM_COUNT 1 186 | #define DELEGATE_TEMPLATE_PARAMS class Param1T 187 | #define DELEGATE_TEMPLATE_ARGS Param1T 188 | #define DELEGATE_PARAMS Param1T a1 189 | #define DELEGATE_ARGS a1 190 | 191 | #include "delegate.impl.hpp" 192 | 193 | #undef DELEGATE_PARAM_COUNT 194 | #undef DELEGATE_TEMPLATE_PARAMS 195 | #undef DELEGATE_TEMPLATE_ARGS 196 | #undef DELEGATE_PARAMS 197 | #undef DELEGATE_ARGS 198 | 199 | #define DELEGATE_PARAM_COUNT 2 200 | #define DELEGATE_TEMPLATE_PARAMS class Param1T, class Param2T 201 | #define DELEGATE_TEMPLATE_ARGS Param1T, Param2T 202 | #define DELEGATE_PARAMS Param1T a1, Param2T a2 203 | #define DELEGATE_ARGS a1, a2 204 | 205 | #include "delegate.impl.hpp" 206 | 207 | #undef DELEGATE_PARAM_COUNT 208 | #undef DELEGATE_TEMPLATE_PARAMS 209 | #undef DELEGATE_TEMPLATE_ARGS 210 | #undef DELEGATE_PARAMS 211 | #undef DELEGATE_ARGS 212 | 213 | #define DELEGATE_PARAM_COUNT 3 214 | #define DELEGATE_TEMPLATE_PARAMS class Param1T, class Param2T, class Param3T 215 | #define DELEGATE_TEMPLATE_ARGS Param1T, Param2T, Param3T 216 | #define DELEGATE_PARAMS Param1T a1, Param2T a2, Param3T a3 217 | #define DELEGATE_ARGS a1, a2, a3 218 | 219 | #include "delegate.impl.hpp" 220 | 221 | #undef DELEGATE_PARAM_COUNT 222 | #undef DELEGATE_TEMPLATE_PARAMS 223 | #undef DELEGATE_TEMPLATE_ARGS 224 | #undef DELEGATE_PARAMS 225 | #undef DELEGATE_ARGS 226 | 227 | #define DELEGATE_PARAM_COUNT 4 228 | #define DELEGATE_TEMPLATE_PARAMS class Param1T, class Param2T, class Param3T, class Param4T 229 | #define DELEGATE_TEMPLATE_ARGS Param1T, Param2T, Param3T, Param4T 230 | #define DELEGATE_PARAMS Param1T a1, Param2T a2, Param3T a3, Param4T a4 231 | #define DELEGATE_ARGS a1, a2, a3, a4 232 | 233 | #include "delegate.impl.hpp" 234 | 235 | #undef DELEGATE_PARAM_COUNT 236 | #undef DELEGATE_TEMPLATE_PARAMS 237 | #undef DELEGATE_TEMPLATE_ARGS 238 | #undef DELEGATE_PARAMS 239 | #undef DELEGATE_ARGS 240 | 241 | #define DELEGATE_PARAM_COUNT 5 242 | #define DELEGATE_TEMPLATE_PARAMS class Param1T, class Param2T, class Param3T, class Param4T, class Param5T 243 | #define DELEGATE_TEMPLATE_ARGS Param1T, Param2T, Param3T, Param4T, Param5T 244 | #define DELEGATE_PARAMS Param1T a1, Param2T a2, Param3T a3, Param4T a4, Param5T a5 245 | #define DELEGATE_ARGS a1, a2, a3, a4, a5 246 | 247 | #include "delegate.impl.hpp" 248 | 249 | #undef DELEGATE_PARAM_COUNT 250 | #undef DELEGATE_TEMPLATE_PARAMS 251 | #undef DELEGATE_TEMPLATE_ARGS 252 | #undef DELEGATE_PARAMS 253 | #undef DELEGATE_ARGS 254 | 255 | #define DELEGATE_PARAM_COUNT 6 256 | #define DELEGATE_TEMPLATE_PARAMS class Param1T, class Param2T, class Param3T, class Param4T, class Param5T, class Param6T 257 | #define DELEGATE_TEMPLATE_ARGS Param1T, Param2T, Param3T, Param4T, Param5T, Param6T 258 | #define DELEGATE_PARAMS Param1T a1, Param2T a2, Param3T a3, Param4T a4, Param5T a5, Param6T a6 259 | #define DELEGATE_ARGS a1, a2, a3, a4, a5, a6 260 | 261 | #include "delegate.impl.hpp" 262 | 263 | #undef DELEGATE_PARAM_COUNT 264 | #undef DELEGATE_TEMPLATE_PARAMS 265 | #undef DELEGATE_TEMPLATE_ARGS 266 | #undef DELEGATE_PARAMS 267 | #undef DELEGATE_ARGS 268 | 269 | #define DELEGATE_PARAM_COUNT 7 270 | #define DELEGATE_TEMPLATE_PARAMS class Param1T, class Param2T, class Param3T, class Param4T, class Param5T, class Param6T, class Param7T 271 | #define DELEGATE_TEMPLATE_ARGS Param1T, Param2T, Param3T, Param4T, Param5T, Param6T, Param7T 272 | #define DELEGATE_PARAMS Param1T a1, Param2T a2, Param3T a3, Param4T a4, Param5T a5, Param6T a6, Param7T a7 273 | #define DELEGATE_ARGS a1, a2, a3, a4, a5, a6, a7 274 | 275 | #include "delegate.impl.hpp" 276 | 277 | #undef DELEGATE_PARAM_COUNT 278 | #undef DELEGATE_TEMPLATE_PARAMS 279 | #undef DELEGATE_TEMPLATE_ARGS 280 | #undef DELEGATE_PARAMS 281 | #undef DELEGATE_ARGS 282 | 283 | #define DELEGATE_PARAM_COUNT 8 284 | #define DELEGATE_TEMPLATE_PARAMS class Param1T, class Param2T, class Param3T, class Param4T, class Param5T, class Param6T, class Param7T, class Param8T 285 | #define DELEGATE_TEMPLATE_ARGS Param1T, Param2T, Param3T, Param4T, Param5T, Param6T, Param7T, Param8T 286 | #define DELEGATE_PARAMS Param1T a1, Param2T a2, Param3T a3, Param4T a4, Param5T a5, Param6T a6, Param7T a7, Param8T a8 287 | #define DELEGATE_ARGS a1, a2, a3, a4, a5, a6, a7, a8 288 | 289 | #include "delegate.impl.hpp" 290 | 291 | #undef DELEGATE_PARAM_COUNT 292 | #undef DELEGATE_TEMPLATE_PARAMS 293 | #undef DELEGATE_TEMPLATE_ARGS 294 | #undef DELEGATE_PARAMS 295 | #undef DELEGATE_ARGS 296 | 297 | 298 | #endif // DELEGATE_H 299 | -------------------------------------------------------------------------------- /delegates/delegate.impl.hpp: -------------------------------------------------------------------------------- 1 | #if !defined(DELEGATE_PARAM_COUNT) 2 | || defined(DELEGATE_TEMPLATE_PARAMS) 3 | || defined(DELEGATE_TEMPLATE_ARGS) 4 | || defined(DELEGATE_PARAMS) 5 | || defined(DELEGATE_ARGS) 6 | 7 | #error "delegate not declared" 8 | #endif 9 | 10 | #if DELEGATE_PARAM_COUNT > 0 11 | #define DELEGATE_COMMA , 12 | #else 13 | #define DELEGATE_COMMA 14 | #endif 15 | 16 | namespace delegates 17 | { 18 | template 19 | class delegate 20 | { 21 | typedef const void* pthis_type; 22 | typedef ReturnT(detail::virtual_class_child::*member_func_type)(DELEGATE_TEMPLATE_ARGS); 23 | typedef ReturnT(*free_func_type)(DELEGATE_TEMPLATE_ARGS); 24 | typedef ReturnT(*free_func_like_member_type)(pthis_type DELEGATE_COMMA DELEGATE_TEMPLATE_ARGS); 25 | typedef ReturnT(*caller_type)(const delegate& DELEGATE_COMMA DELEGATE_TEMPLATE_ARGS); 26 | 27 | typedef detail::comparison_type comparison_type; 28 | typedef bool(*comparator_type)(const delegate&, const delegate&, comparison_type); 29 | 30 | struct member_func_call 31 | { 32 | unsigned char union_[ 33 | (sizeof(free_func_like_member_type) > sizeof(member_func_type) ? 34 | sizeof(free_func_like_member_type) : sizeof(member_func_type))]; 35 | pthis_type pthis_; 36 | }; 37 | 38 | inline 39 | static ReturnT simple_function_caller(const delegate &that DELEGATE_COMMA DELEGATE_PARAMS) 40 | { 41 | free_func_type func; 42 | 43 | std::memcpy(&func, that.union_, sizeof(func)); 44 | 45 | return func(DELEGATE_ARGS); 46 | } 47 | 48 | template< class Y, class real_free_func_like_member_type > 49 | inline 50 | static ReturnT function_caller(const delegate &that DELEGATE_COMMA DELEGATE_PARAMS) 51 | { 52 | member_func_call call; 53 | 54 | std::memcpy(&call, that.union_, sizeof(call)); 55 | 56 | real_free_func_like_member_type func; 57 | Y* pthis = static_cast(const_cast(call.pthis_)); 58 | 59 | std::memcpy(&func, call.union_, sizeof(func)); 60 | 61 | return 62 | func 63 | (pthis DELEGATE_COMMA DELEGATE_ARGS); 64 | } 65 | 66 | template< class Y, class real_free_func_like_member_type > 67 | inline 68 | static ReturnT function_caller_const(const delegate &that DELEGATE_COMMA DELEGATE_PARAMS) 69 | { 70 | member_func_call call; 71 | 72 | std::memcpy(&call, that.union_, sizeof(call)); 73 | 74 | real_free_func_like_member_type func; 75 | const Y* pthis = static_cast(const_cast(call.pthis_)); 76 | 77 | std::memcpy(&func, call.union_, sizeof(func)); 78 | 79 | return 80 | func 81 | (pthis DELEGATE_COMMA DELEGATE_ARGS); 82 | } 83 | 84 | template< class Y, class real_member_func_type > 85 | inline 86 | static ReturnT mfunction_caller(const delegate &that DELEGATE_COMMA DELEGATE_PARAMS) 87 | { 88 | member_func_call call; 89 | 90 | std::memcpy(&call, that.union_, sizeof(call)); 91 | 92 | real_member_func_type func; 93 | Y* pthis = static_cast(const_cast(call.pthis_)); 94 | 95 | std::memcpy(&func, call.union_, sizeof(func)); 96 | 97 | return 98 | (pthis->*func) 99 | (DELEGATE_ARGS); 100 | } 101 | 102 | template< class Y, class real_member_func_type > 103 | inline 104 | static ReturnT mfunction_caller_const(const delegate &that DELEGATE_COMMA DELEGATE_PARAMS) 105 | { 106 | member_func_call call; 107 | 108 | std::memcpy(&call, that.union_, sizeof(call)); 109 | 110 | real_member_func_type func; 111 | const Y* pthis = static_cast(const_cast(call.pthis_)); 112 | 113 | std::memcpy(&func, call.union_, sizeof(func)); 114 | 115 | return 116 | (pthis->*func) 117 | (DELEGATE_ARGS); 118 | } 119 | 120 | template 121 | inline 122 | caller_type get_caller(Y*, ReturnT(*)(Y* DELEGATE_COMMA DELEGATE_TEMPLATE_ARGS)) const 123 | { 124 | typedef ReturnT(*func_type)(Y* DELEGATE_COMMA DELEGATE_TEMPLATE_ARGS); 125 | return &function_caller; 126 | } 127 | 128 | template 129 | inline 130 | caller_type get_caller(const Y*, ReturnT(*)(const Y* DELEGATE_COMMA DELEGATE_TEMPLATE_ARGS)) const 131 | { 132 | typedef ReturnT(*func_type)(const Y * DELEGATE_COMMA DELEGATE_TEMPLATE_ARGS); 133 | return &function_caller_const; 134 | } 135 | 136 | template 137 | inline 138 | caller_type get_caller(X*, ReturnT(Y::*)(DELEGATE_TEMPLATE_ARGS)) const 139 | { 140 | typedef ReturnT(Y::*func_type)(DELEGATE_TEMPLATE_ARGS); 141 | return &mfunction_caller; 142 | } 143 | 144 | template 145 | inline 146 | caller_type get_caller(const X*, ReturnT(Y::*)(DELEGATE_TEMPLATE_ARGS) const) const 147 | { 148 | typedef ReturnT(Y::* func_type)(DELEGATE_TEMPLATE_ARGS) const; 149 | return &mfunction_caller_const; 150 | } 151 | 152 | inline 153 | caller_type get_caller(ReturnT(*)(DELEGATE_TEMPLATE_ARGS)) const 154 | { return &simple_function_caller; } 155 | 156 | inline 157 | static bool simple_function_comparator(const delegate& lhs, const delegate& rhs, comparison_type op) 158 | { 159 | free_func_type lhs_func, rhs_func; 160 | 161 | std::memcpy(&lhs_func, lhs.union_, sizeof(lhs_func)); 162 | std::memcpy(&rhs_func, rhs.union_, sizeof(rhs_func)); 163 | 164 | return detail::compare(lhs_func, rhs_func, op); 165 | } 166 | 167 | template< class Y, class real_free_func_like_member_type > 168 | inline 169 | static bool function_comparator(const delegate& lhs, const delegate& rhs, comparison_type op) 170 | { 171 | member_func_call lhs_call, rhs_call; 172 | 173 | std::memcpy(&lhs_call, lhs.union_, sizeof(lhs_call)); 174 | std::memcpy(&rhs_call, rhs.union_, sizeof(rhs_call)); 175 | 176 | switch (op) 177 | { 178 | case detail::less: 179 | if (detail::compare(lhs_call.pthis_, rhs_call.pthis_, detail::less)) 180 | { 181 | return true; 182 | } 183 | else if (!detail::compare(rhs_call.pthis_, lhs_call.pthis_, detail::less)) 184 | { 185 | real_free_func_like_member_type lhs_func, rhs_func; 186 | std::memcpy(&lhs_func, lhs_call.union_, sizeof(lhs_func)); 187 | std::memcpy(&rhs_func, rhs_call.union_, sizeof(rhs_func)); 188 | return 189 | detail::compare(lhs_func, rhs_func, detail::less); 190 | }break; 191 | case detail::greater: 192 | if (detail::compare(rhs_call.pthis_, lhs_call.pthis_, detail::less)) 193 | { 194 | return true; 195 | } 196 | else if (!detail::compare(lhs_call.pthis_, rhs_call.pthis_, detail::less)) 197 | { 198 | real_free_func_like_member_type lhs_func, rhs_func; 199 | std::memcpy(&lhs_func, lhs_call.union_, sizeof(lhs_func)); 200 | std::memcpy(&rhs_func, rhs_call.union_, sizeof(rhs_func)); 201 | return 202 | detail::compare(rhs_func, lhs_func, detail::less); 203 | }break; 204 | case detail::equal: 205 | if (detail::compare(rhs_call.pthis_, lhs_call.pthis_, detail::equal)) 206 | { 207 | real_free_func_like_member_type lhs_func, rhs_func; 208 | std::memcpy(&lhs_func, lhs_call.union_, sizeof(lhs_func)); 209 | std::memcpy(&rhs_func, rhs_call.union_, sizeof(rhs_func)); 210 | return 211 | detail::compare(lhs_func, rhs_func, detail::equal); 212 | }break; 213 | } 214 | 215 | return false; 216 | } 217 | 218 | template< class Y, class real_free_func_like_member_type > 219 | inline 220 | static bool function_comparator_const(const delegate& lhs, const delegate& rhs, comparison_type op) 221 | { 222 | return function_comparator(lhs, rhs, op); 223 | } 224 | 225 | template< class Y, class real_member_func_type > 226 | inline 227 | static bool mfunction_comparator(const delegate& lhs, const delegate& rhs, comparison_type op) 228 | { 229 | member_func_call lhs_call, rhs_call; 230 | 231 | std::memcpy(&lhs_call, lhs.union_, sizeof(lhs_call)); 232 | std::memcpy(&rhs_call, rhs.union_, sizeof(rhs_call)); 233 | 234 | switch (op) 235 | { 236 | case detail::less: 237 | return detail::compare(lhs_call.pthis_, rhs_call.pthis_, detail::less) || 238 | (!detail::compare(rhs_call.pthis_, lhs_call.pthis_, detail::less) && 239 | std::memcmp(lhs_call.union_, rhs_call.union_, sizeof(lhs_call.union_)) < 0); break; 240 | case detail::greater: 241 | return detail::compare(rhs_call.pthis_, lhs_call.pthis_, detail::less) || 242 | (!detail::compare(lhs_call.pthis_, rhs_call.pthis_, detail::less) && 243 | std::memcmp(rhs_call.union_, lhs_call.union_, sizeof(lhs_call.union_)) < 0); break; 244 | case detail::equal: 245 | return detail::compare(lhs_call.pthis_, rhs_call.pthis_, detail::equal) && 246 | (0 == std::memcmp(lhs_call.union_, rhs_call.union_, sizeof(lhs_call.union_))); break; 247 | } 248 | return false; 249 | } 250 | 251 | template< class Y, class real_member_func_type > 252 | inline 253 | static bool mfunction_comparator_const(const delegate& lhs, const delegate& rhs, comparison_type op) 254 | { 255 | return mfunction_comparator(lhs, rhs, op); 256 | } 257 | 258 | template 259 | inline 260 | comparator_type get_comparator(Y*, ReturnT(*)(Y* DELEGATE_COMMA DELEGATE_TEMPLATE_ARGS)) const 261 | { 262 | typedef ReturnT(*func_type)(Y* DELEGATE_COMMA DELEGATE_TEMPLATE_ARGS); 263 | return &function_comparator; 264 | } 265 | 266 | template 267 | inline 268 | comparator_type get_comparator(const Y*, ReturnT(*)(const Y* DELEGATE_COMMA DELEGATE_TEMPLATE_ARGS)) const 269 | { 270 | typedef ReturnT(*func_type)(const Y * DELEGATE_COMMA DELEGATE_TEMPLATE_ARGS); 271 | return &function_comparator_const; 272 | } 273 | 274 | template 275 | inline 276 | comparator_type get_comparator(X*, ReturnT(Y::*)(DELEGATE_TEMPLATE_ARGS)) const 277 | { 278 | typedef ReturnT(Y::*func_type)(DELEGATE_TEMPLATE_ARGS); 279 | return &mfunction_comparator; 280 | } 281 | 282 | template 283 | inline 284 | comparator_type get_comparator(const X*, ReturnT(Y::*)(DELEGATE_TEMPLATE_ARGS) const) const 285 | { 286 | typedef ReturnT(Y::* func_type)(DELEGATE_TEMPLATE_ARGS) const; 287 | return &mfunction_comparator_const; 288 | } 289 | 290 | inline 291 | comparator_type get_comparator(ReturnT(*)(DELEGATE_TEMPLATE_ARGS)) const 292 | { return &simple_function_comparator; } 293 | 294 | public: 295 | typedef delegate type; 296 | 297 | delegate() 298 | : caller_(NULL) 299 | , comparator_(NULL) 300 | { 301 | std::memset(union_, 0, sizeof(union_)); 302 | } 303 | 304 | template < class X, class Y > 305 | delegate(Y * pthis, 306 | ReturnT(X::* function_to_bind)(DELEGATE_TEMPLATE_ARGS)) 307 | : caller_(get_caller(pthis, function_to_bind)) 308 | , comparator_(get_comparator(pthis, function_to_bind)) 309 | { 310 | 311 | std::memset(union_, 0, sizeof(union_)); 312 | 313 | typename 314 | detail::disable_if_not_convertable 315 | ::type f_call; 316 | 317 | std::memset(&f_call, 0, sizeof(f_call)); 318 | f_call.pthis_ = pthis; 319 | std::memcpy(f_call.union_, &function_to_bind, sizeof(function_to_bind)); 320 | 321 | std::memcpy(union_, &f_call, sizeof(f_call)); 322 | 323 | assert(NULL != pthis); 324 | assert(NULL != function_to_bind); 325 | } 326 | 327 | template < class X, class Y > 328 | delegate(const Y *pthis, 329 | ReturnT(X::* function_to_bind)(DELEGATE_TEMPLATE_ARGS) const) 330 | : caller_(get_caller(pthis, function_to_bind)) 331 | , comparator_(get_comparator(pthis, function_to_bind)) 332 | { 333 | std::memset(union_, 0, sizeof(union_)); 334 | 335 | typename 336 | detail::disable_if_not_convertable 337 | ::type f_call; 338 | 339 | std::memset(&f_call, 0, sizeof(f_call)); 340 | f_call.pthis_ = pthis; 341 | std::memcpy(f_call.union_, &function_to_bind, sizeof(function_to_bind)); 342 | 343 | std::memcpy(union_, &f_call, sizeof(f_call)); 344 | 345 | assert(NULL != pthis); 346 | assert(NULL != function_to_bind); 347 | } 348 | 349 | template < class Y > 350 | delegate(Y *pthis, 351 | ReturnT(*function_to_bind)(Y* DELEGATE_COMMA DELEGATE_TEMPLATE_ARGS)) 352 | : caller_(get_caller(pthis, function_to_bind)) 353 | , comparator_(get_comparator(pthis, function_to_bind)) 354 | { 355 | std::memset(union_, 0, sizeof(union_)); 356 | 357 | member_func_call f_call; 358 | 359 | std::memset(&f_call, 0, sizeof(f_call)); 360 | f_call.pthis_ = pthis; 361 | std::memcpy(f_call.union_, &function_to_bind, sizeof(function_to_bind)); 362 | 363 | std::memcpy(union_, &f_call, sizeof(f_call)); 364 | 365 | assert(NULL != function_to_bind); 366 | } 367 | 368 | template < class Y > 369 | delegate(Y *pthis, 370 | ReturnT(*function_to_bind)(const Y* DELEGATE_COMMA DELEGATE_TEMPLATE_ARGS)) 371 | : caller_(get_caller(pthis, function_to_bind)) 372 | , comparator_(get_comparator(pthis, function_to_bind)) 373 | { 374 | std::memset(union_, 0, sizeof(union_)); 375 | 376 | member_func_call f_call; 377 | 378 | std::memset(&f_call, 0, sizeof(f_call)); 379 | f_call.pthis_ = pthis; 380 | std::memcpy(f_call.union_, &function_to_bind, sizeof(function_to_bind)); 381 | 382 | std::memcpy(union_, &f_call, sizeof(f_call)); 383 | 384 | assert(NULL != function_to_bind); 385 | } 386 | 387 | template < class Y > 388 | delegate(const Y *pthis, 389 | ReturnT(*function_to_bind)(const Y* DELEGATE_COMMA DELEGATE_TEMPLATE_ARGS)) 390 | : caller_(get_caller(pthis, function_to_bind)) 391 | , comparator_(get_comparator(pthis, function_to_bind)) 392 | { 393 | std::memset(union_, 0, sizeof(union_)); 394 | 395 | member_func_call f_call; 396 | 397 | std::memset(&f_call, 0, sizeof(f_call)); 398 | f_call.pthis_ = pthis; 399 | std::memcpy(f_call.union_, &function_to_bind, sizeof(function_to_bind)); 400 | 401 | std::memcpy(union_, &f_call, sizeof(f_call)); 402 | 403 | assert(NULL != function_to_bind); 404 | } 405 | 406 | 407 | delegate(free_func_type function_to_bind) 408 | : caller_(get_caller(function_to_bind)) 409 | , comparator_(get_comparator(function_to_bind)) 410 | { 411 | std::memset(union_, 0, sizeof(union_)); 412 | 413 | std::memcpy(union_, &function_to_bind, sizeof(function_to_bind)); 414 | 415 | assert(NULL != function_to_bind); 416 | } 417 | 418 | void swap(delegate &other) 419 | { 420 | if (this == &other) 421 | return; 422 | 423 | // swap for caller 424 | { 425 | caller_type tmp = caller_; 426 | caller_ = other.caller_; 427 | other.caller_ = tmp; 428 | } 429 | // swap for comparator 430 | { 431 | comparator_type tmp = comparator_; 432 | comparator_ = other.comparator_; 433 | other.comparator_ = tmp; 434 | } 435 | // swap for arrays 436 | { 437 | unsigned char tmp[sizeof(union_)]; 438 | std::memcpy(tmp, union_, sizeof(union_)); 439 | std::memcpy(union_, other.union_, sizeof(union_)); 440 | std::memcpy(other.union_, tmp, sizeof(union_)); 441 | } 442 | } 443 | 444 | friend void swap(delegate& lhs, delegate& rhs) 445 | { 446 | lhs.swap(rhs); 447 | } 448 | 449 | delegate(const delegate &other) 450 | { 451 | caller_ = (other.caller_); 452 | comparator_ = (other.comparator_); 453 | std::memcpy(union_, other.union_, sizeof(union_)); 454 | } 455 | 456 | delegate& operator=(const delegate &other) 457 | { 458 | if (this != &other) 459 | { 460 | type(other).swap(*this); 461 | } 462 | 463 | return *this; 464 | } 465 | 466 | bool operator!() const 467 | { 468 | return NULL == caller_ || NULL == comparator_; 469 | } 470 | 471 | bool operator==(const delegate &other) const 472 | { 473 | if (!detail::compare_equal(caller_, other.caller_)) 474 | return false; 475 | if (!detail::compare_equal(comparator_, other.comparator_)) 476 | return false; 477 | if(NULL != comparator_) 478 | return comparator_(*this, other, detail::equal); 479 | return true; 480 | } 481 | 482 | bool operator!=(const delegate &other) const 483 | { 484 | return !(*this == other); 485 | } 486 | 487 | bool operator<(const delegate &other) const 488 | { 489 | if (!detail::compare_equal(caller_, other.caller_)) 490 | return detail::compare_less(caller_, other.caller_); 491 | if (!detail::compare_equal(comparator_, other.comparator_)) 492 | return detail::compare_less(comparator_, other.comparator_); 493 | if (NULL != comparator_) 494 | return comparator_(*this, other, detail::less); 495 | return false; 496 | } 497 | 498 | bool operator>(const delegate &other) const 499 | { 500 | if (!detail::compare_equal(caller_, other.caller_)) 501 | return detail::compare_greater(caller_, other.caller_); 502 | if (!detail::compare_equal(comparator_, other.comparator_)) 503 | return detail::compare_greater(comparator_, other.comparator_); 504 | if (NULL != comparator_) 505 | return comparator_(*this, other, detail::greater); 506 | return false; 507 | } 508 | 509 | inline 510 | ReturnT operator()(DELEGATE_PARAMS) const 511 | { 512 | return caller_(*this DELEGATE_COMMA DELEGATE_ARGS); 513 | } 514 | 515 | pthis_type ptr() const 516 | { 517 | member_func_call call; 518 | 519 | std::memcpy(&call, union_, sizeof(call)); 520 | 521 | return (call.pthis_); 522 | } 523 | 524 | template < class Y > 525 | inline void bind(Y *pthis, ReturnT(*function_to_bind)(Y* DELEGATE_COMMA DELEGATE_TEMPLATE_ARGS)) { 526 | type(pthis, function_to_bind).swap(*this); 527 | } 528 | 529 | template < class Y > 530 | inline void bind(Y *pthis, ReturnT(*function_to_bind)(const Y* DELEGATE_COMMA DELEGATE_TEMPLATE_ARGS)) { 531 | type(pthis, function_to_bind).swap(*this); 532 | } 533 | 534 | template < class Y > 535 | inline void bind(const Y *pthis, ReturnT(*function_to_bind)(const Y* DELEGATE_COMMA DELEGATE_TEMPLATE_ARGS)) { 536 | type(pthis, function_to_bind).swap(*this); 537 | } 538 | 539 | template < class X, class Y > 540 | inline void bind(Y *pthis, ReturnT(X::* function_to_bind)(DELEGATE_TEMPLATE_ARGS)) { 541 | type(pthis, function_to_bind).swap(*this); 542 | } 543 | 544 | template < class X, class Y > 545 | inline void bind(const Y *pthis, ReturnT(X::* function_to_bind)(DELEGATE_TEMPLATE_ARGS) const) { 546 | type(pthis, function_to_bind).swap(*this); 547 | } 548 | 549 | inline void bind(ReturnT(*function_to_bind)(DELEGATE_TEMPLATE_ARGS)) { 550 | type(function_to_bind).swap(*this); 551 | } 552 | 553 | private: 554 | 555 | // caller function to proper cast "union_" and call function stored in it 556 | caller_type caller_; 557 | 558 | // comparator function to proper cast "union_" and call comparison function 559 | comparator_type comparator_; 560 | 561 | // C++ union imitation 562 | // there we store free function like 'return_type free_function(arguments_type)' 563 | // or 564 | // member_func_call struct with: 565 | // member function like 'return_type some_class_type::member_function(arguments_type)' 566 | // or 567 | // free function accepting class like 'return_type free_function(some_class_type*, arguments_type)' 568 | unsigned char union_[ 569 | sizeof(member_func_call) > sizeof(free_func_type) ? 570 | sizeof(member_func_call) : sizeof(free_func_type)]; 571 | }; 572 | 573 | template 574 | class delegate 575 | : delegate {}; 576 | 577 | template < class X, class Y, class ReturnT DELEGATE_COMMA DELEGATE_TEMPLATE_PARAMS> 578 | delegate 579 | bind(X *pthis, 580 | ReturnT(Y::* function_to_bind)(DELEGATE_TEMPLATE_ARGS)) 581 | { 582 | return delegate(pthis, function_to_bind); 583 | } 584 | 585 | template < class X, class Y, class ReturnT DELEGATE_COMMA DELEGATE_TEMPLATE_PARAMS> 586 | delegate 587 | bind(const X *pthis, 588 | ReturnT(Y::* function_to_bind)(DELEGATE_TEMPLATE_ARGS) const) 589 | { 590 | return delegate(pthis, function_to_bind); 591 | } 592 | 593 | template < class X, class ReturnT DELEGATE_COMMA DELEGATE_TEMPLATE_PARAMS> 594 | delegate 595 | bind(X *pthis, 596 | ReturnT(*function_to_bind)(X* DELEGATE_COMMA DELEGATE_TEMPLATE_ARGS)) 597 | { 598 | return delegate(pthis, function_to_bind); 599 | } 600 | 601 | template < class X, class ReturnT DELEGATE_COMMA DELEGATE_TEMPLATE_PARAMS> 602 | delegate 603 | bind(X *pthis, 604 | ReturnT(*function_to_bind)(const X* DELEGATE_COMMA DELEGATE_TEMPLATE_ARGS)) 605 | { 606 | return delegate(pthis, function_to_bind); 607 | } 608 | 609 | template < class ReturnT DELEGATE_COMMA DELEGATE_TEMPLATE_PARAMS> 610 | delegate 611 | bind(ReturnT(*function_to_bind)(DELEGATE_TEMPLATE_ARGS)) 612 | { 613 | return delegate(function_to_bind); 614 | } 615 | 616 | } 617 | 618 | #undef DELEGATE_COMMA 619 | --------------------------------------------------------------------------------