/* ** Inline definitions for handlers.h, which are particularly long and a bit ** tricky. */ #ifndef UPB_HANDLERS_INL_H_ #define UPB_HANDLERS_INL_H_ #include #include #include "upb/handlers.h" #include "upb/port_def.inc" #ifdef __cplusplus /* Type detection and typedefs for integer types. * For platforms where there are multiple 32-bit or 64-bit types, we need to be * able to enumerate them so we can properly create overloads for all variants. * * If any platform existed where there were three integer types with the same * size, this would have to become more complicated. For example, short, int, * and long could all be 32-bits. Even more diabolically, short, int, long, * and long long could all be 64 bits and still be standard-compliant. * However, few platforms are this strange, and it's unlikely that upb will be * used on the strangest ones. */ /* Can't count on stdint.h limits like INT32_MAX, because in C++ these are * only defined when __STDC_LIMIT_MACROS are defined before the *first* include * of stdint.h. We can't guarantee that someone else didn't include these first * without defining __STDC_LIMIT_MACROS. */ #define UPB_INT32_MAX 0x7fffffffLL #define UPB_INT32_MIN (-UPB_INT32_MAX - 1) #define UPB_INT64_MAX 0x7fffffffffffffffLL #define UPB_INT64_MIN (-UPB_INT64_MAX - 1) #if INT_MAX == UPB_INT32_MAX && INT_MIN == UPB_INT32_MIN #define UPB_INT_IS_32BITS 1 #endif #if LONG_MAX == UPB_INT32_MAX && LONG_MIN == UPB_INT32_MIN #define UPB_LONG_IS_32BITS 1 #endif #if LONG_MAX == UPB_INT64_MAX && LONG_MIN == UPB_INT64_MIN #define UPB_LONG_IS_64BITS 1 #endif #if LLONG_MAX == UPB_INT64_MAX && LLONG_MIN == UPB_INT64_MIN #define UPB_LLONG_IS_64BITS 1 #endif /* We use macros instead of typedefs so we can undefine them later and avoid * leaking them outside this header file. */ #if UPB_INT_IS_32BITS #define UPB_INT32_T int #define UPB_UINT32_T unsigned int #if UPB_LONG_IS_32BITS #define UPB_TWO_32BIT_TYPES 1 #define UPB_INT32ALT_T long #define UPB_UINT32ALT_T unsigned long #endif /* UPB_LONG_IS_32BITS */ #elif UPB_LONG_IS_32BITS /* && !UPB_INT_IS_32BITS */ #define UPB_INT32_T long #define UPB_UINT32_T unsigned long #endif /* UPB_INT_IS_32BITS */ #if UPB_LONG_IS_64BITS #define UPB_INT64_T long #define UPB_UINT64_T unsigned long #if UPB_LLONG_IS_64BITS #define UPB_TWO_64BIT_TYPES 1 #define UPB_INT64ALT_T long long #define UPB_UINT64ALT_T unsigned long long #endif /* UPB_LLONG_IS_64BITS */ #elif UPB_LLONG_IS_64BITS /* && !UPB_LONG_IS_64BITS */ #define UPB_INT64_T long long #define UPB_UINT64_T unsigned long long #endif /* UPB_LONG_IS_64BITS */ #undef UPB_INT32_MAX #undef UPB_INT32_MIN #undef UPB_INT64_MAX #undef UPB_INT64_MIN #undef UPB_INT_IS_32BITS #undef UPB_LONG_IS_32BITS #undef UPB_LONG_IS_64BITS #undef UPB_LLONG_IS_64BITS namespace upb { typedef void CleanupFunc(void *ptr); /* Template to remove "const" from "const T*" and just return "T*". * * We define a nonsense default because otherwise it will fail to instantiate as * a function parameter type even in cases where we don't expect any caller to * actually match the overload. */ class CouldntRemoveConst {}; template struct remove_constptr { typedef CouldntRemoveConst type; }; template struct remove_constptr { typedef T *type; }; /* Template that we use below to remove a template specialization from * consideration if it matches a specific type. */ template struct disable_if_same { typedef void Type; }; template struct disable_if_same {}; template void DeletePointer(void *p) { delete static_cast(p); } template struct FirstUnlessVoidOrBool { typedef T1 value; }; template struct FirstUnlessVoidOrBool { typedef T2 value; }; template struct FirstUnlessVoidOrBool { typedef T2 value; }; template struct is_same { static bool value; }; template struct is_same { static bool value; }; template bool is_same::value = false; template bool is_same::value = true; /* FuncInfo *******************************************************************/ /* Info about the user's original, pre-wrapped function. */ template struct FuncInfo { /* The type of the closure that the function takes (its first param). */ typedef C Closure; /* The return type. */ typedef R Return; }; /* Func ***********************************************************************/ /* Func1, Func2, Func3: Template classes representing a function and its * signature. * * Since the function is a template parameter, calling the function can be * inlined at compile-time and does not require a function pointer at runtime. * These functions are not bound to a handler data so have no data or cleanup * handler. */ struct UnboundFunc { CleanupFunc *GetCleanup() { return nullptr; } void *GetData() { return nullptr; } }; template struct Func1 : public UnboundFunc { typedef R Return; typedef I FuncInfo; static R Call(P1 p1) { return F(p1); } }; template struct Func2 : public UnboundFunc { typedef R Return; typedef I FuncInfo; static R Call(P1 p1, P2 p2) { return F(p1, p2); } }; template struct Func3 : public UnboundFunc { typedef R Return; typedef I FuncInfo; static R Call(P1 p1, P2 p2, P3 p3) { return F(p1, p2, p3); } }; template struct Func4 : public UnboundFunc { typedef R Return; typedef I FuncInfo; static R Call(P1 p1, P2 p2, P3 p3, P4 p4) { return F(p1, p2, p3, p4); } }; template struct Func5 : public UnboundFunc { typedef R Return; typedef I FuncInfo; static R Call(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { return F(p1, p2, p3, p4, p5); } }; /* BoundFunc ******************************************************************/ /* BoundFunc2, BoundFunc3: Like Func2/Func3 except also contains a value that * shall be bound to the function's second parameter. * * Note that the second parameter is a const pointer, but our stored bound value * is non-const so we can free it when the handlers are destroyed. */ template struct BoundFunc { typedef typename remove_constptr::type MutableP2; explicit BoundFunc(MutableP2 data_) : data(data_) {} CleanupFunc *GetCleanup() { return &DeletePointer; } MutableP2 GetData() { return data; } MutableP2 data; }; template struct BoundFunc2 : public BoundFunc { typedef BoundFunc Base; typedef I FuncInfo; explicit BoundFunc2(typename Base::MutableP2 arg) : Base(arg) {} }; template struct BoundFunc3 : public BoundFunc { typedef BoundFunc Base; typedef I FuncInfo; explicit BoundFunc3(typename Base::MutableP2 arg) : Base(arg) {} }; template struct BoundFunc4 : public BoundFunc { typedef BoundFunc Base; typedef I FuncInfo; explicit BoundFunc4(typename Base::MutableP2 arg) : Base(arg) {} }; template struct BoundFunc5 : public BoundFunc { typedef BoundFunc Base; typedef I FuncInfo; explicit BoundFunc5(typename Base::MutableP2 arg) : Base(arg) {} }; /* FuncSig ********************************************************************/ /* FuncSig1, FuncSig2, FuncSig3: template classes reflecting a function * *signature*, but without a specific function attached. * * These classes contain member functions that can be invoked with a * specific function to return a Func/BoundFunc class. */ template struct FuncSig1 { template Func1 > GetFunc() { return Func1 >(); } }; template struct FuncSig2 { template Func2 > GetFunc() { return Func2 >(); } template BoundFunc2 > GetFunc( typename remove_constptr::type param2) { return BoundFunc2 >(param2); } }; template struct FuncSig3 { template Func3 > GetFunc() { return Func3 >(); } template BoundFunc3 > GetFunc( typename remove_constptr::type param2) { return BoundFunc3 >(param2); } }; template struct FuncSig4 { template Func4 > GetFunc() { return Func4 >(); } template BoundFunc4 > GetFunc( typename remove_constptr::type param2) { return BoundFunc4 >(param2); } }; template struct FuncSig5 { template Func5 > GetFunc() { return Func5 >(); } template BoundFunc5 > GetFunc( typename remove_constptr::type param2) { return BoundFunc5 >(param2); } }; /* Overloaded template function that can construct the appropriate FuncSig* * class given a function pointer by deducing the template parameters. */ template inline FuncSig1 MatchFunc(R (*f)(P1)) { UPB_UNUSED(f); /* Only used for template parameter deduction. */ return FuncSig1(); } template inline FuncSig2 MatchFunc(R (*f)(P1, P2)) { UPB_UNUSED(f); /* Only used for template parameter deduction. */ return FuncSig2(); } template inline FuncSig3 MatchFunc(R (*f)(P1, P2, P3)) { UPB_UNUSED(f); /* Only used for template parameter deduction. */ return FuncSig3(); } template inline FuncSig4 MatchFunc(R (*f)(P1, P2, P3, P4)) { UPB_UNUSED(f); /* Only used for template parameter deduction. */ return FuncSig4(); } template inline FuncSig5 MatchFunc(R (*f)(P1, P2, P3, P4, P5)) { UPB_UNUSED(f); /* Only used for template parameter deduction. */ return FuncSig5(); } /* MethodSig ******************************************************************/ /* CallMethod*: a function template that calls a given method. */ template R CallMethod0(C *obj) { return ((*obj).*F)(); } template R CallMethod1(C *obj, P1 arg1) { return ((*obj).*F)(arg1); } template R CallMethod2(C *obj, P1 arg1, P2 arg2) { return ((*obj).*F)(arg1, arg2); } template R CallMethod3(C *obj, P1 arg1, P2 arg2, P3 arg3) { return ((*obj).*F)(arg1, arg2, arg3); } template R CallMethod4(C *obj, P1 arg1, P2 arg2, P3 arg3, P4 arg4) { return ((*obj).*F)(arg1, arg2, arg3, arg4); } /* MethodSig: like FuncSig, but for member functions. * * GetFunc() returns a normal FuncN object, so after calling GetFunc() no * more logic is required to special-case methods. */ template struct MethodSig0 { template Func1, FuncInfo > GetFunc() { return Func1, FuncInfo >(); } }; template struct MethodSig1 { template Func2, FuncInfo > GetFunc() { return Func2, FuncInfo >(); } template BoundFunc2, FuncInfo > GetFunc( typename remove_constptr::type param1) { return BoundFunc2, FuncInfo >( param1); } }; template struct MethodSig2 { template Func3, FuncInfo > GetFunc() { return Func3, FuncInfo >(); } template BoundFunc3, FuncInfo > GetFunc(typename remove_constptr::type param1) { return BoundFunc3, FuncInfo >(param1); } }; template struct MethodSig3 { template Func4, FuncInfo > GetFunc() { return Func4, FuncInfo >(); } template BoundFunc4, FuncInfo > GetFunc(typename remove_constptr::type param1) { return BoundFunc4, FuncInfo >(param1); } }; template struct MethodSig4 { template Func5, FuncInfo > GetFunc() { return Func5, FuncInfo >(); } template BoundFunc5, FuncInfo > GetFunc(typename remove_constptr::type param1) { return BoundFunc5, FuncInfo >( param1); } }; template inline MethodSig0 MatchFunc(R (C::*f)()) { UPB_UNUSED(f); /* Only used for template parameter deduction. */ return MethodSig0(); } template inline MethodSig1 MatchFunc(R (C::*f)(P1)) { UPB_UNUSED(f); /* Only used for template parameter deduction. */ return MethodSig1(); } template inline MethodSig2 MatchFunc(R (C::*f)(P1, P2)) { UPB_UNUSED(f); /* Only used for template parameter deduction. */ return MethodSig2(); } template inline MethodSig3 MatchFunc(R (C::*f)(P1, P2, P3)) { UPB_UNUSED(f); /* Only used for template parameter deduction. */ return MethodSig3(); } template inline MethodSig4 MatchFunc(R (C::*f)(P1, P2, P3, P4)) { UPB_UNUSED(f); /* Only used for template parameter deduction. */ return MethodSig4(); } /* MaybeWrapReturn ************************************************************/ /* Template class that attempts to wrap the return value of the function so it * matches the expected type. There are two main adjustments it may make: * * 1. If the function returns void, make it return the expected type and with * a value that always indicates success. * 2. If the function returns bool, make it return the expected type with a * value that indicates success or failure. * * The "expected type" for return is: * 1. void* for start handlers. If the closure parameter has a different type * we will cast it to void* for the return in the success case. * 2. size_t for string buffer handlers. * 3. bool for everything else. */ /* Template parameters are FuncN type and desired return type. */ template struct MaybeWrapReturn; /* If the return type matches, return the given function unwrapped. */ template struct MaybeWrapReturn { typedef F Func; }; /* Function wrapper that munges the return value from void to (bool)true. */ template bool ReturnTrue2(P1 p1, P2 p2) { F(p1, p2); return true; } template bool ReturnTrue3(P1 p1, P2 p2, P3 p3) { F(p1, p2, p3); return true; } /* Function wrapper that munges the return value from void to (void*)arg1 */ template void *ReturnClosure2(P1 p1, P2 p2) { F(p1, p2); return p1; } template void *ReturnClosure3(P1 p1, P2 p2, P3 p3) { F(p1, p2, p3); return p1; } /* Function wrapper that munges the return value from R to void*. */ template void *CastReturnToVoidPtr2(P1 p1, P2 p2) { return F(p1, p2); } template void *CastReturnToVoidPtr3(P1 p1, P2 p2, P3 p3) { return F(p1, p2, p3); } /* Function wrapper that munges the return value from bool to void*. */ template void *ReturnClosureOrBreak2(P1 p1, P2 p2) { return F(p1, p2) ? p1 : UPB_BREAK; } template void *ReturnClosureOrBreak3(P1 p1, P2 p2, P3 p3) { return F(p1, p2, p3) ? p1 : UPB_BREAK; } /* For the string callback, which takes five params, returns the size param. */ template size_t ReturnStringLen(P1 p1, P2 p2, const char *p3, size_t p4, const upb_bufhandle *p5) { F(p1, p2, p3, p4, p5); return p4; } /* For the string callback, which takes five params, returns the size param or * zero. */ template size_t ReturnNOr0(P1 p1, P2 p2, const char *p3, size_t p4, const upb_bufhandle *p5) { return F(p1, p2, p3, p4, p5) ? p4 : 0; } /* If we have a function returning void but want a function returning bool, wrap * it in a function that returns true. */ template struct MaybeWrapReturn, bool> { typedef Func2, I> Func; }; template struct MaybeWrapReturn, bool> { typedef Func3, I> Func; }; /* If our function returns void but we want one returning void*, wrap it in a * function that returns the first argument. */ template struct MaybeWrapReturn, void *> { typedef Func2, I> Func; }; template struct MaybeWrapReturn, void *> { typedef Func3, I> Func; }; /* If our function returns R* but we want one returning void*, wrap it in a * function that casts to void*. */ template struct MaybeWrapReturn, void *, typename disable_if_same::Type> { typedef Func2, I> Func; }; template struct MaybeWrapReturn, void *, typename disable_if_same::Type> { typedef Func3, I> Func; }; /* If our function returns bool but we want one returning void*, wrap it in a * function that returns either the first param or UPB_BREAK. */ template struct MaybeWrapReturn, void *> { typedef Func2, I> Func; }; template struct MaybeWrapReturn, void *> { typedef Func3, I> Func; }; /* If our function returns void but we want one returning size_t, wrap it in a * function that returns the size argument. */ template struct MaybeWrapReturn< Func5, size_t> { typedef Func5, I> Func; }; /* If our function returns bool but we want one returning size_t, wrap it in a * function that returns either 0 or the buf size. */ template struct MaybeWrapReturn< Func5, size_t> { typedef Func5, I> Func; }; /* ConvertParams **************************************************************/ /* Template class that converts the function parameters if necessary, and * ignores the HandlerData parameter if appropriate. * * Template parameter is the are FuncN function type. */ template struct ConvertParams; /* Function that discards the handler data parameter. */ template R IgnoreHandlerData2(void *p1, const void *hd) { UPB_UNUSED(hd); return F(static_cast(p1)); } template R IgnoreHandlerData3(void *p1, const void *hd, P2Wrapper p2) { UPB_UNUSED(hd); return F(static_cast(p1), p2); } template R IgnoreHandlerData4(void *p1, const void *hd, P2 p2, P3 p3) { UPB_UNUSED(hd); return F(static_cast(p1), p2, p3); } template R IgnoreHandlerData5(void *p1, const void *hd, P2 p2, P3 p3, P4 p4) { UPB_UNUSED(hd); return F(static_cast(p1), p2, p3, p4); } template R IgnoreHandlerDataIgnoreHandle(void *p1, const void *hd, const char *p2, size_t p3, const upb_bufhandle *handle) { UPB_UNUSED(hd); UPB_UNUSED(handle); return F(static_cast(p1), p2, p3); } /* Function that casts the handler data parameter. */ template R CastHandlerData2(void *c, const void *hd) { return F(static_cast(c), static_cast(hd)); } template R CastHandlerData3(void *c, const void *hd, P3Wrapper p3) { return F(static_cast(c), static_cast(hd), p3); } template R CastHandlerData5(void *c, const void *hd, P3 p3, P4 p4, P5 p5) { return F(static_cast(c), static_cast(hd), p3, p4, p5); } template R CastHandlerDataIgnoreHandle(void *c, const void *hd, const char *p3, size_t p4, const upb_bufhandle *handle) { UPB_UNUSED(handle); return F(static_cast(c), static_cast(hd), p3, p4); } /* For unbound functions, ignore the handler data. */ template struct ConvertParams, T> { typedef Func2, I> Func; }; template struct ConvertParams, R2 (*)(P1_2, P2_2, P3_2)> { typedef Func3, I> Func; }; /* For StringBuffer only; this ignores both the handler data and the * upb_bufhandle. */ template struct ConvertParams, T> { typedef Func5, I> Func; }; template struct ConvertParams, T> { typedef Func5, I> Func; }; /* For bound functions, cast the handler data. */ template struct ConvertParams, T> { typedef Func2, I> Func; }; template struct ConvertParams, R2 (*)(P1_2, P2_2, P3_2)> { typedef Func3, I> Func; }; /* For StringBuffer only; this ignores the upb_bufhandle. */ template struct ConvertParams, T> { typedef Func5, I> Func; }; template struct ConvertParams, T> { typedef Func5, I> Func; }; /* utype/ltype are upper/lower-case, ctype is canonical C type, vtype is * variant C type. */ #define TYPE_METHODS(utype, ltype, ctype, vtype) \ template <> \ struct CanonicalType { \ typedef ctype Type; \ }; \ template <> \ inline bool HandlersPtr::SetValueHandler( \ FieldDefPtr f, const HandlersPtr::utype##Handler &handler) { \ handler.AddCleanup(ptr()); \ return upb_handlers_set##ltype(ptr(), f.ptr(), handler.handler(), \ &handler.attr()); \ } TYPE_METHODS(Double, double, double, double) TYPE_METHODS(Float, float, float, float) TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64_T) TYPE_METHODS(UInt32, uint32, uint32_t, UPB_UINT32_T) TYPE_METHODS(Int64, int64, int64_t, UPB_INT64_T) TYPE_METHODS(Int32, int32, int32_t, UPB_INT32_T) TYPE_METHODS(Bool, bool, bool, bool) #ifdef UPB_TWO_32BIT_TYPES TYPE_METHODS(Int32, int32, int32_t, UPB_INT32ALT_T) TYPE_METHODS(UInt32, uint32, uint32_t, UPB_UINT32ALT_T) #endif #ifdef UPB_TWO_64BIT_TYPES TYPE_METHODS(Int64, int64, int64_t, UPB_INT64ALT_T) TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64ALT_T) #endif #undef TYPE_METHODS template <> struct CanonicalType { typedef Status* Type; }; template struct ReturnOf; template struct ReturnOf { typedef R Return; }; template struct ReturnOf { typedef R Return; }; template struct ReturnOf { typedef R Return; }; template struct ReturnOf { typedef R Return; }; template template inline Handler::Handler(F func) : registered_(false), cleanup_data_(func.GetData()), cleanup_func_(func.GetCleanup()) { attr_.handler_data = func.GetData(); typedef typename ReturnOf::Return Return; typedef typename ConvertParams::Func ConvertedParamsFunc; typedef typename MaybeWrapReturn::Func ReturnWrappedFunc; handler_ = ReturnWrappedFunc().Call; /* Set attributes based on what templates can statically tell us about the * user's function. */ /* If the original function returns void, then we know that we wrapped it to * always return ok. */ bool always_ok = is_same::value; attr_.alwaysok = always_ok; /* Closure parameter and return type. */ attr_.closure_type = UniquePtrForType(); /* We use the closure type (from the first parameter) if the return type is * void or bool, since these are the two cases we wrap to return the closure's * type anyway. * * This is all nonsense for non START* handlers, but it doesn't matter because * in that case the value will be ignored. */ typedef typename FirstUnlessVoidOrBool::value EffectiveReturn; attr_.return_closure_type = UniquePtrForType(); } template inline void Handler::AddCleanup(upb_handlers* h) const { UPB_ASSERT(!registered_); registered_ = true; if (cleanup_func_) { bool ok = upb_handlers_addcleanup(h, cleanup_data_, cleanup_func_); UPB_ASSERT(ok); } } } /* namespace upb */ #endif /* __cplusplus */ #undef UPB_TWO_32BIT_TYPES #undef UPB_TWO_64BIT_TYPES #undef UPB_INT32_T #undef UPB_UINT32_T #undef UPB_INT32ALT_T #undef UPB_UINT32ALT_T #undef UPB_INT64_T #undef UPB_UINT64_T #undef UPB_INT64ALT_T #undef UPB_UINT64ALT_T #include "upb/port_undef.inc" #endif /* UPB_HANDLERS_INL_H_ */