| // To generate typewrapping.h from typewrapping.h.pump, execute: |
| // /home/build/google3/third_party/gtest/scripts/pump.py typewrapping.h.pump |
| |
| // Copyright 2009 Google Inc. |
| // Author: tschmelcher@google.com (Tristan Schmelcher) |
| // |
| // A template meta-programming framework for customizable rule-based |
| // type-checking of type wrappers and wrapper functions. |
| // |
| // This framework is useful in a scenario where there are a set of types that |
| // you choose to "wrap" by implementing new preferred types such that the new |
| // and the old can be converted back and forth in some way, but you already have |
| // a library of functions that expect the original types. Example: |
| // |
| // Type A wraps X |
| // Type B wraps Y |
| // Type C wraps Z |
| // |
| // And function X Foo(Y, Z) exists. |
| // |
| // Since A, B, and C are preferred, you choose to implement a wrapper function |
| // with this interface: |
| // |
| // A Foo2(B, C) |
| // |
| // However, this can lead to subtle discrepancies, because if the interface to |
| // Foo ever changes then Foo2 may become out-of-sync. e.g., Foo might have |
| // originally returned void, but later is changed to return an error code. If |
| // the programmer forgets to change Foo2, the code will probably still work, but |
| // with an implicit cast to void inserted by the compiler, potentially leading |
| // to run-time errors or errors in usage. |
| // |
| // The purpose of this library is to prevent these discrepancies from occurring. |
| // You use it as follows: |
| // |
| // First, declare a new wrapping ruleset: |
| // |
| // DECLARE_WRAPPING_RULESET(ruleset_name) |
| // |
| // Then declare rules on what types wrap which other types and how to convert |
| // them: |
| // |
| // DECLARE_WRAPPER(ruleset_name, A, X, variable_name, wrapping_code, |
| // unwrapping_code) |
| // |
| // Where wrapping_code and unwrapping_code are expressions giving the code to |
| // use to wrap and unwrap a variable with the name "variable_name". There are |
| // also some helper macros to declare common wrapping schemes. |
| // |
| // Then implement your wrapped functions like this: |
| // |
| // A Foo_Wrapped(B b, C c) { |
| // return WRAP_CALL2(ruleset_name, A, Foo, B, b, C, c); |
| // } |
| // |
| // WRAP_CALL2 will unwrap b and c (if B and C are wrapped types) and call Foo, |
| // then wrap the result to type A if different from the return type. More |
| // importantly, if the types in Foo's interface do not _exactly_ match the |
| // unwrapped forms of A, B, and C (after typedef-equivalence), then you will get |
| // a compile-time error for a static_cast from the real function type to the |
| // expected one (except on Mac where this check is infeasible), and with no icky |
| // template instantiation errors either! |
| // |
| // There are also macros to wrap/unwrap individual values according to whichever |
| // rule applies to their types: |
| // |
| // WRAP(ruleset_name, A, X, value) // Compile-time error if no associated rule. |
| // |
| // UNWRAP(ruleset_name, A, value) // Infers X. If A is not a wrapper, no change. |
| // |
| // UNWRAP_TYPE(ruleset_name, A) // Evaluates to X. |
| // |
| // |
| // Essentially, the library works by "storing" the DECLARE_WRAPPER calls in |
| // template specializations. When the wrapper or unwrapper is invoked, the |
| // normal C++ template system essentially "looks up" the rule for the given |
| // type(s). |
| // |
| // All of the auto-generated code can be inlined to produce zero impact on |
| // run-time performance and code size (though some compilers may require |
| // gentle encouragement in order for them to do so). |
| |
| #ifndef TALK_SESSION_PHONE_TYPEWRAPPING_H_ |
| #define TALK_SESSION_PHONE_TYPEWRAPPING_H_ |
| |
| #include "webrtc/base/common.h" |
| |
| #ifdef OSX |
| // XCode's GCC doesn't respect typedef-equivalence when casting function pointer |
| // types, so we can't enforce that the wrapped function signatures strictly |
| // match the expected types. Instead we have to forego the nice user-friendly |
| // static_cast check (because it will spuriously fail) and make the Call() |
| // function into a member template below. |
| #define CAST_FUNCTION_(function, ...) \ |
| function |
| #else |
| #define CAST_FUNCTION_(function, ...) \ |
| static_cast<__VA_ARGS__>(function) |
| #endif |
| |
| // Internal helper macros. |
| #define SMART_WRAPPER_(wrapper, toType, fromType, from) \ |
| (wrapper<toType, fromType>::Wrap(from)) |
| |
| #define SMART_UNWRAPPER_(unwrapper, fromType, from) \ |
| (unwrapper<fromType>::Unwrap(from)) |
| |
| #define SMART_UNWRAPPER_TYPE_(unwrapper, fromType) \ |
| typename unwrapper<fromType>::ToType |
| |
| $var n = 27 |
| $range i 0..n |
| |
| $for i [[ |
| $range j 1..i |
| |
| // The code that follows wraps calls to $i-argument functions, unwrapping the |
| // arguments and wrapping the return value as needed. |
| |
| // The usual case. |
| template< |
| template <typename ToType, typename FromType> class Wrapper, |
| template <typename FromType> class Unwrapper, |
| typename ReturnType$for j [[, |
| typename ArgType$j]]> |
| class SmartFunctionWrapper$i { |
| public: |
| typedef SMART_UNWRAPPER_TYPE_(Unwrapper, ReturnType) OriginalReturnType; |
| |
| $for j [[ |
| typedef SMART_UNWRAPPER_TYPE_(Unwrapper, ArgType$j) OriginalArgType$j; |
| |
| ]] |
| typedef OriginalReturnType (*OriginalFunctionType)($for j , [[ |
| |
| OriginalArgType$j]]); |
| |
| #ifdef OSX |
| template <typename F> |
| static FORCE_INLINE ReturnType Call(F function |
| #else |
| static FORCE_INLINE ReturnType Call(OriginalFunctionType function |
| #endif |
| $for j [[, |
| ArgType$j v$j]]) { |
| return SMART_WRAPPER_(Wrapper, ReturnType, OriginalReturnType, |
| (*function)($for j , [[ |
| |
| SMART_UNWRAPPER_(Unwrapper, ArgType$j, v$j)]])); |
| } |
| }; |
| |
| // Special case for functions that return void. (SMART_WRAPPER_ involves |
| // passing the unwrapped value in a function call, which is not a legal thing to |
| // do with void, so we need a special case here that doesn't call |
| // SMART_WRAPPER_()). |
| template< |
| template <typename ToType, typename FromType> class Wrapper, |
| template <typename FromType> class Unwrapper$for j [[, |
| typename ArgType$j]]> |
| class SmartFunctionWrapper$i< |
| Wrapper, |
| Unwrapper, |
| void$for j [[, |
| ArgType$j]]> { |
| public: |
| typedef void OriginalReturnType; |
| |
| $for j [[ |
| typedef SMART_UNWRAPPER_TYPE_(Unwrapper, ArgType$j) OriginalArgType$j; |
| |
| ]] |
| typedef OriginalReturnType (*OriginalFunctionType)($for j , [[ |
| |
| OriginalArgType$j]]); |
| |
| #ifdef OSX |
| template <typename F> |
| static FORCE_INLINE void Call(F function |
| #else |
| static FORCE_INLINE void Call(OriginalFunctionType function |
| #endif |
| $for j [[, |
| ArgType$j v$j]]) { |
| (*function)($for j , [[ |
| |
| SMART_UNWRAPPER_(Unwrapper, ArgType$j, v$j)]]); |
| } |
| }; |
| |
| |
| ]] |
| // Programmer interface follows. Only macros below here should be used outside |
| // this file. |
| |
| #define DECLARE_WRAPPING_RULESET(ruleSet) \ |
| namespace ruleSet { \ |
| \ |
| /* SmartWrapper is for wrapping values. */ \ |
| template<typename ToType, typename FromType> \ |
| class SmartWrapper; \ |
| \ |
| /* Special case where the types are the same. */ \ |
| template<typename T1> \ |
| class SmartWrapper<T1, T1> { \ |
| public: \ |
| static FORCE_INLINE T1 Wrap(T1 from) { \ |
| return from; \ |
| } \ |
| }; \ |
| \ |
| /* Class for unwrapping (i.e., going to the original value). This is done |
| function-style rather than predicate-style. The default rule is to leave |
| the type unchanged. */ \ |
| template<typename FromType> \ |
| class SmartUnwrapper { \ |
| public: \ |
| typedef FromType ToType; \ |
| static FORCE_INLINE ToType Unwrap(FromType from) { \ |
| return from; \ |
| } \ |
| }; \ |
| \ |
| } |
| |
| // Declares a wrapping rule. |
| #define DECLARE_WRAPPER(ruleSet, wrappedType, unwrappedType, var, wrapCode, unwrapCode) \ |
| namespace ruleSet { \ |
| \ |
| template<> \ |
| class SmartWrapper<wrappedType, unwrappedType> { \ |
| public: \ |
| static FORCE_INLINE wrappedType Wrap(unwrappedType var) { \ |
| return wrapCode; \ |
| } \ |
| }; \ |
| \ |
| template<> \ |
| class SmartUnwrapper<wrappedType> { \ |
| public: \ |
| typedef unwrappedType ToType; \ |
| static FORCE_INLINE unwrappedType Unwrap(wrappedType var) { \ |
| return unwrapCode; \ |
| } \ |
| }; \ |
| \ |
| } |
| |
| // Helper macro for declaring a wrapper that wraps/unwraps with reinterpret_cast<>. |
| #define DECLARE_WRAPPER_BY_REINTERPRET_CAST(ruleSet, wrappedType, unwrappedType) \ |
| DECLARE_WRAPPER(ruleSet, wrappedType, unwrappedType, FROM, reinterpret_cast<wrappedType>(FROM), reinterpret_cast<unwrappedType>(FROM)) |
| |
| // Helper macro for declaring a wrapper that wraps/unwraps implicitly. |
| #define DECLARE_WRAPPER_BY_IMPLICIT_CAST(ruleSet, wrappedType, unwrappedType) \ |
| DECLARE_WRAPPER(ruleSet, wrappedType, unwrappedType, FROM, FROM, FROM) |
| |
| // Helper macro for declaring that the pointer types for one type wrap the pointer types for another type. |
| #define DECLARE_POINTER_WRAPPER(ruleSet, wrappedType, unwrappedType) \ |
| DECLARE_WRAPPER_BY_REINTERPRET_CAST(ruleSet, wrappedType*, unwrappedType*) \ |
| DECLARE_WRAPPER_BY_REINTERPRET_CAST(ruleSet, const wrappedType*, const unwrappedType*) \ |
| DECLARE_WRAPPER_BY_REINTERPRET_CAST(ruleSet, wrappedType* const, unwrappedType* const) \ |
| DECLARE_WRAPPER_BY_REINTERPRET_CAST(ruleSet, const wrappedType* const, const unwrappedType* const) \ |
| |
| // Macro to wrap a single value. |
| #define WRAP(ruleSet, toType, fromType, from) \ |
| SMART_WRAPPER_(ruleSet::SmartWrapper, toType, fromType, from) |
| |
| // Macro to unwrap a single value. |
| #define UNWRAP(ruleSet, fromType, from) \ |
| SMART_UNWRAPPER_(ruleSet::SmartUnwrapper, fromType, from) |
| |
| // Macro to get the unwrapped form of a type. |
| #define UNWRAP_TYPE(ruleSet, fromType) \ |
| SMART_UNWRAPPER_TYPE_(ruleSet::SmartUnwrapper, from) |
| |
| // Macros to wrap function calls. |
| |
| $for i [[ |
| $range j 1..i |
| #define WRAP_CALL$i(ruleSet, toType, function$for j [[, argType$j, arg$j]]) \ |
| (SmartFunctionWrapper$i< \ |
| ruleSet::SmartWrapper, \ |
| ruleSet::SmartUnwrapper, \ |
| toType$for j [[, \ |
| argType$j]]>::Call( \ |
| CAST_FUNCTION_( \ |
| &function, \ |
| SmartFunctionWrapper$i< \ |
| ruleSet::SmartWrapper, \ |
| ruleSet::SmartUnwrapper, \ |
| toType$for j [[, \ |
| argType$j]]>::OriginalFunctionType)$for j [[, \ |
| arg$j]])) |
| |
| ]] |
| |
| #endif // TALK_SESSION_PHONE_TYPEWRAPPINGHELPERS_H_ |