OLD | NEW |
| (Empty) |
1 // To generate typewrapping.h from typewrapping.h.pump, execute: | |
2 // /home/build/google3/third_party/gtest/scripts/pump.py typewrapping.h.pump | |
3 | |
4 // Copyright 2009 Google Inc. | |
5 // Author: tschmelcher@google.com (Tristan Schmelcher) | |
6 // | |
7 // A template meta-programming framework for customizable rule-based | |
8 // type-checking of type wrappers and wrapper functions. | |
9 // | |
10 // This framework is useful in a scenario where there are a set of types that | |
11 // you choose to "wrap" by implementing new preferred types such that the new | |
12 // and the old can be converted back and forth in some way, but you already have | |
13 // a library of functions that expect the original types. Example: | |
14 // | |
15 // Type A wraps X | |
16 // Type B wraps Y | |
17 // Type C wraps Z | |
18 // | |
19 // And function X Foo(Y, Z) exists. | |
20 // | |
21 // Since A, B, and C are preferred, you choose to implement a wrapper function | |
22 // with this interface: | |
23 // | |
24 // A Foo2(B, C) | |
25 // | |
26 // However, this can lead to subtle discrepancies, because if the interface to | |
27 // Foo ever changes then Foo2 may become out-of-sync. e.g., Foo might have | |
28 // originally returned void, but later is changed to return an error code. If | |
29 // the programmer forgets to change Foo2, the code will probably still work, but | |
30 // with an implicit cast to void inserted by the compiler, potentially leading | |
31 // to run-time errors or errors in usage. | |
32 // | |
33 // The purpose of this library is to prevent these discrepancies from occurring. | |
34 // You use it as follows: | |
35 // | |
36 // First, declare a new wrapping ruleset: | |
37 // | |
38 // DECLARE_WRAPPING_RULESET(ruleset_name) | |
39 // | |
40 // Then declare rules on what types wrap which other types and how to convert | |
41 // them: | |
42 // | |
43 // DECLARE_WRAPPER(ruleset_name, A, X, variable_name, wrapping_code, | |
44 // unwrapping_code) | |
45 // | |
46 // Where wrapping_code and unwrapping_code are expressions giving the code to | |
47 // use to wrap and unwrap a variable with the name "variable_name". There are | |
48 // also some helper macros to declare common wrapping schemes. | |
49 // | |
50 // Then implement your wrapped functions like this: | |
51 // | |
52 // A Foo_Wrapped(B b, C c) { | |
53 // return WRAP_CALL2(ruleset_name, A, Foo, B, b, C, c); | |
54 // } | |
55 // | |
56 // WRAP_CALL2 will unwrap b and c (if B and C are wrapped types) and call Foo, | |
57 // then wrap the result to type A if different from the return type. More | |
58 // importantly, if the types in Foo's interface do not _exactly_ match the | |
59 // unwrapped forms of A, B, and C (after typedef-equivalence), then you will get | |
60 // a compile-time error for a static_cast from the real function type to the | |
61 // expected one (except on Mac where this check is infeasible), and with no icky | |
62 // template instantiation errors either! | |
63 // | |
64 // There are also macros to wrap/unwrap individual values according to whichever | |
65 // rule applies to their types: | |
66 // | |
67 // WRAP(ruleset_name, A, X, value) // Compile-time error if no associated rule. | |
68 // | |
69 // UNWRAP(ruleset_name, A, value) // Infers X. If A is not a wrapper, no change. | |
70 // | |
71 // UNWRAP_TYPE(ruleset_name, A) // Evaluates to X. | |
72 // | |
73 // | |
74 // Essentially, the library works by "storing" the DECLARE_WRAPPER calls in | |
75 // template specializations. When the wrapper or unwrapper is invoked, the | |
76 // normal C++ template system essentially "looks up" the rule for the given | |
77 // type(s). | |
78 // | |
79 // All of the auto-generated code can be inlined to produce zero impact on | |
80 // run-time performance and code size (though some compilers may require | |
81 // gentle encouragement in order for them to do so). | |
82 | |
83 #ifndef TALK_SESSION_PHONE_TYPEWRAPPING_H_ | |
84 #define TALK_SESSION_PHONE_TYPEWRAPPING_H_ | |
85 | |
86 #include "webrtc/base/common.h" | |
87 | |
88 #ifdef OSX | |
89 // XCode's GCC doesn't respect typedef-equivalence when casting function pointer | |
90 // types, so we can't enforce that the wrapped function signatures strictly | |
91 // match the expected types. Instead we have to forego the nice user-friendly | |
92 // static_cast check (because it will spuriously fail) and make the Call() | |
93 // function into a member template below. | |
94 #define CAST_FUNCTION_(function, ...) \ | |
95 function | |
96 #else | |
97 #define CAST_FUNCTION_(function, ...) \ | |
98 static_cast<__VA_ARGS__>(function) | |
99 #endif | |
100 | |
101 // Internal helper macros. | |
102 #define SMART_WRAPPER_(wrapper, toType, fromType, from) \ | |
103 (wrapper<toType, fromType>::Wrap(from)) | |
104 | |
105 #define SMART_UNWRAPPER_(unwrapper, fromType, from) \ | |
106 (unwrapper<fromType>::Unwrap(from)) | |
107 | |
108 #define SMART_UNWRAPPER_TYPE_(unwrapper, fromType) \ | |
109 typename unwrapper<fromType>::ToType | |
110 | |
111 $var n = 27 | |
112 $range i 0..n | |
113 | |
114 $for i [[ | |
115 $range j 1..i | |
116 | |
117 // The code that follows wraps calls to $i-argument functions, unwrapping the | |
118 // arguments and wrapping the return value as needed. | |
119 | |
120 // The usual case. | |
121 template< | |
122 template <typename ToType, typename FromType> class Wrapper, | |
123 template <typename FromType> class Unwrapper, | |
124 typename ReturnType$for j [[, | |
125 typename ArgType$j]]> | |
126 class SmartFunctionWrapper$i { | |
127 public: | |
128 typedef SMART_UNWRAPPER_TYPE_(Unwrapper, ReturnType) OriginalReturnType; | |
129 | |
130 $for j [[ | |
131 typedef SMART_UNWRAPPER_TYPE_(Unwrapper, ArgType$j) OriginalArgType$j; | |
132 | |
133 ]] | |
134 typedef OriginalReturnType (*OriginalFunctionType)($for j , [[ | |
135 | |
136 OriginalArgType$j]]); | |
137 | |
138 #ifdef OSX | |
139 template <typename F> | |
140 static FORCE_INLINE ReturnType Call(F function | |
141 #else | |
142 static FORCE_INLINE ReturnType Call(OriginalFunctionType function | |
143 #endif | |
144 $for j [[, | |
145 ArgType$j v$j]]) { | |
146 return SMART_WRAPPER_(Wrapper, ReturnType, OriginalReturnType, | |
147 (*function)($for j , [[ | |
148 | |
149 SMART_UNWRAPPER_(Unwrapper, ArgType$j, v$j)]])); | |
150 } | |
151 }; | |
152 | |
153 // Special case for functions that return void. (SMART_WRAPPER_ involves | |
154 // passing the unwrapped value in a function call, which is not a legal thing to | |
155 // do with void, so we need a special case here that doesn't call | |
156 // SMART_WRAPPER_()). | |
157 template< | |
158 template <typename ToType, typename FromType> class Wrapper, | |
159 template <typename FromType> class Unwrapper$for j [[, | |
160 typename ArgType$j]]> | |
161 class SmartFunctionWrapper$i< | |
162 Wrapper, | |
163 Unwrapper, | |
164 void$for j [[, | |
165 ArgType$j]]> { | |
166 public: | |
167 typedef void OriginalReturnType; | |
168 | |
169 $for j [[ | |
170 typedef SMART_UNWRAPPER_TYPE_(Unwrapper, ArgType$j) OriginalArgType$j; | |
171 | |
172 ]] | |
173 typedef OriginalReturnType (*OriginalFunctionType)($for j , [[ | |
174 | |
175 OriginalArgType$j]]); | |
176 | |
177 #ifdef OSX | |
178 template <typename F> | |
179 static FORCE_INLINE void Call(F function | |
180 #else | |
181 static FORCE_INLINE void Call(OriginalFunctionType function | |
182 #endif | |
183 $for j [[, | |
184 ArgType$j v$j]]) { | |
185 (*function)($for j , [[ | |
186 | |
187 SMART_UNWRAPPER_(Unwrapper, ArgType$j, v$j)]]); | |
188 } | |
189 }; | |
190 | |
191 | |
192 ]] | |
193 // Programmer interface follows. Only macros below here should be used outside | |
194 // this file. | |
195 | |
196 #define DECLARE_WRAPPING_RULESET(ruleSet) \ | |
197 namespace ruleSet { \ | |
198 \ | |
199 /* SmartWrapper is for wrapping values. */ \ | |
200 template<typename ToType, typename FromType> \ | |
201 class SmartWrapper; \ | |
202 \ | |
203 /* Special case where the types are the same. */ \ | |
204 template<typename T1> \ | |
205 class SmartWrapper<T1, T1> { \ | |
206 public: \ | |
207 static FORCE_INLINE T1 Wrap(T1 from) { \ | |
208 return from; \ | |
209 } \ | |
210 }; \ | |
211 \ | |
212 /* Class for unwrapping (i.e., going to the original value). This is done | |
213 function-style rather than predicate-style. The default rule is to leave | |
214 the type unchanged. */ \ | |
215 template<typename FromType> \ | |
216 class SmartUnwrapper { \ | |
217 public: \ | |
218 typedef FromType ToType; \ | |
219 static FORCE_INLINE ToType Unwrap(FromType from) { \ | |
220 return from; \ | |
221 } \ | |
222 }; \ | |
223 \ | |
224 } | |
225 | |
226 // Declares a wrapping rule. | |
227 #define DECLARE_WRAPPER(ruleSet, wrappedType, unwrappedType, var, wrapCode, unwr
apCode) \ | |
228 namespace ruleSet { \ | |
229 \ | |
230 template<> \ | |
231 class SmartWrapper<wrappedType, unwrappedType> { \ | |
232 public: \ | |
233 static FORCE_INLINE wrappedType Wrap(unwrappedType var) { \ | |
234 return wrapCode; \ | |
235 } \ | |
236 }; \ | |
237 \ | |
238 template<> \ | |
239 class SmartUnwrapper<wrappedType> { \ | |
240 public: \ | |
241 typedef unwrappedType ToType; \ | |
242 static FORCE_INLINE unwrappedType Unwrap(wrappedType var) { \ | |
243 return unwrapCode; \ | |
244 } \ | |
245 }; \ | |
246 \ | |
247 } | |
248 | |
249 // Helper macro for declaring a wrapper that wraps/unwraps with reinterpret_cast
<>. | |
250 #define DECLARE_WRAPPER_BY_REINTERPRET_CAST(ruleSet, wrappedType, unwrappedType)
\ | |
251 DECLARE_WRAPPER(ruleSet, wrappedType, unwrappedType, FROM, reinterpret_cast<wr
appedType>(FROM), reinterpret_cast<unwrappedType>(FROM)) | |
252 | |
253 // Helper macro for declaring a wrapper that wraps/unwraps implicitly. | |
254 #define DECLARE_WRAPPER_BY_IMPLICIT_CAST(ruleSet, wrappedType, unwrappedType) \ | |
255 DECLARE_WRAPPER(ruleSet, wrappedType, unwrappedType, FROM, FROM, FROM) | |
256 | |
257 // Helper macro for declaring that the pointer types for one type wrap the point
er types for another type. | |
258 #define DECLARE_POINTER_WRAPPER(ruleSet, wrappedType, unwrappedType) \ | |
259 DECLARE_WRAPPER_BY_REINTERPRET_CAST(ruleSet, wrappedType*, unwrappedType*) \ | |
260 DECLARE_WRAPPER_BY_REINTERPRET_CAST(ruleSet, const wrappedType*, const unwrapp
edType*) \ | |
261 DECLARE_WRAPPER_BY_REINTERPRET_CAST(ruleSet, wrappedType* const, unwrappedType
* const) \ | |
262 DECLARE_WRAPPER_BY_REINTERPRET_CAST(ruleSet, const wrappedType* const, const u
nwrappedType* const) \ | |
263 | |
264 // Macro to wrap a single value. | |
265 #define WRAP(ruleSet, toType, fromType, from) \ | |
266 SMART_WRAPPER_(ruleSet::SmartWrapper, toType, fromType, from) | |
267 | |
268 // Macro to unwrap a single value. | |
269 #define UNWRAP(ruleSet, fromType, from) \ | |
270 SMART_UNWRAPPER_(ruleSet::SmartUnwrapper, fromType, from) | |
271 | |
272 // Macro to get the unwrapped form of a type. | |
273 #define UNWRAP_TYPE(ruleSet, fromType) \ | |
274 SMART_UNWRAPPER_TYPE_(ruleSet::SmartUnwrapper, from) | |
275 | |
276 // Macros to wrap function calls. | |
277 | |
278 $for i [[ | |
279 $range j 1..i | |
280 #define WRAP_CALL$i(ruleSet, toType, function$for j [[, argType$j, arg$j]]) \ | |
281 (SmartFunctionWrapper$i< \ | |
282 ruleSet::SmartWrapper, \ | |
283 ruleSet::SmartUnwrapper, \ | |
284 toType$for j [[, \ | |
285 argType$j]]>::Call( \ | |
286 CAST_FUNCTION_( \ | |
287 &function, \ | |
288 SmartFunctionWrapper$i< \ | |
289 ruleSet::SmartWrapper, \ | |
290 ruleSet::SmartUnwrapper, \ | |
291 toType$for j [[, \ | |
292 argType$j]]>::OriginalFunctionType)$for j [[, \ | |
293 arg$j]])) | |
294 | |
295 ]] | |
296 | |
297 #endif // TALK_SESSION_PHONE_TYPEWRAPPINGHELPERS_H_ | |
OLD | NEW |