Chromium Code Reviews| Index: gin/function_template.h |
| diff --git a/gin/function_template.h b/gin/function_template.h |
| index 020357d12fda7d938eee7620f70f25ccfbd8086b..7a52ea541e7556fa88386146590d6cde06471299 100644 |
| --- a/gin/function_template.h |
| +++ b/gin/function_template.h |
| @@ -25,6 +25,10 @@ namespace gin { |
| class PerIsolateData; |
| +enum CreateFunctionTemplateFlags { |
| + HolderIsFirstArgument = 1 << 0, |
| +}; |
| + |
| namespace internal { |
| template<typename T> |
| @@ -35,6 +39,10 @@ template<typename T> |
| struct RemoveConstRef<const T&> { |
| typedef T Type; |
| }; |
| +template<typename T> |
| +struct RemoveConstRef<const T*> { |
|
abarth-chromium
2013/12/04 16:27:55
This seems like a slight misnomer. Maybe we shoul
|
| + typedef T* Type; |
| +}; |
| // CallbackHolder and CallbackHolderBase are used to pass a base::Callback from |
| @@ -57,9 +65,10 @@ class CallbackHolderBase : public Wrappable { |
| template<typename Sig> |
| class CallbackHolder : public CallbackHolderBase { |
| public: |
| - CallbackHolder(const base::Callback<Sig>& callback) |
| - : callback(callback) {} |
| + CallbackHolder(const base::Callback<Sig>& callback, int flags) |
| + : callback(callback), flags(flags) {} |
| base::Callback<Sig> callback; |
| + int flags; |
| private: |
| virtual ~CallbackHolder() {} |
| }; |
| @@ -179,108 +188,141 @@ struct Invoker<void, void, void, void, void> { |
| }; |
| +template<typename T> |
| +bool GetNextArgument(Arguments* args, int create_flags, bool is_first, |
| + T* result) { |
| + if (is_first && (create_flags & HolderIsFirstArgument) != 0) { |
| + return args->GetHolder(result); |
| + } else { |
| + return args->GetNext(result); |
| + } |
| +} |
| + |
| +// For advanced use cases, we allow callers to request the unparsed Arguments |
| +// object and poke around in it directly. |
| +inline bool GetNextArgument(Arguments* args, int flags, bool is_first, |
|
abarth-chromium
2013/12/04 16:27:55
|flags| is slightly inconsistent with the name |cr
|
| + Arguments* result) { |
| + *result = *args; |
| + return true; |
| +} |
| + |
| + |
| // DispatchToCallback converts all the JavaScript arguments to C++ types and |
| // invokes the base::Callback. |
| +template<typename Sig> |
| +struct Dispatcher { |
| +}; |
| + |
| template<typename R> |
| -static void DispatchToCallback( |
| - const v8::FunctionCallbackInfo<v8::Value>& info) { |
| - Arguments args(info); |
| - CallbackHolderBase* holder_base = NULL; |
| - CHECK(args.GetData(&holder_base)); |
| +struct Dispatcher<R()> { |
| + static void DispatchToCallback( |
| + const v8::FunctionCallbackInfo<v8::Value>& info) { |
| + Arguments args(info); |
| + CallbackHolderBase* holder_base = NULL; |
| + CHECK(args.GetData(&holder_base)); |
| - typedef CallbackHolder<R()> HolderT; |
| - HolderT* holder = static_cast<HolderT*>(holder_base); |
| + typedef CallbackHolder<R()> HolderT; |
| + HolderT* holder = static_cast<HolderT*>(holder_base); |
| - Invoker<R>::Go(&args, holder->callback); |
| -} |
| + Invoker<R>::Go(&args, holder->callback); |
| + } |
| +}; |
| template<typename R, typename P1> |
| -static void DispatchToCallback( |
| - const v8::FunctionCallbackInfo<v8::Value>& info) { |
| - Arguments args(info); |
| - CallbackHolderBase* holder_base = NULL; |
| - CHECK(args.GetData(&holder_base)); |
| - |
| - typedef CallbackHolder<R(P1)> HolderT; |
| - HolderT* holder = static_cast<HolderT*>(holder_base); |
| - |
| - typename RemoveConstRef<P1>::Type a1; |
| - if (!args.GetNext(&a1)) { |
| - args.ThrowError(); |
| - return; |
| +struct Dispatcher<R(P1)> { |
| + static void DispatchToCallback( |
| + const v8::FunctionCallbackInfo<v8::Value>& info) { |
| + Arguments args(info); |
| + CallbackHolderBase* holder_base = NULL; |
| + CHECK(args.GetData(&holder_base)); |
| + |
| + typedef CallbackHolder<R(P1)> HolderT; |
| + HolderT* holder = static_cast<HolderT*>(holder_base); |
| + |
| + typename RemoveConstRef<P1>::Type a1; |
| + if (!GetNextArgument(&args, holder->flags, true, &a1)) { |
| + args.ThrowError(); |
| + return; |
| + } |
| + |
| + Invoker<R, P1>::Go(&args, holder->callback, a1); |
| } |
| - |
| - Invoker<R, P1>::Go(&args, holder->callback, a1); |
| -} |
| +}; |
| template<typename R, typename P1, typename P2> |
| -static void DispatchToCallback( |
| - const v8::FunctionCallbackInfo<v8::Value>& info) { |
| - Arguments args(info); |
| - CallbackHolderBase* holder_base = NULL; |
| - CHECK(args.GetData(&holder_base)); |
| - |
| - typedef CallbackHolder<R(P1, P2)> HolderT; |
| - HolderT* holder = static_cast<HolderT*>(holder_base); |
| - |
| - typename RemoveConstRef<P1>::Type a1; |
| - typename RemoveConstRef<P2>::Type a2; |
| - if (!args.GetNext(&a1) || |
| - !args.GetNext(&a2)) { |
| - args.ThrowError(); |
| - return; |
| +struct Dispatcher<R(P1, P2)> { |
| + static void DispatchToCallback( |
| + const v8::FunctionCallbackInfo<v8::Value>& info) { |
| + Arguments args(info); |
| + CallbackHolderBase* holder_base = NULL; |
| + CHECK(args.GetData(&holder_base)); |
| + |
| + typedef CallbackHolder<R(P1, P2)> HolderT; |
| + HolderT* holder = static_cast<HolderT*>(holder_base); |
| + |
| + typename RemoveConstRef<P1>::Type a1; |
| + typename RemoveConstRef<P2>::Type a2; |
| + if (!GetNextArgument(&args, holder->flags, true, &a1) || |
| + !GetNextArgument(&args, holder->flags, false, &a2)) { |
| + args.ThrowError(); |
| + return; |
| + } |
| + |
| + Invoker<R, P1, P2>::Go(&args, holder->callback, a1, a2); |
| } |
| - |
| - Invoker<R, P1, P2>::Go(&args, holder->callback, a1, a2); |
| -} |
| +}; |
| template<typename R, typename P1, typename P2, typename P3> |
| -static void DispatchToCallback( |
| - const v8::FunctionCallbackInfo<v8::Value>& info) { |
| - Arguments args(info); |
| - CallbackHolderBase* holder_base = NULL; |
| - CHECK(args.GetData(&holder_base)); |
| - |
| - typedef CallbackHolder<R(P1, P2, P3)> HolderT; |
| - HolderT* holder = static_cast<HolderT*>(holder_base); |
| - |
| - typename RemoveConstRef<P1>::Type a1; |
| - typename RemoveConstRef<P2>::Type a2; |
| - typename RemoveConstRef<P3>::Type a3; |
| - if (!args.GetNext(&a1) || |
| - !args.GetNext(&a2) || |
| - !args.GetNext(&a3)) { |
| - args.ThrowError(); |
| - return; |
| +struct Dispatcher<R(P1, P2, P3)> { |
| + static void DispatchToCallback( |
| + const v8::FunctionCallbackInfo<v8::Value>& info) { |
| + Arguments args(info); |
| + CallbackHolderBase* holder_base = NULL; |
| + CHECK(args.GetData(&holder_base)); |
| + |
| + typedef CallbackHolder<R(P1, P2, P3)> HolderT; |
| + HolderT* holder = static_cast<HolderT*>(holder_base); |
| + |
| + typename RemoveConstRef<P1>::Type a1; |
| + typename RemoveConstRef<P2>::Type a2; |
| + typename RemoveConstRef<P3>::Type a3; |
| + if (!GetNextArgument(&args, holder->flags, true, &a1) || |
| + !GetNextArgument(&args, holder->flags, false, &a2) || |
| + !GetNextArgument(&args, holder->flags, false, &a3)) { |
| + args.ThrowError(); |
| + return; |
| + } |
| + |
| + Invoker<R, P1, P2, P3>::Go(&args, holder->callback, a1, a2, a3); |
| } |
| - |
| - Invoker<R, P1, P2, P3>::Go(&args, holder->callback, a1, a2, a3); |
| -} |
| +}; |
| template<typename R, typename P1, typename P2, typename P3, typename P4> |
| -static void DispatchToCallback( |
| - const v8::FunctionCallbackInfo<v8::Value>& info) { |
| - Arguments args(info); |
| - CallbackHolderBase* holder_base = NULL; |
| - CHECK(args.GetData(&holder_base)); |
| - |
| - typedef CallbackHolder<R(P1, P2, P3, P4)> HolderT; |
| - HolderT* holder = static_cast<HolderT*>(holder_base); |
| - |
| - typename RemoveConstRef<P1>::Type a1; |
| - typename RemoveConstRef<P2>::Type a2; |
| - typename RemoveConstRef<P3>::Type a3; |
| - typename RemoveConstRef<P4>::Type a4; |
| - if (!args.GetNext(&a1) || |
| - !args.GetNext(&a2) || |
| - !args.GetNext(&a3) || |
| - !args.GetNext(&a4)) { |
| - args.ThrowError(); |
| - return; |
| +struct Dispatcher<R(P1, P2, P3, P4)> { |
| + static void DispatchToCallback( |
| + const v8::FunctionCallbackInfo<v8::Value>& info) { |
| + Arguments args(info); |
| + CallbackHolderBase* holder_base = NULL; |
| + CHECK(args.GetData(&holder_base)); |
| + |
| + typedef CallbackHolder<R(P1, P2, P3, P4)> HolderT; |
| + HolderT* holder = static_cast<HolderT*>(holder_base); |
| + |
| + typename RemoveConstRef<P1>::Type a1; |
| + typename RemoveConstRef<P2>::Type a2; |
| + typename RemoveConstRef<P3>::Type a3; |
| + typename RemoveConstRef<P4>::Type a4; |
| + if (!GetNextArgument(&args, holder->flags, true, &a1) || |
| + !GetNextArgument(&args, holder->flags, false, &a2) || |
| + !GetNextArgument(&args, holder->flags, false, &a3) || |
| + !GetNextArgument(&args, holder->flags, false, &a4)) { |
| + args.ThrowError(); |
| + return; |
| + } |
| + |
| + Invoker<R, P1, P2, P3, P4>::Go(&args, holder->callback, a1, a2, a3, a4); |
| } |
| - |
| - Invoker<R, P1, P2, P3, P4>::Go(&args, holder->callback, a1, a2, a3, a4); |
| -} |
| +}; |
| } // namespace internal |
| @@ -298,61 +340,19 @@ struct Converter<internal::CallbackHolderBase*> |
| : public WrappableConverter<internal::CallbackHolderBase> {}; |
| -// Creates a v8::FunctionTemplate that will run the provided base::Callback each |
| -// time it is called. JavaScript arguments and return values are converted via |
| -// gin::Converter. |
| -template<typename R> |
| -v8::Local<v8::FunctionTemplate> CreateFunctionTemplate( |
| - v8::Isolate* isolate, |
| - const base::Callback<R()> callback) { |
| - typedef internal::CallbackHolder<R()> HolderT; |
| - scoped_refptr<HolderT> holder(new HolderT(callback)); |
| - return v8::FunctionTemplate::New( |
| - &internal::DispatchToCallback<R>, |
| - ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get())); |
| -} |
| - |
| -template<typename R, typename P1> |
| -v8::Local<v8::FunctionTemplate> CreateFunctionTemplate( |
| - v8::Isolate* isolate, |
| - const base::Callback<R(P1)> callback) { |
| - typedef internal::CallbackHolder<R(P1)> HolderT; |
| - scoped_refptr<HolderT> holder(new HolderT(callback)); |
| - return v8::FunctionTemplate::New( |
| - &internal::DispatchToCallback<R, P1>, |
| - ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get())); |
| -} |
| - |
| -template<typename R, typename P1, typename P2> |
| -v8::Local<v8::FunctionTemplate> CreateFunctionTemplate( |
| - v8::Isolate* isolate, |
| - const base::Callback<R(P1, P2)> callback) { |
| - typedef internal::CallbackHolder<R(P1, P2)> HolderT; |
| - scoped_refptr<HolderT> holder(new HolderT(callback)); |
| - return v8::FunctionTemplate::New( |
| - &internal::DispatchToCallback<R, P1, P2>, |
| - ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get())); |
| -} |
| - |
| -template<typename R, typename P1, typename P2, typename P3> |
| -v8::Local<v8::FunctionTemplate> CreateFunctionTemplate( |
| - v8::Isolate* isolate, |
| - const base::Callback<R(P1, P2, P3)> callback) { |
| - typedef internal::CallbackHolder<R(P1, P2, P3)> HolderT; |
| - scoped_refptr<HolderT> holder(new HolderT(callback)); |
| - return v8::FunctionTemplate::New( |
| - &internal::DispatchToCallback<R, P1, P2, P3>, |
| - ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get())); |
| -} |
| - |
| -template<typename R, typename P1, typename P2, typename P3, typename P4> |
| +// CreateFunctionTemplate creates a v8::FunctionTemplate that will create |
| +// JavaScript functions that execute a provided C++ function or base::Callback. |
| +// JavaScript arguments are automatically converted via gin::Converter, as is |
| +// the return value of the C++ function, if any. |
| +template<typename Sig> |
| v8::Local<v8::FunctionTemplate> CreateFunctionTemplate( |
| v8::Isolate* isolate, |
| - const base::Callback<R(P1, P2, P3, P4)> callback) { |
| - typedef internal::CallbackHolder<R(P1, P2, P3, P4)> HolderT; |
| - scoped_refptr<HolderT> holder(new HolderT(callback)); |
| + const base::Callback<Sig> callback, |
| + int flags = 0) { |
| + typedef internal::CallbackHolder<Sig> HolderT; |
| + scoped_refptr<HolderT> holder(new HolderT(callback, flags)); |
| return v8::FunctionTemplate::New( |
| - &internal::DispatchToCallback<R, P1, P2, P3, P4>, |
| + &internal::Dispatcher<Sig>::DispatchToCallback, |
| ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get())); |
| } |