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

Initial Commit of Indexing Suite

[SVN r19296]
This commit is contained in:
Joel de Guzman
2003-07-24 12:02:57 +00:00
parent 3b33f54fb8
commit 957549460b
6 changed files with 1258 additions and 0 deletions

View File

@@ -0,0 +1,362 @@
// (C) Copyright Joel de Guzman 2003.
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies. This
// software is provided "as is" without express or implied warranty, and
// with no claim as to its suitability for any purpose.
#ifndef INDEXING_SUITE_DETAIL_JDG20036_HPP
# define INDEXING_SUITE_DETAIL_JDG20036_HPP
# include <boost/python/extract.hpp>
# include <boost/scoped_ptr.hpp>
# include <boost/detail/binary_search.hpp>
# include <vector>
# include <map>
namespace boost { namespace python { namespace detail {
template <class Proxy>
struct compare_proxy_index
{
// This functor compares a proxy and an index.
// This is used by proxy_group::first_proxy to
// get first proxy with index i.
template <class Index>
bool operator()(PyObject* prox, Index i) const
{
return extract<Proxy&>(prox)().get_index() < i;
}
};
// The proxy_group class holds a vector of container element
// proxies. First, what is a container element proxy? A container
// element proxy acts like a smart pointer holding a reference to
// a container and an index (see container_element, for details).
//
// The proxies are held in a vector always sorted by its index.
// Various functions manage the addition, removal and searching
// of proxies from the vector.
//
template <class Proxy>
class proxy_group
{
public:
typedef typename std::vector<PyObject*>::iterator iterator;
typedef typename Proxy::index_type index_type;
typedef typename Proxy::policies_type policies_type;
iterator
first_proxy(index_type i)
{
// Return the first proxy with index <= i
return boost::detail::lower_bound(
proxies.begin(), proxies.end(),
i, compare_proxy_index<Proxy>());
}
void
remove(Proxy& proxy)
{
// Remove a proxy
for (iterator iter = first_proxy(proxy.get_index());
iter != proxies.end(); ++iter)
{
if (&extract<Proxy&>(*iter)() == &proxy)
{
proxies.erase(iter);
break;
}
}
}
void
add(PyObject* prox)
{
// Add a proxy
proxies.insert(
first_proxy(extract<Proxy&>(prox)().get_index()), prox);
}
void
erase(index_type from, index_type to)
{
// Erase all proxies with indexes from..to
replace(from, to, 0);
}
void
replace(
index_type from,
index_type to,
typename std::vector<PyObject*>::size_type len)
{
// Erase all proxies with indexes from..to.
// Adjust the displaced indexes such that the
// final effect is that we have inserted *len*
// number of proxies in the vacated region. This
// procedure involves adjusting the indexes of
// the proxies.
iterator left = first_proxy(from);
iterator right = proxies.end(); // we'll adjust this later
for (iterator iter = left; iter != right; ++iter)
{
if (extract<Proxy&>(*iter)().get_index() > to)
{
right = iter; // adjust right
break;
}
extract<Proxy&>(*iter)().detach();
}
typename std::vector<PyObject*>::size_type
offset = left-proxies.begin();
proxies.erase(left, right);
right = proxies.begin()+offset;
while (right != proxies.end())
{
extract<Proxy&>(*right)().set_index(
policies_type::adjust_index(
extract<Proxy&>(*right)().get_index(), from, to, len));
++right;
}
}
PyObject*
find(index_type i)
{
// Find the proxy with *exact* index i.
// Return 0 (null) if no proxy with the
// given index is found.
iterator iter = first_proxy(i);
if (iter != proxies.end()
&& extract<Proxy&>(*iter)().get_index() == i)
return *iter;
return 0;
}
typename std::vector<PyObject*>::size_type
size() const
{
// How many proxies are there so far?
return proxies.size();
}
private:
std::vector<PyObject*> proxies;
};
// proxy_links holds a map of Container pointers (keys)
// with proxy_group(s) (data). Various functions manage
// the addition, removal and searching of proxies from
// the map.
//
template <class Proxy, class Container>
class proxy_links
{
public:
typedef std::map<Container*, proxy_group<Proxy> > links_t;
typedef typename Proxy::index_type index_type;
void
remove(Proxy& proxy)
{
// Remove a proxy.
links_t::iterator r = links.find(&proxy.get_container());
if (r != links.end())
{
r->second.remove(proxy);
if (r->second.size() == 0)
links.erase(r);
}
}
void
add(PyObject* prox, Container& container)
{
// Add a proxy
links[&container].add(prox);
}
void
erase(Container& container, index_type from, index_type to)
{
// Erase all proxies with indexes from..to
links_t::iterator r = links.find(&container);
if (r != links.end())
{
r->second.erase(from, to);
if (r->second.size() == 0)
links.erase(r);
}
}
void
replace(
Container& container,
index_type from, index_type to, index_type len)
{
// Erase all proxies with indexes from..to.
// Adjust the displaced indexes such that the
// final effect is that we have inserted *len*
// number of proxies in the vacated region. This
// procedure involves adjusting the indexes of
// the proxies.
links_t::iterator r = links.find(&container);
if (r != links.end())
{
r->second.replace(from, to, len);
if (r->second.size() == 0)
links.erase(r);
}
}
PyObject*
find(Container& container, index_type i)
{
// Find the proxy with *exact* index i.
// Return 0 (null) if no proxy with the given
// index is found.
links_t::iterator r = links.find(&container);
if (r != links.end())
return r->second.find(i);
return 0;
}
private:
links_t links;
};
// container_element is our container proxy class.
// This class acts like a smart pointer to a container
// element. The class holds an index and a reference to
// a container. Dereferencing the smart pointer will
// retrieve the nth (index) element from the container.
//
// A container_element can also be detached from the
// container. In such a detached state, the container_element
// holds a copy of the nth (index) element, which it
// returns when dereferenced.
//
template <class Container, class Index, class Policies>
class container_element
{
public:
typedef Index index_type;
typedef typename Container::value_type element_type;
typedef typename Policies policies_type;
typedef container_element<Container, Index, Policies> self_t;
typedef proxy_group<self_t> links_type;
container_element(object container, Index index)
: ptr()
, container(container)
, index(index)
{
}
container_element(container_element const& ce)
: ptr(ce.ptr.get() == 0 ? 0 : new element_type(*ce.ptr.get()))
, container(ce.container)
, index(ce.index)
{
}
~container_element()
{
if (!is_detached())
get_links().remove(*this);
}
element_type& operator*() const
{
if (is_detached())
return *ptr.get();
return Policies::get_item(get_container(), index);
}
element_type* get() const
{
if (is_detached())
return ptr.get();
return &Policies::get_item(get_container(), index);
}
void
detach()
{
if (!is_detached())
{
ptr.reset(
new element_type(
Policies::get_item(get_container(), index)));
container = object(); // free container. reset it to None
}
}
bool
is_detached() const
{
return ptr.get() != 0;
}
Container&
get_container() const
{
return extract<Container&>(container)();
}
Index
get_index() const
{
return index;
}
void
set_index(Index i)
{
index = i;
}
static proxy_links<self_t, Container>&
get_links()
{
// All container_element(s) maintain links to
// its container in a global map (see proxy_links).
// This global "links" map is a singleton.
static proxy_links<self_t, Container> links;
return links; // singleton
}
private:
container_element& operator=(container_element const& ce);
scoped_ptr<element_type> ptr;
object container;
Index index;
};
} // namespace detail
template <class Container, class Index, class Policies>
inline typename Container::value_type*
get_pointer(detail::container_element<Container, Index, Policies> const& p)
{
// Get the pointer of a container_element smart pointer
return p.get();
}
}} // namespace boost::python
#endif // INDEXING_SUITE_DETAIL_JDG20036_HPP

