diff --git a/include/boost/python/indexing/detail/indexing_suite_detail.hpp b/include/boost/python/indexing/detail/indexing_suite_detail.hpp index 4f6dbb2c..8357ad36 100644 --- a/include/boost/python/indexing/detail/indexing_suite_detail.hpp +++ b/include/boost/python/indexing/detail/indexing_suite_detail.hpp @@ -386,6 +386,233 @@ namespace boost { namespace python { namespace detail { Index index; }; + template < + class Container + , class DerivedPolicies + , class ContainerElement + , class Index + > + struct no_proxy_helper + { + static void + register_container_element() + { + } + + static object + base_get_item_(back_reference const& container, PyObject* i) + { + return object( + DerivedPolicies::get_item( + container.get(), DerivedPolicies:: + convert_index(container.get(), i))); + } + + static void + base_replace_indexes( + Container& container, Index from, + Index to, Index n) + { + } + + static void + base_erase_indexes(Container& container, Index from, Index to) + { + } + }; + + template < + class Container + , class DerivedPolicies + , class ContainerElement + , class Index + > + struct proxy_helper + { + static void + register_container_element() + { + register_ptr_to_python(); + } + + static object + base_get_item_(back_reference const& container, PyObject* i) + { + // Proxy + Index idx = DerivedPolicies::convert_index(container.get(), i); + + if (PyObject* shared = + ContainerElement::get_links().find(container.get(), idx)) + { + handle<> h(python::borrowed(shared)); + return object(h); + } + else + { + object prox(ContainerElement(container.source(), idx)); + ContainerElement:: + get_links().add(prox.ptr(), container.get()); + return prox; + } + } + + static void + base_replace_indexes( + Container& container, Index from, + Index to, Index n) + { + ContainerElement::get_links().replace(container, from, to, n); + } + + static void + base_erase_indexes( + Container& container, Index from, Index to) + { + ContainerElement::get_links().erase(container, from, to); + } + }; + + template < + class Container + , class DerivedPolicies + , class ProxyHandler + , class Element + , class Index + > + struct slice_helper + { + static object + base_get_slice(Container& container, PySliceObject* slice) + { + Index from, to; + base_get_slice_data(container, slice, from, to); + return DerivedPolicies::get_slice(container, from, to); + } + + static void + base_get_slice_data( + Container& container, PySliceObject* slice, Index& from, Index& to) + { + if (Py_None == slice->start) + from = DerivedPolicies::get_min_index(container); + else + from = DerivedPolicies::convert_index(container, slice->start); + + if (Py_None == slice->stop) + to = DerivedPolicies::get_max_index(container); + else + to = DerivedPolicies::convert_index(container, slice->stop); + } + + static void + base_set_slice(Container& container, PySliceObject* slice, PyObject* v) + { + Index from, to; + base_get_slice_data(container, slice, from, to); + + extract elem(v); + // try if elem is an exact Element + if (elem.check()) + { + ProxyHandler::base_replace_indexes(container, from, to, 1); + DerivedPolicies::set_slice(container, from, to, elem()); + } + else + { + // try to convert elem to Element + extract elem(v); + if (elem.check()) + { + ProxyHandler::base_replace_indexes(container, from, to, 1); + DerivedPolicies::set_slice(container, from, to, elem()); + } + else + { + // Otherwise, it must be a list or some container + handle<> l_(python::borrowed(v)); + object l(l_); + + std::vector temp; + for (int i = 0; i < l.attr("__len__")(); i++) + { + object elem(l[i]); + extract x(elem); + // try if elem is an exact Element type + if (x.check()) + { + temp.push_back(x()); + } + else + { + // try to convert elem to Element type + extract x(elem); + if (x.check()) + { + temp.push_back(x()); + } + else + { + PyErr_SetString(PyExc_TypeError, + "Invalid sequence element"); + throw_error_already_set(); + } + } + } + + ProxyHandler::base_replace_indexes(container, from, to, + temp.end()-temp.begin()); + DerivedPolicies::set_slice(container, from, to, + temp.begin(), temp.end()); + } + } + } + + static void + base_delete_slice(Container& container, PySliceObject* slice) + { + Index from, to; + base_get_slice_data(container, slice, from, to); + ProxyHandler::base_erase_indexes(container, from, to); + DerivedPolicies::delete_slice(container, from, to); + } + }; + + template < + class Container + , class DerivedPolicies + , class ProxyHandler + , class Element + , class Index + > + struct no_slice_helper + { + static void + slicing_not_suported() + { + PyErr_SetString(PyExc_RuntimeError, "Slicing not supported"); + throw_error_already_set(); + } + + static object + base_get_slice(Container& container, PySliceObject* slice) + { + slicing_not_suported(); + return object(); + } + + static void + base_set_slice(Container& container, PySliceObject* slice, PyObject* v) + { + slicing_not_suported(); + } + + static void + base_delete_slice(Container& container, PySliceObject* slice) + { + slicing_not_suported(); + } + }; + }} // namespace python::detail template diff --git a/include/boost/python/indexing/indexing_suite.hpp b/include/boost/python/indexing/indexing_suite.hpp index 3bbf6152..531b2f60 100644 --- a/include/boost/python/indexing/indexing_suite.hpp +++ b/include/boost/python/indexing/indexing_suite.hpp @@ -16,7 +16,7 @@ # include namespace boost { namespace python { - + // indexing_suite class. This class is the protocol class for // the management of C++ containers intended to be integrated // to Python. The objective is make a C++ container look and @@ -93,10 +93,12 @@ namespace boost { namespace python { // the function should return the adjusted index when data in the // container at index from..to is replaced by *len* elements. // + template < class Container , class DerivedPolicies , bool NoProxy = false + , bool NoSlice = false , class Element = typename Container::value_type , class Key = typename Container::value_type , class Index = typename Container::size_type @@ -107,6 +109,7 @@ namespace boost { namespace python { Container , DerivedPolicies , NoProxy + , NoSlice , Element , Key , Index @@ -127,25 +130,44 @@ namespace boost { namespace python { , iterator , iterator > >::type def_iterator; - - static void - register_container_element(mpl::false_) - { - register_ptr_to_python(); - } - static void - register_container_element(mpl::true_) - { - } + typedef typename mpl::if_< + no_proxy + , detail::no_proxy_helper< + Container + , DerivedPolicies + , container_element_t + , Index> + , detail::proxy_helper< + Container + , DerivedPolicies + , container_element_t + , Index> >::type + proxy_handler; + typedef typename mpl::if_< + mpl::bool_ + , detail::slice_helper< + Container + , DerivedPolicies + , proxy_handler + , Element + , Index> + , detail::slice_helper< + Container + , DerivedPolicies + , proxy_handler + , Element + , Index> >::type + slice_handler; + public: template void visit(Class& cl) const { // Hook into the class_ generic visitation .def function - register_container_element(no_proxy()); + proxy_handler::register_container_element(); cl .def("__len__", base_size) @@ -157,85 +179,27 @@ namespace boost { namespace python { .def("append", &base_append) .def("extend", &base_extend) - ; + ; } private: - - static object - base_get_item_( - back_reference const& container, - PyObject* i, mpl::false_) - { - // Proxy - Index idx = DerivedPolicies::convert_index(container.get(), i); - - if (PyObject* shared = - container_element_t::get_links().find(container.get(), idx)) - { - handle<> h(borrowed(shared)); - return object(h); - } - else - { - object prox(container_element_t(container.source(), idx)); - container_element_t:: - get_links().add(prox.ptr(), container.get()); - return prox; - } - } - - static object - base_get_item_( - back_reference const& container, - PyObject* i, mpl::true_) - { - // No Proxy - return object( - DerivedPolicies::get_item( - container.get(), DerivedPolicies:: - convert_index(container.get(), i))); - } - + static object base_get_item(back_reference container, PyObject* i) { if (PySlice_Check(i)) - return base_get_slice( + return slice_handler::base_get_slice( container.get(), reinterpret_cast(i)); - return base_get_item_(container, i, no_proxy()); - } - - static object - base_get_slice(Container& container, PySliceObject* slice) - { - Index from, to; - base_get_slice_data(container, slice, from, to); - return DerivedPolicies::get_slice(container, from, to); + return proxy_handler::base_get_item_(container, i); } - - static void - base_get_slice_data( - Container& container, PySliceObject* slice, Index& from, Index& to) - { - if (Py_None == slice->start) - from = 0; - else - from = DerivedPolicies::convert_index(container, slice->start); - - if (Py_None == slice->stop) - to = container.size(); - else - to = DerivedPolicies::convert_index(container, slice->stop); - } static void base_set_item(Container& container, PyObject* i, PyObject* v) { if (PySlice_Check(i)) { - base_set_slice(container, + slice_handler::base_set_slice(container, reinterpret_cast(i), v); } else @@ -269,123 +233,20 @@ namespace boost { namespace python { } } - static void - base_replace_indexes( - Container& container, Index from, - Index to, Index n, mpl::false_) - { - // Proxy - container_element_t::get_links().replace(container, from, to, n); - } - - static void - base_replace_indexes( - Container& container, Index from, - Index to, Index n, mpl::true_) - { - // No Proxy - } - - static void - base_erase_indexes( - Container& container, Index from, Index to, mpl::false_) - { - // Proxy - container_element_t::get_links().erase(container, from, to); - } - - static void - base_erase_indexes( - Container& container, Index from, Index to, mpl::true_) - { - // No Proxy - } - - static void - base_set_slice(Container& container, PySliceObject* slice, PyObject* v) - { - Index from, to; - base_get_slice_data(container, slice, from, to); - - extract elem(v); - // try if elem is an exact Element - if (elem.check()) - { - base_replace_indexes(container, from, to, 1, no_proxy()); - DerivedPolicies::set_slice(container, from, to, elem()); - } - else - { - // try to convert elem to Element - extract elem(v); - if (elem.check()) - { - base_replace_indexes(container, from, to, 1, no_proxy()); - DerivedPolicies::set_slice(container, from, to, elem()); - } - else - { - // Otherwise, it must be a list or some container - handle<> l_(borrowed(v)); - object l(l_); - - std::vector temp; - for (int i = 0; i < l.attr("__len__")(); i++) - { - object elem(l[i]); - extract x(elem); - // try if elem is an exact Element type - if (x.check()) - { - temp.push_back(x()); - } - else - { - // try to convert elem to Element type - extract x(elem); - if (x.check()) - { - temp.push_back(x()); - } - else - { - PyErr_SetString(PyExc_TypeError, - "Invalid sequence element"); - throw_error_already_set(); - } - } - } - - base_replace_indexes(container, from, to, - temp.end()-temp.begin(), no_proxy()); - DerivedPolicies::set_slice(container, from, to, - temp.begin(), temp.end()); - } - } - } - static void base_delete_item(Container& container, PyObject* i) { if (PySlice_Check(i)) { - base_delete_slice(container, reinterpret_cast(i)); + slice_handler::base_delete_slice( + container, reinterpret_cast(i)); return; } Index index = DerivedPolicies::convert_index(container, i); - base_erase_indexes(container, index, index+1, no_proxy()); + proxy_handler::base_erase_indexes(container, index, index+1); DerivedPolicies::delete_item(container, index); - } - - static void - base_delete_slice(Container& container, PySliceObject* slice) - { - Index from, to; - base_get_slice_data(container, slice, from, to); - base_erase_indexes(container, from, to, no_proxy()); - DerivedPolicies::delete_slice(container, from, to); - } + } static size_t base_size(Container& container) @@ -475,44 +336,8 @@ namespace boost { namespace python { DerivedPolicies::extend(container, temp.begin(), temp.end()); } - - static object - get_slice(Container& container, Index from, Index to) - { - // default implementation - PyErr_SetString(PyExc_RuntimeError, "Slicing not supported"); - throw_error_already_set(); - return object(); - } - - static void - set_slice(Container& container, Index from, - Index to, Element const& v) - { - // default implementation - PyErr_SetString(PyExc_RuntimeError, "Slicing not supported"); - throw_error_already_set(); - } - - template - static void - set_slice(Container& container, Index from, - Index to, Iter first, Iter last) - { - // default implementation - PyErr_SetString(PyExc_RuntimeError, "Slicing not supported"); - throw_error_already_set(); - } - - static void - delete_slice(Container& container, Index from, Index to) - { - // default implementation - PyErr_SetString(PyExc_RuntimeError, "Slicing not supported"); - throw_error_already_set(); - } - }; - + }; + }} // namespace boost::python #endif // INDEXING_SUITE_JDG20036_HPP diff --git a/include/boost/python/indexing/vector_indexing_suite.hpp b/include/boost/python/indexing/vector_indexing_suite.hpp index e2c0d50c..17d57958 100644 --- a/include/boost/python/indexing/vector_indexing_suite.hpp +++ b/include/boost/python/indexing/vector_indexing_suite.hpp @@ -115,6 +115,18 @@ namespace boost { namespace python { != container.end(); } + static index_type + get_min_index(Container& container) + { + return 0; + } + + static index_type + get_max_index(Container& container) + { + return container.size(); + } + static index_type convert_index(Container& container, PyObject* i_) {