├── history.txt ├── examples ├── pointersize.cpp ├── example.cpp ├── compare.cpp ├── smoke.cpp ├── bench.cpp └── bench.tcl ├── LICENSE.md ├── README.md └── callback.hpp /history.txt: -------------------------------------------------------------------------------- 1 | Version 1.7 - October 2010 2 | Fixed memory bug with multiple inheritance, virtual inheritance, or unknown classes 3 | 4 | Version 1.5 - March 2010 5 | Callback allocates internal objects with placement new 6 | 7 | Version 1.4 - March 2010 8 | Fixed bug in case of self assignment of callback object 9 | 10 | Version 1.3 - March 2010 11 | First public release 12 | -------------------------------------------------------------------------------- /examples/pointersize.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class one {}; 4 | class two : public one {}; 5 | class three : virtual public one{}; 6 | class four; 7 | 8 | int main(int argc, char *argv[]) 9 | { 10 | printf("This just lists method pointer sizes for your compiler.\n\n"); 11 | typedef void(one::*onepointer)(); 12 | typedef void(two::*twopointer)(); 13 | typedef void(three::*threepointer)(); 14 | typedef void(four::*fourpointer)(); 15 | 16 | printf(" Single: %d bytes.\n", sizeof(onepointer)); 17 | printf("Multiple: %d bytes.\n", sizeof(twopointer)); 18 | printf(" Virtual: %d bytes.\n", sizeof(threepointer)); 19 | printf(" Unknown: %d bytes.\n", sizeof(fourpointer)); 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | PlusCallback 1.7 2 | Copyright (c) 2009-2010 Lewis Van Winkle 3 | 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any damages 6 | arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any purpose, 9 | including commercial applications, and to alter it and redistribute it 10 | freely, subject to the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; you must not 13 | claim that you wrote the original software. If you use this software 14 | in a product, an acknowledgment in the product documentation would be 15 | appreciated but is not required. 16 | 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 20 | 3. This notice may not be removed or altered from any source 21 | distribution. 22 | 23 | 24 | -------------------------------------------------------------------------------- /examples/example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../callback.hpp" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct Dog 9 | { 10 | void Bark(int volume){}; 11 | }; 12 | 13 | struct Cat 14 | { 15 | void Meow(int volume){}; 16 | }; 17 | 18 | Dog spot, rover; //We have two dogs 19 | Cat felix; //and one cat. 20 | 21 | //Define a normal function. 22 | void Func(int a){}; 23 | 24 | 25 | int main(int argc, char *argv[]) 26 | { 27 | //Define a callback to a function returning void and taking 28 | //one int parameter. 29 | cb::Callback1 speak; 30 | 31 | //Point this callback at spot's Bark method. 32 | speak.Reset(&spot, &Dog::Bark); 33 | speak(50); //Spot barks loudly. 34 | 35 | speak.Reset(&rover, &Dog::Bark); 36 | speak(60); //Rovers lets out a mighty bark. 37 | 38 | speak.Reset(&felix, &Cat::Meow); 39 | speak(30); //Felix meows. 40 | 41 | //Callbacks can be set to free functions. 42 | speak = Func; 43 | 44 | //Copy and assignment operators are well defined. 45 | cb::Callback1 copy = speak; 46 | assert(copy == speak); 47 | 48 | //Callbacks can be set to null. 49 | copy.Reset(); 50 | assert(!copy.IsSet()); 51 | 52 | //Callbacks are container safe with a well defined sort order. 53 | std::set > container; 54 | container.insert(speak); 55 | container.insert(copy); 56 | 57 | //Use the helper function MakeX to quickly create callback objects. 58 | container.insert(cb::Make1(&spot, &Dog::Bark)); 59 | container.insert(cb::Make1(&rover, &Dog::Bark)); 60 | container.insert(cb::Make1(&felix, &Cat::Meow)); 61 | 62 | 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C++ Callback Library: PlusCallback 2 | 3 | *Additional documentation at:* 4 | http://codeplea.com/pluscallback 5 | 6 | ## Intro 7 | 8 | PlusCallback is a C++ library, contained in a single header file, that 9 | implements easy to use function and method callbacks. It is completely 10 | contained in one header file, so it's trivial to add to your projects. It also 11 | uses the simplest syntax of any callback method I've ever seen (for C++), and 12 | it's quite flexible. 13 | 14 | ## Code Sample 15 | 16 | //Setup callback for TestObject.Foo(). 17 | cb::Callback1 callback(&TestObject, &TestClass::Foo); 18 | 19 | //Call TestObject.Foo(5). 20 | callback(5); 21 | 22 | //Change callback to a free function. 23 | callback = SomeRandomFunction; 24 | 25 | //Call SomeRandomFunction(8). 26 | callback(8); 27 | 28 | 29 | ## Features 30 | 31 | - Contained in one header file, trivial to install 32 | - Portable ANSI C++ code 33 | - Completely free for any use (zlib license) 34 | - Very simple API 35 | - Type-safe, no macros or casts 36 | - Container storage safe (e.g. std::map, list, vector, etc) 37 | 38 | 39 | ## Installation Instructions 40 | This entire library is contained in one header file. 41 | Simply include *callback.hpp* in your project. 42 | 43 | ## Examples 44 | Some examples are included in the examples directory: 45 | - example.cpp - PlusCallback example walking through most features. 46 | - compare.cpp - Example comparing different callback methods. 47 | - smoke.cpp - Several random tests for PlusCallback. 48 | 49 | ## Building Instructions 50 | This library comes pre-built. If you would like to rebuild this 51 | library, you need to run build.tcl with the TCL interpreter. You 52 | can obtain TCL from http://www.tcl.tk/ 53 | When rebuilding, you can change the maximum number of parameters 54 | supported by callbacks. 55 | -------------------------------------------------------------------------------- /examples/compare.cpp: -------------------------------------------------------------------------------- 1 | ///\file Compares different callback methods. 2 | 3 | //Fun fact, the pre processor turns this next line into about 30,000 lines. 4 | #include 5 | #include 6 | 7 | //This file is only about 2,500 lines long. It was generated by a script about 350 lines long. 8 | //You don't have to be a genius to understand how it works. 9 | #include "../callback.hpp" 10 | 11 | #include 12 | #include 13 | 14 | 15 | 16 | //Just an example method to call. 17 | struct X { 18 | int Foo(int a) {printf("Foo %d\n", a); return a;} 19 | }; 20 | 21 | //And an example free function to call. 22 | int FreeFoo(int a) {printf("FreeFoo %d\n", a); return a;} 23 | 24 | 25 | 26 | //Example of just using raw C++ pointers. 27 | void CppExample() 28 | { 29 | X x; 30 | 31 | //The method pointer and object pointer are stored separately. 32 | int (X::*callback)(int) = &X::Foo; 33 | X* object = &x; 34 | 35 | //Call x.foo(5). Note use of rare ->* operator. 36 | (object->*callback)(5); 37 | 38 | //At this point, there is no easy way to set the callback to 39 | //an object of a different class, a static method, or a free function. 40 | 41 | //Also, C++ doesn't support the < operator for these method callbacks. 42 | //assert(!(callback < callback)); 43 | } 44 | 45 | 46 | 47 | //Example of using boost for callbacks. 48 | void BoostExample() 49 | { 50 | X x; 51 | 52 | //Setup callback for x.foo. Note complexity for simple task. 53 | boost::function callback = std::bind1st(std::mem_fun(&X::Foo), &x); 54 | 55 | /* Or 56 | boost::function callback(boost::bind(&X::Foo, &x, _1)); 57 | */ 58 | 59 | callback(5); //Call x.foo(5); 60 | 61 | //Change callback to free function. 62 | callback = FreeFoo; 63 | 64 | //Call FreeFunction(8). 65 | callback(8); 66 | 67 | //Boost doesn't support the < operator for function callbacks. 68 | //assert(!(callback < callback)); 69 | } 70 | 71 | 72 | 73 | void MyExample() 74 | { 75 | X x; 76 | 77 | //Setup callback for x.foo. 78 | cb::Callback1 callback(&x, &X::Foo); 79 | 80 | //Call x.foo(5). 81 | callback(5); 82 | 83 | //Change callback to free function. 84 | callback = FreeFoo; 85 | 86 | //Call FreeFunction(8). 87 | callback(8); 88 | 89 | //The < operator than works fine. 90 | //One can safely store these callbacks in a set or map container. 91 | assert(!(callback < callback)); 92 | } 93 | 94 | 95 | 96 | int main(int argc, char *argv[]) 97 | { 98 | CppExample(); printf("\n"); 99 | BoostExample(); printf("\n"); 100 | MyExample(); printf("\n"); 101 | return 0; 102 | } 103 | -------------------------------------------------------------------------------- /examples/smoke.cpp: -------------------------------------------------------------------------------- 1 | #include "../callback.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | ///\file This is basically a bunch of random tests for the callback library. 10 | ///It's a bit of a mess and probably not something one should use as learning material. 11 | ///When running this, a tool should be used to check for memory leaks. 12 | ///This test always leaks 12345 bytes of memory on purpose. Any other amount is an error. 13 | 14 | 15 | class A {}; class B {}; class C {}; 16 | 17 | class Test : public A, public B, public virtual C 18 | { 19 | public: 20 | int Return1() {return 1;} 21 | int Return2() {return 2;} 22 | void Turn1(int& a) {a = 1;} 23 | }; 24 | 25 | 26 | class X 27 | { 28 | public: 29 | int Return1() {return 1;} 30 | }; 31 | 32 | 33 | int Free1() {return 1;} 34 | int Free3() {return 3;} 35 | int FreeX2(int a) {return a*2;} 36 | 37 | 38 | int main(int argc, char *argv[]) 39 | { 40 | //Check that asserts are actually on. 41 | { 42 | int checkAsserts = 0; 43 | assert(checkAsserts = 1); 44 | if (!checkAsserts) 45 | { 46 | printf("Error, the code was not compiled with asserts.\n"); 47 | exit(1); 48 | } 49 | } 50 | 51 | 52 | //Leak some memory on purpose to check that 53 | //a memory leak detection tool is working. 54 | char* leak = new char[12345]; 55 | leak = 0; 56 | 57 | std::printf("Begin.\n"); 58 | 59 | Test test; 60 | Test test2; 61 | 62 | { 63 | cb::Callback0 a; 64 | assert(!a.IsSet()); 65 | 66 | //Test callback. 67 | a.Reset(&test, &Test::Return1); 68 | assert(a.IsSet()); 69 | assert(a() == 1); 70 | 71 | //Test reseting callback. 72 | a.Reset(&test, &Test::Return2); 73 | assert(a() == 2); 74 | 75 | //Test equality with generated callbacks. 76 | assert(a == cb::Make0(&test, &Test::Return2)); //same func, same obj 77 | assert(a != cb::Make0(&test2, &Test::Return2)); //same func, diff obj 78 | assert(a != cb::Make0(&test, &Test::Return1)); //diff func, same obj 79 | assert(a != cb::Make0(Free3)); //Free function. 80 | assert(cb::Make0(Free3) == cb::Make0(Free3)); 81 | 82 | //Test equality. 83 | cb::Callback0 b(&test, &Test::Return2); 84 | assert(b.IsSet()); 85 | assert(a == b); 86 | 87 | b.Reset(Free3); 88 | assert(a != b); 89 | 90 | b.Reset(&test, &Test::Return1); 91 | assert(a != b); 92 | 93 | //Test equality with unset callbacks. 94 | b.Reset(); 95 | assert(!b.IsSet()); 96 | assert(a != b); 97 | 98 | a.Reset(); 99 | assert(!a.IsSet()); 100 | assert(a == b); 101 | } 102 | 103 | { 104 | //Test copy constructor. 105 | cb::Callback0 a(&test, &Test::Return1); 106 | cb::Callback0 b(a); 107 | assert(a == b); 108 | assert(a() == b()); 109 | assert(b() == 1); 110 | 111 | cb::Callback0 c(Free1); 112 | cb::Callback0 d(c); 113 | assert(c == d); 114 | assert(c() == d()); 115 | assert(d() == 1); 116 | } 117 | 118 | { 119 | //Test less than and equality some more. 120 | Test test; 121 | Test test2; 122 | X s; 123 | 124 | cb::Callback0 f1(Free1); 125 | cb::Callback0 f3(Free3); 126 | cb::Callback0 a(&test, &Test::Return1); 127 | cb::Callback0 aa(&test, &Test::Return1); 128 | cb::Callback0 b(&test2, &Test::Return1); 129 | cb::Callback0 c(&test, &Test::Return2); 130 | cb::Callback0 d(&s, &X::Return1); 131 | 132 | assert(d != a); 133 | assert(d() == a()); 134 | 135 | assert((f1 < f3) ^ (f3 < f1)); 136 | 137 | assert((f1 < a) && !(a < f1)); 138 | assert((f1 < aa) && !(aa < f1)); 139 | assert((f1 < b) && !(b < f1)); 140 | assert((f1 < c) && !(c < f1)); 141 | assert((f1 < d) && !(d < f1)); 142 | 143 | assert(!(aa < a) && !(a < aa)); 144 | 145 | assert((a < b) ^ (b < a)); 146 | assert((a < c) ^ (c < a)); 147 | assert((c < b) ^ (b < c)); 148 | 149 | assert((a < d) ^ (d < a)); 150 | 151 | f1 = f3 = a = aa = b = c = d; 152 | assert(f1 == f3); 153 | assert(a == aa); 154 | assert(b == c); 155 | assert(f1 == a && f1 == b && b == d); 156 | } 157 | 158 | { 159 | //Test free function callback. 160 | cb::Callback0 a(Free3); 161 | assert(a() == 3); 162 | assert(a == cb::Make0(Free3)); 163 | assert(a != cb::Make0(Free1)); 164 | 165 | cb::Callback1 b(FreeX2); 166 | assert(b(5) == 10); 167 | } 168 | 169 | { 170 | //Test reference parameters. 171 | cb::Callback1 a(&test, &Test::Turn1); 172 | int i = 1000; 173 | a(i); 174 | assert(i == 1); 175 | } 176 | 177 | { 178 | //Test errors by calling unset callback. 179 | try 180 | { 181 | cb::Callback0 a; 182 | a.Call(); 183 | assert(false); 184 | } 185 | catch (std::runtime_error err) 186 | { 187 | assert(err.what() == cb::unset_call_error); 188 | } 189 | } 190 | 191 | { 192 | //Test self assignment. 193 | cb::Callback0 a(&test, &Test::Return1); 194 | a = a; 195 | assert(a() == 1); 196 | 197 | cb::Callback0 b(Free3); 198 | b = b; 199 | assert(b() == 3); 200 | } 201 | 202 | { 203 | //Test container storage. 204 | std::set > set; 205 | std::multiset > mset; 206 | 207 | for (int i = 0; i < 10; ++i) 208 | if (i % 2) 209 | set.insert(cb::Make0(&test, &Test::Return1)); 210 | else 211 | set.insert(cb::Make0(Free1)); 212 | 213 | assert(set.size() == 2); 214 | 215 | for (std::set >::const_iterator it = set.begin(); it != set.end(); ++it) 216 | assert(it->Call() == 1); 217 | 218 | 219 | 220 | for (int i = 0; i < 100; ++i) 221 | if (i % 2) 222 | mset.insert(cb::Make0(&test, &Test::Return1)); 223 | else 224 | mset.insert(cb::Make0(Free1)); 225 | assert(mset.size() == 100); 226 | } 227 | 228 | std::printf("End.\n"); 229 | } 230 | 231 | -------------------------------------------------------------------------------- /examples/bench.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | This file is created by bench.tcl. 5 | You can compile and run this benchmark 6 | by hand and it will produce a readable output. 7 | 8 | Note that higher optimization levels may just 9 | completely optimize out the native C++ tests. 10 | */ 11 | 12 | #include 13 | #include "../callback.hpp" 14 | #include 15 | #include 16 | 17 | //Loops to test with. 18 | const size_t iters = 2100000000; 19 | 20 | //Just an example method to call. 21 | struct X { 22 | int Foo(int* a) {return ++(*a);} 23 | } x; 24 | 25 | 26 | //And an example free function to call. 27 | int FreeFoo(int* a) {return ++(*a);} 28 | 29 | 30 | double GetTime() { 31 | return (double)(clock()) / CLOCKS_PER_SEC; 32 | } 33 | 34 | 35 | double CallbackMethod_native() { 36 | int (X::*callback)(int*) = &X::Foo; X* object = &x; 37 | const double startTime = GetTime(); 38 | int a = 0; 39 | for (size_t i = 0; i < iters; ++i) 40 | { 41 | (object->*callback)(&a); 42 | } 43 | return GetTime() - startTime; 44 | } 45 | 46 | 47 | double CreateAndCallbackMethod_native() { 48 | 49 | const double startTime = GetTime(); 50 | int a = 0; 51 | for (size_t i = 0; i < iters; ++i) 52 | { 53 | int (X::*callback)(int*) = &X::Foo; X* object = &x; (object->*callback)(&a); 54 | } 55 | return GetTime() - startTime; 56 | } 57 | 58 | 59 | double CopyAndCallbackMethod_native() { 60 | int (X::*callback)(int*) = &X::Foo; X* object = &x; 61 | const double startTime = GetTime(); 62 | int a = 0; 63 | for (size_t i = 0; i < iters; ++i) 64 | { 65 | int (X::*callback2)(int*) = callback; X* object2 = object; (object2->*callback2)(&a); 66 | } 67 | return GetTime() - startTime; 68 | } 69 | 70 | 71 | double CallbackFunction_native() { 72 | int (*callback)(int*) = FreeFoo; 73 | const double startTime = GetTime(); 74 | int a = 0; 75 | for (size_t i = 0; i < iters; ++i) 76 | { 77 | (*callback)(&a); 78 | } 79 | return GetTime() - startTime; 80 | } 81 | 82 | 83 | double CreateAndCallbackFunction_native() { 84 | 85 | const double startTime = GetTime(); 86 | int a = 0; 87 | for (size_t i = 0; i < iters; ++i) 88 | { 89 | int (*callback)(int*) = FreeFoo; (*callback)(&a); 90 | } 91 | return GetTime() - startTime; 92 | } 93 | 94 | 95 | double CopyAndCallbackFunction_native() { 96 | int (*callback)(int*) = FreeFoo; 97 | const double startTime = GetTime(); 98 | int a = 0; 99 | for (size_t i = 0; i < iters; ++i) 100 | { 101 | int (*callback2)(int*) = callback; (*callback2)(&a); 102 | } 103 | return GetTime() - startTime; 104 | } 105 | 106 | 107 | double CallbackMethod_BoostFunction() { 108 | boost::function callback(std::bind1st(std::mem_fun(&X::Foo), &x)); 109 | const double startTime = GetTime(); 110 | int a = 0; 111 | for (size_t i = 0; i < iters; ++i) 112 | { 113 | callback(&a); 114 | } 115 | return GetTime() - startTime; 116 | } 117 | 118 | 119 | double CreateAndCallbackMethod_BoostFunction() { 120 | 121 | const double startTime = GetTime(); 122 | int a = 0; 123 | for (size_t i = 0; i < iters; ++i) 124 | { 125 | boost::function callback(std::bind1st(std::mem_fun(&X::Foo), &x)); callback(&a); 126 | } 127 | return GetTime() - startTime; 128 | } 129 | 130 | 131 | double CopyAndCallbackMethod_BoostFunction() { 132 | boost::function callback(std::bind1st(std::mem_fun(&X::Foo), &x)); 133 | const double startTime = GetTime(); 134 | int a = 0; 135 | for (size_t i = 0; i < iters; ++i) 136 | { 137 | boost::function callback2(callback); callback2(&a); 138 | } 139 | return GetTime() - startTime; 140 | } 141 | 142 | 143 | double CallbackFunction_BoostFunction() { 144 | boost::function callback(FreeFoo); 145 | const double startTime = GetTime(); 146 | int a = 0; 147 | for (size_t i = 0; i < iters; ++i) 148 | { 149 | callback(&a); 150 | } 151 | return GetTime() - startTime; 152 | } 153 | 154 | 155 | double CreateAndCallbackFunction_BoostFunction() { 156 | 157 | const double startTime = GetTime(); 158 | int a = 0; 159 | for (size_t i = 0; i < iters; ++i) 160 | { 161 | boost::function callback(FreeFoo); callback(&a); 162 | } 163 | return GetTime() - startTime; 164 | } 165 | 166 | 167 | double CopyAndCallbackFunction_BoostFunction() { 168 | boost::function callback(FreeFoo); 169 | const double startTime = GetTime(); 170 | int a = 0; 171 | for (size_t i = 0; i < iters; ++i) 172 | { 173 | boost::function callback2(callback); callback2(&a); 174 | } 175 | return GetTime() - startTime; 176 | } 177 | 178 | 179 | double CallbackMethod_PlusCallback() { 180 | cb::Callback1 callback(&x, &X::Foo); 181 | const double startTime = GetTime(); 182 | int a = 0; 183 | for (size_t i = 0; i < iters; ++i) 184 | { 185 | callback(&a); 186 | } 187 | return GetTime() - startTime; 188 | } 189 | 190 | 191 | double CreateAndCallbackMethod_PlusCallback() { 192 | 193 | const double startTime = GetTime(); 194 | int a = 0; 195 | for (size_t i = 0; i < iters; ++i) 196 | { 197 | cb::Callback1 callback(&x, &X::Foo); callback(&a); 198 | } 199 | return GetTime() - startTime; 200 | } 201 | 202 | 203 | double CopyAndCallbackMethod_PlusCallback() { 204 | cb::Callback1 callback(&x, &X::Foo); 205 | const double startTime = GetTime(); 206 | int a = 0; 207 | for (size_t i = 0; i < iters; ++i) 208 | { 209 | cb::Callback1 callback2(callback); callback2(&a); 210 | } 211 | return GetTime() - startTime; 212 | } 213 | 214 | 215 | double CallbackFunction_PlusCallback() { 216 | cb::Callback1 callback(FreeFoo); 217 | const double startTime = GetTime(); 218 | int a = 0; 219 | for (size_t i = 0; i < iters; ++i) 220 | { 221 | callback(&a); 222 | } 223 | return GetTime() - startTime; 224 | } 225 | 226 | 227 | double CreateAndCallbackFunction_PlusCallback() { 228 | 229 | const double startTime = GetTime(); 230 | int a = 0; 231 | for (size_t i = 0; i < iters; ++i) 232 | { 233 | cb::Callback1 callback(FreeFoo); callback(&a); 234 | } 235 | return GetTime() - startTime; 236 | } 237 | 238 | 239 | double CopyAndCallbackFunction_PlusCallback() { 240 | cb::Callback1 callback(FreeFoo); 241 | const double startTime = GetTime(); 242 | int a = 0; 243 | for (size_t i = 0; i < iters; ++i) 244 | { 245 | cb::Callback1 callback2(callback); callback2(&a); 246 | } 247 | return GetTime() - startTime; 248 | } 249 | 250 | 251 | int main() { 252 | 253 | printf("native\n"); 254 | printf(" CallbackMethod: %0.3f\n", CallbackMethod_native()); 255 | printf(" CreateAndCallbackMethod: %0.3f\n", CreateAndCallbackMethod_native()); 256 | printf(" CopyAndCallbackMethod: %0.3f\n", CopyAndCallbackMethod_native()); 257 | printf(" CallbackFunction: %0.3f\n", CallbackFunction_native()); 258 | printf(" CreateAndCallbackFunction: %0.3f\n", CreateAndCallbackFunction_native()); 259 | printf(" CopyAndCallbackFunction: %0.3f\n", CopyAndCallbackFunction_native()); 260 | 261 | printf("\n"); 262 | 263 | printf("BoostFunction\n"); 264 | printf(" CallbackMethod: %0.3f\n", CallbackMethod_BoostFunction()); 265 | printf(" CreateAndCallbackMethod: %0.3f\n", CreateAndCallbackMethod_BoostFunction()); 266 | printf(" CopyAndCallbackMethod: %0.3f\n", CopyAndCallbackMethod_BoostFunction()); 267 | printf(" CallbackFunction: %0.3f\n", CallbackFunction_BoostFunction()); 268 | printf(" CreateAndCallbackFunction: %0.3f\n", CreateAndCallbackFunction_BoostFunction()); 269 | printf(" CopyAndCallbackFunction: %0.3f\n", CopyAndCallbackFunction_BoostFunction()); 270 | 271 | printf("\n"); 272 | 273 | printf("PlusCallback\n"); 274 | printf(" CallbackMethod: %0.3f\n", CallbackMethod_PlusCallback()); 275 | printf(" CreateAndCallbackMethod: %0.3f\n", CreateAndCallbackMethod_PlusCallback()); 276 | printf(" CopyAndCallbackMethod: %0.3f\n", CopyAndCallbackMethod_PlusCallback()); 277 | printf(" CallbackFunction: %0.3f\n", CallbackFunction_PlusCallback()); 278 | printf(" CreateAndCallbackFunction: %0.3f\n", CreateAndCallbackFunction_PlusCallback()); 279 | printf(" CopyAndCallbackFunction: %0.3f\n", CopyAndCallbackFunction_PlusCallback()); 280 | 281 | printf("\n"); 282 | 283 | return 0; 284 | } 285 | -------------------------------------------------------------------------------- /examples/bench.tcl: -------------------------------------------------------------------------------- 1 | #This generates C++ benchmark code to compare 2 | #native, boost, and PlusCallback speeds. 3 | 4 | 5 | set iterations 2100000000 6 | 7 | set methods {native BoostFunction PlusCallback} 8 | 9 | #Define the various C++ code. 10 | set CreateMethodCallback(native) {int (X::*callback)(int*) = &X::Foo; X* object = &x;} 11 | set CreateMethodCallback(BoostFunction) {boost::function callback(std::bind1st(std::mem_fun(&X::Foo), &x));} 12 | set CreateMethodCallback(PlusCallback) {cb::Callback1 callback(&x, &X::Foo);} 13 | 14 | set CopyMethodCallback(native) {int (X::*callback2)(int*) = callback; X* object2 = object;} 15 | set CopyMethodCallback(BoostFunction) {boost::function callback2(callback);} 16 | set CopyMethodCallback(PlusCallback) {cb::Callback1 callback2(callback);} 17 | 18 | set InvokeMethodCallback(native) {(object->*callback)(&a);} 19 | set InvokeMethodCallback(BoostFunction) {callback(&a);} 20 | set InvokeMethodCallback(PlusCallback) {callback(&a);} 21 | 22 | set InvokeMethodCallback2(native) {(object2->*callback2)(&a);} 23 | set InvokeMethodCallback2(BoostFunction) {callback2(&a);} 24 | set InvokeMethodCallback2(PlusCallback) {callback2(&a);} 25 | 26 | set CreateFunctionCallback(native) {int (*callback)(int*) = FreeFoo;} 27 | set CreateFunctionCallback(BoostFunction) {boost::function callback(FreeFoo);} 28 | set CreateFunctionCallback(PlusCallback) {cb::Callback1 callback(FreeFoo);} 29 | 30 | set CopyFunctionCallback(native) {int (*callback2)(int*) = callback;} 31 | set CopyFunctionCallback(BoostFunction) {boost::function callback2(callback);} 32 | set CopyFunctionCallback(PlusCallback) {cb::Callback1 callback2(callback);} 33 | 34 | set InvokeFunctionCallback(native) {(*callback)(&a);} 35 | set InvokeFunctionCallback(BoostFunction) {callback(&a);} 36 | set InvokeFunctionCallback(PlusCallback) {callback(&a);} 37 | 38 | set InvokeFunctionCallback2(native) {(*callback2)(&a);} 39 | set InvokeFunctionCallback2(BoostFunction) {callback2(&a);} 40 | set InvokeFunctionCallback2(PlusCallback) {callback2(&a);} 41 | 42 | 43 | puts {Creating C++ code for benchmarking.} 44 | #Create the bench marking code. 45 | set file [open {bench.cpp} {w}] 46 | 47 | puts $file " 48 | 49 | /* 50 | This file is created by bench.tcl. 51 | You can compile and run this benchmark 52 | by hand and it will produce a readable output. 53 | 54 | Note that higher optimization levels may just 55 | completely optimize out the native C++ tests. 56 | */ 57 | 58 | #include 59 | #include \"../callback.hpp\" 60 | #include 61 | #include 62 | 63 | //Loops to test with. 64 | const size_t iters = $iterations; 65 | 66 | //Just an example method to call. 67 | struct X { 68 | int Foo(int* a) {return ++(*a);} 69 | } x; 70 | 71 | 72 | //And an example free function to call. 73 | int FreeFoo(int* a) {return ++(*a);} 74 | 75 | 76 | double GetTime() { 77 | return (double)(clock()) / CLOCKS_PER_SEC; 78 | } 79 | " 80 | 81 | #Creates code for a self timing test function. 82 | proc loop {pretime time} { 83 | return " $pretime 84 | const double startTime = GetTime(); 85 | int a = 0; 86 | for (size_t i = 0; i < iters; ++i) 87 | { 88 | $time 89 | } 90 | return GetTime() - startTime;" 91 | } 92 | 93 | 94 | 95 | set CM CallbackMethod 96 | set CCM CreateAndCallbackMethod 97 | set CPCM CopyAndCallbackMethod 98 | 99 | set CF CallbackFunction 100 | set CCF CreateAndCallbackFunction 101 | set CPCF CopyAndCallbackFunction 102 | 103 | foreach method $methods { 104 | puts $file "\ndouble $CM\_$method\() { 105 | [loop $CreateMethodCallback($method) $InvokeMethodCallback($method)]\n}\n" 106 | 107 | puts $file "\ndouble $CCM\_$method\() { 108 | [loop {} "$CreateMethodCallback($method) $InvokeMethodCallback($method)"]\n}\n" 109 | 110 | puts $file "\ndouble $CPCM\_$method\() { 111 | [loop $CreateMethodCallback($method) "$CopyMethodCallback($method) $InvokeMethodCallback2($method)"]\n}\n" 112 | 113 | puts $file "\ndouble $CF\_$method\() { 114 | [loop $CreateFunctionCallback($method) $InvokeFunctionCallback($method)]\n}\n" 115 | 116 | puts $file "\ndouble $CCF\_$method\() { 117 | [loop {} "$CreateFunctionCallback($method) $InvokeFunctionCallback($method)"]\n}\n" 118 | 119 | puts $file "\ndouble $CPCF\_$method\() { 120 | [loop $CreateFunctionCallback($method) "$CopyFunctionCallback($method) $InvokeFunctionCallback2($method)"]\n}\n" 121 | } 122 | 123 | 124 | puts $file " 125 | int main() { " 126 | 127 | foreach method $methods { 128 | puts $file " 129 | printf(\"$method\\n\");" 130 | foreach test [list $CM $CCM $CPCM $CF $CCF $CPCF] { 131 | puts $file " printf(\"\t$test: %0.3f\\n\", $test\_$method\());" 132 | } 133 | puts $file " 134 | printf(\"\\n\");" 135 | } 136 | 137 | puts $file " 138 | return 0; 139 | }" 140 | 141 | close $file 142 | 143 | 144 | #Attempt to compile and run. 145 | set compileCommand {g++ bench.cpp -Wall -O1 -o bench.exe} 146 | puts "Compiling benchmark with: $compileCommand" 147 | set compileResult [exec -- {*}$compileCommand] 148 | if {$compileResult ne {}} { 149 | puts "Compiling errors:\n$compileResult" 150 | return 151 | } 152 | exec -- strip bench.exe 153 | 154 | 155 | puts {Running benchmark... This should take several minutes...} 156 | set runResult [exec -- bench.exe] 157 | puts "Benchmark Result:\n$runResult\n" 158 | 159 | 160 | set resultLines [split $runResult "\n"] 161 | set index {} 162 | foreach line $resultLines { 163 | switch -regexp -matchvar match -- $line { 164 | "^([^ ]+)$" {set index [lindex $match 1]} 165 | "^\t([^ :]+): ([.0-9]+)$" { 166 | set test [lindex $match 1] 167 | set time [lindex $match 2] 168 | set results($index,$test) $time 169 | } 170 | } 171 | } 172 | 173 | 174 | #Turn results into iterations per second. 175 | set maxTop 0.0 176 | set maxBottom 0.0 177 | foreach index [array names results] { 178 | set time $results($index) 179 | set perSec [expr {$iterations / 1000000.0 / $time}] 180 | 181 | set perSecResults($index) $perSec 182 | 183 | if {[string match native,*Function $index]} { 184 | set maxTop [expr {max($maxTop, $perSec)}] 185 | } else { 186 | set maxBottom [expr {max($maxBottom, $perSec)}] 187 | } 188 | } 189 | 190 | set maxBottom [expr {$maxBottom * 1.2}] 191 | 192 | 193 | 194 | 195 | #Write plot file for Ploticus. 196 | puts {Creating script for plotting.} 197 | set file [open plot.pl w] 198 | 199 | puts $file " 200 | #proc getdata 201 | fieldnameheader: yes 202 | data: 203 | tic method $CM $CCM $CPCM $CF $CCF $CPCF" 204 | 205 | foreach method $methods { 206 | set tic [expr {1+[lsearch -exact $methods $method]}] 207 | 208 | puts $file " $tic $method $perSecResults($method,$CM) $perSecResults($method,$CCM) $perSecResults($method,$CPCM) $perSecResults($method,$CF) $perSecResults($method,$CCF) $perSecResults($method,$CPCF)" 209 | } 210 | 211 | 212 | puts $file " 213 | #proc page 214 | font: Arial 215 | 216 | #proc areadef 217 | rectangle: 1 1 6 3 218 | 219 | xrange: 0.3 3.7 220 | xaxis.stubs: C++ Native 221 | Boost.Function 222 | PlusCallback 223 | 224 | yrange: 0 $maxBottom 225 | //yaxis.label: 10^6 Iterations Per Second 226 | //yaxis.labeldetails: adjust=-.2,.5 227 | yaxis.grid: color=gray(0.9) 228 | yaxis.stubs: inc 50 229 | yaxis.stubrange: 0 [expr {$maxBottom*.8}] 230 | " 231 | 232 | set i 0 233 | set tests {} 234 | 235 | lappend tests $CM {Method Callback} red 236 | lappend tests $CCM {Method Create and Callback} orange 237 | lappend tests $CPCM {Method Copy and Callback} yellow 238 | 239 | lappend tests $CF {Function Callback} green 240 | lappend tests $CCF {Function Create and Callback} blue 241 | lappend tests $CPCF {Function Copy and Callback} purple 242 | 243 | set testCount [expr {[llength $tests] / 3}] 244 | foreach {test label color} $tests { 245 | incr i 246 | 247 | puts $file " 248 | #proc bars 249 | color: $color 250 | legendlabel: $label 251 | locfield: tic 252 | lenfield: $test 253 | cluster: $i / $testCount 254 | outline: no 255 | truncate: yes 256 | #saveas $test 257 | " 258 | } 259 | 260 | 261 | #Replot the native function callbacks above the break. 262 | 263 | set breakBottom [expr {$maxTop - $maxBottom / 6.0}] 264 | 265 | puts $file " 266 | #proc legend 267 | format: down 268 | location: min+.25 min-.4 269 | extent: .5 270 | chunksep: 1 271 | 272 | 273 | #proc areadef 274 | title: Callback Benchmark\\n10^6 Iterations Per Second 275 | titledetails: align=R 276 | rectangle: 1 3 6 3.5 277 | 278 | xrange: 0.3 3.7 279 | 280 | yrange: $breakBottom $maxTop 281 | yaxis.grid: color=gray(0.9) 282 | yaxis.selflocatingstubs: text 283 | $maxTop [format %.0f $maxTop] 284 | " 285 | 286 | 287 | puts $file " 288 | #proc bars 289 | #clone $CF 290 | 291 | #proc bars 292 | #clone $CCF 293 | 294 | #proc bars 295 | #clone $CPCF 296 | 297 | #proc breakaxis 298 | axis: y 299 | location: axis 300 | breakpoint: [expr {$breakBottom-10}] 301 | 302 | //#proc breakaxis 303 | // axis: y 304 | // location: 1.2 305 | // breakpoint: $breakBottom 306 | // linelength: 1 307 | " 308 | 309 | close $file 310 | 311 | puts {Producing plot with ploticus.} 312 | exec -- pl -svg plot.pl 313 | -------------------------------------------------------------------------------- /callback.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PlusCallback 1.7 3 | * Copyright (c) 2009-2010 Lewis Van Winkle 4 | * 5 | * This software is provided 'as-is', without any express or implied 6 | * warranty. In no event will the authors be held liable for any damages 7 | * arising from the use of this software. 8 | * 9 | * Permission is granted to anyone to use this software for any purpose, 10 | * including commercial applications, and to alter it and redistribute it 11 | * freely, subject to the following restrictions: 12 | * 13 | * 1. The origin of this software must not be misrepresented; you must not 14 | * claim that you wrote the original software. If you use this software 15 | * in a product, an acknowledgment in the product documentation would be 16 | * appreciated but is not required. 17 | * 18 | * 2. Altered source versions must be plainly marked as such, and must not be 19 | * misrepresented as being the original software. 20 | * 21 | * 3. This notice may not be removed or altered from any source 22 | * distribution. 23 | */ 24 | 25 | 26 | #ifndef __CALLBACK_HPP__ 27 | #define __CALLBACK_HPP__ 28 | 29 | #include 30 | #include 31 | 32 | 33 | //PlusCallback 1.7 34 | //This library was built on 12.10.2010 to support 35 | //functions with a maximum of 9 parameters. 36 | #define CALLBACK_VERSION 1.7 37 | 38 | 39 | namespace cb 40 | { 41 | 42 | static const std::string unset_call_error("Attempting to invoke null callback."); 43 | 44 | 45 | 46 | ///Stores a callback for a function taking 0 parameters. 47 | ///\tparam R Callback function return type. 48 | template 49 | class Callback0 50 | { 51 | public: 52 | ///Constructs the callback to a specific object and member function. 53 | ///\param object Pointer to the object to call upon. Care should be taken that this object remains valid as long as the callback may be invoked. 54 | ///\param function Member function address to call. 55 | template 56 | Callback0(C* object, R (C::*function)()) 57 | :mCallback(new(&mMem) ChildMethod(object, function)) 58 | { 59 | } 60 | 61 | ///Constructs the callback to a free function or static member function. 62 | ///\param function Free function address to call. 63 | Callback0(R (*function)()) 64 | :mCallback(new(&mMem) ChildFree(function)) 65 | { 66 | } 67 | 68 | ///Constructs a callback that can later be set. 69 | Callback0() 70 | :mCallback(0) 71 | { 72 | } 73 | 74 | Callback0(const Callback0& c) 75 | :mCallback(c.mCallback) 76 | { 77 | if (mCallback) 78 | { 79 | memcpy(mMem, c.mMem, sizeof(mMem)); 80 | mCallback = reinterpret_cast(&mMem); 81 | } 82 | } 83 | 84 | Callback0& operator=(const Callback0& rhs) 85 | { 86 | mCallback = rhs.mCallback; 87 | if (mCallback) 88 | { 89 | memcpy(mMem, rhs.mMem, sizeof(mMem)); 90 | mCallback = reinterpret_cast(&mMem); 91 | } 92 | 93 | return *this; 94 | } 95 | 96 | ~Callback0() 97 | { 98 | } 99 | 100 | ///Sets the callback to a specific object and member function. 101 | ///\param object Pointer to the object to call upon. Care should be taken that this object remains valid as long as the callback may be invoked. 102 | ///\param function Member function address to call. 103 | template 104 | void Reset(C* object, R (C::*function)()) 105 | { 106 | mCallback = new(&mMem) ChildMethod(object, function); 107 | } 108 | 109 | ///Sets the callback to a free function or static member function. 110 | ///\param function Free function address to call. 111 | void Reset(R (*function)()) 112 | { 113 | mCallback = new(&mMem) ChildFree(function); 114 | } 115 | 116 | ///Resests to callback to nothing. 117 | void Reset() 118 | { 119 | mCallback = 0; 120 | } 121 | 122 | ///Note that comparison operators may not work with virtual function callbacks. 123 | bool operator==(const Callback0& rhs) const 124 | { 125 | if (mCallback && rhs.mCallback) 126 | return (*mCallback) == (*(rhs.mCallback)); 127 | else 128 | return mCallback == rhs.mCallback; 129 | } 130 | 131 | ///Note that comparison operators may not work with virtual function callbacks. 132 | bool operator!=(const Callback0& rhs) const 133 | { 134 | return !(*this == rhs); 135 | } 136 | 137 | ///Note that comparison operators may not work with virtual function callbacks. 138 | bool operator<(const Callback0 rhs) const 139 | { 140 | if (mCallback && rhs.mCallback) 141 | return (*mCallback) < (*(rhs.mCallback)); 142 | else 143 | return mCallback < rhs.mCallback; 144 | } 145 | 146 | ///Returns true if the callback has been set, or false if the callback is not set and is invalid. 147 | bool IsSet() const 148 | { 149 | return mCallback; 150 | } 151 | 152 | ///Invokes the callback. 153 | R operator()() const 154 | { 155 | if (mCallback) 156 | return (*mCallback)(); 157 | else 158 | throw std::runtime_error(unset_call_error); 159 | } 160 | 161 | ///Invokes the callback. This function can sometimes be more convenient than the operator(), which does the same thing. 162 | R Call() const 163 | { 164 | if (mCallback) 165 | return (*mCallback)(); 166 | else 167 | throw std::runtime_error(unset_call_error); 168 | } 169 | 170 | private: 171 | class Base 172 | { 173 | public: 174 | Base(){} 175 | virtual R operator()() = 0; 176 | virtual bool operator==(const Base& rhs) const = 0; 177 | virtual bool operator<(const Base& rhs) const = 0; 178 | virtual void* Comp() const = 0; //Returns a pointer used in comparisons. 179 | }; 180 | 181 | class ChildFree : public Base 182 | { 183 | public: 184 | ChildFree(R (*function)()) 185 | :mFunc(function) 186 | {} 187 | 188 | virtual R operator()() 189 | { 190 | return mFunc(); 191 | } 192 | 193 | virtual bool operator==(const Base& rhs) const 194 | { 195 | const ChildFree* const r = dynamic_cast(&rhs); 196 | if (r) 197 | return (mFunc == r->mFunc); 198 | else 199 | return false; 200 | } 201 | 202 | virtual bool operator<(const Base& rhs) const 203 | { 204 | const ChildFree* const r = dynamic_cast(&rhs); 205 | if (r) 206 | return mFunc < r->mFunc; 207 | else 208 | return true; //Free functions will always be less than methods (because comp returns 0). 209 | } 210 | 211 | virtual void* Comp() const 212 | { 213 | return 0; 214 | } 215 | 216 | private: 217 | R (*const mFunc)(); 218 | }; 219 | 220 | template 221 | class ChildMethod : public Base 222 | { 223 | public: 224 | ChildMethod(C* object, R (C::*function)()) 225 | :mObj(object), mFunc(function) 226 | {} 227 | 228 | virtual R operator()() 229 | { 230 | return (mObj->*mFunc)(); 231 | } 232 | 233 | virtual bool operator==(const Base& rhs) const 234 | { 235 | const ChildMethod* const r = dynamic_cast*>(&rhs); 236 | if (r) 237 | return (mObj == r->mObj) && (mFunc == r->mFunc); 238 | else 239 | return false; 240 | } 241 | 242 | virtual bool operator<(const Base& rhs) const 243 | { 244 | const ChildMethod* const r = dynamic_cast*>(&rhs); 245 | if (r) 246 | { 247 | if (mObj != r->mObj) 248 | return mObj < r->mObj; 249 | else 250 | return 0 > memcmp((void*)&mFunc, (void*)&(r->mFunc), sizeof(mFunc)); 251 | } 252 | else 253 | return mObj < rhs.Comp(); 254 | } 255 | 256 | virtual void* Comp() const 257 | { 258 | return mObj; 259 | } 260 | 261 | private: 262 | C* const mObj; 263 | R (C::* const mFunc)(); 264 | }; 265 | 266 | ///This class is only to find the worst case method pointer size. 267 | class unknown; 268 | 269 | char mMem[sizeof(ChildMethod)]; //Reserve memory for creating useful objects later. 270 | Base* mCallback; 271 | }; 272 | 273 | 274 | ///Helper function to construct a callback without bothering to specify template parameters. 275 | template 276 | Callback0 Make0(C* object, R (C::*function)()) 277 | { 278 | return Callback0(object, function); 279 | } 280 | 281 | ///Helper function to construct a callback without bothering to specify template parameters. 282 | template 283 | Callback0 Make0(R (*function)()) 284 | { 285 | return Callback0(function); 286 | } 287 | 288 | 289 | ///Stores a callback for a function taking 1 parameters. 290 | ///\tparam R Callback function return type. 291 | template 292 | class Callback1 293 | { 294 | public: 295 | ///Constructs the callback to a specific object and member function. 296 | ///\param object Pointer to the object to call upon. Care should be taken that this object remains valid as long as the callback may be invoked. 297 | ///\param function Member function address to call. 298 | template 299 | Callback1(C* object, R (C::*function)(T0 t0)) 300 | :mCallback(new(&mMem) ChildMethod(object, function)) 301 | { 302 | } 303 | 304 | ///Constructs the callback to a free function or static member function. 305 | ///\param function Free function address to call. 306 | Callback1(R (*function)(T0 t0)) 307 | :mCallback(new(&mMem) ChildFree(function)) 308 | { 309 | } 310 | 311 | ///Constructs a callback that can later be set. 312 | Callback1() 313 | :mCallback(0) 314 | { 315 | } 316 | 317 | Callback1(const Callback1& c) 318 | :mCallback(c.mCallback) 319 | { 320 | if (mCallback) 321 | { 322 | memcpy(mMem, c.mMem, sizeof(mMem)); 323 | mCallback = reinterpret_cast(&mMem); 324 | } 325 | } 326 | 327 | Callback1& operator=(const Callback1& rhs) 328 | { 329 | mCallback = rhs.mCallback; 330 | if (mCallback) 331 | { 332 | memcpy(mMem, rhs.mMem, sizeof(mMem)); 333 | mCallback = reinterpret_cast(&mMem); 334 | } 335 | 336 | return *this; 337 | } 338 | 339 | ~Callback1() 340 | { 341 | } 342 | 343 | ///Sets the callback to a specific object and member function. 344 | ///\param object Pointer to the object to call upon. Care should be taken that this object remains valid as long as the callback may be invoked. 345 | ///\param function Member function address to call. 346 | template 347 | void Reset(C* object, R (C::*function)(T0 t0)) 348 | { 349 | mCallback = new(&mMem) ChildMethod(object, function); 350 | } 351 | 352 | ///Sets the callback to a free function or static member function. 353 | ///\param function Free function address to call. 354 | void Reset(R (*function)(T0 t0)) 355 | { 356 | mCallback = new(&mMem) ChildFree(function); 357 | } 358 | 359 | ///Resests to callback to nothing. 360 | void Reset() 361 | { 362 | mCallback = 0; 363 | } 364 | 365 | ///Note that comparison operators may not work with virtual function callbacks. 366 | bool operator==(const Callback1& rhs) const 367 | { 368 | if (mCallback && rhs.mCallback) 369 | return (*mCallback) == (*(rhs.mCallback)); 370 | else 371 | return mCallback == rhs.mCallback; 372 | } 373 | 374 | ///Note that comparison operators may not work with virtual function callbacks. 375 | bool operator!=(const Callback1& rhs) const 376 | { 377 | return !(*this == rhs); 378 | } 379 | 380 | ///Note that comparison operators may not work with virtual function callbacks. 381 | bool operator<(const Callback1 rhs) const 382 | { 383 | if (mCallback && rhs.mCallback) 384 | return (*mCallback) < (*(rhs.mCallback)); 385 | else 386 | return mCallback < rhs.mCallback; 387 | } 388 | 389 | ///Returns true if the callback has been set, or false if the callback is not set and is invalid. 390 | bool IsSet() const 391 | { 392 | return mCallback; 393 | } 394 | 395 | ///Invokes the callback. 396 | R operator()(T0 t0) const 397 | { 398 | if (mCallback) 399 | return (*mCallback)(t0); 400 | else 401 | throw std::runtime_error(unset_call_error); 402 | } 403 | 404 | ///Invokes the callback. This function can sometimes be more convenient than the operator(), which does the same thing. 405 | R Call(T0 t0) const 406 | { 407 | if (mCallback) 408 | return (*mCallback)(t0); 409 | else 410 | throw std::runtime_error(unset_call_error); 411 | } 412 | 413 | private: 414 | class Base 415 | { 416 | public: 417 | Base(){} 418 | virtual R operator()(T0 t0) = 0; 419 | virtual bool operator==(const Base& rhs) const = 0; 420 | virtual bool operator<(const Base& rhs) const = 0; 421 | virtual void* Comp() const = 0; //Returns a pointer used in comparisons. 422 | }; 423 | 424 | class ChildFree : public Base 425 | { 426 | public: 427 | ChildFree(R (*function)(T0 t0)) 428 | :mFunc(function) 429 | {} 430 | 431 | virtual R operator()(T0 t0) 432 | { 433 | return mFunc(t0); 434 | } 435 | 436 | virtual bool operator==(const Base& rhs) const 437 | { 438 | const ChildFree* const r = dynamic_cast(&rhs); 439 | if (r) 440 | return (mFunc == r->mFunc); 441 | else 442 | return false; 443 | } 444 | 445 | virtual bool operator<(const Base& rhs) const 446 | { 447 | const ChildFree* const r = dynamic_cast(&rhs); 448 | if (r) 449 | return mFunc < r->mFunc; 450 | else 451 | return true; //Free functions will always be less than methods (because comp returns 0). 452 | } 453 | 454 | virtual void* Comp() const 455 | { 456 | return 0; 457 | } 458 | 459 | private: 460 | R (*const mFunc)(T0 t0); 461 | }; 462 | 463 | template 464 | class ChildMethod : public Base 465 | { 466 | public: 467 | ChildMethod(C* object, R (C::*function)(T0 t0)) 468 | :mObj(object), mFunc(function) 469 | {} 470 | 471 | virtual R operator()(T0 t0) 472 | { 473 | return (mObj->*mFunc)(t0); 474 | } 475 | 476 | virtual bool operator==(const Base& rhs) const 477 | { 478 | const ChildMethod* const r = dynamic_cast*>(&rhs); 479 | if (r) 480 | return (mObj == r->mObj) && (mFunc == r->mFunc); 481 | else 482 | return false; 483 | } 484 | 485 | virtual bool operator<(const Base& rhs) const 486 | { 487 | const ChildMethod* const r = dynamic_cast*>(&rhs); 488 | if (r) 489 | { 490 | if (mObj != r->mObj) 491 | return mObj < r->mObj; 492 | else 493 | return 0 > memcmp((void*)&mFunc, (void*)&(r->mFunc), sizeof(mFunc)); 494 | } 495 | else 496 | return mObj < rhs.Comp(); 497 | } 498 | 499 | virtual void* Comp() const 500 | { 501 | return mObj; 502 | } 503 | 504 | private: 505 | C* const mObj; 506 | R (C::* const mFunc)(T0 t0); 507 | }; 508 | 509 | ///This class is only to find the worst case method pointer size. 510 | class unknown; 511 | 512 | char mMem[sizeof(ChildMethod)]; //Reserve memory for creating useful objects later. 513 | Base* mCallback; 514 | }; 515 | 516 | 517 | ///Helper function to construct a callback without bothering to specify template parameters. 518 | template 519 | Callback1 Make1(C* object, R (C::*function)(T0 t0)) 520 | { 521 | return Callback1(object, function); 522 | } 523 | 524 | ///Helper function to construct a callback without bothering to specify template parameters. 525 | template 526 | Callback1 Make1(R (*function)(T0 t0)) 527 | { 528 | return Callback1(function); 529 | } 530 | 531 | 532 | ///Stores a callback for a function taking 2 parameters. 533 | ///\tparam R Callback function return type. 534 | template 535 | class Callback2 536 | { 537 | public: 538 | ///Constructs the callback to a specific object and member function. 539 | ///\param object Pointer to the object to call upon. Care should be taken that this object remains valid as long as the callback may be invoked. 540 | ///\param function Member function address to call. 541 | template 542 | Callback2(C* object, R (C::*function)(T0 t0, T1 t1)) 543 | :mCallback(new(&mMem) ChildMethod(object, function)) 544 | { 545 | } 546 | 547 | ///Constructs the callback to a free function or static member function. 548 | ///\param function Free function address to call. 549 | Callback2(R (*function)(T0 t0, T1 t1)) 550 | :mCallback(new(&mMem) ChildFree(function)) 551 | { 552 | } 553 | 554 | ///Constructs a callback that can later be set. 555 | Callback2() 556 | :mCallback(0) 557 | { 558 | } 559 | 560 | Callback2(const Callback2& c) 561 | :mCallback(c.mCallback) 562 | { 563 | if (mCallback) 564 | { 565 | memcpy(mMem, c.mMem, sizeof(mMem)); 566 | mCallback = reinterpret_cast(&mMem); 567 | } 568 | } 569 | 570 | Callback2& operator=(const Callback2& rhs) 571 | { 572 | mCallback = rhs.mCallback; 573 | if (mCallback) 574 | { 575 | memcpy(mMem, rhs.mMem, sizeof(mMem)); 576 | mCallback = reinterpret_cast(&mMem); 577 | } 578 | 579 | return *this; 580 | } 581 | 582 | ~Callback2() 583 | { 584 | } 585 | 586 | ///Sets the callback to a specific object and member function. 587 | ///\param object Pointer to the object to call upon. Care should be taken that this object remains valid as long as the callback may be invoked. 588 | ///\param function Member function address to call. 589 | template 590 | void Reset(C* object, R (C::*function)(T0 t0, T1 t1)) 591 | { 592 | mCallback = new(&mMem) ChildMethod(object, function); 593 | } 594 | 595 | ///Sets the callback to a free function or static member function. 596 | ///\param function Free function address to call. 597 | void Reset(R (*function)(T0 t0, T1 t1)) 598 | { 599 | mCallback = new(&mMem) ChildFree(function); 600 | } 601 | 602 | ///Resests to callback to nothing. 603 | void Reset() 604 | { 605 | mCallback = 0; 606 | } 607 | 608 | ///Note that comparison operators may not work with virtual function callbacks. 609 | bool operator==(const Callback2& rhs) const 610 | { 611 | if (mCallback && rhs.mCallback) 612 | return (*mCallback) == (*(rhs.mCallback)); 613 | else 614 | return mCallback == rhs.mCallback; 615 | } 616 | 617 | ///Note that comparison operators may not work with virtual function callbacks. 618 | bool operator!=(const Callback2& rhs) const 619 | { 620 | return !(*this == rhs); 621 | } 622 | 623 | ///Note that comparison operators may not work with virtual function callbacks. 624 | bool operator<(const Callback2 rhs) const 625 | { 626 | if (mCallback && rhs.mCallback) 627 | return (*mCallback) < (*(rhs.mCallback)); 628 | else 629 | return mCallback < rhs.mCallback; 630 | } 631 | 632 | ///Returns true if the callback has been set, or false if the callback is not set and is invalid. 633 | bool IsSet() const 634 | { 635 | return mCallback; 636 | } 637 | 638 | ///Invokes the callback. 639 | R operator()(T0 t0, T1 t1) const 640 | { 641 | if (mCallback) 642 | return (*mCallback)(t0, t1); 643 | else 644 | throw std::runtime_error(unset_call_error); 645 | } 646 | 647 | ///Invokes the callback. This function can sometimes be more convenient than the operator(), which does the same thing. 648 | R Call(T0 t0, T1 t1) const 649 | { 650 | if (mCallback) 651 | return (*mCallback)(t0, t1); 652 | else 653 | throw std::runtime_error(unset_call_error); 654 | } 655 | 656 | private: 657 | class Base 658 | { 659 | public: 660 | Base(){} 661 | virtual R operator()(T0 t0, T1 t1) = 0; 662 | virtual bool operator==(const Base& rhs) const = 0; 663 | virtual bool operator<(const Base& rhs) const = 0; 664 | virtual void* Comp() const = 0; //Returns a pointer used in comparisons. 665 | }; 666 | 667 | class ChildFree : public Base 668 | { 669 | public: 670 | ChildFree(R (*function)(T0 t0, T1 t1)) 671 | :mFunc(function) 672 | {} 673 | 674 | virtual R operator()(T0 t0, T1 t1) 675 | { 676 | return mFunc(t0, t1); 677 | } 678 | 679 | virtual bool operator==(const Base& rhs) const 680 | { 681 | const ChildFree* const r = dynamic_cast(&rhs); 682 | if (r) 683 | return (mFunc == r->mFunc); 684 | else 685 | return false; 686 | } 687 | 688 | virtual bool operator<(const Base& rhs) const 689 | { 690 | const ChildFree* const r = dynamic_cast(&rhs); 691 | if (r) 692 | return mFunc < r->mFunc; 693 | else 694 | return true; //Free functions will always be less than methods (because comp returns 0). 695 | } 696 | 697 | virtual void* Comp() const 698 | { 699 | return 0; 700 | } 701 | 702 | private: 703 | R (*const mFunc)(T0 t0, T1 t1); 704 | }; 705 | 706 | template 707 | class ChildMethod : public Base 708 | { 709 | public: 710 | ChildMethod(C* object, R (C::*function)(T0 t0, T1 t1)) 711 | :mObj(object), mFunc(function) 712 | {} 713 | 714 | virtual R operator()(T0 t0, T1 t1) 715 | { 716 | return (mObj->*mFunc)(t0, t1); 717 | } 718 | 719 | virtual bool operator==(const Base& rhs) const 720 | { 721 | const ChildMethod* const r = dynamic_cast*>(&rhs); 722 | if (r) 723 | return (mObj == r->mObj) && (mFunc == r->mFunc); 724 | else 725 | return false; 726 | } 727 | 728 | virtual bool operator<(const Base& rhs) const 729 | { 730 | const ChildMethod* const r = dynamic_cast*>(&rhs); 731 | if (r) 732 | { 733 | if (mObj != r->mObj) 734 | return mObj < r->mObj; 735 | else 736 | return 0 > memcmp((void*)&mFunc, (void*)&(r->mFunc), sizeof(mFunc)); 737 | } 738 | else 739 | return mObj < rhs.Comp(); 740 | } 741 | 742 | virtual void* Comp() const 743 | { 744 | return mObj; 745 | } 746 | 747 | private: 748 | C* const mObj; 749 | R (C::* const mFunc)(T0 t0, T1 t1); 750 | }; 751 | 752 | ///This class is only to find the worst case method pointer size. 753 | class unknown; 754 | 755 | char mMem[sizeof(ChildMethod)]; //Reserve memory for creating useful objects later. 756 | Base* mCallback; 757 | }; 758 | 759 | 760 | ///Helper function to construct a callback without bothering to specify template parameters. 761 | template 762 | Callback2 Make2(C* object, R (C::*function)(T0 t0, T1 t1)) 763 | { 764 | return Callback2(object, function); 765 | } 766 | 767 | ///Helper function to construct a callback without bothering to specify template parameters. 768 | template 769 | Callback2 Make2(R (*function)(T0 t0, T1 t1)) 770 | { 771 | return Callback2(function); 772 | } 773 | 774 | 775 | ///Stores a callback for a function taking 3 parameters. 776 | ///\tparam R Callback function return type. 777 | template 778 | class Callback3 779 | { 780 | public: 781 | ///Constructs the callback to a specific object and member function. 782 | ///\param object Pointer to the object to call upon. Care should be taken that this object remains valid as long as the callback may be invoked. 783 | ///\param function Member function address to call. 784 | template 785 | Callback3(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2)) 786 | :mCallback(new(&mMem) ChildMethod(object, function)) 787 | { 788 | } 789 | 790 | ///Constructs the callback to a free function or static member function. 791 | ///\param function Free function address to call. 792 | Callback3(R (*function)(T0 t0, T1 t1, T2 t2)) 793 | :mCallback(new(&mMem) ChildFree(function)) 794 | { 795 | } 796 | 797 | ///Constructs a callback that can later be set. 798 | Callback3() 799 | :mCallback(0) 800 | { 801 | } 802 | 803 | Callback3(const Callback3& c) 804 | :mCallback(c.mCallback) 805 | { 806 | if (mCallback) 807 | { 808 | memcpy(mMem, c.mMem, sizeof(mMem)); 809 | mCallback = reinterpret_cast(&mMem); 810 | } 811 | } 812 | 813 | Callback3& operator=(const Callback3& rhs) 814 | { 815 | mCallback = rhs.mCallback; 816 | if (mCallback) 817 | { 818 | memcpy(mMem, rhs.mMem, sizeof(mMem)); 819 | mCallback = reinterpret_cast(&mMem); 820 | } 821 | 822 | return *this; 823 | } 824 | 825 | ~Callback3() 826 | { 827 | } 828 | 829 | ///Sets the callback to a specific object and member function. 830 | ///\param object Pointer to the object to call upon. Care should be taken that this object remains valid as long as the callback may be invoked. 831 | ///\param function Member function address to call. 832 | template 833 | void Reset(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2)) 834 | { 835 | mCallback = new(&mMem) ChildMethod(object, function); 836 | } 837 | 838 | ///Sets the callback to a free function or static member function. 839 | ///\param function Free function address to call. 840 | void Reset(R (*function)(T0 t0, T1 t1, T2 t2)) 841 | { 842 | mCallback = new(&mMem) ChildFree(function); 843 | } 844 | 845 | ///Resests to callback to nothing. 846 | void Reset() 847 | { 848 | mCallback = 0; 849 | } 850 | 851 | ///Note that comparison operators may not work with virtual function callbacks. 852 | bool operator==(const Callback3& rhs) const 853 | { 854 | if (mCallback && rhs.mCallback) 855 | return (*mCallback) == (*(rhs.mCallback)); 856 | else 857 | return mCallback == rhs.mCallback; 858 | } 859 | 860 | ///Note that comparison operators may not work with virtual function callbacks. 861 | bool operator!=(const Callback3& rhs) const 862 | { 863 | return !(*this == rhs); 864 | } 865 | 866 | ///Note that comparison operators may not work with virtual function callbacks. 867 | bool operator<(const Callback3 rhs) const 868 | { 869 | if (mCallback && rhs.mCallback) 870 | return (*mCallback) < (*(rhs.mCallback)); 871 | else 872 | return mCallback < rhs.mCallback; 873 | } 874 | 875 | ///Returns true if the callback has been set, or false if the callback is not set and is invalid. 876 | bool IsSet() const 877 | { 878 | return mCallback; 879 | } 880 | 881 | ///Invokes the callback. 882 | R operator()(T0 t0, T1 t1, T2 t2) const 883 | { 884 | if (mCallback) 885 | return (*mCallback)(t0, t1, t2); 886 | else 887 | throw std::runtime_error(unset_call_error); 888 | } 889 | 890 | ///Invokes the callback. This function can sometimes be more convenient than the operator(), which does the same thing. 891 | R Call(T0 t0, T1 t1, T2 t2) const 892 | { 893 | if (mCallback) 894 | return (*mCallback)(t0, t1, t2); 895 | else 896 | throw std::runtime_error(unset_call_error); 897 | } 898 | 899 | private: 900 | class Base 901 | { 902 | public: 903 | Base(){} 904 | virtual R operator()(T0 t0, T1 t1, T2 t2) = 0; 905 | virtual bool operator==(const Base& rhs) const = 0; 906 | virtual bool operator<(const Base& rhs) const = 0; 907 | virtual void* Comp() const = 0; //Returns a pointer used in comparisons. 908 | }; 909 | 910 | class ChildFree : public Base 911 | { 912 | public: 913 | ChildFree(R (*function)(T0 t0, T1 t1, T2 t2)) 914 | :mFunc(function) 915 | {} 916 | 917 | virtual R operator()(T0 t0, T1 t1, T2 t2) 918 | { 919 | return mFunc(t0, t1, t2); 920 | } 921 | 922 | virtual bool operator==(const Base& rhs) const 923 | { 924 | const ChildFree* const r = dynamic_cast(&rhs); 925 | if (r) 926 | return (mFunc == r->mFunc); 927 | else 928 | return false; 929 | } 930 | 931 | virtual bool operator<(const Base& rhs) const 932 | { 933 | const ChildFree* const r = dynamic_cast(&rhs); 934 | if (r) 935 | return mFunc < r->mFunc; 936 | else 937 | return true; //Free functions will always be less than methods (because comp returns 0). 938 | } 939 | 940 | virtual void* Comp() const 941 | { 942 | return 0; 943 | } 944 | 945 | private: 946 | R (*const mFunc)(T0 t0, T1 t1, T2 t2); 947 | }; 948 | 949 | template 950 | class ChildMethod : public Base 951 | { 952 | public: 953 | ChildMethod(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2)) 954 | :mObj(object), mFunc(function) 955 | {} 956 | 957 | virtual R operator()(T0 t0, T1 t1, T2 t2) 958 | { 959 | return (mObj->*mFunc)(t0, t1, t2); 960 | } 961 | 962 | virtual bool operator==(const Base& rhs) const 963 | { 964 | const ChildMethod* const r = dynamic_cast*>(&rhs); 965 | if (r) 966 | return (mObj == r->mObj) && (mFunc == r->mFunc); 967 | else 968 | return false; 969 | } 970 | 971 | virtual bool operator<(const Base& rhs) const 972 | { 973 | const ChildMethod* const r = dynamic_cast*>(&rhs); 974 | if (r) 975 | { 976 | if (mObj != r->mObj) 977 | return mObj < r->mObj; 978 | else 979 | return 0 > memcmp((void*)&mFunc, (void*)&(r->mFunc), sizeof(mFunc)); 980 | } 981 | else 982 | return mObj < rhs.Comp(); 983 | } 984 | 985 | virtual void* Comp() const 986 | { 987 | return mObj; 988 | } 989 | 990 | private: 991 | C* const mObj; 992 | R (C::* const mFunc)(T0 t0, T1 t1, T2 t2); 993 | }; 994 | 995 | ///This class is only to find the worst case method pointer size. 996 | class unknown; 997 | 998 | char mMem[sizeof(ChildMethod)]; //Reserve memory for creating useful objects later. 999 | Base* mCallback; 1000 | }; 1001 | 1002 | 1003 | ///Helper function to construct a callback without bothering to specify template parameters. 1004 | template 1005 | Callback3 Make3(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2)) 1006 | { 1007 | return Callback3(object, function); 1008 | } 1009 | 1010 | ///Helper function to construct a callback without bothering to specify template parameters. 1011 | template 1012 | Callback3 Make3(R (*function)(T0 t0, T1 t1, T2 t2)) 1013 | { 1014 | return Callback3(function); 1015 | } 1016 | 1017 | 1018 | ///Stores a callback for a function taking 4 parameters. 1019 | ///\tparam R Callback function return type. 1020 | template 1021 | class Callback4 1022 | { 1023 | public: 1024 | ///Constructs the callback to a specific object and member function. 1025 | ///\param object Pointer to the object to call upon. Care should be taken that this object remains valid as long as the callback may be invoked. 1026 | ///\param function Member function address to call. 1027 | template 1028 | Callback4(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3)) 1029 | :mCallback(new(&mMem) ChildMethod(object, function)) 1030 | { 1031 | } 1032 | 1033 | ///Constructs the callback to a free function or static member function. 1034 | ///\param function Free function address to call. 1035 | Callback4(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3)) 1036 | :mCallback(new(&mMem) ChildFree(function)) 1037 | { 1038 | } 1039 | 1040 | ///Constructs a callback that can later be set. 1041 | Callback4() 1042 | :mCallback(0) 1043 | { 1044 | } 1045 | 1046 | Callback4(const Callback4& c) 1047 | :mCallback(c.mCallback) 1048 | { 1049 | if (mCallback) 1050 | { 1051 | memcpy(mMem, c.mMem, sizeof(mMem)); 1052 | mCallback = reinterpret_cast(&mMem); 1053 | } 1054 | } 1055 | 1056 | Callback4& operator=(const Callback4& rhs) 1057 | { 1058 | mCallback = rhs.mCallback; 1059 | if (mCallback) 1060 | { 1061 | memcpy(mMem, rhs.mMem, sizeof(mMem)); 1062 | mCallback = reinterpret_cast(&mMem); 1063 | } 1064 | 1065 | return *this; 1066 | } 1067 | 1068 | ~Callback4() 1069 | { 1070 | } 1071 | 1072 | ///Sets the callback to a specific object and member function. 1073 | ///\param object Pointer to the object to call upon. Care should be taken that this object remains valid as long as the callback may be invoked. 1074 | ///\param function Member function address to call. 1075 | template 1076 | void Reset(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3)) 1077 | { 1078 | mCallback = new(&mMem) ChildMethod(object, function); 1079 | } 1080 | 1081 | ///Sets the callback to a free function or static member function. 1082 | ///\param function Free function address to call. 1083 | void Reset(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3)) 1084 | { 1085 | mCallback = new(&mMem) ChildFree(function); 1086 | } 1087 | 1088 | ///Resests to callback to nothing. 1089 | void Reset() 1090 | { 1091 | mCallback = 0; 1092 | } 1093 | 1094 | ///Note that comparison operators may not work with virtual function callbacks. 1095 | bool operator==(const Callback4& rhs) const 1096 | { 1097 | if (mCallback && rhs.mCallback) 1098 | return (*mCallback) == (*(rhs.mCallback)); 1099 | else 1100 | return mCallback == rhs.mCallback; 1101 | } 1102 | 1103 | ///Note that comparison operators may not work with virtual function callbacks. 1104 | bool operator!=(const Callback4& rhs) const 1105 | { 1106 | return !(*this == rhs); 1107 | } 1108 | 1109 | ///Note that comparison operators may not work with virtual function callbacks. 1110 | bool operator<(const Callback4 rhs) const 1111 | { 1112 | if (mCallback && rhs.mCallback) 1113 | return (*mCallback) < (*(rhs.mCallback)); 1114 | else 1115 | return mCallback < rhs.mCallback; 1116 | } 1117 | 1118 | ///Returns true if the callback has been set, or false if the callback is not set and is invalid. 1119 | bool IsSet() const 1120 | { 1121 | return mCallback; 1122 | } 1123 | 1124 | ///Invokes the callback. 1125 | R operator()(T0 t0, T1 t1, T2 t2, T3 t3) const 1126 | { 1127 | if (mCallback) 1128 | return (*mCallback)(t0, t1, t2, t3); 1129 | else 1130 | throw std::runtime_error(unset_call_error); 1131 | } 1132 | 1133 | ///Invokes the callback. This function can sometimes be more convenient than the operator(), which does the same thing. 1134 | R Call(T0 t0, T1 t1, T2 t2, T3 t3) const 1135 | { 1136 | if (mCallback) 1137 | return (*mCallback)(t0, t1, t2, t3); 1138 | else 1139 | throw std::runtime_error(unset_call_error); 1140 | } 1141 | 1142 | private: 1143 | class Base 1144 | { 1145 | public: 1146 | Base(){} 1147 | virtual R operator()(T0 t0, T1 t1, T2 t2, T3 t3) = 0; 1148 | virtual bool operator==(const Base& rhs) const = 0; 1149 | virtual bool operator<(const Base& rhs) const = 0; 1150 | virtual void* Comp() const = 0; //Returns a pointer used in comparisons. 1151 | }; 1152 | 1153 | class ChildFree : public Base 1154 | { 1155 | public: 1156 | ChildFree(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3)) 1157 | :mFunc(function) 1158 | {} 1159 | 1160 | virtual R operator()(T0 t0, T1 t1, T2 t2, T3 t3) 1161 | { 1162 | return mFunc(t0, t1, t2, t3); 1163 | } 1164 | 1165 | virtual bool operator==(const Base& rhs) const 1166 | { 1167 | const ChildFree* const r = dynamic_cast(&rhs); 1168 | if (r) 1169 | return (mFunc == r->mFunc); 1170 | else 1171 | return false; 1172 | } 1173 | 1174 | virtual bool operator<(const Base& rhs) const 1175 | { 1176 | const ChildFree* const r = dynamic_cast(&rhs); 1177 | if (r) 1178 | return mFunc < r->mFunc; 1179 | else 1180 | return true; //Free functions will always be less than methods (because comp returns 0). 1181 | } 1182 | 1183 | virtual void* Comp() const 1184 | { 1185 | return 0; 1186 | } 1187 | 1188 | private: 1189 | R (*const mFunc)(T0 t0, T1 t1, T2 t2, T3 t3); 1190 | }; 1191 | 1192 | template 1193 | class ChildMethod : public Base 1194 | { 1195 | public: 1196 | ChildMethod(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3)) 1197 | :mObj(object), mFunc(function) 1198 | {} 1199 | 1200 | virtual R operator()(T0 t0, T1 t1, T2 t2, T3 t3) 1201 | { 1202 | return (mObj->*mFunc)(t0, t1, t2, t3); 1203 | } 1204 | 1205 | virtual bool operator==(const Base& rhs) const 1206 | { 1207 | const ChildMethod* const r = dynamic_cast*>(&rhs); 1208 | if (r) 1209 | return (mObj == r->mObj) && (mFunc == r->mFunc); 1210 | else 1211 | return false; 1212 | } 1213 | 1214 | virtual bool operator<(const Base& rhs) const 1215 | { 1216 | const ChildMethod* const r = dynamic_cast*>(&rhs); 1217 | if (r) 1218 | { 1219 | if (mObj != r->mObj) 1220 | return mObj < r->mObj; 1221 | else 1222 | return 0 > memcmp((void*)&mFunc, (void*)&(r->mFunc), sizeof(mFunc)); 1223 | } 1224 | else 1225 | return mObj < rhs.Comp(); 1226 | } 1227 | 1228 | virtual void* Comp() const 1229 | { 1230 | return mObj; 1231 | } 1232 | 1233 | private: 1234 | C* const mObj; 1235 | R (C::* const mFunc)(T0 t0, T1 t1, T2 t2, T3 t3); 1236 | }; 1237 | 1238 | ///This class is only to find the worst case method pointer size. 1239 | class unknown; 1240 | 1241 | char mMem[sizeof(ChildMethod)]; //Reserve memory for creating useful objects later. 1242 | Base* mCallback; 1243 | }; 1244 | 1245 | 1246 | ///Helper function to construct a callback without bothering to specify template parameters. 1247 | template 1248 | Callback4 Make4(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3)) 1249 | { 1250 | return Callback4(object, function); 1251 | } 1252 | 1253 | ///Helper function to construct a callback without bothering to specify template parameters. 1254 | template 1255 | Callback4 Make4(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3)) 1256 | { 1257 | return Callback4(function); 1258 | } 1259 | 1260 | 1261 | ///Stores a callback for a function taking 5 parameters. 1262 | ///\tparam R Callback function return type. 1263 | template 1264 | class Callback5 1265 | { 1266 | public: 1267 | ///Constructs the callback to a specific object and member function. 1268 | ///\param object Pointer to the object to call upon. Care should be taken that this object remains valid as long as the callback may be invoked. 1269 | ///\param function Member function address to call. 1270 | template 1271 | Callback5(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4)) 1272 | :mCallback(new(&mMem) ChildMethod(object, function)) 1273 | { 1274 | } 1275 | 1276 | ///Constructs the callback to a free function or static member function. 1277 | ///\param function Free function address to call. 1278 | Callback5(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4)) 1279 | :mCallback(new(&mMem) ChildFree(function)) 1280 | { 1281 | } 1282 | 1283 | ///Constructs a callback that can later be set. 1284 | Callback5() 1285 | :mCallback(0) 1286 | { 1287 | } 1288 | 1289 | Callback5(const Callback5& c) 1290 | :mCallback(c.mCallback) 1291 | { 1292 | if (mCallback) 1293 | { 1294 | memcpy(mMem, c.mMem, sizeof(mMem)); 1295 | mCallback = reinterpret_cast(&mMem); 1296 | } 1297 | } 1298 | 1299 | Callback5& operator=(const Callback5& rhs) 1300 | { 1301 | mCallback = rhs.mCallback; 1302 | if (mCallback) 1303 | { 1304 | memcpy(mMem, rhs.mMem, sizeof(mMem)); 1305 | mCallback = reinterpret_cast(&mMem); 1306 | } 1307 | 1308 | return *this; 1309 | } 1310 | 1311 | ~Callback5() 1312 | { 1313 | } 1314 | 1315 | ///Sets the callback to a specific object and member function. 1316 | ///\param object Pointer to the object to call upon. Care should be taken that this object remains valid as long as the callback may be invoked. 1317 | ///\param function Member function address to call. 1318 | template 1319 | void Reset(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4)) 1320 | { 1321 | mCallback = new(&mMem) ChildMethod(object, function); 1322 | } 1323 | 1324 | ///Sets the callback to a free function or static member function. 1325 | ///\param function Free function address to call. 1326 | void Reset(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4)) 1327 | { 1328 | mCallback = new(&mMem) ChildFree(function); 1329 | } 1330 | 1331 | ///Resests to callback to nothing. 1332 | void Reset() 1333 | { 1334 | mCallback = 0; 1335 | } 1336 | 1337 | ///Note that comparison operators may not work with virtual function callbacks. 1338 | bool operator==(const Callback5& rhs) const 1339 | { 1340 | if (mCallback && rhs.mCallback) 1341 | return (*mCallback) == (*(rhs.mCallback)); 1342 | else 1343 | return mCallback == rhs.mCallback; 1344 | } 1345 | 1346 | ///Note that comparison operators may not work with virtual function callbacks. 1347 | bool operator!=(const Callback5& rhs) const 1348 | { 1349 | return !(*this == rhs); 1350 | } 1351 | 1352 | ///Note that comparison operators may not work with virtual function callbacks. 1353 | bool operator<(const Callback5 rhs) const 1354 | { 1355 | if (mCallback && rhs.mCallback) 1356 | return (*mCallback) < (*(rhs.mCallback)); 1357 | else 1358 | return mCallback < rhs.mCallback; 1359 | } 1360 | 1361 | ///Returns true if the callback has been set, or false if the callback is not set and is invalid. 1362 | bool IsSet() const 1363 | { 1364 | return mCallback; 1365 | } 1366 | 1367 | ///Invokes the callback. 1368 | R operator()(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4) const 1369 | { 1370 | if (mCallback) 1371 | return (*mCallback)(t0, t1, t2, t3, t4); 1372 | else 1373 | throw std::runtime_error(unset_call_error); 1374 | } 1375 | 1376 | ///Invokes the callback. This function can sometimes be more convenient than the operator(), which does the same thing. 1377 | R Call(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4) const 1378 | { 1379 | if (mCallback) 1380 | return (*mCallback)(t0, t1, t2, t3, t4); 1381 | else 1382 | throw std::runtime_error(unset_call_error); 1383 | } 1384 | 1385 | private: 1386 | class Base 1387 | { 1388 | public: 1389 | Base(){} 1390 | virtual R operator()(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4) = 0; 1391 | virtual bool operator==(const Base& rhs) const = 0; 1392 | virtual bool operator<(const Base& rhs) const = 0; 1393 | virtual void* Comp() const = 0; //Returns a pointer used in comparisons. 1394 | }; 1395 | 1396 | class ChildFree : public Base 1397 | { 1398 | public: 1399 | ChildFree(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4)) 1400 | :mFunc(function) 1401 | {} 1402 | 1403 | virtual R operator()(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4) 1404 | { 1405 | return mFunc(t0, t1, t2, t3, t4); 1406 | } 1407 | 1408 | virtual bool operator==(const Base& rhs) const 1409 | { 1410 | const ChildFree* const r = dynamic_cast(&rhs); 1411 | if (r) 1412 | return (mFunc == r->mFunc); 1413 | else 1414 | return false; 1415 | } 1416 | 1417 | virtual bool operator<(const Base& rhs) const 1418 | { 1419 | const ChildFree* const r = dynamic_cast(&rhs); 1420 | if (r) 1421 | return mFunc < r->mFunc; 1422 | else 1423 | return true; //Free functions will always be less than methods (because comp returns 0). 1424 | } 1425 | 1426 | virtual void* Comp() const 1427 | { 1428 | return 0; 1429 | } 1430 | 1431 | private: 1432 | R (*const mFunc)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4); 1433 | }; 1434 | 1435 | template 1436 | class ChildMethod : public Base 1437 | { 1438 | public: 1439 | ChildMethod(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4)) 1440 | :mObj(object), mFunc(function) 1441 | {} 1442 | 1443 | virtual R operator()(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4) 1444 | { 1445 | return (mObj->*mFunc)(t0, t1, t2, t3, t4); 1446 | } 1447 | 1448 | virtual bool operator==(const Base& rhs) const 1449 | { 1450 | const ChildMethod* const r = dynamic_cast*>(&rhs); 1451 | if (r) 1452 | return (mObj == r->mObj) && (mFunc == r->mFunc); 1453 | else 1454 | return false; 1455 | } 1456 | 1457 | virtual bool operator<(const Base& rhs) const 1458 | { 1459 | const ChildMethod* const r = dynamic_cast*>(&rhs); 1460 | if (r) 1461 | { 1462 | if (mObj != r->mObj) 1463 | return mObj < r->mObj; 1464 | else 1465 | return 0 > memcmp((void*)&mFunc, (void*)&(r->mFunc), sizeof(mFunc)); 1466 | } 1467 | else 1468 | return mObj < rhs.Comp(); 1469 | } 1470 | 1471 | virtual void* Comp() const 1472 | { 1473 | return mObj; 1474 | } 1475 | 1476 | private: 1477 | C* const mObj; 1478 | R (C::* const mFunc)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4); 1479 | }; 1480 | 1481 | ///This class is only to find the worst case method pointer size. 1482 | class unknown; 1483 | 1484 | char mMem[sizeof(ChildMethod)]; //Reserve memory for creating useful objects later. 1485 | Base* mCallback; 1486 | }; 1487 | 1488 | 1489 | ///Helper function to construct a callback without bothering to specify template parameters. 1490 | template 1491 | Callback5 Make5(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4)) 1492 | { 1493 | return Callback5(object, function); 1494 | } 1495 | 1496 | ///Helper function to construct a callback without bothering to specify template parameters. 1497 | template 1498 | Callback5 Make5(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4)) 1499 | { 1500 | return Callback5(function); 1501 | } 1502 | 1503 | 1504 | ///Stores a callback for a function taking 6 parameters. 1505 | ///\tparam R Callback function return type. 1506 | template 1507 | class Callback6 1508 | { 1509 | public: 1510 | ///Constructs the callback to a specific object and member function. 1511 | ///\param object Pointer to the object to call upon. Care should be taken that this object remains valid as long as the callback may be invoked. 1512 | ///\param function Member function address to call. 1513 | template 1514 | Callback6(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)) 1515 | :mCallback(new(&mMem) ChildMethod(object, function)) 1516 | { 1517 | } 1518 | 1519 | ///Constructs the callback to a free function or static member function. 1520 | ///\param function Free function address to call. 1521 | Callback6(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)) 1522 | :mCallback(new(&mMem) ChildFree(function)) 1523 | { 1524 | } 1525 | 1526 | ///Constructs a callback that can later be set. 1527 | Callback6() 1528 | :mCallback(0) 1529 | { 1530 | } 1531 | 1532 | Callback6(const Callback6& c) 1533 | :mCallback(c.mCallback) 1534 | { 1535 | if (mCallback) 1536 | { 1537 | memcpy(mMem, c.mMem, sizeof(mMem)); 1538 | mCallback = reinterpret_cast(&mMem); 1539 | } 1540 | } 1541 | 1542 | Callback6& operator=(const Callback6& rhs) 1543 | { 1544 | mCallback = rhs.mCallback; 1545 | if (mCallback) 1546 | { 1547 | memcpy(mMem, rhs.mMem, sizeof(mMem)); 1548 | mCallback = reinterpret_cast(&mMem); 1549 | } 1550 | 1551 | return *this; 1552 | } 1553 | 1554 | ~Callback6() 1555 | { 1556 | } 1557 | 1558 | ///Sets the callback to a specific object and member function. 1559 | ///\param object Pointer to the object to call upon. Care should be taken that this object remains valid as long as the callback may be invoked. 1560 | ///\param function Member function address to call. 1561 | template 1562 | void Reset(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)) 1563 | { 1564 | mCallback = new(&mMem) ChildMethod(object, function); 1565 | } 1566 | 1567 | ///Sets the callback to a free function or static member function. 1568 | ///\param function Free function address to call. 1569 | void Reset(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)) 1570 | { 1571 | mCallback = new(&mMem) ChildFree(function); 1572 | } 1573 | 1574 | ///Resests to callback to nothing. 1575 | void Reset() 1576 | { 1577 | mCallback = 0; 1578 | } 1579 | 1580 | ///Note that comparison operators may not work with virtual function callbacks. 1581 | bool operator==(const Callback6& rhs) const 1582 | { 1583 | if (mCallback && rhs.mCallback) 1584 | return (*mCallback) == (*(rhs.mCallback)); 1585 | else 1586 | return mCallback == rhs.mCallback; 1587 | } 1588 | 1589 | ///Note that comparison operators may not work with virtual function callbacks. 1590 | bool operator!=(const Callback6& rhs) const 1591 | { 1592 | return !(*this == rhs); 1593 | } 1594 | 1595 | ///Note that comparison operators may not work with virtual function callbacks. 1596 | bool operator<(const Callback6 rhs) const 1597 | { 1598 | if (mCallback && rhs.mCallback) 1599 | return (*mCallback) < (*(rhs.mCallback)); 1600 | else 1601 | return mCallback < rhs.mCallback; 1602 | } 1603 | 1604 | ///Returns true if the callback has been set, or false if the callback is not set and is invalid. 1605 | bool IsSet() const 1606 | { 1607 | return mCallback; 1608 | } 1609 | 1610 | ///Invokes the callback. 1611 | R operator()(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) const 1612 | { 1613 | if (mCallback) 1614 | return (*mCallback)(t0, t1, t2, t3, t4, t5); 1615 | else 1616 | throw std::runtime_error(unset_call_error); 1617 | } 1618 | 1619 | ///Invokes the callback. This function can sometimes be more convenient than the operator(), which does the same thing. 1620 | R Call(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) const 1621 | { 1622 | if (mCallback) 1623 | return (*mCallback)(t0, t1, t2, t3, t4, t5); 1624 | else 1625 | throw std::runtime_error(unset_call_error); 1626 | } 1627 | 1628 | private: 1629 | class Base 1630 | { 1631 | public: 1632 | Base(){} 1633 | virtual R operator()(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) = 0; 1634 | virtual bool operator==(const Base& rhs) const = 0; 1635 | virtual bool operator<(const Base& rhs) const = 0; 1636 | virtual void* Comp() const = 0; //Returns a pointer used in comparisons. 1637 | }; 1638 | 1639 | class ChildFree : public Base 1640 | { 1641 | public: 1642 | ChildFree(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)) 1643 | :mFunc(function) 1644 | {} 1645 | 1646 | virtual R operator()(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) 1647 | { 1648 | return mFunc(t0, t1, t2, t3, t4, t5); 1649 | } 1650 | 1651 | virtual bool operator==(const Base& rhs) const 1652 | { 1653 | const ChildFree* const r = dynamic_cast(&rhs); 1654 | if (r) 1655 | return (mFunc == r->mFunc); 1656 | else 1657 | return false; 1658 | } 1659 | 1660 | virtual bool operator<(const Base& rhs) const 1661 | { 1662 | const ChildFree* const r = dynamic_cast(&rhs); 1663 | if (r) 1664 | return mFunc < r->mFunc; 1665 | else 1666 | return true; //Free functions will always be less than methods (because comp returns 0). 1667 | } 1668 | 1669 | virtual void* Comp() const 1670 | { 1671 | return 0; 1672 | } 1673 | 1674 | private: 1675 | R (*const mFunc)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5); 1676 | }; 1677 | 1678 | template 1679 | class ChildMethod : public Base 1680 | { 1681 | public: 1682 | ChildMethod(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)) 1683 | :mObj(object), mFunc(function) 1684 | {} 1685 | 1686 | virtual R operator()(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) 1687 | { 1688 | return (mObj->*mFunc)(t0, t1, t2, t3, t4, t5); 1689 | } 1690 | 1691 | virtual bool operator==(const Base& rhs) const 1692 | { 1693 | const ChildMethod* const r = dynamic_cast*>(&rhs); 1694 | if (r) 1695 | return (mObj == r->mObj) && (mFunc == r->mFunc); 1696 | else 1697 | return false; 1698 | } 1699 | 1700 | virtual bool operator<(const Base& rhs) const 1701 | { 1702 | const ChildMethod* const r = dynamic_cast*>(&rhs); 1703 | if (r) 1704 | { 1705 | if (mObj != r->mObj) 1706 | return mObj < r->mObj; 1707 | else 1708 | return 0 > memcmp((void*)&mFunc, (void*)&(r->mFunc), sizeof(mFunc)); 1709 | } 1710 | else 1711 | return mObj < rhs.Comp(); 1712 | } 1713 | 1714 | virtual void* Comp() const 1715 | { 1716 | return mObj; 1717 | } 1718 | 1719 | private: 1720 | C* const mObj; 1721 | R (C::* const mFunc)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5); 1722 | }; 1723 | 1724 | ///This class is only to find the worst case method pointer size. 1725 | class unknown; 1726 | 1727 | char mMem[sizeof(ChildMethod)]; //Reserve memory for creating useful objects later. 1728 | Base* mCallback; 1729 | }; 1730 | 1731 | 1732 | ///Helper function to construct a callback without bothering to specify template parameters. 1733 | template 1734 | Callback6 Make6(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)) 1735 | { 1736 | return Callback6(object, function); 1737 | } 1738 | 1739 | ///Helper function to construct a callback without bothering to specify template parameters. 1740 | template 1741 | Callback6 Make6(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)) 1742 | { 1743 | return Callback6(function); 1744 | } 1745 | 1746 | 1747 | ///Stores a callback for a function taking 7 parameters. 1748 | ///\tparam R Callback function return type. 1749 | template 1750 | class Callback7 1751 | { 1752 | public: 1753 | ///Constructs the callback to a specific object and member function. 1754 | ///\param object Pointer to the object to call upon. Care should be taken that this object remains valid as long as the callback may be invoked. 1755 | ///\param function Member function address to call. 1756 | template 1757 | Callback7(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)) 1758 | :mCallback(new(&mMem) ChildMethod(object, function)) 1759 | { 1760 | } 1761 | 1762 | ///Constructs the callback to a free function or static member function. 1763 | ///\param function Free function address to call. 1764 | Callback7(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)) 1765 | :mCallback(new(&mMem) ChildFree(function)) 1766 | { 1767 | } 1768 | 1769 | ///Constructs a callback that can later be set. 1770 | Callback7() 1771 | :mCallback(0) 1772 | { 1773 | } 1774 | 1775 | Callback7(const Callback7& c) 1776 | :mCallback(c.mCallback) 1777 | { 1778 | if (mCallback) 1779 | { 1780 | memcpy(mMem, c.mMem, sizeof(mMem)); 1781 | mCallback = reinterpret_cast(&mMem); 1782 | } 1783 | } 1784 | 1785 | Callback7& operator=(const Callback7& rhs) 1786 | { 1787 | mCallback = rhs.mCallback; 1788 | if (mCallback) 1789 | { 1790 | memcpy(mMem, rhs.mMem, sizeof(mMem)); 1791 | mCallback = reinterpret_cast(&mMem); 1792 | } 1793 | 1794 | return *this; 1795 | } 1796 | 1797 | ~Callback7() 1798 | { 1799 | } 1800 | 1801 | ///Sets the callback to a specific object and member function. 1802 | ///\param object Pointer to the object to call upon. Care should be taken that this object remains valid as long as the callback may be invoked. 1803 | ///\param function Member function address to call. 1804 | template 1805 | void Reset(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)) 1806 | { 1807 | mCallback = new(&mMem) ChildMethod(object, function); 1808 | } 1809 | 1810 | ///Sets the callback to a free function or static member function. 1811 | ///\param function Free function address to call. 1812 | void Reset(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)) 1813 | { 1814 | mCallback = new(&mMem) ChildFree(function); 1815 | } 1816 | 1817 | ///Resests to callback to nothing. 1818 | void Reset() 1819 | { 1820 | mCallback = 0; 1821 | } 1822 | 1823 | ///Note that comparison operators may not work with virtual function callbacks. 1824 | bool operator==(const Callback7& rhs) const 1825 | { 1826 | if (mCallback && rhs.mCallback) 1827 | return (*mCallback) == (*(rhs.mCallback)); 1828 | else 1829 | return mCallback == rhs.mCallback; 1830 | } 1831 | 1832 | ///Note that comparison operators may not work with virtual function callbacks. 1833 | bool operator!=(const Callback7& rhs) const 1834 | { 1835 | return !(*this == rhs); 1836 | } 1837 | 1838 | ///Note that comparison operators may not work with virtual function callbacks. 1839 | bool operator<(const Callback7 rhs) const 1840 | { 1841 | if (mCallback && rhs.mCallback) 1842 | return (*mCallback) < (*(rhs.mCallback)); 1843 | else 1844 | return mCallback < rhs.mCallback; 1845 | } 1846 | 1847 | ///Returns true if the callback has been set, or false if the callback is not set and is invalid. 1848 | bool IsSet() const 1849 | { 1850 | return mCallback; 1851 | } 1852 | 1853 | ///Invokes the callback. 1854 | R operator()(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) const 1855 | { 1856 | if (mCallback) 1857 | return (*mCallback)(t0, t1, t2, t3, t4, t5, t6); 1858 | else 1859 | throw std::runtime_error(unset_call_error); 1860 | } 1861 | 1862 | ///Invokes the callback. This function can sometimes be more convenient than the operator(), which does the same thing. 1863 | R Call(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) const 1864 | { 1865 | if (mCallback) 1866 | return (*mCallback)(t0, t1, t2, t3, t4, t5, t6); 1867 | else 1868 | throw std::runtime_error(unset_call_error); 1869 | } 1870 | 1871 | private: 1872 | class Base 1873 | { 1874 | public: 1875 | Base(){} 1876 | virtual R operator()(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) = 0; 1877 | virtual bool operator==(const Base& rhs) const = 0; 1878 | virtual bool operator<(const Base& rhs) const = 0; 1879 | virtual void* Comp() const = 0; //Returns a pointer used in comparisons. 1880 | }; 1881 | 1882 | class ChildFree : public Base 1883 | { 1884 | public: 1885 | ChildFree(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)) 1886 | :mFunc(function) 1887 | {} 1888 | 1889 | virtual R operator()(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) 1890 | { 1891 | return mFunc(t0, t1, t2, t3, t4, t5, t6); 1892 | } 1893 | 1894 | virtual bool operator==(const Base& rhs) const 1895 | { 1896 | const ChildFree* const r = dynamic_cast(&rhs); 1897 | if (r) 1898 | return (mFunc == r->mFunc); 1899 | else 1900 | return false; 1901 | } 1902 | 1903 | virtual bool operator<(const Base& rhs) const 1904 | { 1905 | const ChildFree* const r = dynamic_cast(&rhs); 1906 | if (r) 1907 | return mFunc < r->mFunc; 1908 | else 1909 | return true; //Free functions will always be less than methods (because comp returns 0). 1910 | } 1911 | 1912 | virtual void* Comp() const 1913 | { 1914 | return 0; 1915 | } 1916 | 1917 | private: 1918 | R (*const mFunc)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6); 1919 | }; 1920 | 1921 | template 1922 | class ChildMethod : public Base 1923 | { 1924 | public: 1925 | ChildMethod(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)) 1926 | :mObj(object), mFunc(function) 1927 | {} 1928 | 1929 | virtual R operator()(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) 1930 | { 1931 | return (mObj->*mFunc)(t0, t1, t2, t3, t4, t5, t6); 1932 | } 1933 | 1934 | virtual bool operator==(const Base& rhs) const 1935 | { 1936 | const ChildMethod* const r = dynamic_cast*>(&rhs); 1937 | if (r) 1938 | return (mObj == r->mObj) && (mFunc == r->mFunc); 1939 | else 1940 | return false; 1941 | } 1942 | 1943 | virtual bool operator<(const Base& rhs) const 1944 | { 1945 | const ChildMethod* const r = dynamic_cast*>(&rhs); 1946 | if (r) 1947 | { 1948 | if (mObj != r->mObj) 1949 | return mObj < r->mObj; 1950 | else 1951 | return 0 > memcmp((void*)&mFunc, (void*)&(r->mFunc), sizeof(mFunc)); 1952 | } 1953 | else 1954 | return mObj < rhs.Comp(); 1955 | } 1956 | 1957 | virtual void* Comp() const 1958 | { 1959 | return mObj; 1960 | } 1961 | 1962 | private: 1963 | C* const mObj; 1964 | R (C::* const mFunc)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6); 1965 | }; 1966 | 1967 | ///This class is only to find the worst case method pointer size. 1968 | class unknown; 1969 | 1970 | char mMem[sizeof(ChildMethod)]; //Reserve memory for creating useful objects later. 1971 | Base* mCallback; 1972 | }; 1973 | 1974 | 1975 | ///Helper function to construct a callback without bothering to specify template parameters. 1976 | template 1977 | Callback7 Make7(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)) 1978 | { 1979 | return Callback7(object, function); 1980 | } 1981 | 1982 | ///Helper function to construct a callback without bothering to specify template parameters. 1983 | template 1984 | Callback7 Make7(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)) 1985 | { 1986 | return Callback7(function); 1987 | } 1988 | 1989 | 1990 | ///Stores a callback for a function taking 8 parameters. 1991 | ///\tparam R Callback function return type. 1992 | template 1993 | class Callback8 1994 | { 1995 | public: 1996 | ///Constructs the callback to a specific object and member function. 1997 | ///\param object Pointer to the object to call upon. Care should be taken that this object remains valid as long as the callback may be invoked. 1998 | ///\param function Member function address to call. 1999 | template 2000 | Callback8(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)) 2001 | :mCallback(new(&mMem) ChildMethod(object, function)) 2002 | { 2003 | } 2004 | 2005 | ///Constructs the callback to a free function or static member function. 2006 | ///\param function Free function address to call. 2007 | Callback8(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)) 2008 | :mCallback(new(&mMem) ChildFree(function)) 2009 | { 2010 | } 2011 | 2012 | ///Constructs a callback that can later be set. 2013 | Callback8() 2014 | :mCallback(0) 2015 | { 2016 | } 2017 | 2018 | Callback8(const Callback8& c) 2019 | :mCallback(c.mCallback) 2020 | { 2021 | if (mCallback) 2022 | { 2023 | memcpy(mMem, c.mMem, sizeof(mMem)); 2024 | mCallback = reinterpret_cast(&mMem); 2025 | } 2026 | } 2027 | 2028 | Callback8& operator=(const Callback8& rhs) 2029 | { 2030 | mCallback = rhs.mCallback; 2031 | if (mCallback) 2032 | { 2033 | memcpy(mMem, rhs.mMem, sizeof(mMem)); 2034 | mCallback = reinterpret_cast(&mMem); 2035 | } 2036 | 2037 | return *this; 2038 | } 2039 | 2040 | ~Callback8() 2041 | { 2042 | } 2043 | 2044 | ///Sets the callback to a specific object and member function. 2045 | ///\param object Pointer to the object to call upon. Care should be taken that this object remains valid as long as the callback may be invoked. 2046 | ///\param function Member function address to call. 2047 | template 2048 | void Reset(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)) 2049 | { 2050 | mCallback = new(&mMem) ChildMethod(object, function); 2051 | } 2052 | 2053 | ///Sets the callback to a free function or static member function. 2054 | ///\param function Free function address to call. 2055 | void Reset(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)) 2056 | { 2057 | mCallback = new(&mMem) ChildFree(function); 2058 | } 2059 | 2060 | ///Resests to callback to nothing. 2061 | void Reset() 2062 | { 2063 | mCallback = 0; 2064 | } 2065 | 2066 | ///Note that comparison operators may not work with virtual function callbacks. 2067 | bool operator==(const Callback8& rhs) const 2068 | { 2069 | if (mCallback && rhs.mCallback) 2070 | return (*mCallback) == (*(rhs.mCallback)); 2071 | else 2072 | return mCallback == rhs.mCallback; 2073 | } 2074 | 2075 | ///Note that comparison operators may not work with virtual function callbacks. 2076 | bool operator!=(const Callback8& rhs) const 2077 | { 2078 | return !(*this == rhs); 2079 | } 2080 | 2081 | ///Note that comparison operators may not work with virtual function callbacks. 2082 | bool operator<(const Callback8 rhs) const 2083 | { 2084 | if (mCallback && rhs.mCallback) 2085 | return (*mCallback) < (*(rhs.mCallback)); 2086 | else 2087 | return mCallback < rhs.mCallback; 2088 | } 2089 | 2090 | ///Returns true if the callback has been set, or false if the callback is not set and is invalid. 2091 | bool IsSet() const 2092 | { 2093 | return mCallback; 2094 | } 2095 | 2096 | ///Invokes the callback. 2097 | R operator()(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) const 2098 | { 2099 | if (mCallback) 2100 | return (*mCallback)(t0, t1, t2, t3, t4, t5, t6, t7); 2101 | else 2102 | throw std::runtime_error(unset_call_error); 2103 | } 2104 | 2105 | ///Invokes the callback. This function can sometimes be more convenient than the operator(), which does the same thing. 2106 | R Call(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) const 2107 | { 2108 | if (mCallback) 2109 | return (*mCallback)(t0, t1, t2, t3, t4, t5, t6, t7); 2110 | else 2111 | throw std::runtime_error(unset_call_error); 2112 | } 2113 | 2114 | private: 2115 | class Base 2116 | { 2117 | public: 2118 | Base(){} 2119 | virtual R operator()(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) = 0; 2120 | virtual bool operator==(const Base& rhs) const = 0; 2121 | virtual bool operator<(const Base& rhs) const = 0; 2122 | virtual void* Comp() const = 0; //Returns a pointer used in comparisons. 2123 | }; 2124 | 2125 | class ChildFree : public Base 2126 | { 2127 | public: 2128 | ChildFree(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)) 2129 | :mFunc(function) 2130 | {} 2131 | 2132 | virtual R operator()(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) 2133 | { 2134 | return mFunc(t0, t1, t2, t3, t4, t5, t6, t7); 2135 | } 2136 | 2137 | virtual bool operator==(const Base& rhs) const 2138 | { 2139 | const ChildFree* const r = dynamic_cast(&rhs); 2140 | if (r) 2141 | return (mFunc == r->mFunc); 2142 | else 2143 | return false; 2144 | } 2145 | 2146 | virtual bool operator<(const Base& rhs) const 2147 | { 2148 | const ChildFree* const r = dynamic_cast(&rhs); 2149 | if (r) 2150 | return mFunc < r->mFunc; 2151 | else 2152 | return true; //Free functions will always be less than methods (because comp returns 0). 2153 | } 2154 | 2155 | virtual void* Comp() const 2156 | { 2157 | return 0; 2158 | } 2159 | 2160 | private: 2161 | R (*const mFunc)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7); 2162 | }; 2163 | 2164 | template 2165 | class ChildMethod : public Base 2166 | { 2167 | public: 2168 | ChildMethod(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)) 2169 | :mObj(object), mFunc(function) 2170 | {} 2171 | 2172 | virtual R operator()(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) 2173 | { 2174 | return (mObj->*mFunc)(t0, t1, t2, t3, t4, t5, t6, t7); 2175 | } 2176 | 2177 | virtual bool operator==(const Base& rhs) const 2178 | { 2179 | const ChildMethod* const r = dynamic_cast*>(&rhs); 2180 | if (r) 2181 | return (mObj == r->mObj) && (mFunc == r->mFunc); 2182 | else 2183 | return false; 2184 | } 2185 | 2186 | virtual bool operator<(const Base& rhs) const 2187 | { 2188 | const ChildMethod* const r = dynamic_cast*>(&rhs); 2189 | if (r) 2190 | { 2191 | if (mObj != r->mObj) 2192 | return mObj < r->mObj; 2193 | else 2194 | return 0 > memcmp((void*)&mFunc, (void*)&(r->mFunc), sizeof(mFunc)); 2195 | } 2196 | else 2197 | return mObj < rhs.Comp(); 2198 | } 2199 | 2200 | virtual void* Comp() const 2201 | { 2202 | return mObj; 2203 | } 2204 | 2205 | private: 2206 | C* const mObj; 2207 | R (C::* const mFunc)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7); 2208 | }; 2209 | 2210 | ///This class is only to find the worst case method pointer size. 2211 | class unknown; 2212 | 2213 | char mMem[sizeof(ChildMethod)]; //Reserve memory for creating useful objects later. 2214 | Base* mCallback; 2215 | }; 2216 | 2217 | 2218 | ///Helper function to construct a callback without bothering to specify template parameters. 2219 | template 2220 | Callback8 Make8(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)) 2221 | { 2222 | return Callback8(object, function); 2223 | } 2224 | 2225 | ///Helper function to construct a callback without bothering to specify template parameters. 2226 | template 2227 | Callback8 Make8(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)) 2228 | { 2229 | return Callback8(function); 2230 | } 2231 | 2232 | 2233 | ///Stores a callback for a function taking 9 parameters. 2234 | ///\tparam R Callback function return type. 2235 | template 2236 | class Callback9 2237 | { 2238 | public: 2239 | ///Constructs the callback to a specific object and member function. 2240 | ///\param object Pointer to the object to call upon. Care should be taken that this object remains valid as long as the callback may be invoked. 2241 | ///\param function Member function address to call. 2242 | template 2243 | Callback9(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)) 2244 | :mCallback(new(&mMem) ChildMethod(object, function)) 2245 | { 2246 | } 2247 | 2248 | ///Constructs the callback to a free function or static member function. 2249 | ///\param function Free function address to call. 2250 | Callback9(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)) 2251 | :mCallback(new(&mMem) ChildFree(function)) 2252 | { 2253 | } 2254 | 2255 | ///Constructs a callback that can later be set. 2256 | Callback9() 2257 | :mCallback(0) 2258 | { 2259 | } 2260 | 2261 | Callback9(const Callback9& c) 2262 | :mCallback(c.mCallback) 2263 | { 2264 | if (mCallback) 2265 | { 2266 | memcpy(mMem, c.mMem, sizeof(mMem)); 2267 | mCallback = reinterpret_cast(&mMem); 2268 | } 2269 | } 2270 | 2271 | Callback9& operator=(const Callback9& rhs) 2272 | { 2273 | mCallback = rhs.mCallback; 2274 | if (mCallback) 2275 | { 2276 | memcpy(mMem, rhs.mMem, sizeof(mMem)); 2277 | mCallback = reinterpret_cast(&mMem); 2278 | } 2279 | 2280 | return *this; 2281 | } 2282 | 2283 | ~Callback9() 2284 | { 2285 | } 2286 | 2287 | ///Sets the callback to a specific object and member function. 2288 | ///\param object Pointer to the object to call upon. Care should be taken that this object remains valid as long as the callback may be invoked. 2289 | ///\param function Member function address to call. 2290 | template 2291 | void Reset(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)) 2292 | { 2293 | mCallback = new(&mMem) ChildMethod(object, function); 2294 | } 2295 | 2296 | ///Sets the callback to a free function or static member function. 2297 | ///\param function Free function address to call. 2298 | void Reset(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)) 2299 | { 2300 | mCallback = new(&mMem) ChildFree(function); 2301 | } 2302 | 2303 | ///Resests to callback to nothing. 2304 | void Reset() 2305 | { 2306 | mCallback = 0; 2307 | } 2308 | 2309 | ///Note that comparison operators may not work with virtual function callbacks. 2310 | bool operator==(const Callback9& rhs) const 2311 | { 2312 | if (mCallback && rhs.mCallback) 2313 | return (*mCallback) == (*(rhs.mCallback)); 2314 | else 2315 | return mCallback == rhs.mCallback; 2316 | } 2317 | 2318 | ///Note that comparison operators may not work with virtual function callbacks. 2319 | bool operator!=(const Callback9& rhs) const 2320 | { 2321 | return !(*this == rhs); 2322 | } 2323 | 2324 | ///Note that comparison operators may not work with virtual function callbacks. 2325 | bool operator<(const Callback9 rhs) const 2326 | { 2327 | if (mCallback && rhs.mCallback) 2328 | return (*mCallback) < (*(rhs.mCallback)); 2329 | else 2330 | return mCallback < rhs.mCallback; 2331 | } 2332 | 2333 | ///Returns true if the callback has been set, or false if the callback is not set and is invalid. 2334 | bool IsSet() const 2335 | { 2336 | return mCallback; 2337 | } 2338 | 2339 | ///Invokes the callback. 2340 | R operator()(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) const 2341 | { 2342 | if (mCallback) 2343 | return (*mCallback)(t0, t1, t2, t3, t4, t5, t6, t7, t8); 2344 | else 2345 | throw std::runtime_error(unset_call_error); 2346 | } 2347 | 2348 | ///Invokes the callback. This function can sometimes be more convenient than the operator(), which does the same thing. 2349 | R Call(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) const 2350 | { 2351 | if (mCallback) 2352 | return (*mCallback)(t0, t1, t2, t3, t4, t5, t6, t7, t8); 2353 | else 2354 | throw std::runtime_error(unset_call_error); 2355 | } 2356 | 2357 | private: 2358 | class Base 2359 | { 2360 | public: 2361 | Base(){} 2362 | virtual R operator()(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) = 0; 2363 | virtual bool operator==(const Base& rhs) const = 0; 2364 | virtual bool operator<(const Base& rhs) const = 0; 2365 | virtual void* Comp() const = 0; //Returns a pointer used in comparisons. 2366 | }; 2367 | 2368 | class ChildFree : public Base 2369 | { 2370 | public: 2371 | ChildFree(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)) 2372 | :mFunc(function) 2373 | {} 2374 | 2375 | virtual R operator()(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) 2376 | { 2377 | return mFunc(t0, t1, t2, t3, t4, t5, t6, t7, t8); 2378 | } 2379 | 2380 | virtual bool operator==(const Base& rhs) const 2381 | { 2382 | const ChildFree* const r = dynamic_cast(&rhs); 2383 | if (r) 2384 | return (mFunc == r->mFunc); 2385 | else 2386 | return false; 2387 | } 2388 | 2389 | virtual bool operator<(const Base& rhs) const 2390 | { 2391 | const ChildFree* const r = dynamic_cast(&rhs); 2392 | if (r) 2393 | return mFunc < r->mFunc; 2394 | else 2395 | return true; //Free functions will always be less than methods (because comp returns 0). 2396 | } 2397 | 2398 | virtual void* Comp() const 2399 | { 2400 | return 0; 2401 | } 2402 | 2403 | private: 2404 | R (*const mFunc)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8); 2405 | }; 2406 | 2407 | template 2408 | class ChildMethod : public Base 2409 | { 2410 | public: 2411 | ChildMethod(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)) 2412 | :mObj(object), mFunc(function) 2413 | {} 2414 | 2415 | virtual R operator()(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) 2416 | { 2417 | return (mObj->*mFunc)(t0, t1, t2, t3, t4, t5, t6, t7, t8); 2418 | } 2419 | 2420 | virtual bool operator==(const Base& rhs) const 2421 | { 2422 | const ChildMethod* const r = dynamic_cast*>(&rhs); 2423 | if (r) 2424 | return (mObj == r->mObj) && (mFunc == r->mFunc); 2425 | else 2426 | return false; 2427 | } 2428 | 2429 | virtual bool operator<(const Base& rhs) const 2430 | { 2431 | const ChildMethod* const r = dynamic_cast*>(&rhs); 2432 | if (r) 2433 | { 2434 | if (mObj != r->mObj) 2435 | return mObj < r->mObj; 2436 | else 2437 | return 0 > memcmp((void*)&mFunc, (void*)&(r->mFunc), sizeof(mFunc)); 2438 | } 2439 | else 2440 | return mObj < rhs.Comp(); 2441 | } 2442 | 2443 | virtual void* Comp() const 2444 | { 2445 | return mObj; 2446 | } 2447 | 2448 | private: 2449 | C* const mObj; 2450 | R (C::* const mFunc)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8); 2451 | }; 2452 | 2453 | ///This class is only to find the worst case method pointer size. 2454 | class unknown; 2455 | 2456 | char mMem[sizeof(ChildMethod)]; //Reserve memory for creating useful objects later. 2457 | Base* mCallback; 2458 | }; 2459 | 2460 | 2461 | ///Helper function to construct a callback without bothering to specify template parameters. 2462 | template 2463 | Callback9 Make9(C* object, R (C::*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)) 2464 | { 2465 | return Callback9(object, function); 2466 | } 2467 | 2468 | ///Helper function to construct a callback without bothering to specify template parameters. 2469 | template 2470 | Callback9 Make9(R (*function)(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)) 2471 | { 2472 | return Callback9(function); 2473 | } 2474 | 2475 | } 2476 | #endif /*__CALLBACK_HPP__*/ 2477 | 2478 | --------------------------------------------------------------------------------