Unverified Commit e95b9a3d authored by Carlos Mastalli's avatar Carlos Mastalli Committed by GitHub
Browse files

Merge pull request #1041 from cmastalli/topic/set-iterable-in-python

Made iterable the std::set bindings
parents 888ae833 36f103e1
Pipeline #17439 passed with stage
in 52 minutes and 37 seconds
///////////////////////////////////////////////////////////////////////////////
// BSD 3-Clause License
//
// Copyright (C) 2019-2020, LAAS-CNRS, University of Edinburgh,
// Copyright (C) 2020, INRIA
// Copyright (C) 2019-2022, LAAS-CNRS, University of Edinburgh, INRIA
// Copyright note valid unless otherwise stated in individual files.
// All rights reserved.
///////////////////////////////////////////////////////////////////////////////
......@@ -42,8 +41,7 @@ struct PickleMap : public PickleVector<Container> {
template <typename Container>
struct dict_to_map {
static void register_converter() {
boost::python::converter::registry::push_back(&dict_to_map::convertible, &dict_to_map::construct,
boost::python::type_id<Container>());
bp::converter::registry::push_back(&dict_to_map::convertible, &dict_to_map::construct, bp::type_id<Container>());
}
/// Check if conversion is possible
......@@ -54,8 +52,8 @@ struct dict_to_map {
}
/// Perform the conversion
static void construct(PyObject* object, boost::python::converter::rvalue_from_python_stage1_data* data) {
// convert the PyObject pointed to by `object` to a boost::python::dict
static void construct(PyObject* object, bp::converter::rvalue_from_python_stage1_data* data) {
// convert the PyObject pointed to by `object` to a bp::dict
bp::handle<> handle(bp::borrowed(object)); // "smart ptr"
bp::dict dict(handle);
......@@ -96,7 +94,7 @@ struct dict_to_map {
data->convertible = storage;
}
static boost::python::dict todict(Container& self) {
static bp::dict todict(Container& self) {
bp::dict dict;
typename Container::const_iterator it;
for (it = self.begin(); it != self.end(); ++it) {
......@@ -116,14 +114,13 @@ struct dict_to_map {
*/
template <class Key, class T, class Compare = std::less<Key>,
class Allocator = std::allocator<std::pair<const Key, T> >, bool NoProxy = false>
struct StdMapPythonVisitor
: public boost::python::map_indexing_suite<typename std::map<Key, T, Compare, Allocator>, NoProxy>,
public dict_to_map<std::map<Key, T, Compare, Allocator> > {
struct StdMapPythonVisitor : public bp::map_indexing_suite<typename std::map<Key, T, Compare, Allocator>, NoProxy>,
public dict_to_map<std::map<Key, T, Compare, Allocator> > {
typedef std::map<Key, T, Compare, Allocator> Container;
typedef dict_to_map<Container> FromPythonDictConverter;
static void expose(const std::string& class_name, const std::string& doc_string = "") {
namespace bp = boost::python;
namespace bp = bp;
bp::class_<Container>(class_name.c_str(), doc_string.c_str())
.def(StdMapPythonVisitor())
......
///////////////////////////////////////////////////////////////////////////////
// BSD 3-Clause License
//
// Copyright (C) 2022, University of Oxford
// Copyright (C) 2019-2020, LAAS-CNRS, University of Edinburgh
// Copyright (C) 2020, INRIA
// Copyright (C) 2019-2022, LAAS-CNRS, University of Edinburgh, INRIA
// University of Oxford
// Copyright note valid unless otherwise stated in individual files.
// All rights reserved.
///////////////////////////////////////////////////////////////////////////////
......@@ -14,9 +13,7 @@
#include <set>
#include <boost/python/stl_iterator.hpp>
#include <boost/python/to_python_converter.hpp>
#include <boost/python/suite/indexing/indexing_suite.hpp>
#include <iostream>
#include "set_indexing_suite.hpp"
namespace crocoddyl {
namespace python {
......@@ -30,19 +27,21 @@ namespace bp = boost::python;
* \sa Pickle
*/
template <typename Container>
struct PickleSet : boost::python::pickle_suite {
static boost::python::tuple getinitargs(const Container&) { return boost::python::make_tuple(); }
static boost::python::tuple getstate(boost::python::object op) {
struct PickleSet : bp::pickle_suite {
static bp::tuple getinitargs(const Container&) { return bp::make_tuple(); }
static bp::tuple getstate(bp::object op) {
bp::list list;
const Container& ret = boost::python::extract<const Container&>(op);
const Container& ret = bp::extract<const Container&>(op);
for (const auto& it : ret) {
list.append(it);
}
return boost::python::make_tuple(list);
return bp::make_tuple(list);
}
static void setstate(boost::python::object op, boost::python::tuple tup) {
Container& o = boost::python::extract<Container&>(op)();
boost::python::stl_input_iterator<typename Container::value_type> begin(tup[0]), end;
static void setstate(bp::object op, bp::tuple tup) {
Container& o = bp::extract<Container&>(op)();
bp::stl_input_iterator<typename Container::value_type> begin(tup[0]), end;
o.insert(begin, end);
}
};
......@@ -52,8 +51,7 @@ template <typename Container>
struct set_to_set {
/** @note Registers converter from a python iterable type to the provided type. */
static void register_converter() {
boost::python::converter::registry::push_back(&set_to_set::convertible, &set_to_set::construct,
boost::python::type_id<Container>());
bp::converter::registry::push_back(&set_to_set::convertible, &set_to_set::construct, bp::type_id<Container>());
}
/** @brief Check if PyObject is iterable. */
......@@ -78,7 +76,7 @@ struct set_to_set {
* Container Concept requirements:
* * Container::value_type is CopyConstructable.
*/
static void construct(PyObject* object, boost::python::converter::rvalue_from_python_stage1_data* data) {
static void construct(PyObject* object, bp::converter::rvalue_from_python_stage1_data* data) {
// Object is a borrowed reference, so create a handle indicting it is
// borrowed for proper reference counting.
bp::handle<> handle(bp::borrowed(object));
......@@ -99,7 +97,7 @@ struct set_to_set {
data->convertible = storage;
}
static boost::python::object toset(Container& self) {
static bp::object toset(Container& self) {
PyObject* set = PySet_New(NULL);
for (auto it = self.begin(); it != self.end(); ++it) {
PySet_Add(set, bp::object(*it).ptr());
......@@ -120,16 +118,14 @@ struct set_to_set {
* returned to Python.
*/
template <class T, class Compare = std::less<T>, class Allocator = std::allocator<T>, bool NoProxy = false>
struct StdSetPythonVisitor : public set_to_set<std::set<T, Compare, Allocator>> {
struct StdSetPythonVisitor : public set_indexing_suite<typename std::set<T, Compare, Allocator>, NoProxy>,
set_to_set<std::set<T, Compare, Allocator>> {
typedef std::set<T, Compare, Allocator> Container;
typedef set_to_set<Container> FromPythonSetConverter;
static void expose(const std::string& class_name, const std::string& doc_string = "") {
namespace bp = boost::python;
bp::class_<Container>(class_name.c_str(), doc_string.c_str())
// .def(StdSetPythonVisitor()); // TODO: Needs an indexing_suite for
// set
.def(StdSetPythonVisitor())
.def("toset", &FromPythonSetConverter::toset, bp::arg("self"), "Returns the std::set as a Python set.")
.def_pickle(PickleSet<Container>());
// Register conversion
......
///////////////////////////////////////////////////////////////////////////////
// BSD 3-Clause License
//
// Copyright (C) 2022, University of Edinburgh
// Copyright note valid unless otherwise stated in individual files.
// All rights reserved.
///////////////////////////////////////////////////////////////////////////////
#ifndef BINDINGS_PYTHON_CROCODDYL_UTILS_SET_INDEXING_SUITE_HPP_
#define BINDINGS_PYTHON_CROCODDYL_UTILS_SET_INDEXING_SUITE_HPP_
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
namespace crocoddyl {
namespace python {
template <typename Container, bool NoProxy, typename DerivedPolicies>
class set_indexing_suite;
namespace detail {
template <typename Container, bool NoProxy>
class final_set_derived_policies
: public crocoddyl::python::set_indexing_suite<Container, NoProxy,
final_set_derived_policies<Container, NoProxy> > {};
} // namespace detail
// The set_indexing_suite class is a predefined indexing_suite derived
// class for wrapping std::set (and std::set like) classes. It provides
// all the policies required by the indexing_suite (see indexing_suite).
// Example usage:
//
// class X {...};
//
// ...
//
// class_<std::set<X> >("XSet")
// .def(set_indexing_suite<std::set<X> >())
// ;
//
// By default indexed elements are returned by proxy. This can be
// disabled by supplying *true* in the NoProxy template parameter.
//
template <typename Container, bool NoProxy = false,
typename DerivedPolicies = detail::final_set_derived_policies<Container, NoProxy> >
class set_indexing_suite : public boost::python::vector_indexing_suite<Container, NoProxy, DerivedPolicies> {
typedef boost::python::vector_indexing_suite<Container, NoProxy, DerivedPolicies> base;
public:
typedef typename base::data_type data_type;
typedef typename base::index_type index_type;
typedef typename base::key_type key_type;
template <class Class>
static void extension_def(Class& class_) {
class_.def("add", &function<DerivedPolicies::add>)
.def("remove", &function<DerivedPolicies::remove>)
.def("discard", &function<DerivedPolicies::discard>)
.def("clear", &DerivedPolicies::clear);
}
static bool contains(Container& container, key_type const& key) { return container.find(key) != container.end(); }
static void add(Container& container, data_type const& v) { container.insert(v); }
static void discard(Container& container, data_type const& v) { container.erase(v); }
static void remove(Container& container, data_type const& v) {
if (!container.erase(v)) {
PyErr_SetString(PyExc_KeyError, "Element doesn't exist");
boost::python::throw_error_already_set();
}
}
static void clear(Container& container) { container.clear(); }
static data_type get_item(Container& container, index_type i) { return *std::next(container.begin(), i); }
static void set_item(Container&, index_type, data_type const&) { not_supported(); }
static void delete_item(Container& container, index_type i) { container.erase(advance(container.begin(), i)); }
static boost::python::object get_slice(Container& container, index_type from, index_type to) {
if (from > to) return boost::python::object(Container());
auto s = slice(container, from, to);
return boost::python::object(Container(s.first, s.second));
}
static void set_slice(Container&, index_type, index_type, data_type const&) { not_supported(); }
template <typename Iter>
static void set_slice(Container&, index_type, index_type, Iter, Iter) {
not_supported();
}
static void delete_slice(Container& container, index_type from, index_type to) {
if (to >= from) {
auto s = slice(container, from, to);
container.erase(s.first, s.second);
}
}
private:
static typename Container::iterator advance(typename Container::iterator it, typename Container::difference_type i) {
return std::advance(it, i), it;
}
static std::pair<typename Container::iterator, typename Container::iterator> slice(Container& container,
index_type from, index_type to) {
BOOST_ASSERT(to >= from);
std::pair<typename Container::iterator, typename Container::iterator> s;
s.first = container.begin();
std::advance(s.first, from);
s.second = s.first;
std::advance(s.second, to - from);
return s;
}
template <void (*fn)(Container&, data_type const&)>
static void function(Container& container, const boost::python::object v) {
using namespace boost::python;
extract<data_type&> elemRef(v);
if (elemRef.check()) {
fn(container, elemRef());
} else {
extract<data_type> elem(v);
if (elem.check()) {
fn(container, elem());
} else {
PyErr_SetString(PyExc_TypeError, "Invalid type");
throw_error_already_set();
}
}
}
static void not_supported() {
PyErr_SetString(PyExc_TypeError, "__setitem__ not supported for set object");
boost::python::throw_error_already_set();
}
};
} // namespace python
} // namespace crocoddyl
#endif // BINDINGS_PYTHON_CROCODDYL_UTILS_SET_INDEXING_SUITE_HPP_
///////////////////////////////////////////////////////////////////////////////
// BSD 3-Clause License
//
// Copyright (C) 2019-2020, LAAS-CNRS, University of Edinburgh
// Copyright (C) 2020, INRIA
// Copyright (C) 2019-2022, LAAS-CNRS, University of Edinburgh, INRIA
// Copyright note valid unless otherwise stated in individual files.
// All rights reserved.
///////////////////////////////////////////////////////////////////////////////
......@@ -27,14 +26,12 @@ namespace bp = boost::python;
* \sa Pickle
*/
template <typename Container>
struct PickleVector : boost::python::pickle_suite {
static boost::python::tuple getinitargs(const Container&) { return boost::python::make_tuple(); }
static boost::python::tuple getstate(boost::python::object op) {
return boost::python::make_tuple(boost::python::list(boost::python::extract<const Container&>(op)()));
}
static void setstate(boost::python::object op, boost::python::tuple tup) {
Container& o = boost::python::extract<Container&>(op)();
boost::python::stl_input_iterator<typename Container::value_type> begin(tup[0]), end;
struct PickleVector : bp::pickle_suite {
static bp::tuple getinitargs(const Container&) { return bp::make_tuple(); }
static bp::tuple getstate(bp::object op) { return bp::make_tuple(bp::list(bp::extract<const Container&>(op)())); }
static void setstate(bp::object op, bp::tuple tup) {
Container& o = bp::extract<Container&>(op)();
bp::stl_input_iterator<typename Container::value_type> begin(tup[0]), end;
o.insert(o.begin(), begin, end);
}
};
......@@ -44,8 +41,8 @@ template <typename Container>
struct list_to_vector {
/** @note Registers converter from a python iterable type to the provided type. */
static void register_converter() {
boost::python::converter::registry::push_back(&list_to_vector::convertible, &list_to_vector::construct,
boost::python::type_id<Container>());
bp::converter::registry::push_back(&list_to_vector::convertible, &list_to_vector::construct,
bp::type_id<Container>());
}
/** @brief Check if PyObject is iterable. */
......@@ -73,7 +70,7 @@ struct list_to_vector {
* * Container can be constructed and populated with two iterators.
* i.e. Container(begin, end)
*/
static void construct(PyObject* object, boost::python::converter::rvalue_from_python_stage1_data* data) {
static void construct(PyObject* object, bp::converter::rvalue_from_python_stage1_data* data) {
// Object is a borrowed reference, so create a handle indicting it is
// borrowed for proper reference counting.
bp::handle<> handle(bp::borrowed(object));
......@@ -94,7 +91,7 @@ struct list_to_vector {
data->convertible = storage;
}
static boost::python::list tolist(Container& self) {
static bp::list tolist(Container& self) {
typedef bp::iterator<Container> iterator;
bp::list list(iterator()(self));
return list;
......@@ -109,14 +106,13 @@ struct list_to_vector {
* @param[in] NoProxy When set to false, the elements will be copied when returned to Python.
*/
template <class T, class Allocator = std::allocator<T>, bool NoProxy = false>
struct StdVectorPythonVisitor
: public boost::python::vector_indexing_suite<typename std::vector<T, Allocator>, NoProxy>,
public list_to_vector<std::vector<T, Allocator> > {
struct StdVectorPythonVisitor : public bp::vector_indexing_suite<typename std::vector<T, Allocator>, NoProxy>,
public list_to_vector<std::vector<T, Allocator> > {
typedef std::vector<T, Allocator> Container;
typedef list_to_vector<Container> FromPythonListConverter;
static void expose(const std::string& class_name, const std::string& doc_string = "") {
namespace bp = boost::python;
namespace bp = bp;
bp::class_<Container>(class_name.c_str(), doc_string.c_str())
.def(StdVectorPythonVisitor())
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment