/* vim: set sw=4 sts=4 et foldmethod=syntax : */ /* * Copyright (c) 2007 Piotr JaroszyƄski * * This file is part of the Paludis package manager. Paludis is free software; * you can redistribute it and/or modify it under the terms of the GNU General * Public License version 2, as published by the Free Software Foundation. * * Paludis 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., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef PALUDIS_GUARD_PYTHON_ITERABLE_HH #define PALUDIS_GUARD_PYTHON_ITERABLE_HH 1 #include #include #include #include #include #include namespace paludis { namespace python { template struct IsConvertible { static const bool value = std::is_convertible::value; }; template <> struct IsConvertible { static const bool value = true; }; template struct IsConvertible > { static const bool value = std::is_convertible::UnderlyingType>::value; }; template struct ConditionalAdd { static void add(C_ &, PyObject *) { } }; template struct ConditionalAdd, true> { static void add(Set & c, PyObject * ptr) { const char * str = PyString_AsString(ptr); c.insert(To_(std::string(str))); } }; template struct ConditionalAdd, true> { static void add(Sequence & c, PyObject * ptr) { const char * str = PyString_AsString(ptr); c.push_back(To_(std::string(str))); } }; template struct RegisterSequenceSPTRFromPython { static std::string _name; RegisterSequenceSPTRFromPython(const std::string & name) { boost::python::converter::registry::push_back(&convertible, &construct, boost::python::type_id > >()); _name = name; } static void * convertible(PyObject * obj_ptr) { if (boost::python::extract(obj_ptr).check() || obj_ptr == Py_None) return obj_ptr; else return 0; } static void construct(PyObject * obj_ptr, boost::python::converter::rvalue_from_python_stage1_data * data) { typedef boost::python::converter::rvalue_from_python_storage > > Storage; void * storage = reinterpret_cast(data)->storage.bytes; data->convertible = storage; if (obj_ptr == Py_None) { new (storage) std::shared_ptr >(); return; } else new (storage) std::shared_ptr >(new Sequence()); Sequence * s(reinterpret_cast > *>(storage)->get()); boost::python::list l = boost::python::extract(obj_ptr); while (PyList_Size(obj_ptr)) { boost::python::object o(l.pop()); if (boost::python::extract(o).check()) { V_ * ptr = boost::python::extract(o); s->push_back(*ptr); } else if (IsConvertible::value && PyString_Check(o.ptr())) { ConditionalAdd, IsConvertible::value>::add(*s, o.ptr()); } else { typedef std::shared_ptr > sptr; reinterpret_cast(storage)->sptr::~shared_ptr(); throw PythonContainerConversionError(_name, "sequence", o.ptr()->ob_type->tp_name); } } } }; template std::string RegisterSequenceSPTRFromPython::_name("unknown"); template struct RegisterSetSPTRFromPython { static std::string _name; RegisterSetSPTRFromPython(const std::string & name) { boost::python::converter::registry::push_back(&convertible, &construct, boost::python::type_id > >()); _name = name; } static void * convertible(PyObject * obj_ptr) { if (boost::python::extract(obj_ptr).check() || obj_ptr == Py_None) return obj_ptr; else return 0; } static void construct(PyObject * obj_ptr, boost::python::converter::rvalue_from_python_stage1_data * data) { typedef boost::python::converter::rvalue_from_python_storage > > Storage; void * storage = reinterpret_cast(data)->storage.bytes; data->convertible = storage; if (obj_ptr == Py_None) { new (storage) std::shared_ptr >(); return; } else new (storage) std::shared_ptr >(new Set()); Set * s(reinterpret_cast > *>(storage)->get()); boost::python::list l = boost::python::extract(obj_ptr); while (PyList_Size(obj_ptr)) { boost::python::object o(l.pop()); if (boost::python::extract(o).check()) { V_ * ptr = boost::python::extract(o); s->insert(*ptr); } else if (IsConvertible::value && PyString_Check(o.ptr())) { ConditionalAdd, IsConvertible::value>::add(*s, o.ptr()); } else { typedef std::shared_ptr > sptr; reinterpret_cast(storage)->sptr::~shared_ptr(); throw PythonContainerConversionError(_name, "set", o.ptr()->ob_type->tp_name); } } } }; template std::string RegisterSetSPTRFromPython::_name("unknown"); // expose iterable classes template class class_iterable : public boost::python::class_ { public: class_iterable(const std::string & name, const std::string & class_doc, bool converter=false) : boost::python::class_(name.c_str(), class_doc.c_str(), boost::python::no_init) { this->def("__iter__", boost::python::range(&C_::begin, &C_::end)); register_shared_ptrs_to_python(); if (converter) { if (std::is_same >::value) RegisterSequenceSPTRFromPython tmp(name); else if (std::is_same >::value) RegisterSetSPTRFromPython tmp(name); else throw PythonError("Can't register l-value converter for '" + name +"'."); } } }; } // namespace paludis::python } // namespace paludis #endif