reapack

Package manager for REAPER
Log | Files | Refs | Submodules | README | LICENSE

commit 250ba75ea88e017af4e19b7f52dbe76ff33efd1e
parent dc31a93cdc5221d5c4ea72906368afd936d4db79
Author: cfillion <cfillion@users.noreply.github.com>
Date:   Thu,  4 Apr 2019 02:40:02 -0400

refactor reascript vararg wrappers without preprocessing

Diffstat:
Msrc/action.hpp | 3++-
Msrc/api.cpp | 33+++++++++++++++++++--------------
Msrc/api.hpp | 23+++++++++++++----------
Msrc/api_helper.hpp | 83+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Msrc/event.hpp | 23++++++++++++-----------
Msrc/reapack.hpp | 2+-
Msrc/string.hpp | 5+++--
Mvendor/vcpkg-deps.txt | 2+-
8 files changed, 103 insertions(+), 71 deletions(-)

diff --git a/src/action.hpp b/src/action.hpp @@ -43,7 +43,8 @@ private: class ActionList { public: - template<class... Args> Action *add(Args&&... args) { + template<typename... Args> Action *add(Args&&... args) + { auto action = std::make_unique<Action>(args...); m_list.emplace(action->id(), std::move(action)); diff --git a/src/api.cpp b/src/api.cpp @@ -17,28 +17,33 @@ #include "api.hpp" -#include <cstdio> +#include <string> #include <reaper_plugin_functions.h> -APIDef::APIDef(const APIFunc *func) - : m_func(func) +using namespace std::string_literals; + +#define KEY(prefix) (prefix "_ReaPack_"s + m_func->name) + +APIReg::APIReg(const APIFunc *func) + : m_func(func), + m_impl(KEY("API")), m_vararg(KEY("APIvararg")), m_help(KEY("APIdef")) { - plugin_register(m_func->cKey, m_func->cImpl); - plugin_register(m_func->reascriptKey, m_func->reascriptImpl); - plugin_register(m_func->definitionKey, m_func->definition); + registerFunc(); } -APIDef::~APIDef() +APIReg::~APIReg() { - unregister(m_func->cKey, m_func->cImpl); - unregister(m_func->reascriptKey, m_func->reascriptImpl); - unregister(m_func->definitionKey, m_func->definition); + m_impl.insert(m_impl.begin(), '-'); + m_vararg.insert(m_vararg.begin(), '-'); + m_help.insert(m_help.begin(), '-'); + + registerFunc(); } -void APIDef::unregister(const char *key, void *ptr) +void APIReg::registerFunc() const { - char buf[255]; - snprintf(buf, sizeof(buf), "-%s", key); - plugin_register(buf, ptr); + plugin_register(m_impl.c_str(), m_func->cImpl); + plugin_register(m_vararg.c_str(), m_func->reascriptImpl); + plugin_register(m_help.c_str(), m_func->definition); } diff --git a/src/api.hpp b/src/api.hpp @@ -18,27 +18,30 @@ #ifndef REAPACK_API_HPP #define REAPACK_API_HPP +#include <string> + struct APIFunc { - const char *cKey; + const char *name; void *cImpl; - - const char *reascriptKey; void *reascriptImpl; - - const char *definitionKey; void *definition; }; -class APIDef { +class APIReg { public: - APIDef(const APIFunc *); - APIDef(const APIDef &) = delete; - ~APIDef(); + APIReg(const APIFunc *); + APIReg(const APIReg &) = delete; + ~APIReg(); private: - void unregister(const char *key, void *ptr); + void registerFunc() const; const APIFunc *m_func; + + // plugin_register requires these to not be temporaries + std::string m_impl; + std::string m_vararg; + std::string m_help; }; namespace API { diff --git a/src/api_helper.hpp b/src/api_helper.hpp @@ -18,48 +18,69 @@ #ifndef REAPACK_API_HELPER_HPP #define REAPACK_API_HELPER_HPP -#include <boost/mpl/aux_/preprocessor/token_equal.hpp> +#include <tuple> + #include <boost/preprocessor.hpp> -#define API_PREFIX "ReaPack_" +template<typename T> +struct ReaScriptAPI; + +template<typename R, typename... Args> +struct ReaScriptAPI<R(*)(Args...)> +{ + static void *applyVarArg(R(*fn)(Args...), void **argv, int argc) + { + if(static_cast<size_t>(argc) < sizeof...(Args)) + return nullptr; + + const auto &voidArgs = makeTuple(argv, std::index_sequence_for<Args...>{}); + const auto &args = *reinterpret_cast<const std::tuple<Args...> *>(&voidArgs); + + if constexpr (std::is_void_v<R>) { + std::apply(fn, args); + return nullptr; + } + else { + // cast integers to have the same size as a pointer to avoid warnings + using IntPtrR = std::conditional_t<std::is_integral_v<R>, intptr_t, R>; + const auto value = static_cast<IntPtrR>(std::apply(fn, args)); + return reinterpret_cast<void *>(value); + } + } + +private: + template<size_t... I> + static auto makeTuple(void **argv, std::index_sequence<I...>) + { + return std::make_tuple(argv[I]...); + } +}; -#define BOOST_MPL_PP_TOKEN_EQUAL_void(x) x -#define BOOST_MPL_PP_TOKEN_EQUAL_bool(x) x -#define BOOST_MPL_PP_TOKEN_EQUAL_int(x) x -#define IS_VOID(type) BOOST_MPL_PP_TOKEN_EQUAL(type, void) -#define IS_BOOL(type) BOOST_MPL_PP_TOKEN_EQUAL(type, bool) -#define IS_INT(type) BOOST_MPL_PP_TOKEN_EQUAL(type, int) +template<auto fn> +void *InvokeReaScriptAPI(void **argv, int argc) +{ + return ReaScriptAPI<decltype(fn)>::applyVarArg(fn, argv, argc); +} #define ARG_TYPE(arg) BOOST_PP_TUPLE_ELEM(2, 0, arg) #define ARG_NAME(arg) BOOST_PP_TUPLE_ELEM(2, 1, arg) -// produce an appropriate conversion from void* to any type -#define VOIDP_TO(type, val) \ - BOOST_PP_IF(IS_BOOL(type), val != 0, \ - (type) BOOST_PP_EXPR_IF(IS_INT(type), (intptr_t)) val) - #define DEFARGS(r, data, i, arg) BOOST_PP_COMMA_IF(i) ARG_TYPE(arg) ARG_NAME(arg) -#define CALLARGS(r, data, i, arg) \ - BOOST_PP_COMMA_IF(i) VOIDP_TO(ARG_TYPE(arg), argv[i]) #define DOCARGS(r, macro, i, arg) \ BOOST_PP_EXPR_IF(i, ",") BOOST_PP_STRINGIZE(macro(arg)) -#define DEFINE_API(type, name, args, help, ...) \ - namespace API_##name { \ - static type cImpl(BOOST_PP_SEQ_FOR_EACH_I(DEFARGS, _, args)) __VA_ARGS__ \ - static void *reascriptImpl(void **argv, int argc) { \ - BOOST_PP_EXPR_IF(BOOST_PP_NOT(IS_VOID(type)), return (void *)(intptr_t)) \ - cImpl(BOOST_PP_SEQ_FOR_EACH_I(CALLARGS, _, args)); \ - BOOST_PP_EXPR_IF(IS_VOID(type), return nullptr;) \ - } \ - static const char *definition = #type "\0" \ - BOOST_PP_SEQ_FOR_EACH_I(DOCARGS, ARG_TYPE, args) "\0" \ - BOOST_PP_SEQ_FOR_EACH_I(DOCARGS, ARG_NAME, args) "\0" help; \ - }; \ - APIFunc API::name = {\ - "API_" API_PREFIX #name, (void *)&API_##name::cImpl, \ - "APIvararg_" API_PREFIX #name, (void *)&API_##name::reascriptImpl, \ - "APIdef_" API_PREFIX #name, (void *)API_##name::definition, \ +#define DEFINE_API(type, name, args, help, ...) \ + static type API_##name(BOOST_PP_SEQ_FOR_EACH_I(DEFARGS, _, args)) __VA_ARGS__ \ + \ + APIFunc API::name { #name, \ + reinterpret_cast<void *>(&API_##name), \ + reinterpret_cast<void *>(&InvokeReaScriptAPI<API_##name>), \ + reinterpret_cast<void *>(const_cast<char *>( \ + #type "\0" \ + BOOST_PP_SEQ_FOR_EACH_I(DOCARGS, ARG_TYPE, args) "\0" \ + BOOST_PP_SEQ_FOR_EACH_I(DOCARGS, ARG_NAME, args) "\0" \ + help \ + )) \ } #endif diff --git a/src/event.hpp b/src/event.hpp @@ -26,15 +26,16 @@ #include <optional> #include <vector> -template<class T> +template<typename T> class Event; -template<class R, class... Args> +template<typename R, typename... Args> class Event<R(Args...)> { public: - typedef std::function<R(Args...)> Handler; - typedef typename std::conditional< - std::is_void<R>::value, void, std::optional<R>>::type ReturnType; + using Handler = std::function<R(Args...)>; + using ReturnType = std::conditional_t< + std::is_void_v<R>, void, std::optional<R> + >; Event() = default; Event(const Event &) = delete; @@ -50,7 +51,7 @@ public: ReturnType operator()(Args... args) const { - if constexpr (std::is_void<R>::value) { + if constexpr (std::is_void_v<R>) { for(const auto &func : m_handlers) func(std::forward<Args>(args)...); } @@ -67,7 +68,7 @@ private: }; namespace AsyncEventImpl { - typedef std::function<void ()> MainThreadFunc; + using MainThreadFunc = std::function<void ()>; class Loop { public: @@ -97,10 +98,10 @@ namespace AsyncEventImpl { }; }; -template<class T> +template<typename T> class AsyncEvent; -template<class R, class... Args> +template<typename R, typename... Args> class AsyncEvent<R(Args...)> : public Event<R(Args...)> { public: using typename Event<R(Args...)>::ReturnType; @@ -112,7 +113,7 @@ public: // don't wait until the next timer tick to return nothing if there are no // handlers currently subscribed to the event if(!*this) { - if constexpr (std::is_void<R>::value) + if constexpr (std::is_void_v<R>) promise->set_value(); else promise->set_value(std::nullopt); @@ -121,7 +122,7 @@ public: } m_emitter.runInMainThread([=] { - if constexpr (std::is_void<R>::value) { + if constexpr (std::is_void_v<R>) { Event<R(Args...)>::operator()(args...); promise->set_value(); } diff --git a/src/reapack.hpp b/src/reapack.hpp @@ -86,7 +86,7 @@ private: UseRootPath m_useRootPath; Config m_config; ActionList m_actions; - std::list<APIDef> m_api; + std::list<APIReg> m_api; Transaction *m_tx; std::unique_ptr<About> m_about; diff --git a/src/string.hpp b/src/string.hpp @@ -33,8 +33,9 @@ namespace String { std::string indent(const std::string &); - template<typename T, typename = std::enable_if_t<std::is_arithmetic<T>::value>> - std::string number(const T v) { + template<typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>> + std::string number(const T v) + { std::ostringstream stream; ImplDetail::imbueStream(stream); stream << v; diff --git a/vendor/vcpkg-deps.txt b/vendor/vcpkg-deps.txt @@ -1 +1 @@ -boost-algorithm boost-core boost-lexical-cast boost-logic boost-mpl boost-preprocessor boost-range catch2 curl sqlite3 +boost-algorithm boost-core boost-lexical-cast boost-logic boost-preprocessor boost-range catch2 curl sqlite3