// 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::Wrap(from)) #define SMART_UNWRAPPER_(unwrapper, fromType, from) \ (unwrapper::Unwrap(from)) #define SMART_UNWRAPPER_TYPE_(unwrapper, fromType) \ typename unwrapper::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 class Wrapper, template 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 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 class Wrapper, template 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 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 \ class SmartWrapper; \ \ /* Special case where the types are the same. */ \ template \ class SmartWrapper { \ 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 \ 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 { \ public: \ static FORCE_INLINE wrappedType Wrap(unwrappedType var) { \ return wrapCode; \ } \ }; \ \ template<> \ class SmartUnwrapper { \ 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(FROM), reinterpret_cast(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_