View File

@@ -0,0 +1,407 @@
// (C) Copyright Joel de Guzman 2003.
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies. This
// software is provided "as is" without express or implied warranty, and
// with no claim as to its suitability for any purpose.
#ifndef INDEXING_SUITE_JDG20036_HPP
# define INDEXING_SUITE_JDG20036_HPP
# include <boost/python/class.hpp>
# include <boost/python/register_ptr_to_python.hpp>
# include <boost/python/indexing/detail/indexing_suite_detail.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
// feel and behave exactly as we'd expect a Python container.
// By default indexed elements are returned by proxy. This can be
// disabled by supplying *true* in the NoProxy template parameter.
//
// Derived classes provide the hooks needed by the indexing_suite
// to do its job:
//
// static element_type&
// get_item(Container& container, index_type i);
//
// static object
// get_slice(Container& container, index_type from, index_type to);
//
// static void
// set_item(Container& container, index_type i, element_type const& v);
//
// static void
// set_slice(
// Container& container, index_type from,
// index_type to, element_type const& v
// );
//
// template <class Iter>
// static void
// set_slice(Container& container, index_type from,
// index_type to, Iter first, Iter last
// );
//
// static void
// delete_item(Container& container, index_type i);
//
// static void
// delete_slice(Container& container, index_type from, index_type to);
//
// static size_t
// size(Container& container);
//
// static index_type
// convert_index(Container& container, PyObject* i);
//
// static index_type
// adjust_index(index_type current, index_type from,
// index_type to, size_type len
// );
//
// Most of these policies are self explanatory. convert_index and
// adjust_index, however, deserves some explanation.
//
// convert_index converts an Python index into a C++ index that the
// container can handle. For instance, negative indexes in Python, by
// convention, indexes from the right (e.g. C[-1] indexes the rightmost
// element in C). convert_index should handle the necessary conversion
// for the C++ container (e.g. convert -1 to C.size()-1). convert_index
// should also be able to convert the type of the index (A dynamic Python
// type) to the actual type that the C++ container expects.
//
// When a container expands or contracts, held indexes to its elements
// must be adjusted to follow the movement of data. For instance, if
// we erase 3 elements, starting from index 0 from a 5 element vector,
// what used to be at index 4 will now be at index 1:
//
// [a][b][c][d][e] ---> [d][e]
// ^ ^
// 4 1
//
// adjust_index takes care of the adjustment. Given a current index,
// 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
, class Element = typename Container::value_type
, class Index = typename Container::size_type
>
class indexing_suite
: public def_arg<
indexing_suite<
Container
, DerivedPolicies
, NoProxy
, Element
, Index
> >
{
public:
typedef detail::container_element<Container, Index, DerivedPolicies>
container_element_t;
template <class Class>
void visit(Class& cl) const
{
// Hook into the class_ generic visitation .def function
register_ptr_to_python<container_element_t>();
cl
.def("__len__", base_size)
.def("__setitem__", &base_set_item)
.def("__delitem__", &base_delete_item)
.def("__getitem__", &base_get_item)
;
}
private:
typedef boost::mpl::bool_<NoProxy> no_proxy;
static object
base_get_item_(
back_reference<Container&> const& container,
PyObject* i, boost::mpl::false_)
{
// Proxy
Index idx = DerivedPolicies::convert_index(container.get(), i);
if (PyObject* shared =
container_element_t::get_links().find(container.get(), idx))
{
return extract<object>(shared);
}
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, boost::mpl::true_)
{
// No Proxy
return object(
DerivedPolicies::get_item(
container, 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(
container.get(), reinterpret_cast<PySliceObject*>(i));
return base_get_item_(container, i,
boost::mpl::or_<
no_proxy
, boost::mpl::or_<
boost::is_integral<Element>
, boost::is_float<Element>
, boost::is_pointer<Element>
, boost::is_member_pointer<Element>
, boost::is_enum<Element>
>
>());
}
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
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,
reinterpret_cast<PySliceObject*>(i), v);
}
else
{
extract<Element&> elem(v);
// try if elem is an exact Element
if (elem.check())
{
DerivedPolicies::
set_item(container,
DerivedPolicies::
convert_index(container, i), elem());
}
else
{
// try to convert elem to Element
extract<Element> elem(v);
if (elem.check())
{
DerivedPolicies::
set_item(container,
DerivedPolicies::
convert_index(container, i), elem());
}
else
{
PyErr_SetString(PyExc_TypeError, "Invalid assignment");
throw_error_already_set();
}
}
}
}
static void
base_replace_indexes(
Container& container, Index from,
Index to, Index n, boost::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, boost::mpl::true_)
{
// No Proxy
}
static void
base_erase_indexes(
Container& container, Index from, Index to, boost::mpl::false_)
{
// Proxy
container_element_t::get_links().erase(container, from, to);
}
static void
base_erase_indexes(
Container& container, Index from, Index to, boost::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_(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 list 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));
return;
}
Index index = DerivedPolicies::convert_index(container, i);
base_erase_indexes(container, index, index+1, no_proxy());
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)
{
return DerivedPolicies::size(container);
}
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

