// // Augment pybind11's {map,vector}_bind() with set_bind() for mapping std::set // to Python's sets. // // This code is copied and adapted from pybind11's version for vector. // #include PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(detail) /* For a set data structure, recursively check the value type (which is * std::pair for maps) */ template struct is_comparable::is_set>> { static constexpr const bool value = is_comparable::value; }; /* Fallback functions */ template void set_if_copy_constructible(const Args&...) {} template void set_if_equal_operator(const Args&...) {} template void set_if_insertion_operator(const Args&...) {} template void set_modifiers(const Args&...) {} template void set_if_copy_constructible( enable_if_t::value && std::is_copy_constructible::value, Class_>& cl) { cl.def(init(), "Copy constructor"); } template void set_if_equal_operator(enable_if_t::value, Class_>& cl) { cl.def(self == self); cl.def(self != self); } // Set modifiers -- requires a copyable set_type: template void set_modifiers( enable_if_t::value, Class_>& cl) { using T = typename Set::value_type; cl.def(init([](iterable it) { Set rval; for (handle h : it) rval.insert(h.cast()); return rval; })); cl.def( "add", [](Set& s, const T& x) { s.insert(x); }, arg("x"), "Insert an item into this set."); cl.def( "remove", [](Set& s, const T& x) { s.erase(x); }, arg("x"), "Removes an item from this set."); cl.def("clear", [](Set& s) { s.clear(); }, "Empties this set."); } // To iterate by copying objects, as std::set iterators are const. template void set_accessor(Class_& cl) { using T = typename Set::value_type; using ItType = typename Set::iterator; cl.def( "__iter__", [](Set& s) { return make_iterator( s.begin(), s.end()); }, keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ ); } template auto set_if_insertion_operator(Class_& cl, std::string const& name) -> decltype(std::declval() << std::declval(), void()) { cl.def( "__repr__", [name](Set& s) { std::ostringstream t; bool first = true; t << name << "{"; for (const auto& i : s) { if (!first) t << ", "; t << i; first = false; } t << '}'; return t.str(); }, "Return the canonical string representation of this set."); } PYBIND11_NAMESPACE_END(detail) // // std::set // template , typename... Args> class_ bind_set(module& m, std::string const& name, Args&&... args) { using Class_ = class_; Class_ cl(m, name.c_str(), std::forward(args)...); cl.def(init<>()); // Register copy constructor (if possible) detail::set_if_copy_constructible(cl); // Register comparison-related operators and functions (if possible) detail::set_if_equal_operator(cl); // Register stream insertion operator (if possible) detail::set_if_insertion_operator(cl, name); // Modifiers require copyable set value type detail::set_modifiers(cl); // Accessor and iterator; return by value if copyable, otherwise we return by // ref + keep-alive detail::set_accessor(cl); cl.def( "__bool__", [](const Set& s) -> bool { return !s.empty(); }, "Check whether the set is nonempty"); cl.def("__len__", &Set::size); return cl; } PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)