| 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 |