From 54e447c0a9d1c85927526e73639b79625b1ba9bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Mon, 4 May 2020 01:47:30 +0200 Subject: [PATCH] Switch from boost variant/tuple to std. --- src/runner/proxypluginwrappers.cpp | 17 +-- src/runner/pythonrunner.cpp | 19 +-- src/runner/tuple_helper.h | 197 ++++------------------------- src/runner/variant_helper.h | 8 +- 4 files changed, 45 insertions(+), 196 deletions(-) diff --git a/src/runner/proxypluginwrappers.cpp b/src/runner/proxypluginwrappers.cpp index fe87be8..861d919 100644 --- a/src/runner/proxypluginwrappers.cpp +++ b/src/runner/proxypluginwrappers.cpp @@ -7,7 +7,8 @@ #include "pythonwrapperutilities.h" #include "sipApiAccess.h" -#include +#include +#include namespace boost { @@ -309,10 +310,10 @@ IPluginInstaller::EInstallResult IPluginInstallerSimpleWrapper::install( { namespace bpy = boost::python; - using return_type = boost::variant, boost::tuple, QString, int>> ; + using return_type = std::variant, std::tuple, QString, int>> ; auto ret = basicWrapperFunctionImplementation(this, "install", boost::ref(modName), tree, version, nexusID); - return boost::apply_visitor([&](auto const& t) { + return std::visit([&](auto const& t) { using type = std::decay_t; if constexpr (std::is_same_v) { return t; @@ -321,16 +322,16 @@ IPluginInstaller::EInstallResult IPluginInstallerSimpleWrapper::install( tree = t; return IPluginInstaller::RESULT_SUCCESS; } - else if constexpr (std::is_same_v, QString, int>>) { - tree = boost::get<0>(t); - version = boost::get<1>(t); - nexusID = boost::get<2>(t); + else if constexpr (std::is_same_v, QString, int>>) { + tree = std::get<0>(t); + version = std::get<1>(t); + nexusID = std::get<2>(t); return IPluginInstaller::RESULT_SUCCESS; } else { static_assert("Type not handled in boost::apply_visitor."); } - }, ret); + }, ret); } /// end IPluginInstallerSimple Wrapper diff --git a/src/runner/pythonrunner.cpp b/src/runner/pythonrunner.cpp index 6214b2e..10fecc5 100644 --- a/src/runner/pythonrunner.cpp +++ b/src/runner/pythonrunner.cpp @@ -23,6 +23,9 @@ // sip and qt slots seems to conflict #include +#include +#include + #ifndef Q_MOC_RUN #include #include @@ -657,12 +660,12 @@ BOOST_PYTHON_MODULE(mobase) utils::register_associative_container(); // Tuple: - bpy::register_tuple, QString, int>>(); + bpy::register_tuple, QString, int>>(); // Variants: - bpy::register_variant, boost::tuple, QString, int>>>(); - bpy::register_variant>(); - bpy::register_variant>(); + bpy::register_variant, std::tuple, QString, int>>>(); + bpy::register_variant>(); + bpy::register_variant>(); // Functions: Functor_converter(); // converter for the onRefreshed-callback @@ -671,7 +674,7 @@ BOOST_PYTHON_MODULE(mobase) Functor_converter(); Functor_converter(); Functor_converter(); - Functor_converter(QString const&)>(); + Functor_converter(QString const&)>(); Functor_converter const&)>(); @@ -867,7 +870,7 @@ BOOST_PYTHON_MODULE(mobase) IFileTree* p, std::shared_ptr entry, IFileTree::InsertPolicy insertPolicy) { return p->insert(entry, insertPolicy) != p->end(); }, bpy::arg("policy") = IFileTree::InsertPolicy::FAIL_IF_EXISTS) - .def("merge", +[](IFileTree* p, std::shared_ptr other, bool returnOverwrites) -> boost::variant { + .def("merge", +[](IFileTree* p, std::shared_ptr other, bool returnOverwrites) -> std::variant { IFileTree::OverwritesType overwrites; auto result = p->merge(other, returnOverwrites ? &overwrites : nullptr); if (result == IFileTree::MERGE_FAILED) { @@ -1008,10 +1011,10 @@ BOOST_PYTHON_MODULE(mobase) .def("reset", +[](GuessedValue* gv, const GuessedValue& other) { *gv = other; }, bpy::return_self<>()) // Use an intermediate lambda to avoid having to register the std::function conversion: - .def("setFilter", +[](GuessedValue* gv, std::function(QString const&)> fn) { + .def("setFilter", +[](GuessedValue* gv, std::function(QString const&)> fn) { gv->setFilter([fn](QString& s) { auto ret = fn(s); - return boost::apply_visitor([&s](auto v) { + return std::visit([&s](auto v) { if constexpr (std::is_same_v) { s = v; return true; diff --git a/src/runner/tuple_helper.h b/src/runner/tuple_helper.h index 10ed25b..d9bae07 100644 --- a/src/runner/tuple_helper.h +++ b/src/runner/tuple_helper.h @@ -1,154 +1,43 @@ -// From: https://pyplusplus.readthedocs.io/en/latest/troubleshooting_guide/automatic_conversion/tuples.hpp.html -// Copyright 2004-2007 Roman Yakovenko. -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#ifndef TUPLES_HPP_16_JAN_2007 -#define TUPLES_HPP_16_JAN_2007 +#ifndef TUPLE_HELPER_H +#define TUPLE_HELPER_H #include -#include #include //len function -#include -#include - -/** - * Converts boost::tuples::tuple<...> to\from Python tuple - * - * The conversion is done "on-the-fly", you should only register the conversion - * with your tuple classes. - * For example: - * - * typedef boost::tuples::tuple< int, double, std::string > triplet; - * boost::python::register_tuple< triplet >(); - * - * That's all. After this point conversion to\from next types will be handled - * by Boost.Python library: - * - * triplet - * triplet& ( return type only ) - * const triplet - * const triplet& - * - * Implementation description. - * The conversion uses Boost.Python custom r-value converters. r-value converters - * is very powerful and undocumented feature of the library. The only documentation - * we have is http://boost.org/libs/python/doc/v2/faq.html#custom_string . - * - * The conversion consists from two parts: "to" and "from". - * - * "To" conversion - * The "to" part is pretty easy and well documented ( http://docs.python.org/api/api.html ). - * You should use Python C API to create an instance of a class and than you - * initialize the relevant members of the instance. - * - * "From" conversion - * Lets start from analyzing one of the use case Boost.Python library have to - * deal with: - * - * void do_smth( const triplet& arg ){...} - * - * In order to allow calling this function from Python, the library should keep - * parameter "arg" alive until the function returns. In other words, the library - * should provide instances life-time management. The provided interface is not - * ideal and could be improved. You have to implement two functions: - * - * void* convertible( PyObject* obj ) - * Checks whether the "obj" could be converted to an instance of the desired - * class. If true, the function should return "obj", otherwise NULL - * - * void construct( PyObject* obj, converter::rvalue_from_python_stage1_data* data) - * Constructs the instance of the desired class. This function will be called - * if and only if "convertible" function returned true. The first argument - * is Python object, which was passed as parameter to "convertible" function. - * The second object is some kind of memory allocator for one object. Basically - * it keeps a memory chunk. You will use the memory for object allocation. - * - * For some unclear for me reason, the library implements "C style Inheritance" - * ( http://www.embedded.com/97/fe29712.htm ). So, in order to create new - * object in the storage you have to cast to the "right" class: - * - * typedef converter::rvalue_from_python_storage storage_t; - * storage_t* the_storage = reinterpret_cast( data ); - * void* memory_chunk = the_storage->storage.bytes; - * - * "memory_chunk" points to the memory, where the instance will be allocated. - * - * In order to create object at specific location, you should use placement new - * operator: - * - * your_type_t* instance = new (memory_chunk) your_type_t(); - * - * Now, you can continue to initialize the instance. - * - * instance->set_xyz = read xyz from obj - * - * If "your_type_t" constructor requires some arguments, "read" the Python - * object before you call the constructor: - * - * xyz_type xyz = read xyz from obj - * your_type_t* instance = new (memory_chunk) your_type_t(xyz); - * - * Hint: - * In most case you don't really need\have to work with C Python API. Let - * Boost.Python library to do some work for you! - * - **/ namespace boost { namespace python { - namespace details { - - //Small helper function, introduced to allow short syntax for index incrementing - template< int index> - typename mpl::next< mpl::int_< index > >::type increment_index() { - typedef typename mpl::next< mpl::int_< index > >::type next_index_type; - return next_index_type(); - } - - } - - template< class TTuple > + template struct to_py_tuple { - typedef mpl::int_< tuples::length< TTuple >::value > length_type; - static PyObject* convert(const TTuple& c_tuple) { list values; //add all c_tuple items to "values" list - convert_impl(c_tuple, values, mpl::int_< 0 >(), length_type()); + convert_impl(c_tuple, values, std::make_index_sequence>{}); //create Python tuple from the list return incref(python::tuple(values).ptr()); } private: - template< int index, int length > - static void - convert_impl(const TTuple& c_tuple, list& values, mpl::int_< index >, mpl::int_< length >) { - values.append(c_tuple.template get< index >()); - convert_impl(c_tuple, values, details::increment_index(), length_type()); + template + static void convert_impl(const TTuple& c_tuple, list& values, std::index_sequence) { + values.append(std::get(c_tuple)); + convert_impl(c_tuple, values, std::index_sequence{}); } - template< int length > - static void - convert_impl(const TTuple&, list& values, mpl::int_< length >, mpl::int_< length >) - {} + static void convert_impl(const TTuple&, list& values, std::index_sequence<>) {} }; - template< class TTuple> + template struct from_py_sequence { - typedef TTuple tuple_type; + using tuple_type = TTuple; + using index_sequence = std::make_index_sequence>; - typedef mpl::int_< tuples::length< TTuple >::value > length_type; - - static void* - convertible(PyObject* py_obj) { + static void* convertible(PyObject* py_obj) { if (!PySequence_Check(py_obj)) { return 0; @@ -160,11 +49,11 @@ namespace boost { python::object py_sequence(handle<>(borrowed(py_obj))); - if (tuples::length< TTuple >::value != len(py_sequence)) { + if (std::tuple_size_v != len(py_sequence)) { return 0; } - if (convertible_impl(py_sequence, mpl::int_< 0 >(), length_type())) { + if (convertible_impl(py_sequence, index_sequence{})) { return py_obj; } else { @@ -172,8 +61,7 @@ namespace boost { } } - static void - construct(PyObject* py_obj, converter::rvalue_from_python_stage1_data* data) { + static void construct(PyObject* py_obj, converter::rvalue_from_python_stage1_data* data) { typedef converter::rvalue_from_python_storage storage_t; storage_t* the_storage = reinterpret_cast(data); void* memory_chunk = the_storage->storage.bytes; @@ -181,60 +69,21 @@ namespace boost { data->convertible = memory_chunk; python::object py_sequence(handle<>(borrowed(py_obj))); - construct_impl(py_sequence, *c_tuple, mpl::int_< 0 >(), length_type()); - } - - static TTuple to_c_tuple(PyObject* py_obj) { - if (!convertible(py_obj)) { - throw std::runtime_error("Unable to construct boost::tuples::tuple from Python object!"); - } - TTuple c_tuple; - python::object py_sequence(handle<>(borrowed(py_obj))); - construct_impl(py_sequence, c_tuple, mpl::int_< 0 >(), length_type()); - return c_tuple; + construct_impl(py_sequence, *c_tuple, index_sequence{}); } private: - template< int index, int length > - static bool - convertible_impl(const python::object& py_sequence, mpl::int_< index >, mpl::int_< length >) { - - typedef typename tuples::element< index, TTuple>::type element_type; - - object element = py_sequence[index]; - extract type_checker(element); - if (!type_checker.check()) { - return false; - } - else { - return convertible_impl(py_sequence, details::increment_index(), length_type()); - } + template + static bool convertible_impl(const python::object& py_sequence, std::index_sequence) { + return (... && extract>(py_sequence[Is]).check()); } - template< int length > - static bool - convertible_impl(const python::object& py_sequence, mpl::int_< length >, mpl::int_< length >) { - return true; + template + static void construct_impl(const python::object& py_sequence, TTuple& c_tuple, std::index_sequence) { + c_tuple = tuple_type{ extract>(py_sequence[Is])... }; } - template< int index, int length > - static void - construct_impl(const python::object& py_sequence, TTuple& c_tuple, mpl::int_< index >, mpl::int_< length >) { - - typedef typename tuples::element< index, TTuple>::type element_type; - - object element = py_sequence[index]; - c_tuple.template get< index >() = extract(element); - - construct_impl(py_sequence, c_tuple, details::increment_index(), length_type()); - } - - template< int length > - static void - construct_impl(const python::object& py_sequence, TTuple& c_tuple, mpl::int_< length >, mpl::int_< length >) - {} - }; template< class TTuple> diff --git a/src/runner/variant_helper.h b/src/runner/variant_helper.h index 618160f..b28c1cc 100644 --- a/src/runner/variant_helper.h +++ b/src/runner/variant_helper.h @@ -2,13 +2,9 @@ #define VARIANT_HELPER_H #include -#include -#include //len function -#include -#include /** - * Creates boost::variant from python object. Greatly inspired by register_tuple<>. + * Register variant(s) from and to python object. Greatly inspired by register_tuple<>. */ namespace boost { @@ -18,7 +14,7 @@ namespace boost { struct to_py_variant { static PyObject* convert(const TVariant& c_variant) { - object value = boost::apply_visitor([](auto const& value) { + object value = std::visit([](auto const& value) { return object{ value }; }, c_variant); //create Python object from the list