|
|
|
/*
|
|
|
|
** 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"
|
|
|
|
|
|
|
|
#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
|
|
|
|
|
|
|
|
#endif /* UPB_HANDLERS_INL_H_ */
|