2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-23 05:42:30 +00:00

Clean-up, refactored and added NoSlice option.

[SVN r19488]
This commit is contained in:
Joel de Guzman
2003-08-07 17:16:07 +00:00
parent fe0b59f559
commit 53726746b8
3 changed files with 284 additions and 220 deletions

View File

@@ -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<Container&> 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<ContainerElement>();
}
static object
base_get_item_(back_reference<Container&> 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<Element&> 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<Element> 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<Element> temp;
for (int i = 0; i < l.attr("__len__")(); i++)
{
object elem(l[i]);
extract<Element const&> 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<Element> 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 <class Container, class Index, class Policies>

View File

@@ -16,7 +16,7 @@
# include <boost/mpl/not.hpp>
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<Container>
, iterator<Container, return_internal_reference<> > >::type
def_iterator;
static void
register_container_element(mpl::false_)
{
register_ptr_to_python<container_element_t>();
}
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_<NoSlice>
, detail::slice_helper<
Container
, DerivedPolicies
, proxy_handler
, Element
, Index>
, detail::slice_helper<
Container
, DerivedPolicies
, proxy_handler
, Element
, Index> >::type
slice_handler;
public:
template <class Class>
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<Container&> 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<Container&> 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&> container, PyObject* i)
{
if (PySlice_Check(i))
return base_get_slice(
return slice_handler::base_get_slice(
container.get(), reinterpret_cast<PySliceObject*>(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<PySliceObject*>(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<Element&> 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<Element> 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<Element> temp;
for (int i = 0; i < l.attr("__len__")(); i++)
{
object elem(l[i]);
extract<Element const&> 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<Element> 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<PySliceObject*>(i));
slice_handler::base_delete_slice(
container, reinterpret_cast<PySliceObject*>(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 <class Iter>
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

View File

@@ -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_)
{