From 735c49b6ad67166ccbcc8e3717681bb560fbf1cf Mon Sep 17 00:00:00 2001 From: kolczyk Date: Fri, 24 Oct 2014 06:06:04 -0700 Subject: [gin] Use variadic templates in gin/function_template.h Replace pump.py generated gin/function_template.h with variadic template version. This results in a concise code which does not require the use of pump preprocessor. Similar effort for base/callback.h is happening in https://codereview.chromium.org/610423003/ BUG= Review URL: https://codereview.chromium.org/671433004 Cr-Commit-Position: refs/heads/master@{#301089} --- gin/function_template.h | 416 ++++++++----------------------------------- gin/function_template.h.pump | 240 ------------------------- gin/wrappable_unittest.cc | 8 +- 3 files changed, 74 insertions(+), 590 deletions(-) delete mode 100644 gin/function_template.h.pump (limited to 'gin') diff --git a/gin/function_template.h b/gin/function_template.h index 7ba54b5..955ff53 100644 --- a/gin/function_template.h +++ b/gin/function_template.h @@ -1,16 +1,10 @@ -// This file was GENERATED by command: -// pump.py function_template.h.pump -// DO NOT EDIT BY HAND!!! - - +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. #ifndef GIN_FUNCTION_TEMPLATE_H_ #define GIN_FUNCTION_TEMPLATE_H_ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - #include "base/callback.h" #include "base/logging.h" #include "gin/arguments.h" @@ -80,180 +74,6 @@ class CallbackHolder : public CallbackHolderBase { DISALLOW_COPY_AND_ASSIGN(CallbackHolder); }; - -// This set of templates invokes a base::Callback, converts the return type to a -// JavaScript value, and returns that value to script via the provided -// gin::Arguments object. -// -// In C++, you can declare the function foo(void), but you can't pass a void -// expression to foo. As a result, we must specialize the case of Callbacks that -// have the void return type. -template -struct Invoker { - inline static void Go( - Arguments* args, - const base::Callback& callback, - const P1& a1, - const P2& a2, - const P3& a3, - const P4& a4, - const P5& a5, - const P6& a6) { - args->Return(callback.Run(a1, a2, a3, a4, a5, a6)); - } -}; -template -struct Invoker { - inline static void Go( - Arguments* args, - const base::Callback& callback, - const P1& a1, - const P2& a2, - const P3& a3, - const P4& a4, - const P5& a5, - const P6& a6) { - callback.Run(a1, a2, a3, a4, a5, a6); - } -}; - -template -struct Invoker { - inline static void Go( - Arguments* args, - const base::Callback& callback, - const P1& a1, - const P2& a2, - const P3& a3, - const P4& a4, - const P5& a5) { - args->Return(callback.Run(a1, a2, a3, a4, a5)); - } -}; -template -struct Invoker { - inline static void Go( - Arguments* args, - const base::Callback& callback, - const P1& a1, - const P2& a2, - const P3& a3, - const P4& a4, - const P5& a5) { - callback.Run(a1, a2, a3, a4, a5); - } -}; - -template -struct Invoker { - inline static void Go( - Arguments* args, - const base::Callback& callback, - const P1& a1, - const P2& a2, - const P3& a3, - const P4& a4) { - args->Return(callback.Run(a1, a2, a3, a4)); - } -}; -template -struct Invoker { - inline static void Go( - Arguments* args, - const base::Callback& callback, - const P1& a1, - const P2& a2, - const P3& a3, - const P4& a4) { - callback.Run(a1, a2, a3, a4); - } -}; - -template -struct Invoker { - inline static void Go( - Arguments* args, - const base::Callback& callback, - const P1& a1, - const P2& a2, - const P3& a3) { - args->Return(callback.Run(a1, a2, a3)); - } -}; -template -struct Invoker { - inline static void Go( - Arguments* args, - const base::Callback& callback, - const P1& a1, - const P2& a2, - const P3& a3) { - callback.Run(a1, a2, a3); - } -}; - -template -struct Invoker { - inline static void Go( - Arguments* args, - const base::Callback& callback, - const P1& a1, - const P2& a2) { - args->Return(callback.Run(a1, a2)); - } -}; -template -struct Invoker { - inline static void Go( - Arguments* args, - const base::Callback& callback, - const P1& a1, - const P2& a2) { - callback.Run(a1, a2); - } -}; - -template -struct Invoker { - inline static void Go( - Arguments* args, - const base::Callback& callback, - const P1& a1) { - args->Return(callback.Run(a1)); - } -}; -template -struct Invoker { - inline static void Go( - Arguments* args, - const base::Callback& callback, - const P1& a1) { - callback.Run(a1); - } -}; - -template -struct Invoker { - inline static void Go( - Arguments* args, - const base::Callback& callback) { - args->Return(callback.Run()); - } -}; -template<> -struct Invoker { - inline static void Go( - Arguments* args, - const base::Callback& callback) { - callback.Run(); - } -}; - - template bool GetNextArgument(Arguments* args, int create_flags, bool is_first, T* result) { @@ -284,170 +104,88 @@ inline bool GetNextArgument(Arguments* args, int create_flags, return true; } +// Classes for generating and storing an argument pack of integer indices +// (based on well-known "indices trick", see: http://goo.gl/bKKojn): +template +struct IndicesHolder {}; -// DispatchToCallback converts all the JavaScript arguments to C++ types and -// invokes the base::Callback. -template -struct Dispatcher { +template +struct IndicesGenerator { + using type = typename IndicesGenerator::type; }; - -template -struct Dispatcher { - static void DispatchToCallback( - const v8::FunctionCallbackInfo& info) { - Arguments args(info); - v8::Handle v8_holder; - CHECK(args.GetData(&v8_holder)); - CallbackHolderBase* holder_base = reinterpret_cast( - v8_holder->Value()); - - typedef CallbackHolder HolderT; - HolderT* holder = static_cast(holder_base); - - Invoker::Go(&args, holder->callback); - } +template +struct IndicesGenerator<0, indices...> { + using type = IndicesHolder; }; -template -struct Dispatcher { - static void DispatchToCallback( - const v8::FunctionCallbackInfo& info) { - Arguments args(info); - v8::Handle v8_holder; - CHECK(args.GetData(&v8_holder)); - CallbackHolderBase* holder_base = reinterpret_cast( - v8_holder->Value()); +// Class template for extracting and storing single argument for callback +// at position |index|. +template +struct ArgumentHolder { + using ArgLocalType = typename CallbackParamTraits::LocalType; - typedef CallbackHolder HolderT; - HolderT* holder = static_cast(holder_base); - - typename CallbackParamTraits::LocalType a1; - if (!GetNextArgument(&args, holder->flags, true, &a1)) { - args.ThrowError(); - return; - } + ArgLocalType value; + bool ok; - Invoker::Go(&args, holder->callback, a1); + ArgumentHolder(Arguments* args, int create_flags) + : ok(GetNextArgument(args, create_flags, index == 0, &value)) { + if (!ok) + args->ThrowError(); } }; -template -struct Dispatcher { - static void DispatchToCallback( - const v8::FunctionCallbackInfo& info) { - Arguments args(info); - v8::Handle v8_holder; - CHECK(args.GetData(&v8_holder)); - CallbackHolderBase* holder_base = reinterpret_cast( - v8_holder->Value()); - - typedef CallbackHolder HolderT; - HolderT* holder = static_cast(holder_base); +// Class template for converting arguments from JavaScript to C++ and running +// the callback with them. +template +class Invoker {}; - typename CallbackParamTraits::LocalType a1; - typename CallbackParamTraits::LocalType a2; - if (!GetNextArgument(&args, holder->flags, true, &a1) || - !GetNextArgument(&args, holder->flags, false, &a2)) { - args.ThrowError(); - return; - } +template +class Invoker, ArgTypes...> + : public ArgumentHolder... { + public: + // Invoker<> inherits from ArgumentHolder<> for each argument. + // C++ has always been strict about the class initialization order, + // so it is guaranteed ArgumentHolders will be initialized (and thus, will + // extract arguments from Arguments) in the right order. + Invoker(Arguments* args, int create_flags) + : ArgumentHolder(args, create_flags)..., + args_(args) {} - Invoker::Go(&args, holder->callback, a1, a2); + bool IsOK() { + return And(ArgumentHolder::ok...); } -}; - -template -struct Dispatcher { - static void DispatchToCallback( - const v8::FunctionCallbackInfo& info) { - Arguments args(info); - v8::Handle v8_holder; - CHECK(args.GetData(&v8_holder)); - CallbackHolderBase* holder_base = reinterpret_cast( - v8_holder->Value()); - typedef CallbackHolder HolderT; - HolderT* holder = static_cast(holder_base); - - typename CallbackParamTraits::LocalType a1; - typename CallbackParamTraits::LocalType a2; - typename CallbackParamTraits::LocalType a3; - if (!GetNextArgument(&args, holder->flags, true, &a1) || - !GetNextArgument(&args, holder->flags, false, &a2) || - !GetNextArgument(&args, holder->flags, false, &a3)) { - args.ThrowError(); - return; - } - - Invoker::Go(&args, holder->callback, a1, a2, a3); + template + void DispatchToCallback(base::Callback callback) { + args_->Return(callback.Run(ArgumentHolder::value...)); } -}; -template -struct Dispatcher { - static void DispatchToCallback( - const v8::FunctionCallbackInfo& info) { - Arguments args(info); - v8::Handle v8_holder; - CHECK(args.GetData(&v8_holder)); - CallbackHolderBase* holder_base = reinterpret_cast( - v8_holder->Value()); - - typedef CallbackHolder HolderT; - HolderT* holder = static_cast(holder_base); - - typename CallbackParamTraits::LocalType a1; - typename CallbackParamTraits::LocalType a2; - typename CallbackParamTraits::LocalType a3; - typename CallbackParamTraits::LocalType 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::Go(&args, holder->callback, a1, a2, a3, a4); + // In C++, you can declare the function foo(void), but you can't pass a void + // expression to foo. As a result, we must specialize the case of Callbacks + // that have the void return type. + void DispatchToCallback(base::Callback callback) { + callback.Run(ArgumentHolder::value...); } -}; -template -struct Dispatcher { - static void DispatchToCallback( - const v8::FunctionCallbackInfo& info) { - Arguments args(info); - v8::Handle v8_holder; - CHECK(args.GetData(&v8_holder)); - CallbackHolderBase* holder_base = reinterpret_cast( - v8_holder->Value()); - - typedef CallbackHolder HolderT; - HolderT* holder = static_cast(holder_base); - - typename CallbackParamTraits::LocalType a1; - typename CallbackParamTraits::LocalType a2; - typename CallbackParamTraits::LocalType a3; - typename CallbackParamTraits::LocalType a4; - typename CallbackParamTraits::LocalType a5; - 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) || - !GetNextArgument(&args, holder->flags, false, &a5)) { - args.ThrowError(); - return; - } - - Invoker::Go(&args, holder->callback, a1, a2, a3, a4, - a5); + private: + static bool And() { return true; } + template + static bool And(bool arg1, T... args) { + return arg1 && And(args...); } + + Arguments* args_; }; -template -struct Dispatcher { +// DispatchToCallback converts all the JavaScript arguments to C++ types and +// invokes the base::Callback. +template +struct Dispatcher {}; + +template +struct Dispatcher { static void DispatchToCallback( const v8::FunctionCallbackInfo& info) { Arguments args(info); @@ -456,27 +194,13 @@ struct Dispatcher { CallbackHolderBase* holder_base = reinterpret_cast( v8_holder->Value()); - typedef CallbackHolder HolderT; + typedef CallbackHolder HolderT; HolderT* holder = static_cast(holder_base); - typename CallbackParamTraits::LocalType a1; - typename CallbackParamTraits::LocalType a2; - typename CallbackParamTraits::LocalType a3; - typename CallbackParamTraits::LocalType a4; - typename CallbackParamTraits::LocalType a5; - typename CallbackParamTraits::LocalType a6; - 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) || - !GetNextArgument(&args, holder->flags, false, &a5) || - !GetNextArgument(&args, holder->flags, false, &a6)) { - args.ThrowError(); - return; - } - - Invoker::Go(&args, holder->callback, a1, a2, a3, - a4, a5, a6); + using Indices = typename IndicesGenerator::type; + Invoker invoker(&args, holder->flags); + if (invoker.IsOK()) + invoker.DispatchToCallback(holder->callback); } }; diff --git a/gin/function_template.h.pump b/gin/function_template.h.pump deleted file mode 100644 index 20b2821..0000000 --- a/gin/function_template.h.pump +++ /dev/null @@ -1,240 +0,0 @@ -$$ This is a pump file for generating file templates. Pump is a python -$$ script that is part of the Google Test suite of utilities. Description -$$ can be found here: -$$ -$$ http://code.google.com/p/googletest/wiki/PumpManual -$$ - -#ifndef GIN_FUNCTION_TEMPLATE_H_ -#define GIN_FUNCTION_TEMPLATE_H_ - -$var MAX_ARITY = 6 - -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/callback.h" -#include "base/logging.h" -#include "gin/arguments.h" -#include "gin/converter.h" -#include "gin/gin_export.h" -#include "v8/include/v8.h" - -namespace gin { - -class PerIsolateData; - -enum CreateFunctionTemplateFlags { - HolderIsFirstArgument = 1 << 0, -}; - -namespace internal { - -template -struct CallbackParamTraits { - typedef T LocalType; -}; -template -struct CallbackParamTraits { - typedef T LocalType; -}; -template -struct CallbackParamTraits { - typedef T* LocalType; -}; - - -// CallbackHolder and CallbackHolderBase are used to pass a base::Callback from -// CreateFunctionTemplate through v8 (via v8::FunctionTemplate) to -// DispatchToCallback, where it is invoked. - -// This simple base class is used so that we can share a single object template -// among every CallbackHolder instance. -class GIN_EXPORT CallbackHolderBase { - public: - v8::Handle GetHandle(v8::Isolate* isolate); - - protected: - explicit CallbackHolderBase(v8::Isolate* isolate); - virtual ~CallbackHolderBase(); - - private: - static void WeakCallback( - const v8::WeakCallbackData& data); - - v8::Persistent v8_ref_; - - DISALLOW_COPY_AND_ASSIGN(CallbackHolderBase); -}; - -template -class CallbackHolder : public CallbackHolderBase { - public: - CallbackHolder(v8::Isolate* isolate, - const base::Callback& callback, - int flags) - : CallbackHolderBase(isolate), callback(callback), flags(flags) {} - base::Callback callback; - int flags; - private: - virtual ~CallbackHolder() {} - - DISALLOW_COPY_AND_ASSIGN(CallbackHolder); -}; - - -// This set of templates invokes a base::Callback, converts the return type to a -// JavaScript value, and returns that value to script via the provided -// gin::Arguments object. -// -// In C++, you can declare the function foo(void), but you can't pass a void -// expression to foo. As a result, we must specialize the case of Callbacks that -// have the void return type. - -$range ARITY 0..MAX_ARITY -$for ARITY [[ -$var INV_ARITY = MAX_ARITY - ARITY -$range ARG 1..INV_ARITY -$range VOID INV_ARITY+1..MAX_ARITY - -$if ARITY == 0 [[ -template -struct Invoker { -]] $else [[ -template -struct Invoker { -]] - - inline static void Go( - Arguments* args, - const base::Callback& callback$for ARG [[, - const P$(ARG)& a$(ARG)]]) { - args->Return(callback.Run($for ARG, [[a$(ARG)]])); - } -}; -template<$for ARG , [[typename P$(ARG)]]> -struct Invoker { - inline static void Go( - Arguments* args, - const base::Callback& callback$for ARG [[, - const P$(ARG)& a$(ARG)]]) { - callback.Run($for ARG, [[a$(ARG)]]); - } -}; - - -]] - -template -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 create_flags, bool is_first, - Arguments* result) { - *result = *args; - return true; -} -inline bool GetNextArgument(Arguments* args, int create_flags, bool is_first, - Arguments** result) { - *result = args; - return true; -} - -// It's common for clients to just need the isolate, so we make that easy. -inline bool GetNextArgument(Arguments* args, int create_flags, - bool is_first, v8::Isolate** result) { - *result = args->isolate(); - return true; -} - - -// DispatchToCallback converts all the JavaScript arguments to C++ types and -// invokes the base::Callback. -template -struct Dispatcher { -}; - -$range ARITY 0..MAX_ARITY -$for ARITY [[ -$range ARG 1..ARITY - -template -struct Dispatcher { - static void DispatchToCallback( - const v8::FunctionCallbackInfo& info) { - Arguments args(info); - v8::Handle v8_holder; - CHECK(args.GetData(&v8_holder)); - CallbackHolderBase* holder_base = reinterpret_cast( - v8_holder->Value()); - - typedef CallbackHolder HolderT; - HolderT* holder = static_cast(holder_base); - -$if ARITY != 0 [[ - - -$for ARG [[ typename CallbackParamTraits::LocalType a$(ARG); - -]] - if ($for ARG || - [[!GetNextArgument(&args, holder->flags, $if ARG == 1 [[true]] $else [[false]], &a$(ARG))]]) { - args.ThrowError(); - return; - } - -]] - - Invoker::Go(&args, holder->callback$for ARG [[, a$(ARG)]]); - } -}; - -]] - -} // namespace internal - - -// 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 -v8::Local CreateFunctionTemplate( - v8::Isolate* isolate, const base::Callback callback, - int callback_flags = 0) { - typedef internal::CallbackHolder HolderT; - HolderT* holder = new HolderT(isolate, callback, callback_flags); - - return v8::FunctionTemplate::New( - isolate, - &internal::Dispatcher::DispatchToCallback, - ConvertToV8 >(isolate, - holder->GetHandle(isolate))); -} - -// CreateFunctionHandler installs a CallAsFunction handler on the given -// object template that forwards to a provided C++ function or base::Callback. -template -void CreateFunctionHandler(v8::Isolate* isolate, - v8::Local tmpl, - const base::Callback callback, - int callback_flags = 0) { - typedef internal::CallbackHolder HolderT; - HolderT* holder = new HolderT(isolate, callback, callback_flags); - tmpl->SetCallAsFunctionHandler(&internal::Dispatcher::DispatchToCallback, - ConvertToV8 >( - isolate, holder->GetHandle(isolate))); -} - -} // namespace gin - -#endif // GIN_FUNCTION_TEMPLATE_H_ diff --git a/gin/wrappable_unittest.cc b/gin/wrappable_unittest.cc index 8dbaf30..ef0dce4 100644 --- a/gin/wrappable_unittest.cc +++ b/gin/wrappable_unittest.cc @@ -94,11 +94,11 @@ class MyCallableObject : public Wrappable { ~MyCallableObject() override {} - void Call(int val, const gin::Arguments& arguments) { + void Call(int val1, int val2, int val3, const gin::Arguments& arguments) { if (arguments.IsConstructCall()) arguments.ThrowTypeError("Cannot be called as constructor."); else - result_ = val; + result_ = val1; } int result_; @@ -230,7 +230,7 @@ TEST_F(WrappableTest, CallAsFunction) { EXPECT_EQ(0, object->result()); v8::Handle source = StringToV8(isolate, "(function(obj) {" - "obj(42);" + "obj(42, 2, 5);" "})"); gin::TryCatch try_catch; v8::Handle script = v8::Script::Compile(source); @@ -253,7 +253,7 @@ TEST_F(WrappableTest, CallAsConstructor) { EXPECT_EQ(0, object->result()); v8::Handle source = StringToV8(isolate, "(function(obj) {" - "new obj(42);" + "new obj(42, 2, 5);" "})"); gin::TryCatch try_catch; v8::Handle script = v8::Script::Compile(source); -- cgit v1.1