From d5961bb76c65171e8eb868edf03c5330fa479a67 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Wed, 29 Nov 2017 11:53:45 +0100 Subject: [PATCH] Re-implement WrapFunction() using C++11 features --- lib/base/CMakeLists.txt | 2 +- lib/base/array-script.cpp | 34 +-- lib/base/boolean-script.cpp | 2 +- lib/base/configobject-script.cpp | 4 +- lib/base/datetime-script.cpp | 2 +- lib/base/dictionary-script.cpp | 16 +- lib/base/function-script.cpp | 4 +- lib/base/function.hpp | 22 +- lib/base/functionwrapper.cpp | 41 --- lib/base/functionwrapper.hpp | 437 ++++++------------------------- lib/base/json-script.cpp | 4 +- lib/base/math-script.cpp | 42 +-- lib/base/number-script.cpp | 2 +- lib/base/object-script.cpp | 6 +- lib/base/string-script.cpp | 22 +- lib/base/typetype-script.cpp | 2 +- lib/config/vmops.hpp | 39 ++- lib/icinga/checkable-script.cpp | 2 +- test/livestatus-fixture.cpp | 2 +- 19 files changed, 187 insertions(+), 498 deletions(-) delete mode 100644 lib/base/functionwrapper.cpp diff --git a/lib/base/CMakeLists.txt b/lib/base/CMakeLists.txt index 049226e9c..97b9209ea 100644 --- a/lib/base/CMakeLists.txt +++ b/lib/base/CMakeLists.txt @@ -34,7 +34,7 @@ set(base_SOURCES json-script.cpp loader.cpp logger.cpp logger.thpp math-script.cpp netstring.cpp networkstream.cpp number.cpp number-script.cpp object.cpp object-script.cpp objecttype.cpp primitivetype.cpp process.cpp ringbuffer.cpp scriptframe.cpp - function.cpp function.thpp function-script.cpp functionwrapper.cpp + function.cpp function.thpp function-script.cpp perfdatavalue.cpp perfdatavalue.thpp scriptglobal.cpp scriptutils.cpp serializer.cpp socket.cpp socketevents.cpp socketevents-epoll.cpp socketevents-poll.cpp stacktrace.cpp statsfunction.cpp stdiostream.cpp stream.cpp streamlogger.cpp streamlogger.thpp string.cpp string-script.cpp diff --git a/lib/base/array-script.cpp b/lib/base/array-script.cpp index 1e9fd9965..dd9d5628d 100644 --- a/lib/base/array-script.cpp +++ b/lib/base/array-script.cpp @@ -265,23 +265,23 @@ Object::Ptr Array::GetPrototype(void) if (!prototype) { prototype = new Dictionary(); - prototype->Set("len", new Function("Array#len", WrapFunction(ArrayLen), {}, true)); - prototype->Set("set", new Function("Array#set", WrapFunction(ArraySet), { "index", "value" })); - prototype->Set("get", new Function("Array#get", WrapFunction(ArrayGet), { "index" })); - prototype->Set("add", new Function("Array#add", WrapFunction(ArrayAdd), { "value" })); - prototype->Set("remove", new Function("Array#remove", WrapFunction(ArrayRemove), { "index" })); - prototype->Set("contains", new Function("Array#contains", WrapFunction(ArrayContains), { "value" }, true)); - prototype->Set("clear", new Function("Array#clear", WrapFunction(ArrayClear))); - prototype->Set("sort", new Function("Array#sort", WrapFunction(ArraySort), { "less_cmp" }, true)); - prototype->Set("shallow_clone", new Function("Array#shallow_clone", WrapFunction(ArrayShallowClone), {}, true)); - prototype->Set("join", new Function("Array#join", WrapFunction(ArrayJoin), { "separator" }, true)); - prototype->Set("reverse", new Function("Array#reverse", WrapFunction(ArrayReverse), {}, true)); - prototype->Set("map", new Function("Array#map", WrapFunction(ArrayMap), { "func" }, true)); - prototype->Set("reduce", new Function("Array#reduce", WrapFunction(ArrayReduce), { "reduce" }, true)); - prototype->Set("filter", new Function("Array#filter", WrapFunction(ArrayFilter), { "func" }, true)); - prototype->Set("any", new Function("Array#any", WrapFunction(ArrayAny), { "func" }, true)); - prototype->Set("all", new Function("Array#all", WrapFunction(ArrayAll), { "func" }, true)); - prototype->Set("unique", new Function("Array#unique", WrapFunction(ArrayUnique), {}, true)); + prototype->Set("len", new Function("Array#len", ArrayLen, {}, true)); + prototype->Set("set", new Function("Array#set", ArraySet, { "index", "value" })); + prototype->Set("get", new Function("Array#get", ArrayGet, { "index" })); + prototype->Set("add", new Function("Array#add", ArrayAdd, { "value" })); + prototype->Set("remove", new Function("Array#remove", ArrayRemove, { "index" })); + prototype->Set("contains", new Function("Array#contains", ArrayContains, { "value" }, true)); + prototype->Set("clear", new Function("Array#clear", ArrayClear)); + prototype->Set("sort", new Function("Array#sort", ArraySort, { "less_cmp" }, true)); + prototype->Set("shallow_clone", new Function("Array#shallow_clone", ArrayShallowClone, {}, true)); + prototype->Set("join", new Function("Array#join", ArrayJoin, { "separator" }, true)); + prototype->Set("reverse", new Function("Array#reverse", ArrayReverse, {}, true)); + prototype->Set("map", new Function("Array#map", ArrayMap, { "func" }, true)); + prototype->Set("reduce", new Function("Array#reduce", ArrayReduce, { "reduce" }, true)); + prototype->Set("filter", new Function("Array#filter", ArrayFilter, { "func" }, true)); + prototype->Set("any", new Function("Array#any", ArrayAny, { "func" }, true)); + prototype->Set("all", new Function("Array#all", ArrayAll, { "func" }, true)); + prototype->Set("unique", new Function("Array#unique", ArrayUnique, {}, true)); } return prototype; diff --git a/lib/base/boolean-script.cpp b/lib/base/boolean-script.cpp index 75c979ada..5741c06ad 100644 --- a/lib/base/boolean-script.cpp +++ b/lib/base/boolean-script.cpp @@ -38,7 +38,7 @@ Object::Ptr Boolean::GetPrototype(void) if (!prototype) { prototype = new Dictionary(); - prototype->Set("to_string", new Function("Boolean#to_string", WrapFunction(BooleanToString), {}, true)); + prototype->Set("to_string", new Function("Boolean#to_string", BooleanToString, {}, true)); } return prototype; diff --git a/lib/base/configobject-script.cpp b/lib/base/configobject-script.cpp index dfe4455b6..d413c4ada 100644 --- a/lib/base/configobject-script.cpp +++ b/lib/base/configobject-script.cpp @@ -45,8 +45,8 @@ Object::Ptr ConfigObject::GetPrototype(void) if (!prototype) { prototype = new Dictionary(); - prototype->Set("modify_attribute", new Function("ConfigObject#modify_attribute", WrapFunction(ConfigObjectModifyAttribute), { "attr", "value" }, false)); - prototype->Set("restore_attribute", new Function("ConfigObject#restore_attribute", WrapFunction(ConfigObjectRestoreAttribute), { "attr", "value" }, false)); + prototype->Set("modify_attribute", new Function("ConfigObject#modify_attribute", ConfigObjectModifyAttribute, { "attr", "value" }, false)); + prototype->Set("restore_attribute", new Function("ConfigObject#restore_attribute", ConfigObjectRestoreAttribute, { "attr", "value" }, false)); } return prototype; diff --git a/lib/base/datetime-script.cpp b/lib/base/datetime-script.cpp index 7d9a14cc2..d838790b5 100644 --- a/lib/base/datetime-script.cpp +++ b/lib/base/datetime-script.cpp @@ -39,7 +39,7 @@ Object::Ptr DateTime::GetPrototype(void) if (!prototype) { prototype = new Dictionary(); - prototype->Set("format", new Function("DateTime#format", WrapFunction(DateTimeFormat), { "format" })); + prototype->Set("format", new Function("DateTime#format", DateTimeFormat, { "format" })); } return prototype; diff --git a/lib/base/dictionary-script.cpp b/lib/base/dictionary-script.cpp index 66aa26cbd..0e976c097 100644 --- a/lib/base/dictionary-script.cpp +++ b/lib/base/dictionary-script.cpp @@ -97,14 +97,14 @@ Object::Ptr Dictionary::GetPrototype(void) if (!prototype) { prototype = new Dictionary(); - prototype->Set("len", new Function("Dictionary#len", WrapFunction(DictionaryLen), {}, true)); - prototype->Set("set", new Function("Dictionary#set", WrapFunction(DictionarySet), { "key", "value" })); - prototype->Set("get", new Function("Dictionary#get", WrapFunction(DictionaryGet), { "key" })); - prototype->Set("remove", new Function("Dictionary#remove", WrapFunction(DictionaryRemove), { "key" })); - prototype->Set("contains", new Function("Dictionary#contains", WrapFunction(DictionaryContains), { "key" }, true)); - prototype->Set("shallow_clone", new Function("Dictionary#shallow_clone", WrapFunction(DictionaryShallowClone), {}, true)); - prototype->Set("keys", new Function("Dictionary#keys", WrapFunction(DictionaryKeys), {}, true)); - prototype->Set("values", new Function("Dictionary#values", WrapFunction(DictionaryValues), {}, true)); + prototype->Set("len", new Function("Dictionary#len", DictionaryLen, {}, true)); + prototype->Set("set", new Function("Dictionary#set", DictionarySet, { "key", "value" })); + prototype->Set("get", new Function("Dictionary#get", DictionaryGet, { "key" })); + prototype->Set("remove", new Function("Dictionary#remove", DictionaryRemove, { "key" })); + prototype->Set("contains", new Function("Dictionary#contains", DictionaryContains, { "key" }, true)); + prototype->Set("shallow_clone", new Function("Dictionary#shallow_clone", DictionaryShallowClone, {}, true)); + prototype->Set("keys", new Function("Dictionary#keys", DictionaryKeys, {}, true)); + prototype->Set("values", new Function("Dictionary#values", DictionaryValues, {}, true)); } return prototype; diff --git a/lib/base/function-script.cpp b/lib/base/function-script.cpp index dab4255de..09e85939d 100644 --- a/lib/base/function-script.cpp +++ b/lib/base/function-script.cpp @@ -59,8 +59,8 @@ Object::Ptr Function::GetPrototype(void) if (!prototype) { prototype = new Dictionary(); - prototype->Set("call", new Function("Function#call", WrapFunction(FunctionCall))); - prototype->Set("callv", new Function("Function#callv", WrapFunction(FunctionCallV))); + prototype->Set("call", new Function("Function#call", FunctionCall)); + prototype->Set("callv", new Function("Function#callv", FunctionCallV)); } return prototype; diff --git a/lib/base/function.hpp b/lib/base/function.hpp index ed88db18b..6f257863f 100644 --- a/lib/base/function.hpp +++ b/lib/base/function.hpp @@ -42,8 +42,11 @@ public: typedef std::function& arguments)> Callback; - Function(const String& name, const Callback& function, const std::vector& args = std::vector(), - bool side_effect_free = false, bool deprecated = false); + template + Function(const String& name, F function, const std::vector& args = std::vector(), + bool side_effect_free = false, bool deprecated = false) + : Function(name, WrapFunction(function), args, side_effect_free, deprecated) + { } Value Invoke(const std::vector& arguments = std::vector()); Value Invoke(const Value& otherThis, const std::vector& arguments = std::vector()); @@ -64,17 +67,20 @@ public: private: Callback m_Callback; + + Function(const String& name, const Callback& function, const std::vector& args, + bool side_effect_free, bool deprecated); }; #define REGISTER_SCRIPTFUNCTION_NS(ns, name, callback, args) \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \ - Function::Ptr sf = new icinga::Function(#ns "#" #name, WrapFunction(callback), String(args).Split(":"), false); \ + Function::Ptr sf = new icinga::Function(#ns "#" #name, callback, String(args).Split(":"), false); \ ScriptGlobal::Set(#ns "." #name, sf); \ }, 10) #define REGISTER_SCRIPTFUNCTION_NS_PREFIX(ns, name, callback, args) \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \ - Function::Ptr sf = new icinga::Function(#ns "#" #name, WrapFunction(callback), String(args).Split(":"), false); \ + Function::Ptr sf = new icinga::Function(#ns "#" #name, callback, String(args).Split(":"), false); \ ScriptGlobal::Set(#ns "." #name, sf); \ Function::Ptr dsf = new icinga::Function("Deprecated#__" #name " (deprecated)", WrapFunction(callback), String(args).Split(":"), false, true); \ ScriptGlobal::Set("Deprecated.__" #name, dsf); \ @@ -82,7 +88,7 @@ private: #define REGISTER_SCRIPTFUNCTION_NS_DEPRECATED(ns, name, callback, args) \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \ - Function::Ptr sf = new icinga::Function(#ns "#" #name, WrapFunction(callback), String(args).Split(":"), false); \ + Function::Ptr sf = new icinga::Function(#ns "#" #name, callback, String(args).Split(":"), false); \ ScriptGlobal::Set(#ns "." #name, sf); \ Function::Ptr dsf = new icinga::Function("Deprecated#" #name " (deprecated)", WrapFunction(callback), String(args).Split(":"), false, true); \ ScriptGlobal::Set("Deprecated." #name, dsf); \ @@ -90,13 +96,13 @@ private: #define REGISTER_SAFE_SCRIPTFUNCTION_NS(ns, name, callback, args) \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \ - Function::Ptr sf = new icinga::Function(#ns "#" #name, WrapFunction(callback), String(args).Split(":"), true); \ + Function::Ptr sf = new icinga::Function(#ns "#" #name, callback, String(args).Split(":"), true); \ ScriptGlobal::Set(#ns "." #name, sf); \ }, 10) #define REGISTER_SAFE_SCRIPTFUNCTION_NS_PREFIX(ns, name, callback, args) \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \ - Function::Ptr sf = new icinga::Function(#ns "#" #name, WrapFunction(callback), String(args).Split(":"), true); \ + Function::Ptr sf = new icinga::Function(#ns "#" #name, callback, String(args).Split(":"), true); \ ScriptGlobal::Set(#ns "." #name, sf); \ Function::Ptr dsf = new icinga::Function("Deprecated#__" #name " (deprecated)", WrapFunction(callback), String(args).Split(":"), true, true); \ ScriptGlobal::Set("Deprecated.__" #name, dsf); \ @@ -104,7 +110,7 @@ private: #define REGISTER_SAFE_SCRIPTFUNCTION_NS_DEPRECATED(ns, name, callback, args) \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \ - Function::Ptr sf = new icinga::Function(#ns "#" #name, WrapFunction(callback), String(args).Split(":"), true); \ + Function::Ptr sf = new icinga::Function(#ns "#" #name, callback, String(args).Split(":"), true); \ ScriptGlobal::Set(#ns "." #name, sf); \ Function::Ptr dsf = new icinga::Function("Deprecated#" #name " (deprecated)", WrapFunction(callback), String(args).Split(":"), true, true); \ ScriptGlobal::Set("Deprecated." #name, dsf); \ diff --git a/lib/base/functionwrapper.cpp b/lib/base/functionwrapper.cpp deleted file mode 100644 index f99a0f73a..000000000 --- a/lib/base/functionwrapper.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/****************************************************************************** - * Icinga 2 * - * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of the GNU General Public License * - * as published by the Free Software Foundation; either version 2 * - * of the License, or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software Foundation * - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * - ******************************************************************************/ - -#include "base/functionwrapper.hpp" - -using namespace icinga; - -Value icinga::FunctionWrapperVV(void (*function)(void), const std::vector&) -{ - function(); - - return Empty; -} - -Value icinga::FunctionWrapperVA(void (*function)(const std::vector&), const std::vector& arguments) -{ - function(arguments); - - return Empty; -} - -std::function& arguments)> icinga::WrapFunction(void (*function)(void)) -{ - return std::bind(&FunctionWrapperVV, function, _1); -} diff --git a/lib/base/functionwrapper.hpp b/lib/base/functionwrapper.hpp index 835a79961..a87efeeaf 100644 --- a/lib/base/functionwrapper.hpp +++ b/lib/base/functionwrapper.hpp @@ -17,390 +17,115 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ -#ifndef SCRIPTFUNCTIONWRAPPER_H -#define SCRIPTFUNCTIONWRAPPER_H +#ifndef FUNCTIONWRAPPER_H +#define FUNCTIONWRAPPER_H #include "base/i2-base.hpp" #include "base/value.hpp" #include +#include using namespace std::placeholders; namespace icinga { -Value FunctionWrapperVV(void (*function)(void), const std::vector& arguments); -Value FunctionWrapperVA(void (*function)(const std::vector&), const std::vector& arguments); - -std::function& arguments)> I2_BASE_API WrapFunction(void (*function)(void)); - -template -Value FunctionWrapperR(TR (*function)(void), const std::vector&) +inline std::function&)> WrapFunction(const std::function&)>& function) { - return function(); + return function; } -template -std::function& arguments)> WrapFunction(TR (*function)(void)) +inline std::function&)> WrapFunction(void (*function)(const std::vector&)) { - return std::bind(&FunctionWrapperR, function, _1); + return [function](const std::vector& arguments) { + function(arguments); + return Empty; + }; } - -template -Value FunctionWrapperV(void (*function)(T0), const std::vector& arguments) +template +std::function&)> WrapFunction(Return (*function)(const std::vector&)) { - if (arguments.size() < 1) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); - else if (arguments.size() > 1) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); - - function(static_cast(arguments[0])); - - return Empty; + return [function](const std::vector& arguments) { + return static_cast(function(arguments)); + }; } -template -std::function& arguments)> WrapFunction(void (*function)(T0)) +template +struct indices { + using next = indices; +}; + +template +struct build_indices { + using type = typename build_indices::type::next; +}; + +template <> +struct build_indices<0> { + using type = indices<>; +}; + +template +using BuildIndices = typename build_indices::type; + +struct unpack_caller { - return std::bind(&FunctionWrapperV, function, _1); -} +private: + template + auto call(FuncType f, const std::vector& args, indices) -> decltype(f(args[I]...)) + { + return f(args[I]...); + } -template -Value FunctionWrapperR(TR (*function)(T0), const std::vector& arguments) +public: + template + auto operator () (FuncType f, const std::vector& args) + -> decltype(call(f, args, BuildIndices::type>::arity>{})) + { + return call(f, args, BuildIndices::type>::arity>{}); + } +}; + +enum class enabler_t {}; + +template +using EnableIf = typename std::enable_if::type; + +template +std::function&)> WrapFunction(FuncType function, + EnableIf())), void>::value>* = 0) { - if (arguments.size() < 1) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); - else if (arguments.size() > 1) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); + return [function](const std::vector& arguments) { + constexpr int arity = boost::function_traits::type>::arity; - return function(static_cast(arguments[0])); + if (arguments.size() < arity) + BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); + else if (arguments.size() > arity) + BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); + + unpack_caller()(function, arguments); + return Empty; + }; } -template -std::function& arguments)> WrapFunction(TR (*function)(T0)) +template +std::function&)> WrapFunction(FuncType function, + EnableIf())), void>::value>* = 0) { - return std::bind(&FunctionWrapperR, function, _1); -} + return [function](const std::vector& arguments) { + constexpr int arity = boost::function_traits::type>::arity; -template -Value FunctionWrapperV(void (*function)(T0, T1), const std::vector& arguments) -{ - if (arguments.size() < 2) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); - else if (arguments.size() > 2) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); + if (arity > 0) { + if (arguments.size() < arity) + BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); + else if (arguments.size() > arity) + BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); + } - function(static_cast(arguments[0]), - static_cast(arguments[1])); - - return Empty; -} - -template -std::function& arguments)> WrapFunction(void (*function)(T0, T1)) -{ - return std::bind(&FunctionWrapperV, function, _1); -} - -template -Value FunctionWrapperR(TR (*function)(T0, T1), const std::vector& arguments) -{ - if (arguments.size() < 2) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); - else if (arguments.size() > 2) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); - - return function(static_cast(arguments[0]), - static_cast(arguments[1])); -} - -template -std::function& arguments)> WrapFunction(TR (*function)(T0, T1)) -{ - return std::bind(&FunctionWrapperR, function, _1); -} - -template -Value FunctionWrapperV(void (*function)(T0, T1, T2), const std::vector& arguments) -{ - if (arguments.size() < 3) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); - else if (arguments.size() > 3) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); - - function(static_cast(arguments[0]), - static_cast(arguments[1]), - static_cast(arguments[2])); - - return Empty; -} - -template -std::function& arguments)> WrapFunction(void (*function)(T0, T1, T2)) -{ - return std::bind(&FunctionWrapperV, function, _1); -} - -template -Value FunctionWrapperR(TR (*function)(T0, T1, T2), const std::vector& arguments) -{ - if (arguments.size() < 3) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); - else if (arguments.size() > 3) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); - - return function(static_cast(arguments[0]), - static_cast(arguments[1]), - static_cast(arguments[2])); -} - -template -std::function& arguments)> WrapFunction(TR (*function)(T0, T1, T2)) -{ - return std::bind(&FunctionWrapperR, function, _1); -} - -template -Value FunctionWrapperV(void (*function)(T0, T1, T2, T3), const std::vector& arguments) -{ - if (arguments.size() < 4) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); - else if (arguments.size() > 4) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); - - function(static_cast(arguments[0]), - static_cast(arguments[1]), - static_cast(arguments[2]), - static_cast(arguments[3])); - - return Empty; -} - -template -std::function& arguments)> WrapFunction(void (*function)(T0, T1, T2, T3)) -{ - return std::bind(&FunctionWrapperV, function, _1); -} - -template -Value FunctionWrapperR(TR (*function)(T0, T1, T2, T3), const std::vector& arguments) -{ - if (arguments.size() < 4) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); - else if (arguments.size() > 4) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); - - return function(static_cast(arguments[0]), - static_cast(arguments[1]), - static_cast(arguments[2]), - static_cast(arguments[3])); -} - -template -std::function& arguments)> WrapFunction(TR (*function)(T0, T1, T2, T3)) -{ - return std::bind(&FunctionWrapperR, function, _1); -} - -template -Value FunctionWrapperV(void (*function)(T0, T1, T2, T3, T4), const std::vector& arguments) -{ - if (arguments.size() < 5) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); - else if (arguments.size() > 5) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); - - function(static_cast(arguments[0]), - static_cast(arguments[1]), - static_cast(arguments[2]), - static_cast(arguments[3]), - static_cast(arguments[4])); - - return Empty; -} - -template -std::function& arguments)> WrapFunction(void (*function)(T0, T1, T2, T3, T4)) -{ - return std::bind(&FunctionWrapperV, function, _1); -} - -template -Value FunctionWrapperR(TR (*function)(T0, T1, T2, T3, T4), const std::vector& arguments) -{ - if (arguments.size() < 5) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); - else if (arguments.size() > 5) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); - - return function(static_cast(arguments[0]), - static_cast(arguments[1]), - static_cast(arguments[2]), - static_cast(arguments[3]), - static_cast(arguments[4])); -} - -template -std::function& arguments)> WrapFunction(TR (*function)(T0, T1, T2, T3, T4)) -{ - return std::bind(&FunctionWrapperR, function, _1); -} - -template -Value FunctionWrapperV(void (*function)(T0, T1, T2, T3, T4, T5), const std::vector& arguments) -{ - if (arguments.size() < 6) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); - else if (arguments.size() > 6) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); - - function(static_cast(arguments[0]), - static_cast(arguments[1]), - static_cast(arguments[2]), - static_cast(arguments[3]), - static_cast(arguments[4]), - static_cast(arguments[5])); - - return Empty; -} - -template -std::function& arguments)> WrapFunction(void (*function)(T0, T1, T2, T3, T4, T5)) -{ - return std::bind(&FunctionWrapperV, function, _1); -} - -template -Value FunctionWrapperR(TR (*function)(T0, T1, T2, T3, T4, T5), const std::vector& arguments) -{ - if (arguments.size() < 6) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); - else if (arguments.size() > 6) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); - - return function(static_cast(arguments[0]), - static_cast(arguments[1]), - static_cast(arguments[2]), - static_cast(arguments[3]), - static_cast(arguments[4]), - static_cast(arguments[5])); -} - -template -std::function& arguments)> WrapFunction(TR (*function)(T0, T1, T2, T3, T4, T5)) -{ - return std::bind(&FunctionWrapperR, function, _1); -} - -template -Value FunctionWrapperV(void (*function)(T0, T1, T2, T3, T4, T5, T6), const std::vector& arguments) -{ - if (arguments.size() < 7) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); - else if (arguments.size() > 7) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); - - function(static_cast(arguments[0]), - static_cast(arguments[1]), - static_cast(arguments[2]), - static_cast(arguments[3]), - static_cast(arguments[4]), - static_cast(arguments[5]), - static_cast(arguments[6])); - - return Empty; -} - -template -std::function& arguments)> WrapFunction(void (*function)(T0, T1, T2, T3, T4, T5, T6)) -{ - return std::bind(&FunctionWrapperV, function, _1); -} - -template -Value FunctionWrapperR(TR (*function)(T0, T1, T2, T3, T4, T5, T6), const std::vector& arguments) -{ - if (arguments.size() < 7) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); - else if (arguments.size() > 7) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); - - return function(static_cast(arguments[0]), - static_cast(arguments[1]), - static_cast(arguments[2]), - static_cast(arguments[3]), - static_cast(arguments[4]), - static_cast(arguments[5]), - static_cast(arguments[6])); -} - -template -std::function& arguments)> WrapFunction(TR (*function)(T0, T1, T2, T3, T4, T5, T6)) -{ - return std::bind(&FunctionWrapperR, function, _1); -} - -template -Value FunctionWrapperV(void (*function)(T0, T1, T2, T3, T4, T5, T6, T7), const std::vector& arguments) -{ - if (arguments.size() < 8) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); - else if (arguments.size() > 8) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); - - function(static_cast(arguments[0]), - static_cast(arguments[1]), - static_cast(arguments[2]), - static_cast(arguments[3]), - static_cast(arguments[4]), - static_cast(arguments[5]), - static_cast(arguments[6]), - static_cast(arguments[7])); - - return Empty; -} - -template -std::function& arguments)> WrapFunction(void (*function)(T0, T1, T2, T3, T4, T5, T6, T7)) -{ - return std::bind(&FunctionWrapperV, function, _1); -} - -template -Value FunctionWrapperR(TR (*function)(T0, T1, T2, T3, T4, T5, T6, T7), const std::vector& arguments) -{ - if (arguments.size() < 8) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); - else if (arguments.size() > 8) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); - - return function(static_cast(arguments[0]), - static_cast(arguments[1]), - static_cast(arguments[2]), - static_cast(arguments[3]), - static_cast(arguments[4]), - static_cast(arguments[5]), - static_cast(arguments[6]), - static_cast(arguments[7])); -} - -template -std::function& arguments)> WrapFunction(TR (*function)(T0, T1, T2, T3, T4, T5, T6, T7)) -{ - return std::bind(&FunctionWrapperR, function, _1); -} - -template -std::function& arguments)> WrapFunction(TR (*function)(const std::vector&)) -{ - return std::bind(function, _1); -} - -inline std::function& arguments)> WrapFunction(void (*function)(const std::vector&)) -{ - return std::bind(&FunctionWrapperVA, function, _1); + return unpack_caller()(function, arguments); + }; } } -#endif /* SCRIPTFUNCTION_H */ +#endif /* FUNCTIONWRAPPER_H */ diff --git a/lib/base/json-script.cpp b/lib/base/json-script.cpp index e342f5ee2..3776b499d 100644 --- a/lib/base/json-script.cpp +++ b/lib/base/json-script.cpp @@ -35,8 +35,8 @@ INITIALIZE_ONCE([]() { Dictionary::Ptr jsonObj = new Dictionary(); /* Methods */ - jsonObj->Set("encode", new Function("Json#encode", WrapFunction(JsonEncodeShim), { "value" }, true)); - jsonObj->Set("decode", new Function("Json#decode", WrapFunction(JsonDecode), { "value" }, true)); + jsonObj->Set("encode", new Function("Json#encode", JsonEncodeShim, { "value" }, true)); + jsonObj->Set("decode", new Function("Json#decode", JsonDecode, { "value" }, true)); ScriptGlobal::Set("Json", jsonObj); }); diff --git a/lib/base/math-script.cpp b/lib/base/math-script.cpp index eb1f4b449..994d567ac 100644 --- a/lib/base/math-script.cpp +++ b/lib/base/math-script.cpp @@ -171,27 +171,27 @@ INITIALIZE_ONCE([]() { mathObj->Set("SQRT2", 1.41421356237309504880); /* Methods */ - mathObj->Set("abs", new Function("Math#abs", WrapFunction(MathAbs), { "x" }, true)); - mathObj->Set("acos", new Function("Math#acos", WrapFunction(MathAcos), { "x" }, true)); - mathObj->Set("asin", new Function("Math#asin", WrapFunction(MathAsin), { "x" }, true)); - mathObj->Set("atan", new Function("Math#atan", WrapFunction(MathAtan), { "x" }, true)); - mathObj->Set("atan2", new Function("Math#atan2", WrapFunction(MathAtan2), { "x", "y" }, true)); - mathObj->Set("ceil", new Function("Math#ceil", WrapFunction(MathCeil), { "x" }, true)); - mathObj->Set("cos", new Function("Math#cos", WrapFunction(MathCos), { "x" }, true)); - mathObj->Set("exp", new Function("Math#exp", WrapFunction(MathExp), { "x" }, true)); - mathObj->Set("floor", new Function("Math#floor", WrapFunction(MathFloor), { "x" }, true)); - mathObj->Set("log", new Function("Math#log", WrapFunction(MathLog), { "x" }, true)); - mathObj->Set("max", new Function("Math#max", WrapFunction(MathMax), {}, true)); - mathObj->Set("min", new Function("Math#min", WrapFunction(MathMin), {}, true)); - mathObj->Set("pow", new Function("Math#pow", WrapFunction(MathPow), { "x", "y" }, true)); - mathObj->Set("random", new Function("Math#random", WrapFunction(MathRandom), {}, true)); - mathObj->Set("round", new Function("Math#round", WrapFunction(MathRound), { "x" }, true)); - mathObj->Set("sin", new Function("Math#sin", WrapFunction(MathSin), { "x" }, true)); - mathObj->Set("sqrt", new Function("Math#sqrt", WrapFunction(MathSqrt), { "x" }, true)); - mathObj->Set("tan", new Function("Math#tan", WrapFunction(MathTan), { "x" }, true)); - mathObj->Set("isnan", new Function("Math#isnan", WrapFunction(MathIsnan), { "x" }, true)); - mathObj->Set("isinf", new Function("Math#isinf", WrapFunction(MathIsinf), { "x" }, true)); - mathObj->Set("sign", new Function("Math#sign", WrapFunction(MathSign), { "x" }, true)); + mathObj->Set("abs", new Function("Math#abs", MathAbs, { "x" }, true)); + mathObj->Set("acos", new Function("Math#acos", MathAcos, { "x" }, true)); + mathObj->Set("asin", new Function("Math#asin", MathAsin, { "x" }, true)); + mathObj->Set("atan", new Function("Math#atan", MathAtan, { "x" }, true)); + mathObj->Set("atan2", new Function("Math#atan2", MathAtan2, { "x", "y" }, true)); + mathObj->Set("ceil", new Function("Math#ceil", MathCeil, { "x" }, true)); + mathObj->Set("cos", new Function("Math#cos", MathCos, { "x" }, true)); + mathObj->Set("exp", new Function("Math#exp", MathExp, { "x" }, true)); + mathObj->Set("floor", new Function("Math#floor", MathFloor, { "x" }, true)); + mathObj->Set("log", new Function("Math#log", MathLog, { "x" }, true)); + mathObj->Set("max", new Function("Math#max", MathMax, {}, true)); + mathObj->Set("min", new Function("Math#min", MathMin, {}, true)); + mathObj->Set("pow", new Function("Math#pow", MathPow, { "x", "y" }, true)); + mathObj->Set("random", new Function("Math#random", MathRandom, {}, true)); + mathObj->Set("round", new Function("Math#round", MathRound, { "x" }, true)); + mathObj->Set("sin", new Function("Math#sin", MathSin, { "x" }, true)); + mathObj->Set("sqrt", new Function("Math#sqrt", MathSqrt, { "x" }, true)); + mathObj->Set("tan", new Function("Math#tan", MathTan, { "x" }, true)); + mathObj->Set("isnan", new Function("Math#isnan", MathIsnan, { "x" }, true)); + mathObj->Set("isinf", new Function("Math#isinf", MathIsinf, { "x" }, true)); + mathObj->Set("sign", new Function("Math#sign", MathSign, { "x" }, true)); ScriptGlobal::Set("Math", mathObj); }); diff --git a/lib/base/number-script.cpp b/lib/base/number-script.cpp index 4366277c7..7967b0650 100644 --- a/lib/base/number-script.cpp +++ b/lib/base/number-script.cpp @@ -37,7 +37,7 @@ Object::Ptr Number::GetPrototype(void) if (!prototype) { prototype = new Dictionary(); - prototype->Set("to_string", new Function("Number#to_string", WrapFunction(NumberToString), {}, true)); + prototype->Set("to_string", new Function("Number#to_string", NumberToString, {}, true)); } return prototype; diff --git a/lib/base/object-script.cpp b/lib/base/object-script.cpp index c8112a402..3e9faff28 100644 --- a/lib/base/object-script.cpp +++ b/lib/base/object-script.cpp @@ -52,9 +52,9 @@ Object::Ptr Object::GetPrototype(void) if (!prototype) { prototype = new Dictionary(); - prototype->Set("to_string", new Function("Object#to_string", WrapFunction(ObjectToString), {}, true)); - prototype->Set("notify_attribute", new Function("Object#notify_attribute", WrapFunction(ObjectNotifyAttribute), { "attribute" }, false)); - prototype->Set("clone", new Function("Object#clone", WrapFunction(ObjectClone), {}, true)); + prototype->Set("to_string", new Function("Object#to_string", ObjectToString, {}, true)); + prototype->Set("notify_attribute", new Function("Object#notify_attribute", ObjectNotifyAttribute, { "attribute" }, false)); + prototype->Set("clone", new Function("Object#clone", ObjectClone, {}, true)); } return prototype; diff --git a/lib/base/string-script.cpp b/lib/base/string-script.cpp index 60af63dda..e84026112 100644 --- a/lib/base/string-script.cpp +++ b/lib/base/string-script.cpp @@ -145,17 +145,17 @@ Object::Ptr String::GetPrototype(void) if (!prototype) { prototype = new Dictionary(); - prototype->Set("len", new Function("String#len", WrapFunction(StringLen), {}, true)); - prototype->Set("to_string", new Function("String#to_string", WrapFunction(StringToString), {}, true)); - prototype->Set("substr", new Function("String#substr", WrapFunction(StringSubstr), { "start", "len" }, true)); - prototype->Set("upper", new Function("String#upper", WrapFunction(StringUpper), {}, true)); - prototype->Set("lower", new Function("String#lower", WrapFunction(StringLower), {}, true)); - prototype->Set("split", new Function("String#split", WrapFunction(StringSplit), { "delims" }, true)); - prototype->Set("find", new Function("String#find", WrapFunction(StringFind), { "str", "start" }, true)); - prototype->Set("contains", new Function("String#contains", WrapFunction(StringContains), { "str" }, true)); - prototype->Set("replace", new Function("String#replace", WrapFunction(StringReplace), { "search", "replacement" }, true)); - prototype->Set("reverse", new Function("String#reverse", WrapFunction(StringReverse), {}, true)); - prototype->Set("trim", new Function("String#trim", WrapFunction(StringTrim), {}, true)); + prototype->Set("len", new Function("String#len", StringLen, {}, true)); + prototype->Set("to_string", new Function("String#to_string", StringToString, {}, true)); + prototype->Set("substr", new Function("String#substr", StringSubstr, { "start", "len" }, true)); + prototype->Set("upper", new Function("String#upper", StringUpper, {}, true)); + prototype->Set("lower", new Function("String#lower", StringLower, {}, true)); + prototype->Set("split", new Function("String#split", StringSplit, { "delims" }, true)); + prototype->Set("find", new Function("String#find", StringFind, { "str", "start" }, true)); + prototype->Set("contains", new Function("String#contains", StringContains, { "str" }, true)); + prototype->Set("replace", new Function("String#replace", StringReplace, { "search", "replacement" }, true)); + prototype->Set("reverse", new Function("String#reverse", StringReverse, {}, true)); + prototype->Set("trim", new Function("String#trim", StringTrim, {}, true)); } return prototype; diff --git a/lib/base/typetype-script.cpp b/lib/base/typetype-script.cpp index 08d616b2e..66452fdcc 100644 --- a/lib/base/typetype-script.cpp +++ b/lib/base/typetype-script.cpp @@ -48,7 +48,7 @@ Object::Ptr TypeType::GetPrototype(void) if (!prototype) { prototype = new Dictionary(); - prototype->Set("register_attribute_handler", new Function("Type#register_attribute_handler", WrapFunction(TypeRegisterAttributeHandler), { "field", "callback" }, false)); + prototype->Set("register_attribute_handler", new Function("Type#register_attribute_handler", TypeRegisterAttributeHandler, { "field", "callback" }, false)); } return prototype; diff --git a/lib/config/vmops.hpp b/lib/config/vmops.hpp index c64ac1064..25999e60b 100644 --- a/lib/config/vmops.hpp +++ b/lib/config/vmops.hpp @@ -109,11 +109,27 @@ public: } - static inline Value NewFunction(ScriptFrame& frame, const String& name, const std::vector& args, + static inline Value NewFunction(ScriptFrame& frame, const String& name, const std::vector& argNames, std::map *closedVars, const boost::shared_ptr& expression) { - return new Function(name, std::bind(&FunctionWrapper, _1, args, - EvaluateClosedVars(frame, closedVars), expression), args); + auto evaluatedClosedVars = EvaluateClosedVars(frame, closedVars); + + auto wrapper = [argNames, evaluatedClosedVars, expression](const std::vector& arguments) { + if (arguments.size() < argNames.size()) + BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function")); + + ScriptFrame *frame = ScriptFrame::GetCurrentFrame(); + + if (evaluatedClosedVars) + evaluatedClosedVars->CopyTo(frame->Locals); + + for (std::vector::size_type i = 0; i < std::min(arguments.size(), argNames.size()); i++) + frame->Locals->Set(argNames[i], arguments[i]); + + return expression->Evaluate(*frame); + }; + + return new Function(name, wrapper, argNames); } static inline Value NewApply(ScriptFrame& frame, const String& type, const String& target, const String& name, const boost::shared_ptr& filter, @@ -236,23 +252,6 @@ public: } private: - static inline Value FunctionWrapper(const std::vector& arguments, - const std::vector& funcargs, const Dictionary::Ptr& closedVars, const boost::shared_ptr& expr) - { - if (arguments.size() < funcargs.size()) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function")); - - ScriptFrame *frame = ScriptFrame::GetCurrentFrame(); - - if (closedVars) - closedVars->CopyTo(frame->Locals); - - for (std::vector::size_type i = 0; i < std::min(arguments.size(), funcargs.size()); i++) - frame->Locals->Set(funcargs[i], arguments[i]); - - return expr->Evaluate(*frame); - } - static inline Dictionary::Ptr EvaluateClosedVars(ScriptFrame& frame, std::map *closedVars) { Dictionary::Ptr locals; diff --git a/lib/icinga/checkable-script.cpp b/lib/icinga/checkable-script.cpp index 40626fef9..31a58a3d4 100644 --- a/lib/icinga/checkable-script.cpp +++ b/lib/icinga/checkable-script.cpp @@ -39,7 +39,7 @@ Object::Ptr Checkable::GetPrototype(void) if (!prototype) { prototype = new Dictionary(); - prototype->Set("process_check_result", new Function("Checkable#process_check_result", WrapFunction(CheckableProcessCheckResult), { "cr" }, false)); + prototype->Set("process_check_result", new Function("Checkable#process_check_result", CheckableProcessCheckResult, { "cr" }, false)); } return prototype; diff --git a/test/livestatus-fixture.cpp b/test/livestatus-fixture.cpp index a6bd7ea3b..054d05827 100644 --- a/test/livestatus-fixture.cpp +++ b/test/livestatus-fixture.cpp @@ -31,7 +31,7 @@ struct LivestatusFixture { BOOST_TEST_MESSAGE("Preparing config objects..."); - ConfigItem::RunWithActivationContext(new Function("CreateTestObjects", WrapFunction(CreateTestObjects))); + ConfigItem::RunWithActivationContext(new Function("CreateTestObjects", CreateTestObjects)); } static void CreateTestObjects(void)