mirror of https://github.com/grpc/grpc.git
The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#)
https://grpc.io/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
923 lines
31 KiB
923 lines
31 KiB
/* |
|
** Inline definitions for handlers.h, which are particularly long and a bit |
|
** tricky. |
|
*/ |
|
|
|
#ifndef UPB_HANDLERS_INL_H_ |
|
#define UPB_HANDLERS_INL_H_ |
|
|
|
#include <limits.h> |
|
#include <stddef.h> |
|
#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 <class T> struct remove_constptr { typedef CouldntRemoveConst type; }; |
|
template <class T> struct remove_constptr<const T *> { typedef T *type; }; |
|
|
|
/* Template that we use below to remove a template specialization from |
|
* consideration if it matches a specific type. */ |
|
template <class T, class U> struct disable_if_same { typedef void Type; }; |
|
template <class T> struct disable_if_same<T, T> {}; |
|
|
|
template <class T> void DeletePointer(void *p) { delete static_cast<T>(p); } |
|
|
|
template <class T1, class T2> |
|
struct FirstUnlessVoidOrBool { |
|
typedef T1 value; |
|
}; |
|
|
|
template <class T2> |
|
struct FirstUnlessVoidOrBool<void, T2> { |
|
typedef T2 value; |
|
}; |
|
|
|
template <class T2> |
|
struct FirstUnlessVoidOrBool<bool, T2> { |
|
typedef T2 value; |
|
}; |
|
|
|
template<class T, class U> |
|
struct is_same { |
|
static bool value; |
|
}; |
|
|
|
template<class T> |
|
struct is_same<T, T> { |
|
static bool value; |
|
}; |
|
|
|
template<class T, class U> |
|
bool is_same<T, U>::value = false; |
|
|
|
template<class T> |
|
bool is_same<T, T>::value = true; |
|
|
|
/* FuncInfo *******************************************************************/ |
|
|
|
/* Info about the user's original, pre-wrapped function. */ |
|
template <class C, class R = void> |
|
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 <class R, class P1, R F(P1), class I> |
|
struct Func1 : public UnboundFunc { |
|
typedef R Return; |
|
typedef I FuncInfo; |
|
static R Call(P1 p1) { return F(p1); } |
|
}; |
|
|
|
template <class R, class P1, class P2, R F(P1, P2), class I> |
|
struct Func2 : public UnboundFunc { |
|
typedef R Return; |
|
typedef I FuncInfo; |
|
static R Call(P1 p1, P2 p2) { return F(p1, p2); } |
|
}; |
|
|
|
template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I> |
|
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 <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4), |
|
class I> |
|
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 <class R, class P1, class P2, class P3, class P4, class P5, |
|
R F(P1, P2, P3, P4, P5), class I> |
|
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 <class T> |
|
struct BoundFunc { |
|
typedef typename remove_constptr<T>::type MutableP2; |
|
explicit BoundFunc(MutableP2 data_) : data(data_) {} |
|
CleanupFunc *GetCleanup() { return &DeletePointer<MutableP2>; } |
|
MutableP2 GetData() { return data; } |
|
MutableP2 data; |
|
}; |
|
|
|
template <class R, class P1, class P2, R F(P1, P2), class I> |
|
struct BoundFunc2 : public BoundFunc<P2> { |
|
typedef BoundFunc<P2> Base; |
|
typedef I FuncInfo; |
|
explicit BoundFunc2(typename Base::MutableP2 arg) : Base(arg) {} |
|
}; |
|
|
|
template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I> |
|
struct BoundFunc3 : public BoundFunc<P2> { |
|
typedef BoundFunc<P2> Base; |
|
typedef I FuncInfo; |
|
explicit BoundFunc3(typename Base::MutableP2 arg) : Base(arg) {} |
|
}; |
|
|
|
template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4), |
|
class I> |
|
struct BoundFunc4 : public BoundFunc<P2> { |
|
typedef BoundFunc<P2> Base; |
|
typedef I FuncInfo; |
|
explicit BoundFunc4(typename Base::MutableP2 arg) : Base(arg) {} |
|
}; |
|
|
|
template <class R, class P1, class P2, class P3, class P4, class P5, |
|
R F(P1, P2, P3, P4, P5), class I> |
|
struct BoundFunc5 : public BoundFunc<P2> { |
|
typedef BoundFunc<P2> 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 <class R, class P1> |
|
struct FuncSig1 { |
|
template <R F(P1)> |
|
Func1<R, P1, F, FuncInfo<P1, R> > GetFunc() { |
|
return Func1<R, P1, F, FuncInfo<P1, R> >(); |
|
} |
|
}; |
|
|
|
template <class R, class P1, class P2> |
|
struct FuncSig2 { |
|
template <R F(P1, P2)> |
|
Func2<R, P1, P2, F, FuncInfo<P1, R> > GetFunc() { |
|
return Func2<R, P1, P2, F, FuncInfo<P1, R> >(); |
|
} |
|
|
|
template <R F(P1, P2)> |
|
BoundFunc2<R, P1, P2, F, FuncInfo<P1, R> > GetFunc( |
|
typename remove_constptr<P2>::type param2) { |
|
return BoundFunc2<R, P1, P2, F, FuncInfo<P1, R> >(param2); |
|
} |
|
}; |
|
|
|
template <class R, class P1, class P2, class P3> |
|
struct FuncSig3 { |
|
template <R F(P1, P2, P3)> |
|
Func3<R, P1, P2, P3, F, FuncInfo<P1, R> > GetFunc() { |
|
return Func3<R, P1, P2, P3, F, FuncInfo<P1, R> >(); |
|
} |
|
|
|
template <R F(P1, P2, P3)> |
|
BoundFunc3<R, P1, P2, P3, F, FuncInfo<P1, R> > GetFunc( |
|
typename remove_constptr<P2>::type param2) { |
|
return BoundFunc3<R, P1, P2, P3, F, FuncInfo<P1, R> >(param2); |
|
} |
|
}; |
|
|
|
template <class R, class P1, class P2, class P3, class P4> |
|
struct FuncSig4 { |
|
template <R F(P1, P2, P3, P4)> |
|
Func4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> > GetFunc() { |
|
return Func4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> >(); |
|
} |
|
|
|
template <R F(P1, P2, P3, P4)> |
|
BoundFunc4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> > GetFunc( |
|
typename remove_constptr<P2>::type param2) { |
|
return BoundFunc4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> >(param2); |
|
} |
|
}; |
|
|
|
template <class R, class P1, class P2, class P3, class P4, class P5> |
|
struct FuncSig5 { |
|
template <R F(P1, P2, P3, P4, P5)> |
|
Func5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> > GetFunc() { |
|
return Func5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> >(); |
|
} |
|
|
|
template <R F(P1, P2, P3, P4, P5)> |
|
BoundFunc5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> > GetFunc( |
|
typename remove_constptr<P2>::type param2) { |
|
return BoundFunc5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> >(param2); |
|
} |
|
}; |
|
|
|
/* Overloaded template function that can construct the appropriate FuncSig* |
|
* class given a function pointer by deducing the template parameters. */ |
|
template <class R, class P1> |
|
inline FuncSig1<R, P1> MatchFunc(R (*f)(P1)) { |
|
UPB_UNUSED(f); /* Only used for template parameter deduction. */ |
|
return FuncSig1<R, P1>(); |
|
} |
|
|
|
template <class R, class P1, class P2> |
|
inline FuncSig2<R, P1, P2> MatchFunc(R (*f)(P1, P2)) { |
|
UPB_UNUSED(f); /* Only used for template parameter deduction. */ |
|
return FuncSig2<R, P1, P2>(); |
|
} |
|
|
|
template <class R, class P1, class P2, class P3> |
|
inline FuncSig3<R, P1, P2, P3> MatchFunc(R (*f)(P1, P2, P3)) { |
|
UPB_UNUSED(f); /* Only used for template parameter deduction. */ |
|
return FuncSig3<R, P1, P2, P3>(); |
|
} |
|
|
|
template <class R, class P1, class P2, class P3, class P4> |
|
inline FuncSig4<R, P1, P2, P3, P4> MatchFunc(R (*f)(P1, P2, P3, P4)) { |
|
UPB_UNUSED(f); /* Only used for template parameter deduction. */ |
|
return FuncSig4<R, P1, P2, P3, P4>(); |
|
} |
|
|
|
template <class R, class P1, class P2, class P3, class P4, class P5> |
|
inline FuncSig5<R, P1, P2, P3, P4, P5> MatchFunc(R (*f)(P1, P2, P3, P4, P5)) { |
|
UPB_UNUSED(f); /* Only used for template parameter deduction. */ |
|
return FuncSig5<R, P1, P2, P3, P4, P5>(); |
|
} |
|
|
|
/* MethodSig ******************************************************************/ |
|
|
|
/* CallMethod*: a function template that calls a given method. */ |
|
template <class R, class C, R (C::*F)()> |
|
R CallMethod0(C *obj) { |
|
return ((*obj).*F)(); |
|
} |
|
|
|
template <class R, class C, class P1, R (C::*F)(P1)> |
|
R CallMethod1(C *obj, P1 arg1) { |
|
return ((*obj).*F)(arg1); |
|
} |
|
|
|
template <class R, class C, class P1, class P2, R (C::*F)(P1, P2)> |
|
R CallMethod2(C *obj, P1 arg1, P2 arg2) { |
|
return ((*obj).*F)(arg1, arg2); |
|
} |
|
|
|
template <class R, class C, class P1, class P2, class P3, R (C::*F)(P1, P2, P3)> |
|
R CallMethod3(C *obj, P1 arg1, P2 arg2, P3 arg3) { |
|
return ((*obj).*F)(arg1, arg2, arg3); |
|
} |
|
|
|
template <class R, class C, class P1, class P2, class P3, class P4, |
|
R (C::*F)(P1, P2, P3, P4)> |
|
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 <class R, class C> |
|
struct MethodSig0 { |
|
template <R (C::*F)()> |
|
Func1<R, C *, CallMethod0<R, C, F>, FuncInfo<C *, R> > GetFunc() { |
|
return Func1<R, C *, CallMethod0<R, C, F>, FuncInfo<C *, R> >(); |
|
} |
|
}; |
|
|
|
template <class R, class C, class P1> |
|
struct MethodSig1 { |
|
template <R (C::*F)(P1)> |
|
Func2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> > GetFunc() { |
|
return Func2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> >(); |
|
} |
|
|
|
template <R (C::*F)(P1)> |
|
BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> > GetFunc( |
|
typename remove_constptr<P1>::type param1) { |
|
return BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> >( |
|
param1); |
|
} |
|
}; |
|
|
|
template <class R, class C, class P1, class P2> |
|
struct MethodSig2 { |
|
template <R (C::*F)(P1, P2)> |
|
Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>, FuncInfo<C *, R> > |
|
GetFunc() { |
|
return Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>, |
|
FuncInfo<C *, R> >(); |
|
} |
|
|
|
template <R (C::*F)(P1, P2)> |
|
BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>, FuncInfo<C *, R> > |
|
GetFunc(typename remove_constptr<P1>::type param1) { |
|
return BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>, |
|
FuncInfo<C *, R> >(param1); |
|
} |
|
}; |
|
|
|
template <class R, class C, class P1, class P2, class P3> |
|
struct MethodSig3 { |
|
template <R (C::*F)(P1, P2, P3)> |
|
Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>, FuncInfo<C *, R> > |
|
GetFunc() { |
|
return Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>, |
|
FuncInfo<C *, R> >(); |
|
} |
|
|
|
template <R (C::*F)(P1, P2, P3)> |
|
BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>, |
|
FuncInfo<C *, R> > |
|
GetFunc(typename remove_constptr<P1>::type param1) { |
|
return BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>, |
|
FuncInfo<C *, R> >(param1); |
|
} |
|
}; |
|
|
|
template <class R, class C, class P1, class P2, class P3, class P4> |
|
struct MethodSig4 { |
|
template <R (C::*F)(P1, P2, P3, P4)> |
|
Func5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>, |
|
FuncInfo<C *, R> > |
|
GetFunc() { |
|
return Func5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>, |
|
FuncInfo<C *, R> >(); |
|
} |
|
|
|
template <R (C::*F)(P1, P2, P3, P4)> |
|
BoundFunc5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>, |
|
FuncInfo<C *, R> > |
|
GetFunc(typename remove_constptr<P1>::type param1) { |
|
return BoundFunc5<R, C *, P1, P2, P3, P4, |
|
CallMethod4<R, C, P1, P2, P3, P4, F>, FuncInfo<C *, R> >( |
|
param1); |
|
} |
|
}; |
|
|
|
template <class R, class C> |
|
inline MethodSig0<R, C> MatchFunc(R (C::*f)()) { |
|
UPB_UNUSED(f); /* Only used for template parameter deduction. */ |
|
return MethodSig0<R, C>(); |
|
} |
|
|
|
template <class R, class C, class P1> |
|
inline MethodSig1<R, C, P1> MatchFunc(R (C::*f)(P1)) { |
|
UPB_UNUSED(f); /* Only used for template parameter deduction. */ |
|
return MethodSig1<R, C, P1>(); |
|
} |
|
|
|
template <class R, class C, class P1, class P2> |
|
inline MethodSig2<R, C, P1, P2> MatchFunc(R (C::*f)(P1, P2)) { |
|
UPB_UNUSED(f); /* Only used for template parameter deduction. */ |
|
return MethodSig2<R, C, P1, P2>(); |
|
} |
|
|
|
template <class R, class C, class P1, class P2, class P3> |
|
inline MethodSig3<R, C, P1, P2, P3> MatchFunc(R (C::*f)(P1, P2, P3)) { |
|
UPB_UNUSED(f); /* Only used for template parameter deduction. */ |
|
return MethodSig3<R, C, P1, P2, P3>(); |
|
} |
|
|
|
template <class R, class C, class P1, class P2, class P3, class P4> |
|
inline MethodSig4<R, C, P1, P2, P3, P4> MatchFunc(R (C::*f)(P1, P2, P3, P4)) { |
|
UPB_UNUSED(f); /* Only used for template parameter deduction. */ |
|
return MethodSig4<R, C, P1, P2, P3, P4>(); |
|
} |
|
|
|
/* 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 <class F, class R, class Enable = void> |
|
struct MaybeWrapReturn; |
|
|
|
/* If the return type matches, return the given function unwrapped. */ |
|
template <class F> |
|
struct MaybeWrapReturn<F, typename F::Return> { |
|
typedef F Func; |
|
}; |
|
|
|
/* Function wrapper that munges the return value from void to (bool)true. */ |
|
template <class P1, class P2, void F(P1, P2)> |
|
bool ReturnTrue2(P1 p1, P2 p2) { |
|
F(p1, p2); |
|
return true; |
|
} |
|
|
|
template <class P1, class P2, class P3, void F(P1, P2, P3)> |
|
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 <class P1, class P2, void F(P1, P2)> |
|
void *ReturnClosure2(P1 p1, P2 p2) { |
|
F(p1, p2); |
|
return p1; |
|
} |
|
|
|
template <class P1, class P2, class P3, void F(P1, P2, P3)> |
|
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 <class R, class P1, class P2, R F(P1, P2)> |
|
void *CastReturnToVoidPtr2(P1 p1, P2 p2) { |
|
return F(p1, p2); |
|
} |
|
|
|
template <class R, class P1, class P2, class P3, R F(P1, P2, P3)> |
|
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 <class P1, class P2, bool F(P1, P2)> |
|
void *ReturnClosureOrBreak2(P1 p1, P2 p2) { |
|
return F(p1, p2) ? p1 : UPB_BREAK; |
|
} |
|
|
|
template <class P1, class P2, class P3, bool F(P1, P2, P3)> |
|
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 <class P1, class P2, |
|
void F(P1, P2, const char *, size_t, const upb_bufhandle *)> |
|
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 <class P1, class P2, |
|
bool F(P1, P2, const char *, size_t, const upb_bufhandle *)> |
|
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 <class P1, class P2, void F(P1, P2), class I> |
|
struct MaybeWrapReturn<Func2<void, P1, P2, F, I>, bool> { |
|
typedef Func2<bool, P1, P2, ReturnTrue2<P1, P2, F>, I> Func; |
|
}; |
|
|
|
template <class P1, class P2, class P3, void F(P1, P2, P3), class I> |
|
struct MaybeWrapReturn<Func3<void, P1, P2, P3, F, I>, bool> { |
|
typedef Func3<bool, P1, P2, P3, ReturnTrue3<P1, P2, P3, F>, I> Func; |
|
}; |
|
|
|
/* If our function returns void but we want one returning void*, wrap it in a |
|
* function that returns the first argument. */ |
|
template <class P1, class P2, void F(P1, P2), class I> |
|
struct MaybeWrapReturn<Func2<void, P1, P2, F, I>, void *> { |
|
typedef Func2<void *, P1, P2, ReturnClosure2<P1, P2, F>, I> Func; |
|
}; |
|
|
|
template <class P1, class P2, class P3, void F(P1, P2, P3), class I> |
|
struct MaybeWrapReturn<Func3<void, P1, P2, P3, F, I>, void *> { |
|
typedef Func3<void *, P1, P2, P3, ReturnClosure3<P1, P2, P3, F>, I> Func; |
|
}; |
|
|
|
/* If our function returns R* but we want one returning void*, wrap it in a |
|
* function that casts to void*. */ |
|
template <class R, class P1, class P2, R *F(P1, P2), class I> |
|
struct MaybeWrapReturn<Func2<R *, P1, P2, F, I>, void *, |
|
typename disable_if_same<R *, void *>::Type> { |
|
typedef Func2<void *, P1, P2, CastReturnToVoidPtr2<R *, P1, P2, F>, I> Func; |
|
}; |
|
|
|
template <class R, class P1, class P2, class P3, R *F(P1, P2, P3), class I> |
|
struct MaybeWrapReturn<Func3<R *, P1, P2, P3, F, I>, void *, |
|
typename disable_if_same<R *, void *>::Type> { |
|
typedef Func3<void *, P1, P2, P3, CastReturnToVoidPtr3<R *, P1, P2, P3, F>, 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 <class P1, class P2, bool F(P1, P2), class I> |
|
struct MaybeWrapReturn<Func2<bool, P1, P2, F, I>, void *> { |
|
typedef Func2<void *, P1, P2, ReturnClosureOrBreak2<P1, P2, F>, I> Func; |
|
}; |
|
|
|
template <class P1, class P2, class P3, bool F(P1, P2, P3), class I> |
|
struct MaybeWrapReturn<Func3<bool, P1, P2, P3, F, I>, void *> { |
|
typedef Func3<void *, P1, P2, P3, ReturnClosureOrBreak3<P1, P2, P3, F>, 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 <class P1, class P2, |
|
void F(P1, P2, const char *, size_t, const upb_bufhandle *), class I> |
|
struct MaybeWrapReturn< |
|
Func5<void, P1, P2, const char *, size_t, const upb_bufhandle *, F, I>, |
|
size_t> { |
|
typedef Func5<size_t, P1, P2, const char *, size_t, const upb_bufhandle *, |
|
ReturnStringLen<P1, P2, F>, 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 <class P1, class P2, |
|
bool F(P1, P2, const char *, size_t, const upb_bufhandle *), class I> |
|
struct MaybeWrapReturn< |
|
Func5<bool, P1, P2, const char *, size_t, const upb_bufhandle *, F, I>, |
|
size_t> { |
|
typedef Func5<size_t, P1, P2, const char *, size_t, const upb_bufhandle *, |
|
ReturnNOr0<P1, P2, F>, 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 <class F, class T> |
|
struct ConvertParams; |
|
|
|
/* Function that discards the handler data parameter. */ |
|
template <class R, class P1, R F(P1)> |
|
R IgnoreHandlerData2(void *p1, const void *hd) { |
|
UPB_UNUSED(hd); |
|
return F(static_cast<P1>(p1)); |
|
} |
|
|
|
template <class R, class P1, class P2Wrapper, class P2Wrapped, |
|
R F(P1, P2Wrapped)> |
|
R IgnoreHandlerData3(void *p1, const void *hd, P2Wrapper p2) { |
|
UPB_UNUSED(hd); |
|
return F(static_cast<P1>(p1), p2); |
|
} |
|
|
|
template <class R, class P1, class P2, class P3, R F(P1, P2, P3)> |
|
R IgnoreHandlerData4(void *p1, const void *hd, P2 p2, P3 p3) { |
|
UPB_UNUSED(hd); |
|
return F(static_cast<P1>(p1), p2, p3); |
|
} |
|
|
|
template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)> |
|
R IgnoreHandlerData5(void *p1, const void *hd, P2 p2, P3 p3, P4 p4) { |
|
UPB_UNUSED(hd); |
|
return F(static_cast<P1>(p1), p2, p3, p4); |
|
} |
|
|
|
template <class R, class P1, R F(P1, const char*, size_t)> |
|
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>(p1), p2, p3); |
|
} |
|
|
|
/* Function that casts the handler data parameter. */ |
|
template <class R, class P1, class P2, R F(P1, P2)> |
|
R CastHandlerData2(void *c, const void *hd) { |
|
return F(static_cast<P1>(c), static_cast<P2>(hd)); |
|
} |
|
|
|
template <class R, class P1, class P2, class P3Wrapper, class P3Wrapped, |
|
R F(P1, P2, P3Wrapped)> |
|
R CastHandlerData3(void *c, const void *hd, P3Wrapper p3) { |
|
return F(static_cast<P1>(c), static_cast<P2>(hd), p3); |
|
} |
|
|
|
template <class R, class P1, class P2, class P3, class P4, class P5, |
|
R F(P1, P2, P3, P4, P5)> |
|
R CastHandlerData5(void *c, const void *hd, P3 p3, P4 p4, P5 p5) { |
|
return F(static_cast<P1>(c), static_cast<P2>(hd), p3, p4, p5); |
|
} |
|
|
|
template <class R, class P1, class P2, R F(P1, P2, const char *, size_t)> |
|
R CastHandlerDataIgnoreHandle(void *c, const void *hd, const char *p3, |
|
size_t p4, const upb_bufhandle *handle) { |
|
UPB_UNUSED(handle); |
|
return F(static_cast<P1>(c), static_cast<P2>(hd), p3, p4); |
|
} |
|
|
|
/* For unbound functions, ignore the handler data. */ |
|
template <class R, class P1, R F(P1), class I, class T> |
|
struct ConvertParams<Func1<R, P1, F, I>, T> { |
|
typedef Func2<R, void *, const void *, IgnoreHandlerData2<R, P1, F>, I> Func; |
|
}; |
|
|
|
template <class R, class P1, class P2, R F(P1, P2), class I, |
|
class R2, class P1_2, class P2_2, class P3_2> |
|
struct ConvertParams<Func2<R, P1, P2, F, I>, |
|
R2 (*)(P1_2, P2_2, P3_2)> { |
|
typedef Func3<R, void *, const void *, P3_2, |
|
IgnoreHandlerData3<R, P1, P3_2, P2, F>, I> Func; |
|
}; |
|
|
|
/* For StringBuffer only; this ignores both the handler data and the |
|
* upb_bufhandle. */ |
|
template <class R, class P1, R F(P1, const char *, size_t), class I, class T> |
|
struct ConvertParams<Func3<R, P1, const char *, size_t, F, I>, T> { |
|
typedef Func5<R, void *, const void *, const char *, size_t, |
|
const upb_bufhandle *, IgnoreHandlerDataIgnoreHandle<R, P1, F>, |
|
I> Func; |
|
}; |
|
|
|
template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4), |
|
class I, class T> |
|
struct ConvertParams<Func4<R, P1, P2, P3, P4, F, I>, T> { |
|
typedef Func5<R, void *, const void *, P2, P3, P4, |
|
IgnoreHandlerData5<R, P1, P2, P3, P4, F>, I> Func; |
|
}; |
|
|
|
/* For bound functions, cast the handler data. */ |
|
template <class R, class P1, class P2, R F(P1, P2), class I, class T> |
|
struct ConvertParams<BoundFunc2<R, P1, P2, F, I>, T> { |
|
typedef Func2<R, void *, const void *, CastHandlerData2<R, P1, P2, F>, I> |
|
Func; |
|
}; |
|
|
|
template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I, |
|
class R2, class P1_2, class P2_2, class P3_2> |
|
struct ConvertParams<BoundFunc3<R, P1, P2, P3, F, I>, |
|
R2 (*)(P1_2, P2_2, P3_2)> { |
|
typedef Func3<R, void *, const void *, P3_2, |
|
CastHandlerData3<R, P1, P2, P3_2, P3, F>, I> Func; |
|
}; |
|
|
|
/* For StringBuffer only; this ignores the upb_bufhandle. */ |
|
template <class R, class P1, class P2, R F(P1, P2, const char *, size_t), |
|
class I, class T> |
|
struct ConvertParams<BoundFunc4<R, P1, P2, const char *, size_t, F, I>, T> { |
|
typedef Func5<R, void *, const void *, const char *, size_t, |
|
const upb_bufhandle *, |
|
CastHandlerDataIgnoreHandle<R, P1, P2, F>, I> |
|
Func; |
|
}; |
|
|
|
template <class R, class P1, class P2, class P3, class P4, class P5, |
|
R F(P1, P2, P3, P4, P5), class I, class T> |
|
struct ConvertParams<BoundFunc5<R, P1, P2, P3, P4, P5, F, I>, T> { |
|
typedef Func5<R, void *, const void *, P3, P4, P5, |
|
CastHandlerData5<R, P1, P2, P3, P4, P5, F>, 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<vtype> { \ |
|
typedef ctype Type; \ |
|
}; \ |
|
template <> \ |
|
inline bool HandlersPtr::SetValueHandler<vtype>( \ |
|
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<Status*> { |
|
typedef Status* Type; |
|
}; |
|
|
|
template <class F> struct ReturnOf; |
|
|
|
template <class R, class P1, class P2> |
|
struct ReturnOf<R (*)(P1, P2)> { |
|
typedef R Return; |
|
}; |
|
|
|
template <class R, class P1, class P2, class P3> |
|
struct ReturnOf<R (*)(P1, P2, P3)> { |
|
typedef R Return; |
|
}; |
|
|
|
template <class R, class P1, class P2, class P3, class P4> |
|
struct ReturnOf<R (*)(P1, P2, P3, P4)> { |
|
typedef R Return; |
|
}; |
|
|
|
template <class R, class P1, class P2, class P3, class P4, class P5> |
|
struct ReturnOf<R (*)(P1, P2, P3, P4, P5)> { |
|
typedef R Return; |
|
}; |
|
|
|
|
|
template <class T> |
|
template <class F> |
|
inline Handler<T>::Handler(F func) |
|
: registered_(false), |
|
cleanup_data_(func.GetData()), |
|
cleanup_func_(func.GetCleanup()) { |
|
attr_.handler_data = func.GetData(); |
|
typedef typename ReturnOf<T>::Return Return; |
|
typedef typename ConvertParams<F, T>::Func ConvertedParamsFunc; |
|
typedef typename MaybeWrapReturn<ConvertedParamsFunc, Return>::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<typename F::FuncInfo::Return, void>::value; |
|
attr_.alwaysok = always_ok; |
|
|
|
/* Closure parameter and return type. */ |
|
attr_.closure_type = UniquePtrForType<typename F::FuncInfo::Closure>(); |
|
|
|
/* 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<typename F::FuncInfo::Return, |
|
typename F::FuncInfo::Closure>::value |
|
EffectiveReturn; |
|
attr_.return_closure_type = UniquePtrForType<EffectiveReturn>(); |
|
} |
|
|
|
template <class T> |
|
inline void Handler<T>::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_ */
|
|
|