1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
|
#pragma once
#include "Blob.h"
namespace util {
namespace fn {
// Internal helpers for the function class.
typedef Blob<2 * sizeof(void *)> PtrBlob; // Size is larger for complex fn ptrs sometimes
// Do nothing
template <class ReturnType, class ParameterType>
ReturnType simpleNop(void *, const PtrBlob &ptr, ParameterType param) {
return ReturnType();
}
template <class ReturnType>
ReturnType simpleNopVoid(void *, const PtrBlob &ptr) {
return ReturnType();
}
// Run a simple function pointer
template <class ReturnType, class ParameterType>
ReturnType simpleFnExecute(void *, const PtrBlob &ptr, ParameterType param) {
typedef ReturnType (* FnPtr)(ParameterType);
FnPtr fnPtr = ptr.get<FnPtr>();
return (*fnPtr)(param);
}
template <class ReturnType>
ReturnType simpleFnExecuteVoid(void *, const PtrBlob &ptr) {
typedef ReturnType (* FnPtr)();
FnPtr fnPtr = ptr.get<FnPtr>();
return (*fnPtr)();
}
// Run a member function ptr
template <class ReturnType, class ParameterType, class C>
ReturnType memberFnExecute(void *thisPtr, const PtrBlob &ptr, ParameterType param) {
typedef ReturnType (C:: *FnPtr)(ParameterType);
FnPtr fnPtr = ptr.get<FnPtr>();
C *cThisPtr = (C *)thisPtr;
return (cThisPtr->*fnPtr)(param);
}
template <class ReturnType, class C>
ReturnType memberFnExecuteVoid(void *thisPtr, const PtrBlob &ptr) {
typedef ReturnType (C:: *FnPtr)();
FnPtr fnPtr = ptr.get<FnPtr>();
C *cThisPtr = (C *)thisPtr;
return (cThisPtr->*fnPtr)();
}
}
// Function pointer class. This class encapsulates a function pointer either to a simple C-style function
// or to a member function. If it contains a member function to a class, it will also contain the "this" pointer
// for that instance, so that functions encapsulated inside this object always can be treated as a simple C-style
// function.
// In the case of an empty function pointer, it will simply return ReturnType() for the specified return type.
template <class ReturnType, class ParameterType = void>
class Fn {
public:
// Create an empty fn ptr
Fn() {
thisPtr = null;
toExecute = &fn::simpleNop<ReturnType, ParameterType>;
}
// Create from a simple function pointer.
Fn(ReturnType (*fnPtr)(ParameterType)) {
thisPtr = null;
this->fnPtr.set(fnPtr);
toExecute = &fn::simpleFnExecute<ReturnType, ParameterType>;
}
// Create from a member function.
template <class C>
Fn(C *thisPtr, ReturnType (C::* fnPtr)(ParameterType)) {
this->thisPtr = thisPtr;
this->fnPtr.set(fnPtr);
toExecute = &fn::memberFnExecute<ReturnType, ParameterType, C>;
}
inline ReturnType operator ()(ParameterType p) const {
return (*toExecute)(thisPtr, fnPtr, p);
}
bool operator ==(const Fn<ReturnType, ParameterType> &other) const {
if (thisPtr != other.thisPtr) return false;
if (fnPtr != other.fnPtr) return false;
if (toExecute != other.toExecute) return false;
return true;
}
inline bool operator !=(const Fn<ReturnType, ParameterType> &other) const { return !(*this == other); }
private:
void *thisPtr;
fn::PtrBlob fnPtr;
ReturnType (* toExecute)(void *, const fn::PtrBlob &, ParameterType);
};
// Specialization for <X, void>
template <class ReturnType>
class Fn<ReturnType, void> {
public:
// Create an empty fn ptr
Fn() {
thisPtr = null;
toExecute = &fn::simpleNopVoid<ReturnType>;
}
// Create from a simple function pointer.
Fn(ReturnType (*fnPtr)()) {
thisPtr = null;
this->fnPtr.set(fnPtr);
toExecute = &fn::simpleFnExecuteVoid<ReturnType>;
}
// Create from a member function.
template <class C>
Fn(C *thisPtr, ReturnType (C::* fnPtr)()) {
this->thisPtr = thisPtr;
this->fnPtr.set(fnPtr);
toExecute = &fn::memberFnExecuteVoid<ReturnType, C>;
}
inline ReturnType operator ()() const {
return (*toExecute)(thisPtr, fnPtr);
}
bool operator ==(const Fn<ReturnType, void> &other) const {
if (thisPtr != other.thisPtr) return false;
if (fnPtr != other.fnPtr) return false;
if (toExecute != other.toExecute) return false;
return true;
}
inline bool operator !=(const Fn<ReturnType, void> &other) const { return !(*this == other); }
private:
void *thisPtr;
fn::PtrBlob fnPtr;
ReturnType (* toExecute)(void *, const fn::PtrBlob &);
};
// Create objects easily
template <class A, class B>
inline Fn<A, B> simpleFn(A (* p)(B)) {
return Fn<A, B>(p);
}
template <class A>
inline Fn<A, void> simpleVoidFn(A (* p)()) {
return Fn<A, void>(p);
}
template <class A, class B, class C>
inline Fn<A, B> memberFn(C *t, A (C:: *p)(B) const) {
return Fn<A, B>(t, (A (C:: *)(B))p);
}
template <class A, class B, class C>
inline Fn<A, B> memberFn(C *t, A (C:: *p)(B)) {
return Fn<A, B>(t, p);
}
template <class A, class C>
inline Fn<A, void> memberVoidFn(C *t, A (C:: *p)() const) {
return Fn<A, void>(t, (A (C:: *)())p);
}
template <class A, class C>
inline Fn<A, void> memberVoidFn(C *t, A (C:: *p)()) {
return Fn<A, void>(t, p);
}
}
|