-
Notifications
You must be signed in to change notification settings - Fork 1
/
func_utils.h
156 lines (142 loc) · 7.92 KB
/
func_utils.h
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
#pragma once
#define _USE_MATH_DEFINES // use constants from the library
#include <tuple>
#include <type_traits>
struct FuncUtils {
template <typename T> struct return_type;
template <typename R, typename C, typename... Args>
struct return_type<R (C::*)(Args...)> {
using type = R;
};
template <typename R, typename C, typename... Args>
struct return_type<R (C::*)(Args...) &> {
using type = R;
};
template <typename R, typename C, typename... Args>
struct return_type<R (C::*)(Args...) &&> {
using type = R;
};
template <typename R, typename C, typename... Args>
struct return_type<R (C::*)(Args...) const> {
using type = R;
};
template <typename R, typename C, typename... Args>
struct return_type<R (C::*)(Args...) const &> {
using type = R;
};
template <typename R, typename C, typename... Args>
struct return_type<R (C::*)(Args...) const &&> {
using type = R;
};
template <typename R, typename C, typename... Args>
struct return_type<R (C::*)(Args...) volatile> {
using type = R;
};
template <typename R, typename C, typename... Args>
struct return_type<R (C::*)(Args...) volatile &> {
using type = R;
};
template <typename R, typename C, typename... Args>
struct return_type<R (C::*)(Args...) volatile &&> {
using type = R;
};
template <typename R, typename C, typename... Args>
struct return_type<R (C::*)(Args...) const volatile> {
using type = R;
};
template <typename R, typename C, typename... Args>
struct return_type<R (C::*)(Args...) const volatile &> {
using type = R;
};
template <typename R, typename C, typename... Args>
struct return_type<R (C::*)(Args...) const volatile &&> {
using type = R;
};
template <typename T> using return_type_t = typename return_type<T>::type;
#define CHECK_IF_EXISTS(x) \
template <typename T> struct has_##x { \
typedef char one; \
struct two { \
char x[2]; \
}; \
template <typename C> static one test(decltype(&C::x)); \
template <typename C> static two test(...); \
enum { value = sizeof(test<T>(0)) == sizeof(char) }; \
}; \
template <typename T, typename R, typename... K> \
static typename std::enable_if< \
has_##x<T>::value, FuncUtils::return_type_t<decltype(&T::x)>>::type \
CallIfExists_##x(T *obj, R def, const K &...args) { \
(void)def; \
return obj->x(args...); \
} \
template <typename T, typename R, typename... K> \
static \
typename std::enable_if<!has_##x<T>::value, R>::type CallIfExists_##x( \
T *obj, R def, const K &...args) { \
(void)obj; \
static_cast<void>(std::make_tuple(args...)); \
return def; \
}; \
template <typename T, typename... K> \
static typename std::enable_if<has_##x<T>::value, void>::type \
CallIfExists_##x(T *obj, const K &...args) { \
obj->x(args...); \
} \
template <typename T, typename... K> \
static typename std::enable_if<!has_##x<T>::value, void>::type \
CallIfExists_##x(T *obj, const K &...args) { \
static_cast<void>(std::make_tuple(args...)); \
(void)obj; \
}; \
template <typename T, typename R, typename... K> \
static typename std::enable_if< \
has_##x<T>::value, FuncUtils::return_type_t<decltype(&(T::x))>>::type \
CallStaticIfExists_##x(R def, const K &...args) { \
(void)def; \
return T::x(args...); \
} \
template <typename T, typename R, typename... K> \
static typename std::enable_if<!has_##x<T>::value, R>::type \
CallStaticIfExists_##x(R def, const K &...args) { \
static_cast<void>(std::make_tuple(args...)); \
return def; \
}; \
template <typename T, typename... K> \
static typename std::enable_if<has_##x<T>::value>::type \
CallStaticIfExists_##x(const K &...args) { \
T::x(args...); \
} \
template <typename T, typename... K> \
static typename std::enable_if<!has_##x<T>::value>::type \
CallStaticIfExists_##x(const K &...args) { \
static_cast<void>(std::make_tuple(args...)); \
}; \
template <typename T, typename R> \
static typename std::enable_if<FuncUtils::has_##x<T>::value, R>::type \
GetIfExists_##x() { \
return &T::x; \
} \
template <typename T, typename R> \
static typename std::enable_if<!FuncUtils::has_##x<T>::value, R>::type \
GetIfExists_##x() { \
return nullptr; \
}
CHECK_IF_EXISTS(mark) // called while gc marking
CHECK_IF_EXISTS(release) // called which gc release, to release any custom
// allocated memory
CHECK_IF_EXISTS(depend) // called while DEBUG_GC is on, to mark any of the
// members necessary for its gc representation
CHECK_IF_EXISTS(gc_repr) // called while DEBUG_GC is on, to print a
// representation of the object while release
//
//
CHECK_IF_EXISTS(preInit) // called while init'ing a builtin module, before
// calling 'init'. a module can allocate custom
// structures and memory if it chooses to do so.
CHECK_IF_EXISTS(init) // called while init'ing a builtin module, a
// BuiltinModule* is passed, all the members are
// needed to be registered on this.
CHECK_IF_EXISTS(destroy) // called while gc releasing a builtin module.
// current instance of the module is passed
};