@@ -0,0 +1,141 @@
// (C) Copyright Joel de Guzman 2003.
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies. This
// software is provided "as is" without express or implied warranty, and
// with no claim as to its suitability for any purpose.
#ifndef VECTOR_INDEXING_SUITE_JDG20036_HPP
# define VECTOR_INDEXING_SUITE_JDG20036_HPP
# include <boost/python/indexing/indexing_suite.hpp>
namespace boost { namespace python {
// Forward declaration
template <class Container, bool NoProxy, class DerivedPolicies>
class vector_indexing_suite;
namespace detail
{
template <class Container, bool NoProxy>
class final
: public vector_indexing_suite<Container,
NoProxy, final<Container, NoProxy> > {};
}
// The vector_indexing_suite class is a predefined indexing_suite derived
// class for wrapping std::vector (and std::vector like) classes. It provides
// all the policies required by the indexing_suite (see indexing_suite).
// Example usage:
//
// class X {...}
//
// ...
//
// class_<std::vector<X> >("XVec")
// .def(vector_indexing_suite<std::vector<X> >())
// ;
//
// By default indexed elements are returned by proxy. This can be
// disabled by supplying *true* in the NoProxy template parameter.
//
template <
class Container,
bool NoProxy = false,
class DerivedPolicies = detail::final<Container, NoProxy> >
class vector_indexing_suite
: public indexing_suite<Container, DerivedPolicies, NoProxy>
{
public:
typedef typename Container::value_type element_type;
typedef typename Container::size_type index_type;
typedef typename Container::size_type size_type;
typedef typename Container::difference_type difference_type;
static element_type&
get_item(Container& container, index_type i)
{
return container[i];
}
static object
get_slice(Container& container, index_type from, index_type to)
{
return object(Container(container.begin(), container.end()));
}
static void
set_item(Container& container, index_type i, element_type const& v)
{
container[i] = v;
}
static void
set_slice(Container& container, index_type from,
index_type to, element_type const& v)
{
container.erase(container.begin()+from, container.begin()+to);
container.insert(container.begin()+from, v);
}
template <class Iter>
static void
set_slice(Container& container, index_type from,
index_type to, Iter first, Iter last)
{
container.erase(container.begin()+from, container.begin()+to);
container.insert(container.begin()+from, first, last);
}
static void
delete_item(Container& container, index_type i)
{
container.erase(container.begin()+i);
}
static void
delete_slice(Container& container, index_type from, index_type to)
{
container.erase(container.begin()+from, container.begin()+to);
}
static size_t
size(Container& container)
{
return container.size();
}
static index_type
convert_index(Container& container, PyObject* i_)
{
extract<long> i(i_);
if (i.check())
{
long index = i();
if (index < 0)
index += DerivedPolicies::size(container);
if (index >= container.size() || index < 0)
{
PyErr_SetString(PyExc_IndexError, "Index out of range");
throw_error_already_set();
}
return index;
}
PyErr_SetString(PyExc_TypeError, "Invalid index type");
throw_error_already_set();
return index_type();
}
static index_type
adjust_index(index_type current, index_type from,
index_type to, size_type len)
{
return current - (difference_type(to) - from - len);
}
};
}} // namespace boost::python
#endif // VECTOR_INDEXING_SUITE_JDG20036_HPP

View File

@@ -141,6 +141,8 @@ bpl-test nested ;
bpl-test docstring ;
bpl-test vector_indexing_suite ;
if $(TEST_BIENSTMAN_NON_BUGS)
{
bpl-test bienstman4 ;

View File

@@ -0,0 +1,40 @@
#include <boost/python/indexing/vector_indexing_suite.hpp>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include <boost/python/implicit.hpp>
using namespace boost::python;
struct X // a container element
{
std::string s;
X():s("default") {}
X(std::string s):s(s) {}
std::string repr() const { return s; }
void reset() { s = "reset"; }
void foo() { s = "foo"; }
};
std::string x_value(X const& x)
{
return "gotya " + x.s;
}
BOOST_PYTHON_MODULE(vector_indexing_suite_ext)
{
class_<X>("X")
.def(init<>())
.def(init<X>())
.def(init<std::string>())
.def("__repr__", &X::repr)
.def("reset", &X::reset)
.def("foo", &X::foo)
;
def("x_value", x_value);
implicitly_convertible<std::string, X>();
class_<std::vector<X> >("XVec")
.def(vector_indexing_suite<std::vector<X> >())
;
}

View File

@@ -0,0 +1,306 @@
'''
#####################################################################
# Check an object that we will use as container element
#####################################################################
>>> from vector_indexing_suite_ext import *
>>> x = X('hi')
>>> x
hi
>>> x.reset() # a member function that modifies X
>>> x
reset
>>> x.foo() # another member function that modifies X
>>> x
foo
# test that a string is implicitly convertible
# to an X
>>> x_value('bochi bochi')
'gotya bochi bochi'
#####################################################################
# Utility
#####################################################################
>>> def print_xvec(xvec):
... s = '[ '
... for x in xvec:
... s += repr(x)
... s += ' '
... s += ']'
... print s
#####################################################################
# Replace all the contents using slice syntax
#####################################################################
>>> v = XVec()
>>> v[:] = [X('a'),X('b'),X('c'),X('d'),X('e')]
>>> print_xvec(v)
[ a b c d e ]
#####################################################################
# Indexing
#####################################################################
>>> len(v)
5
>>> v[0]
a
>>> v[1]
b
>>> v[2]
c
>>> v[3]
d
>>> v[4]
e
>>> v[-1]
e
>>> v[-2]
d
>>> v[-3]
c
>>> v[-4]
b
>>> v[-5]
a
#####################################################################
# Deleting an element
#####################################################################
>>> del v[0]
>>> v[0] = 'yaba' # must do implicit conversion
>>> print_xvec(v)
[ yaba c d e ]
#####################################################################
# Calling a mutating function of a container element
#####################################################################
>>> v[3].reset()
>>> v[3]
reset
#####################################################################
# Copying a container element
#####################################################################
>>> x = X(v[3])
>>> x
reset
>>> x.foo()
>>> x
foo
>>> v[3] # should not be changed to 'foo'
reset
#####################################################################
# Referencing a container element
#####################################################################
>>> x = v[3]
>>> x
reset
>>> x.foo()
>>> x
foo
>>> v[3] # should be changed to 'foo'
foo
#####################################################################
# Slice
#####################################################################
>>> sl = v[0:2]
>>> print_xvec(v)
[ yaba c d foo ]
>>> sl[0].reset()
>>> sl[0]
reset
#####################################################################
# Reset the container again
#####################################################################
>>> v[:] = ['a','b','c','d','e'] # perform implicit conversion to X
>>> print_xvec(v)
[ a b c d e ]
#####################################################################
# Slice: replace [1:3] with an element
#####################################################################
>>> v[1:3] = X('z')
>>> print_xvec(v)
[ a z d e ]
#####################################################################
# Slice: replace [0:2] with a list
#####################################################################
>>> v[0:2] = ['1','2','3','4'] # perform implicit conversion to X
>>> print_xvec(v)
[ 1 2 3 4 d e ]
#####################################################################
# Slice: delete [3:4]
#####################################################################
>>> del v[3:4]
>>> print_xvec(v)
[ 1 2 3 d e ]
#####################################################################
# Slice: set [3:] to a list
#####################################################################
>>> v[3:] = [X('trailing'), X('stuff')] # a list
>>> print_xvec(v)
[ 1 2 3 trailing stuff ]
#####################################################################
# Slice: delete [:3]
#####################################################################
>>> del v[:3]
>>> print_xvec(v)
[ trailing stuff ]
#####################################################################
# Slice: insert a tuple to [0:0]
#####################################################################
>>> v[0:0] = ('leading','stuff') # can also be a tuple
>>> print_xvec(v)
[ leading stuff trailing stuff ]
#####################################################################
# Reset the container again
#####################################################################
>>> v[:] = ['a','b','c','d','e']
#####################################################################
# Some references to the container elements
#####################################################################
>>> z0 = v[0]
>>> z1 = v[1]
>>> z2 = v[2]
>>> z3 = v[3]
>>> z4 = v[4]
>>> z0 # proxy
a
>>> z1 # proxy
b
>>> z2 # proxy
c
>>> z3 # proxy
d
>>> z4 # proxy
e
#####################################################################
# Delete a container element
#####################################################################
>>> del v[2]
>>> print_xvec(v)
[ a b d e ]
#####################################################################
# Show that the references are still valid
#####################################################################
>>> z0 # proxy
a
>>> z1 # proxy
b
>>> z2 # proxy detached
c
>>> z3 # proxy index adjusted
d
>>> z4 # proxy index adjusted
e
#####################################################################
# Delete all container elements
#####################################################################
>>> del v[:]
>>> print_xvec(v)
[ ]
#####################################################################
# Show that the references are still valid
#####################################################################
>>> z0 # proxy detached
a
>>> z1 # proxy detached
b
>>> z2 # proxy detached
c
>>> z3 # proxy detached
d
>>> z4 # proxy detached
e
#####################################################################
# Reset the container again
#####################################################################
>>> v[:] = ['a','b','c','d','e']
#####################################################################
# renew the references to the container elements
#####################################################################
>>> z0 = v[0]
>>> z1 = v[1]
>>> z2 = v[2]
>>> z3 = v[3]
>>> z4 = v[4]
>>> z0 # proxy
a
>>> z1 # proxy
b
>>> z2 # proxy
c
>>> z3 # proxy
d
>>> z4 # proxy
e
#####################################################################
# Set [2:4] to a list such that there will be more elements
#####################################################################
>>> v[2:4] = ['x','y','v']
>>> print_xvec(v)
[ a b x y v e ]
#####################################################################
# Show that the references are still valid
#####################################################################
>>> z0 # proxy
a
>>> z1 # proxy
b
>>> z2 # proxy detached
c
>>> z3 # proxy detached
d
>>> z4 # proxy index adjusted
e
#####################################################################
# END....
#####################################################################
'''
def run(args = None):
import sys
import doctest
if args is not None:
sys.argv = args
return doctest.testmod(sys.modules.get(__name__))
if __name__ == '__main__':
print 'running...'
import sys
sys.exit(run()[0])